Repository: zulip/zulip

Issue:
Permissions and warning for custom emoji overriding unicode emoji
Only administrators/owners should be able to override unicode emoji

1. If an administrator attempts to override a unicode emoji with a custom emoji, they should get a warning. #16937 attempts to fix this, but it is currently not working in production.

We should also shorten the warning message and avoid referring to "unicode" to avoid confusing non-technical users:
>**Override built-in emoji?**
> Uploading a custom emoji with the name **<name>** will override the built-in **<name>** emoji. Continue?

2. If a non-administrator attempts to override an emoji, show an error in the same style as the error for overriding custom emoji (screenshot below). Text: "Failed: An emoji with this name already exists. Only administrators can override built-in emoji."

Error for overriding custom emoji:
<img width="531" alt="Screen Shot 2021-06-15 at 2 30 38 PM" src="https://user-images.githubusercontent.com/2090066/122126418-915e9880-cde6-11eb-86f6-0a4338478739.png">

Related issue: #18269
[Related CZO thread](https://chat.zulip.org/#narrow/stream/2-general/topic/ok.20emoji)



Discussion:
Hello @zulip/server-emoji, @zulip/server-settings members, this issue was labeled with the "area: emoji", "area: settings (admin/org)" labels, so you may want to check it out!

<!-- areaLabelAddition -->
@aryanshridhar FYI
Thanks alya!
@zulipbot claim

Resolving patch:
diff --git a/zerver/views/realm_emoji.py b/zerver/views/realm_emoji.py
--- a/zerver/views/realm_emoji.py
+++ b/zerver/views/realm_emoji.py
@@ -4,7 +4,7 @@
 
 from zerver.decorator import require_member_or_admin
 from zerver.lib.actions import check_add_realm_emoji, do_remove_realm_emoji
-from zerver.lib.emoji import check_emoji_admin, check_valid_emoji_name
+from zerver.lib.emoji import check_emoji_admin, check_valid_emoji_name, name_to_codepoint
 from zerver.lib.request import REQ, JsonableError, has_request_variables
 from zerver.lib.response import json_success
 from zerver.models import RealmEmoji, UserProfile
@@ -23,6 +23,7 @@ def upload_emoji(
     request: HttpRequest, user_profile: UserProfile, emoji_name: str = REQ(path_only=True)
 ) -> HttpResponse:
     emoji_name = emoji_name.strip().replace(" ", "_")
+    valid_built_in_emoji = name_to_codepoint.keys()
     check_valid_emoji_name(emoji_name)
     check_emoji_admin(user_profile)
     if RealmEmoji.objects.filter(
@@ -31,6 +32,9 @@ def upload_emoji(
         raise JsonableError(_("A custom emoji with this name already exists."))
     if len(request.FILES) != 1:
         raise JsonableError(_("You must upload exactly one file."))
+    if emoji_name in valid_built_in_emoji:
+        if not user_profile.is_realm_admin:
+            raise JsonableError(_("Only administrators can override built-in emoji."))
     emoji_file = list(request.FILES.values())[0]
     if (settings.MAX_EMOJI_FILE_SIZE_MIB * 1024 * 1024) < emoji_file.size:
         raise JsonableError(


Test patch:
diff --git a/zerver/tests/test_realm_emoji.py b/zerver/tests/test_realm_emoji.py
--- a/zerver/tests/test_realm_emoji.py
+++ b/zerver/tests/test_realm_emoji.py
@@ -79,6 +79,28 @@ def test_upload(self) -> None:
         author = UserProfile.objects.get(id=test_emoji["author_id"])
         self.assertEqual(author.email, email)
 
+    def test_override_built_in_emoji_by_admin(self) -> None:
+        # Test that only administrators can override built-in emoji.
+        self.login("othello")
+        with get_test_image_file("img.png") as fp1:
+            emoji_data = {"f1": fp1}
+            result = self.client_post("/json/realm/emoji/laughing", info=emoji_data)
+        self.assert_json_error(
+            result,
+            "Only administrators can override built-in emoji.",
+        )
+
+        user = self.example_user("iago")
+        email = user.email
+        self.login_user(user)
+        with get_test_image_file("img.png") as fp1:
+            emoji_data = {"f1": fp1}
+            result = self.client_post("/json/realm/emoji/smile", info=emoji_data)
+        self.assert_json_success(result)
+        self.assertEqual(200, result.status_code)
+        realm_emoji = RealmEmoji.objects.get(name="smile")
+        self.assertEqual(realm_emoji.author.email, email)
+
     def test_realm_emoji_repr(self) -> None:
         realm_emoji = RealmEmoji.objects.get(name="green_tick")
         file_name = str(realm_emoji.id) + ".png"