diff --git a/static/images/email-gateway-bot.png b/static/images/email-gateway-bot.png deleted file mode 100644 index ce10f48fc2..0000000000 Binary files a/static/images/email-gateway-bot.png and /dev/null differ diff --git a/static/images/static_avatars/emailgateway-medium.png b/static/images/static_avatars/emailgateway-medium.png new file mode 100644 index 0000000000..348f0f2ff5 Binary files /dev/null and b/static/images/static_avatars/emailgateway-medium.png differ diff --git a/static/images/static_avatars/emailgateway.png b/static/images/static_avatars/emailgateway.png new file mode 100644 index 0000000000..9e3f840c4c Binary files /dev/null and b/static/images/static_avatars/emailgateway.png differ diff --git a/static/images/static_avatars/notification-bot-medium.png b/static/images/static_avatars/notification-bot-medium.png new file mode 100644 index 0000000000..74edb620e5 Binary files /dev/null and b/static/images/static_avatars/notification-bot-medium.png differ diff --git a/static/images/static_avatars/notification-bot.png b/static/images/static_avatars/notification-bot.png new file mode 100644 index 0000000000..e179b5fc8d Binary files /dev/null and b/static/images/static_avatars/notification-bot.png differ diff --git a/static/images/static_avatars/welcome-bot-medium.png b/static/images/static_avatars/welcome-bot-medium.png new file mode 100644 index 0000000000..df0252864d Binary files /dev/null and b/static/images/static_avatars/welcome-bot-medium.png differ diff --git a/static/images/static_avatars/welcome-bot.png b/static/images/static_avatars/welcome-bot.png new file mode 100644 index 0000000000..dfc7f27c56 Binary files /dev/null and b/static/images/static_avatars/welcome-bot.png differ diff --git a/static/images/welcome-bot.png b/static/images/welcome-bot.png deleted file mode 100644 index 4a65e65d97..0000000000 Binary files a/static/images/welcome-bot.png and /dev/null differ diff --git a/zerver/lib/avatar.py b/zerver/lib/avatar.py index f33cdc6c22..33533af0fc 100644 --- a/zerver/lib/avatar.py +++ b/zerver/lib/avatar.py @@ -12,14 +12,11 @@ from zerver.lib.thumbnail import MEDIUM_AVATAR_SIZE from zerver.lib.upload import get_avatar_url from zerver.lib.url_encoding import append_url_query_string from zerver.models import UserProfile +from zerver.models.users import is_cross_realm_bot_email -SYSTEM_BOTS_AVATAR_FILES = { - # This is also used in zerver/lib/storage.py to ensure - # these files are hashed when served as static files. - settings.WELCOME_BOT: "images/welcome-bot.png", - settings.NOTIFICATION_BOT: "images/logo/zulip-icon-square.svg", - settings.EMAIL_GATEWAY_BOT: "images/email-gateway-bot.png", -} +STATIC_AVATARS_DIR = "images/static_avatars/" + +DEFAULT_AVATAR_FILE = "images/default-avatar.png" def avatar_url( @@ -36,6 +33,22 @@ def avatar_url( ) +def get_system_bots_avatar_file_name(email: str) -> str: + system_bot_avatar_name_map = { + settings.WELCOME_BOT: "welcome-bot", + settings.NOTIFICATION_BOT: "notification-bot", + settings.EMAIL_GATEWAY_BOT: "emailgateway", + } + return urljoin(STATIC_AVATARS_DIR, system_bot_avatar_name_map.get(email, "unknown")) + + +def get_static_avatar_url(email: str, medium: bool) -> str: + avatar_file_name = get_system_bots_avatar_file_name(email) + avatar_file_name += "-medium.png" if medium else ".png" + + return staticfiles_storage.url(avatar_file_name) + + def get_avatar_field( user_id: int, realm_id: int, @@ -63,9 +76,8 @@ def get_avatar_field( """ # System bots have hardcoded avatars - system_bot_avatar = SYSTEM_BOTS_AVATAR_FILES.get(email) - if system_bot_avatar: - return staticfiles_storage.url(system_bot_avatar) + if is_cross_realm_bot_email(email): + return get_static_avatar_url(email, medium) """ If our client knows how to calculate gravatar hashes, we diff --git a/zerver/lib/storage.py b/zerver/lib/storage.py index 956b62ed96..abd7b1d06f 100644 --- a/zerver/lib/storage.py +++ b/zerver/lib/storage.py @@ -10,7 +10,7 @@ from django.core.files.base import File from django.core.files.storage import FileSystemStorage from typing_extensions import override -from zerver.lib.avatar import SYSTEM_BOTS_AVATAR_FILES +from zerver.lib.avatar import STATIC_AVATARS_DIR if settings.DEBUG: from django.contrib.staticfiles.finders import find @@ -40,11 +40,11 @@ class IgnoreBundlesManifestStaticFilesStorage(ManifestStaticFilesStorage): # use a no-op hash function for these already-hashed # assets. return name - if name in SYSTEM_BOTS_AVATAR_FILES.values(): + if name.startswith(STATIC_AVATARS_DIR): # For these avatar files, we want to make sure they are # so they can hit our Nginx caching block for static files. - # We don't need to worry about stale caches since system bot - # avatars rarely change. + # We don't need to worry about stale caches since these are + # only used by the system bots. return super().hashed_name(name, content, filename) if name == "generated/emoji/emoji_api.json": # Unlike most .json files, we do want to hash this file; diff --git a/zerver/tests/test_upload.py b/zerver/tests/test_upload.py index a6acaa5021..2b172c0668 100644 --- a/zerver/tests/test_upload.py +++ b/zerver/tests/test_upload.py @@ -1532,6 +1532,29 @@ class AvatarTest(UploadSerializeMixin, ZulipTestCase): result = self.client_post("/json/users/me/avatar", {"file": fp}) self.assert_json_error(result, "Uploaded file is larger than the allowed limit of 0 MiB") + def test_system_bot_avatars_url(self) -> None: + self.login("hamlet") + system_bot_emails = [ + settings.NOTIFICATION_BOT, + settings.WELCOME_BOT, + settings.EMAIL_GATEWAY_BOT, + ] + internal_realm = get_realm(settings.SYSTEM_BOT_REALM) + + for email in system_bot_emails: + system_bot = get_system_bot(email, internal_realm.id) + response = self.client_get(f"/avatar/{email}") + redirect_url = response["Location"] + self.assertEqual(redirect_url, str(avatar_url(system_bot))) + self.assertTrue(str(redirect_url).endswith(".png")) + self.assertFalse(str(redirect_url).endswith("unknown.png")) + + response = self.client_get(f"/avatar/{email}/medium") + redirect_url = response["Location"] + self.assertEqual(redirect_url, str(avatar_url(system_bot, medium=True))) + self.assertTrue(str(redirect_url).endswith("-medium.png")) + self.assertFalse(str(redirect_url).endswith("unknown-medium.png")) + class RealmIconTest(UploadSerializeMixin, ZulipTestCase): def test_multiple_upload_failure(self) -> None: