refactor(webapp): remove emoji web app logo option

Drop the emoji-logo feature (and its font picker) from the Web App. Only
an uploaded/linked image logo and favicon remain; when no logo is set,
the default project logo is shown. Existing emoji-logo overrides are
ignored — the keys are gone from the manifest, so the override service
skips them and the app falls back to the default logo.

- Remove WEBAPP_LOGO_USE_EMOJI / WEBAPP_LOGO_EMOJI / WEBAPP_LOGO_EMOJI_FONT
  settings, validators, manifest entries and override/runtime plumbing.
- Strip the animated-emoji fetch/cache subsystem, the /webapp-emoji route
  and emoji branches from logo/favicon resolution; leftover emoji cache
  files are now purged on appearance save.
- Simplify BrandMark to an image-only component and drop the emoji UI
  from the admin Appearance section.
- Regenerate the demo settings manifest and clean docs, locales, nginx
  and demo data of emoji-logo references.
This commit is contained in:
3252a8
2026-06-03 10:55:52 +03:00
parent 58de153370
commit 101119911a
39 changed files with 50 additions and 1356 deletions
-1
View File
@@ -35,7 +35,6 @@ def _settings(default_language: str = "ru"):
DEFAULT_LANGUAGE=default_language,
EMAIL_CODE_TTL_SECONDS=600,
WEBAPP_LOGO_URL="",
WEBAPP_LOGO_USE_EMOJI=False,
WEBAPP_PRIMARY_COLOR="#00fe7a",
WEBAPP_TITLE="Mini Shop",
)
-1
View File
@@ -206,7 +206,6 @@ def test_email_templates_use_override_only_language_without_base_locale_file(tmp
DEFAULT_LANGUAGE="ru",
EMAIL_CODE_TTL_SECONDS=600,
WEBAPP_LOGO_URL="",
WEBAPP_LOGO_USE_EMOJI=False,
WEBAPP_PRIMARY_COLOR="#00fe7a",
WEBAPP_TITLE="Remnawave",
)
-1
View File
@@ -342,7 +342,6 @@ class WebAppSecurityTests(unittest.IsolatedAsyncioTestCase):
DEFAULT_LANGUAGE="ru",
EMAIL_CODE_TTL_SECONDS=600,
WEBAPP_LOGO_URL="",
WEBAPP_LOGO_USE_EMOJI=False,
WEBAPP_PRIMARY_COLOR="#00fe7a",
WEBAPP_TITLE="Remnawave",
)
-7
View File
@@ -127,9 +127,6 @@ class SettingsTests(unittest.TestCase):
POSTGRES_PASSWORD="app_password",
WEBAPP_PRIMARY_COLOR="#ff0000",
WEBAPP_LOGO_URL="https://cdn.example.com/logo.png",
WEBAPP_LOGO_USE_EMOJI=True,
WEBAPP_LOGO_EMOJI="🔥",
WEBAPP_LOGO_EMOJI_FONT="twemoji",
WEBAPP_FAVICON_USE_CUSTOM=True,
WEBAPP_FAVICON_URL="https://cdn.example.com/favicon.png",
WEBAPP_LOGO_FAVICON_URL="/webapp-favicon/abcdef1234567890/icon-180.png",
@@ -137,9 +134,6 @@ class SettingsTests(unittest.TestCase):
self.assertEqual(settings.WEBAPP_PRIMARY_COLOR, "#00fe7a")
self.assertIsNone(settings.WEBAPP_LOGO_URL)
self.assertFalse(settings.WEBAPP_LOGO_USE_EMOJI)
self.assertEqual(settings.WEBAPP_LOGO_EMOJI, "🫥")
self.assertEqual(settings.WEBAPP_LOGO_EMOJI_FONT, "system")
self.assertFalse(settings.WEBAPP_FAVICON_USE_CUSTOM)
self.assertIsNone(settings.WEBAPP_FAVICON_URL)
self.assertIsNone(settings.WEBAPP_LOGO_FAVICON_URL)
@@ -202,7 +196,6 @@ class SettingsTests(unittest.TestCase):
POSTGRES_PASSWORD="app_password",
)
settings.WEBAPP_LOGO_URL = "/webapp-uploaded-logo/logo-1111111111111111.png"
settings.WEBAPP_LOGO_USE_EMOJI = False
settings.WEBAPP_LOGO_FAVICON_URL = "/webapp-favicon/aaaaaaaaaaaaaaaa/icon-180.png"
settings.WEBAPP_FAVICON_USE_CUSTOM = True
settings.WEBAPP_FAVICON_URL = "/webapp-favicon/bbbbbbbbbbbbbbbb/icon-180.png"
@@ -74,7 +74,6 @@ def _settings(**overrides):
SUBSCRIPTION_MINI_APP_URL="https://app.example.test/",
WEBAPP_PRIMARY_COLOR="#00fe7a",
WEBAPP_TITLE="Minishop",
WEBAPP_LOGO_USE_EMOJI=False,
WEBAPP_LOGO_URL="",
email_auth_configured=True,
**overrides,
-1
View File
@@ -38,7 +38,6 @@ def _settings(**overrides):
"WEBAPP_PRIMARY_COLOR": "#00fe7a",
"WEBAPP_TITLE": "Mini Shop",
"WEBAPP_LOGO_URL": "",
"WEBAPP_LOGO_USE_EMOJI": False,
}
values.update(overrides)
return SimpleNamespace(**values)
+7 -68
View File
@@ -351,7 +351,7 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
)
def test_default_webapp_logo_is_used_without_admin_upload(self):
settings = SimpleNamespace(WEBAPP_LOGO_USE_EMOJI=False, WEBAPP_LOGO_URL="")
settings = SimpleNamespace(WEBAPP_LOGO_URL="")
self.assertEqual(
subscription_webapp._resolve_webapp_logo_url(settings),
@@ -360,7 +360,6 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
async def test_webapp_logo_route_serves_configured_uploaded_logo(self):
settings = SimpleNamespace(
WEBAPP_LOGO_USE_EMOJI=False,
WEBAPP_LOGO_URL="/webapp-uploaded-logo/logo-1111111111111111.png",
)
request = SimpleNamespace(app={"settings": settings})
@@ -375,14 +374,6 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
self.assertEqual(response.content_type, "image/png")
self.assertEqual(response.body, b"logo")
def test_webapp_logo_is_hidden_when_emoji_logo_is_enabled(self):
settings = SimpleNamespace(
WEBAPP_LOGO_USE_EMOJI=True,
WEBAPP_LOGO_URL="/webapp-uploaded-logo/logo-abcdef1234567890.png",
)
self.assertEqual(subscription_webapp._resolve_webapp_logo_url(settings), "")
def test_custom_webapp_favicon_takes_precedence(self):
settings = SimpleNamespace(
WEBAPP_FAVICON_USE_CUSTOM=True,
@@ -470,7 +461,6 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
settings = SimpleNamespace(
WEBAPP_ENABLED=True,
WEBAPP_LOGO_URL="",
WEBAPP_LOGO_USE_EMOJI=False,
WEBAPP_FAVICON_USE_CUSTOM=True,
WEBAPP_FAVICON_URL=f"/webapp-favicon/{digest}/icon-180.png",
WEBAPP_LOGO_FAVICON_URL="",
@@ -491,7 +481,6 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
settings = SimpleNamespace(
WEBAPP_ENABLED=True,
WEBAPP_LOGO_URL="",
WEBAPP_LOGO_USE_EMOJI=False,
WEBAPP_FAVICON_USE_CUSTOM=False,
WEBAPP_FAVICON_URL="",
WEBAPP_LOGO_FAVICON_URL="",
@@ -592,16 +581,14 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
(favicons / "aaaaaaaaaaaaaaaa" / "icon-180.png").write_bytes(b"keep")
(favicons / "bbbbbbbbbbbbbbbb" / "icon-180.png").write_bytes(b"keep")
(favicons / "cccccccccccccccc" / "icon-180.png").write_bytes(b"remove")
(emoji / "1f929.512.gif").write_bytes(b"keep")
(emoji / "1f929.512.webp").write_bytes(b"keep")
# Emoji logos were removed; any leftover emoji cache files are purged.
(emoji / "1f929.512.gif").write_bytes(b"remove")
(emoji / "1f929.512.webp").write_bytes(b"remove")
(emoji / "1f525.512.gif").write_bytes(b"remove")
settings = SimpleNamespace(
WEBAPP_LOGO_URL="/webapp-uploaded-logo/logo-1111111111111111.png",
WEBAPP_FAVICON_URL="/webapp-favicon/aaaaaaaaaaaaaaaa/icon-180.png",
WEBAPP_LOGO_FAVICON_URL="/webapp-favicon/bbbbbbbbbbbbbbbb/icon-180.png",
WEBAPP_LOGO_USE_EMOJI=True,
WEBAPP_LOGO_EMOJI="🤩",
WEBAPP_LOGO_EMOJI_FONT="noto-color-animated",
)
with (
@@ -616,8 +603,8 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
self.assertTrue((favicons / "aaaaaaaaaaaaaaaa").exists())
self.assertTrue((favicons / "bbbbbbbbbbbbbbbb").exists())
self.assertFalse((favicons / "cccccccccccccccc").exists())
self.assertTrue((emoji / "1f929.512.gif").exists())
self.assertTrue((emoji / "1f929.512.webp").exists())
self.assertFalse((emoji / "1f929.512.gif").exists())
self.assertFalse((emoji / "1f929.512.webp").exists())
self.assertFalse((emoji / "1f525.512.gif").exists())
async def test_persist_appearance_upload_writes_overrides_and_clears_caches(self):
@@ -632,7 +619,6 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
)
updates = {
"WEBAPP_LOGO_URL": "/webapp-uploaded-logo/logo-1111111111111111.png",
"WEBAPP_LOGO_USE_EMOJI": False,
}
with (
@@ -709,12 +695,6 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
self.assertEqual(bumped.theme_by_key("custom").assets_version, 4)
def test_animated_emoji_asset_path_uses_same_origin_route(self):
self.assertEqual(
subscription_webapp._webapp_animated_emoji_asset_path("🤩"),
"/webapp-emoji/1f929/512.gif",
)
def test_telegram_avatar_url_uses_same_origin_account_route(self):
avatar = SimpleNamespace(
user_id=123,
@@ -1323,7 +1303,7 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
logo_url = "https://cdn.example.com/logo.png"
logo = (b"cached-logo", "image/png")
app = {
"settings": SimpleNamespace(WEBAPP_LOGO_URL=logo_url, WEBAPP_LOGO_USE_EMOJI=False),
"settings": SimpleNamespace(WEBAPP_LOGO_URL=logo_url),
"webapp_logo_cache": None,
"webapp_logo_cache_lock": asyncio.Lock(),
}
@@ -1343,44 +1323,3 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
fetch_logo.assert_not_called()
self.assertEqual(app["webapp_logo_cache"], (logo_url, logo[0], logo[1]))
def test_webapp_animated_emoji_disk_cache_roundtrip(self):
with tempfile.TemporaryDirectory() as tmpdir:
with patch.object(webapp_assets, "WEBAPP_EMOJI_CACHE_DIR", Path(tmpdir)):
subscription_webapp._write_webapp_animated_emoji_to_disk(
"1f929",
"gif",
(b"gif-bytes", "image/gif"),
)
self.assertEqual(
subscription_webapp._read_webapp_animated_emoji_from_disk("1f929", "gif"),
(b"gif-bytes", "image/gif"),
)
async def test_warm_webapp_animated_emoji_cache_uses_disk_cache(self):
with tempfile.TemporaryDirectory() as tmpdir:
app = {
"settings": SimpleNamespace(
WEBAPP_LOGO_USE_EMOJI=True,
WEBAPP_LOGO_EMOJI="🤩",
WEBAPP_LOGO_EMOJI_FONT="noto-color-animated",
),
"webapp_emoji_cache": {},
"webapp_emoji_cache_lock": asyncio.Lock(),
}
with (
patch.object(webapp_assets, "WEBAPP_EMOJI_CACHE_DIR", Path(tmpdir)),
patch.object(webapp_assets, "_fetch_webapp_animated_emoji") as fetch_emoji,
):
subscription_webapp._write_webapp_animated_emoji_to_disk(
"1f929",
"gif",
(b"cached-gif", "image/gif"),
)
await subscription_webapp._warm_webapp_animated_emoji_cache(app)
fetch_emoji.assert_not_called()
self.assertEqual(app["webapp_emoji_cache"]["1f929:gif"], (b"cached-gif", "image/gif"))
-1
View File
@@ -90,7 +90,6 @@ class WebAppRouteContractTests(unittest.TestCase):
("GET", "/robots.txt"): "robots_txt_route",
("GET", "/webapp-logo"): "webapp_logo_route",
("GET", "/webapp-uploaded-logo/{filename}"): "webapp_uploaded_logo_route",
("GET", "/webapp-emoji/{codepoints}/512.{ext}"): "webapp_animated_emoji_route",
("GET", "/subscription_webapp.css"): "css_asset_route",
("GET", "/subscription_webapp_admin.css"): "admin_css_asset_route",
("GET", "/webapp-theme-css/{path}"): "theme_css_asset_route",