mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-31 12:03:46 +00:00 
			
		
		
		
	settings: Add can_add_custom_emoji_group realm setting.
				
					
				
			Added `can_add_custom_emoji_group` setting to replace `add_custom_emoji_policy`.
This commit is contained in:
		| @@ -20,6 +20,14 @@ format used by the Zulip server that they are interacting with. | ||||
|  | ||||
| ## Changes in Zulip 10.0 | ||||
|  | ||||
| **Feature level 307** | ||||
|  | ||||
| * `PATCH /realm`, [`GET /events`](/api/get-events), | ||||
|   [`POST /register`](/api/register-queue): | ||||
|   Added `can_add_custom_emoji_group` realm setting which is a | ||||
|   [group-setting value](/api/group-setting-values) describing the set of users | ||||
|   with permission to add custom emoji in the organization. | ||||
|  | ||||
| **Feature level 306** | ||||
|  | ||||
| * [`GET /events`](/api/get-events): Removed the `extra_data` optional | ||||
|   | ||||
| @@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3" | ||||
| # new level means in api_docs/changelog.md, as well as "**Changes**" | ||||
| # entries in the endpoint's documentation in `zulip.yaml`. | ||||
|  | ||||
| API_FEATURE_LEVEL = 306  # Last bumped for adding `max_file_upload_size_mib`. | ||||
| API_FEATURE_LEVEL = 307  # Last bumped for can_add_custom_emoji_group. | ||||
|  | ||||
| # Bump the minor PROVISION_VERSION to indicate that folks should provision | ||||
| # only when going from an old version of the code to a newer version. Bump | ||||
|   | ||||
| @@ -21,6 +21,7 @@ import * as settings_sections from "./settings_sections"; | ||||
| import * as settings_toggle from "./settings_toggle"; | ||||
| import * as settings_users from "./settings_users"; | ||||
| import {current_user, realm} from "./state_data"; | ||||
| import * as user_groups from "./user_groups"; | ||||
|  | ||||
| const admin_settings_label = { | ||||
|     // Organization profile | ||||
| @@ -125,7 +126,6 @@ export function build_page() { | ||||
|         realm_require_unique_names: realm.realm_require_unique_names, | ||||
|         realm_email_changes_disabled: realm.realm_email_changes_disabled, | ||||
|         realm_avatar_changes_disabled: realm.realm_avatar_changes_disabled, | ||||
|         realm_add_custom_emoji_policy: realm.realm_add_custom_emoji_policy, | ||||
|         can_add_emojis: settings_data.user_can_add_custom_emoji(), | ||||
|         can_create_new_bots: settings_bots.can_create_new_bots(), | ||||
|         realm_message_content_edit_limit_minutes: | ||||
| @@ -186,6 +186,10 @@ export function build_page() { | ||||
|         policy_values: settings_config.common_policy_values, | ||||
|         realm_can_delete_any_message_group: realm.realm_can_delete_any_message_group, | ||||
|         realm_can_delete_own_message_group: realm.realm_can_delete_own_message_group, | ||||
|         realm_can_add_custom_emoji_group: realm.realm_can_add_custom_emoji_group, | ||||
|         realm_can_add_custom_emoji_group_name: user_groups.get_user_group_from_id( | ||||
|             realm.realm_can_add_custom_emoji_group, | ||||
|         ).name, | ||||
|         ...settings_org.get_organization_settings_options(), | ||||
|         demote_inactive_streams_values: settings_config.demote_inactive_streams_values, | ||||
|         web_mark_read_on_scroll_policy_values: | ||||
|   | ||||
| @@ -205,7 +205,6 @@ export function dispatch_normal_event(event) { | ||||
|  | ||||
|         case "realm": { | ||||
|             const realm_settings = { | ||||
|                 add_custom_emoji_policy: settings_emoji.update_custom_emoji_ui, | ||||
|                 allow_edit_history: noop, | ||||
|                 allow_message_editing: noop, | ||||
|                 edit_topic_policy: noop, | ||||
| @@ -300,6 +299,10 @@ export function dispatch_normal_event(event) { | ||||
|                                     gear_menu.rerender(); | ||||
|                                 } | ||||
|  | ||||
|                                 if (key === "can_add_custom_emoji_group") { | ||||
|                                     settings_emoji.update_custom_emoji_ui(); | ||||
|                                 } | ||||
|  | ||||
|                                 if ( | ||||
|                                     key === "can_create_public_channel_group" || | ||||
|                                     key === "can_create_private_channel_group" || | ||||
|   | ||||
| @@ -218,7 +218,6 @@ export function get_subsection_property_elements($subsection: JQuery): HTMLEleme | ||||
| type simple_dropdown_realm_settings = Pick< | ||||
|     typeof realm, | ||||
|     | "realm_invite_to_stream_policy" | ||||
|     | "realm_add_custom_emoji_policy" | ||||
|     | "realm_invite_to_realm_policy" | ||||
|     | "realm_wildcard_mention_policy" | ||||
|     | "realm_move_messages_between_streams_policy" | ||||
| @@ -482,6 +481,7 @@ const dropdown_widget_map = new Map<string, DropdownWidget | null>([ | ||||
|     ["can_remove_subscribers_group", null], | ||||
|     ["realm_can_access_all_users_group", null], | ||||
|     ["can_mention_group", null], | ||||
|     ["realm_can_add_custom_emoji_group", null], | ||||
|     ["realm_can_create_groups", null], | ||||
|     ["realm_can_create_public_channel_group", null], | ||||
|     ["realm_can_create_private_channel_group", null], | ||||
| @@ -807,6 +807,7 @@ export function check_realm_settings_property_changed(elem: HTMLElement): boolea | ||||
|         case "realm_default_code_block_language": | ||||
|         case "realm_create_multiuse_invite_group": | ||||
|         case "realm_can_access_all_users_group": | ||||
|         case "realm_can_add_custom_emoji_group": | ||||
|         case "realm_can_create_groups": | ||||
|         case "realm_can_create_public_channel_group": | ||||
|         case "realm_can_create_private_channel_group": | ||||
| @@ -1047,6 +1048,7 @@ export function populate_data_for_realm_settings_request( | ||||
|                 } | ||||
|  | ||||
|                 const realm_group_settings_using_new_api_format = new Set([ | ||||
|                     "can_add_custom_emoji_group", | ||||
|                     "can_create_groups", | ||||
|                     "can_create_private_channel_group", | ||||
|                     "can_create_public_channel_group", | ||||
|   | ||||
| @@ -240,7 +240,11 @@ export function user_can_create_user_groups(): boolean { | ||||
| } | ||||
|  | ||||
| export function user_can_add_custom_emoji(): boolean { | ||||
|     return user_has_permission(realm.realm_add_custom_emoji_policy); | ||||
|     return user_has_permission_for_group_setting( | ||||
|         realm.realm_can_add_custom_emoji_group, | ||||
|         "can_add_custom_emoji_group", | ||||
|         "realm", | ||||
|     ); | ||||
| } | ||||
|  | ||||
| export function user_can_move_messages_to_another_topic(): boolean { | ||||
|   | ||||
| @@ -18,11 +18,11 @@ import * as ListWidget from "./list_widget"; | ||||
| import * as loading from "./loading"; | ||||
| import * as people from "./people"; | ||||
| import * as scroll_util from "./scroll_util"; | ||||
| import * as settings_config from "./settings_config"; | ||||
| import * as settings_data from "./settings_data"; | ||||
| import {current_user, realm} from "./state_data"; | ||||
| import * as ui_report from "./ui_report"; | ||||
| import * as upload_widget from "./upload_widget"; | ||||
| import * as user_groups from "./user_groups"; | ||||
| import * as util from "./util"; | ||||
|  | ||||
| const meta = { | ||||
| @@ -45,8 +45,9 @@ function can_delete_emoji(emoji: ServerEmoji): boolean { | ||||
|  | ||||
| export function update_custom_emoji_ui(): void { | ||||
|     const rendered_tip = render_settings_emoji_settings_tip({ | ||||
|         realm_add_custom_emoji_policy: realm.realm_add_custom_emoji_policy, | ||||
|         policy_values: settings_config.common_policy_values, | ||||
|         realm_can_add_custom_emoji_group_name: user_groups.get_user_group_from_id( | ||||
|             realm.realm_can_add_custom_emoji_group, | ||||
|         ).name, | ||||
|     }); | ||||
|     $("#emoji-settings").find(".emoji-settings-tip-container").html(rendered_tip); | ||||
|     if (!settings_data.user_can_add_custom_emoji()) { | ||||
|   | ||||
| @@ -125,7 +125,6 @@ export function get_org_type_dropdown_options() { | ||||
|  | ||||
| const simple_dropdown_properties = [ | ||||
|     "realm_invite_to_stream_policy", | ||||
|     "realm_add_custom_emoji_policy", | ||||
|     "realm_invite_to_realm_policy", | ||||
|     "realm_wildcard_mention_policy", | ||||
|     "realm_move_messages_between_streams_policy", | ||||
| @@ -509,6 +508,7 @@ export function discard_realm_property_element_changes(elem) { | ||||
|         case "realm_create_multiuse_invite_group": | ||||
|         case "realm_direct_message_initiator_group": | ||||
|         case "realm_direct_message_permission_group": | ||||
|         case "realm_can_add_custom_emoji_group": | ||||
|         case "realm_can_access_all_users_group": | ||||
|         case "realm_can_create_groups": | ||||
|         case "realm_can_create_public_channel_group": | ||||
|   | ||||
| @@ -267,7 +267,6 @@ const realm_schema = z.object({ | ||||
|     max_topic_length: z.number(), | ||||
|     password_min_guesses: z.number(), | ||||
|     password_min_length: z.number(), | ||||
|     realm_add_custom_emoji_policy: z.number(), | ||||
|     realm_allow_edit_history: z.boolean(), | ||||
|     realm_allow_message_editing: z.boolean(), | ||||
|     realm_authentication_methods: z.record( | ||||
| @@ -287,6 +286,7 @@ const realm_schema = z.object({ | ||||
|     realm_bot_creation_policy: z.number(), | ||||
|     realm_bot_domain: z.string(), | ||||
|     realm_can_access_all_users_group: z.number(), | ||||
|     realm_can_add_custom_emoji_group: z.number(), | ||||
|     realm_can_create_groups: z.number(), | ||||
|     realm_can_create_public_channel_group: z.number(), | ||||
|     realm_can_create_private_channel_group: z.number(), | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| {{#if is_guest}} | ||||
|     <div class='tip'>{{t "Guests cannot edit custom emoji." }}</div> | ||||
| {{else if (eq realm_add_custom_emoji_policy policy_values.by_admins_only.code) }} | ||||
| {{else if (eq realm_can_add_custom_emoji_group_name "role:administrators") }} | ||||
|     <div class='tip'>{{t "This organization is configured so that only administrators can add custom emoji." }}</div> | ||||
| {{else if (eq realm_add_custom_emoji_policy policy_values.by_moderators_only.code)}} | ||||
| {{else if (eq realm_can_add_custom_emoji_group_name "role:moderators")}} | ||||
|     <div class='tip'>{{t 'This organization is configured so that administrators and moderators can add custom emoji.'}}</div> | ||||
| {{else if (eq realm_add_custom_emoji_policy policy_values.by_full_members.code)}} | ||||
| {{else if (eq realm_can_add_custom_emoji_group_name "role:fullmembers")}} | ||||
|     <div class='tip'>{{t 'This organization is configured so that full members can add custom emoji.'}}</div> | ||||
| {{else}} | ||||
|     <div class='tip'>{{t "This organization is configured so that any member of this organization can add custom emoji." }}</div> | ||||
|   | ||||
| @@ -350,12 +350,10 @@ | ||||
|                   value_type="number" | ||||
|                   is_setting_disabled=(not is_owner)}} | ||||
|  | ||||
|                 <div class="input-group"> | ||||
|                     <label for="realm_add_custom_emoji_policy" class="settings-field-label">{{t "Who can add custom emoji" }}</label> | ||||
|                     <select name="realm_add_custom_emoji_policy" class="setting-widget prop-element settings_select bootstrap-focus-style" id="id_realm_add_custom_emoji_policy" data-setting-widget-type="number"> | ||||
|                         {{> dropdown_options_widget option_values=common_policy_values}} | ||||
|                     </select> | ||||
|                 </div> | ||||
|                 {{> ../dropdown_widget_with_label | ||||
|                   widget_name="realm_can_add_custom_emoji_group" | ||||
|                   label=(t 'Who can add custom emoji') | ||||
|                   value_type="number"}} | ||||
|             </div> | ||||
|         </div> | ||||
|     </form> | ||||
|   | ||||
| @@ -462,6 +462,7 @@ run_test("realm settings", ({override}) => { | ||||
|     override(settings_org, "check_disable_direct_message_initiator_group_dropdown", noop); | ||||
|     override(settings_org, "sync_realm_settings", noop); | ||||
|     override(settings_bots, "update_bot_permissions_ui", noop); | ||||
|     override(settings_emoji, "update_custom_emoji_ui", noop); | ||||
|     override(settings_invites, "update_invite_user_panel", noop); | ||||
|     override(sidebar_ui, "update_invite_user_option", noop); | ||||
|     override(gear_menu, "rerender", noop); | ||||
| @@ -582,6 +583,7 @@ run_test("realm settings", ({override}) => { | ||||
|     override(realm, "realm_message_content_edit_limit_seconds", 0); | ||||
|     override(realm, "realm_edit_topic_policy", 3); | ||||
|     override(realm, "realm_authentication_methods", {Google: {enabled: false, available: true}}); | ||||
|     override(realm, "realm_can_add_custom_emoji_group", 1); | ||||
|     override(realm, "realm_can_create_public_channel_group", 1); | ||||
|     override(realm, "realm_direct_message_permission_group", 1); | ||||
|     override(realm, "realm_plan_type", 2); | ||||
| @@ -596,6 +598,7 @@ run_test("realm settings", ({override}) => { | ||||
|     assert_same(realm.realm_authentication_methods, { | ||||
|         Google: {enabled: true, available: true}, | ||||
|     }); | ||||
|     assert_same(realm.realm_can_add_custom_emoji_group, 3); | ||||
|     assert_same(realm.realm_can_create_public_channel_group, 3); | ||||
|     assert_same(realm.realm_direct_message_permission_group, 3); | ||||
|     assert_same(realm.realm_plan_type, 3); | ||||
|   | ||||
| @@ -368,6 +368,7 @@ exports.fixtures = { | ||||
|             authentication_methods: { | ||||
|                 Google: {enabled: true, available: true}, | ||||
|             }, | ||||
|             can_add_custom_emoji_group: 3, | ||||
|             can_create_public_channel_group: 3, | ||||
|             direct_message_permission_group: 3, | ||||
|             plan_type: 3, | ||||
|   | ||||
| @@ -167,11 +167,6 @@ test_policy( | ||||
|     "realm_move_messages_between_streams_policy", | ||||
|     settings_data.user_can_move_messages_between_streams, | ||||
| ); | ||||
| test_policy( | ||||
|     "user_can_add_custom_emoji", | ||||
|     "realm_add_custom_emoji_policy", | ||||
|     settings_data.user_can_add_custom_emoji, | ||||
| ); | ||||
|  | ||||
| function test_message_policy(label, policy, validation_func) { | ||||
|     run_test(label, ({override}) => { | ||||
| @@ -244,6 +239,11 @@ run_test("user_can_move_messages_between_streams_nobody_case", ({override}) => { | ||||
|     assert.equal(settings_data.user_can_move_messages_between_streams(), false); | ||||
| }); | ||||
|  | ||||
| test_realm_group_settings( | ||||
|     "realm_can_add_custom_emoji_group", | ||||
|     settings_data.user_can_add_custom_emoji, | ||||
| ); | ||||
|  | ||||
| test_realm_group_settings( | ||||
|     "realm_can_delete_any_message_group", | ||||
|     settings_data.user_can_delete_any_message, | ||||
|   | ||||
| @@ -102,7 +102,6 @@ function createSaveButtons(subsection) { | ||||
| function test_submit_settings_form(override, submit_form) { | ||||
|     Object.assign(realm, { | ||||
|         realm_bot_creation_policy: settings_bots.bot_creation_policy_values.restricted.code, | ||||
|         realm_add_custom_emoji_policy: settings_config.common_policy_values.by_admins_only.code, | ||||
|         realm_waiting_period_threshold: 1, | ||||
|         realm_default_language: '"es"', | ||||
|         realm_invite_to_stream_policy: settings_config.common_policy_values.by_admins_only.code, | ||||
| @@ -138,11 +137,6 @@ function test_submit_settings_form(override, submit_form) { | ||||
|     $invite_to_stream_policy_elem.attr("id", "id_realm_invite_to_stream_policy"); | ||||
|     $invite_to_stream_policy_elem.data = () => "number"; | ||||
|  | ||||
|     const $add_custom_emoji_policy_elem = $("#id_realm_add_custom_emoji_policy"); | ||||
|     $add_custom_emoji_policy_elem.val("1"); | ||||
|     $add_custom_emoji_policy_elem.attr("id", "id_realm_add_custom_emoji_policy"); | ||||
|     $add_custom_emoji_policy_elem.data = () => "number"; | ||||
|  | ||||
|     const $bot_creation_policy_elem = $("#id_realm_bot_creation_policy"); | ||||
|     $bot_creation_policy_elem.val("1"); | ||||
|     $bot_creation_policy_elem.attr("id", "id_realm_bot_creation_policy"); | ||||
| @@ -156,7 +150,6 @@ function test_submit_settings_form(override, submit_form) { | ||||
|     let $subsection_elem = $(`#org-${CSS.escape(subsection)}`); | ||||
|     $subsection_elem.set_find_results(".prop-element", [ | ||||
|         $bot_creation_policy_elem, | ||||
|         $add_custom_emoji_policy_elem, | ||||
|         $invite_to_realm_policy_elem, | ||||
|         $invite_to_stream_policy_elem, | ||||
|     ]); | ||||
| @@ -169,7 +162,6 @@ function test_submit_settings_form(override, submit_form) { | ||||
|         bot_creation_policy: 1, | ||||
|         invite_to_realm_policy: 2, | ||||
|         invite_to_stream_policy: 1, | ||||
|         add_custom_emoji_policy: 1, | ||||
|     }; | ||||
|     assert.deepEqual(data, expected_value); | ||||
|  | ||||
|   | ||||
| @@ -35,6 +35,9 @@ mock_esm("../src/compose_state", { | ||||
| mock_esm("../src/pm_list", { | ||||
|     update_private_messages() {}, | ||||
| }); | ||||
| mock_esm("../src/settings", { | ||||
|     update_lock_icon_in_sidebar() {}, | ||||
| }); | ||||
| mock_esm("../src/settings_linkifiers", { | ||||
|     maybe_disable_widgets() {}, | ||||
| }); | ||||
|   | ||||
| @@ -1059,6 +1059,7 @@ group_setting_update_data_type = DictType( | ||||
|     optional_keys=[ | ||||
|         ("create_multiuse_invite_group", int), | ||||
|         ("can_access_all_users_group", int), | ||||
|         ("can_add_custom_emoji_group", group_setting_type), | ||||
|         ("can_create_groups", group_setting_type), | ||||
|         ("can_create_public_channel_group", group_setting_type), | ||||
|         ("can_create_private_channel_group", group_setting_type), | ||||
|   | ||||
							
								
								
									
										23
									
								
								zerver/migrations/0603_realm_can_add_custom_emoji_group.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								zerver/migrations/0603_realm_can_add_custom_emoji_group.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # Generated by Django 5.0.9 on 2024-10-04 07:01 | ||||
|  | ||||
| import django.db.models.deletion | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|     dependencies = [ | ||||
|         ("zerver", "0602_remap_can_manage_all_groups"), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name="realm", | ||||
|             name="can_add_custom_emoji_group", | ||||
|             field=models.ForeignKey( | ||||
|                 null=True, | ||||
|                 on_delete=django.db.models.deletion.RESTRICT, | ||||
|                 related_name="+", | ||||
|                 to="zerver.usergroup", | ||||
|             ), | ||||
|         ), | ||||
|     ] | ||||
| @@ -0,0 +1,43 @@ | ||||
| # Generated by Django 4.2.1 on 2023-06-12 10:47 | ||||
|  | ||||
| from django.db import migrations | ||||
| from django.db.backends.base.schema import BaseDatabaseSchemaEditor | ||||
| from django.db.migrations.state import StateApps | ||||
| from django.db.models import OuterRef | ||||
|  | ||||
|  | ||||
| def set_default_value_for_can_add_custom_emoji_group( | ||||
|     apps: StateApps, schema_editor: BaseDatabaseSchemaEditor | ||||
| ) -> None: | ||||
|     Realm = apps.get_model("zerver", "Realm") | ||||
|     NamedUserGroup = apps.get_model("zerver", "NamedUserGroup") | ||||
|  | ||||
|     add_custom_emoji_policy_to_group_name = { | ||||
|         1: "role:members", | ||||
|         2: "role:administrators", | ||||
|         3: "role:fullmembers", | ||||
|         4: "role:moderators", | ||||
|     } | ||||
|  | ||||
|     for id, group_name in add_custom_emoji_policy_to_group_name.items(): | ||||
|         Realm.objects.filter(can_add_custom_emoji_group=None, add_custom_emoji_policy=id).update( | ||||
|             can_add_custom_emoji_group=NamedUserGroup.objects.filter( | ||||
|                 name=group_name, realm=OuterRef("id"), is_system_group=True | ||||
|             ).values("pk") | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|     atomic = False | ||||
|  | ||||
|     dependencies = [ | ||||
|         ("zerver", "0603_realm_can_add_custom_emoji_group"), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.RunPython( | ||||
|             set_default_value_for_can_add_custom_emoji_group, | ||||
|             elidable=True, | ||||
|             reverse_code=migrations.RunPython.noop, | ||||
|         ) | ||||
|     ] | ||||
| @@ -0,0 +1,22 @@ | ||||
| # Generated by Django 5.0.9 on 2024-10-04 07:06 | ||||
|  | ||||
| import django.db.models.deletion | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|     dependencies = [ | ||||
|         ("zerver", "0604_set_default_value_for_can_add_custom_emoji_group"), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.AlterField( | ||||
|             model_name="realm", | ||||
|             name="can_add_custom_emoji_group", | ||||
|             field=models.ForeignKey( | ||||
|                 on_delete=django.db.models.deletion.RESTRICT, | ||||
|                 related_name="+", | ||||
|                 to="zerver.usergroup", | ||||
|             ), | ||||
|         ), | ||||
|     ] | ||||
| @@ -287,6 +287,11 @@ class Realm(models.Model):  # type: ignore[django-manager-missing] # django-stub | ||||
|         default=CommonPolicyEnum.MEMBERS_ONLY | ||||
|     ) | ||||
|  | ||||
|     # Who in the organization is allowed to add custom emojis. | ||||
|     can_add_custom_emoji_group = models.ForeignKey( | ||||
|         "UserGroup", on_delete=models.RESTRICT, related_name="+" | ||||
|     ) | ||||
|  | ||||
|     # Who in the organization is allowed to create streams. | ||||
|     can_create_public_channel_group = models.ForeignKey( | ||||
|         "UserGroup", on_delete=models.RESTRICT, related_name="+" | ||||
| @@ -704,6 +709,15 @@ class Realm(models.Model):  # type: ignore[django-manager-missing] # django-stub | ||||
|             id_field_name="can_access_all_users_group_id", | ||||
|             allowed_system_groups=[SystemGroups.EVERYONE, SystemGroups.MEMBERS], | ||||
|         ), | ||||
|         can_add_custom_emoji_group=GroupPermissionSetting( | ||||
|             require_system_group=False, | ||||
|             allow_internet_group=False, | ||||
|             allow_owners_group=False, | ||||
|             allow_nobody_group=False, | ||||
|             allow_everyone_group=False, | ||||
|             default_group_name=SystemGroups.MEMBERS, | ||||
|             id_field_name="can_add_custom_emoji_group_id", | ||||
|         ), | ||||
|         can_create_groups=GroupPermissionSetting( | ||||
|             require_system_group=False, | ||||
|             allow_internet_group=False, | ||||
| @@ -794,6 +808,7 @@ class Realm(models.Model):  # type: ignore[django-manager-missing] # django-stub | ||||
|     ) | ||||
|  | ||||
|     REALM_PERMISSION_GROUP_SETTINGS_WITH_NEW_API_FORMAT = [ | ||||
|         "can_add_custom_emoji_group", | ||||
|         "can_create_groups", | ||||
|         "can_create_private_channel_group", | ||||
|         "can_create_public_channel_group", | ||||
| @@ -1181,6 +1196,8 @@ def get_realm_with_settings(realm_id: int) -> Realm: | ||||
|     return Realm.objects.select_related( | ||||
|         "can_access_all_users_group", | ||||
|         "can_access_all_users_group__named_user_group", | ||||
|         "can_add_custom_emoji_group", | ||||
|         "can_add_custom_emoji_group__named_user_group", | ||||
|         "can_create_groups", | ||||
|         "can_create_groups__named_user_group", | ||||
|         "can_create_public_channel_group", | ||||
|   | ||||
| @@ -816,6 +816,7 @@ class UserProfile(AbstractBaseUser, PermissionsMixin, UserBaseSettings): | ||||
|  | ||||
|         if policy_name not in [ | ||||
|             "add_custom_emoji_policy", | ||||
|             "can_add_custom_emoji_group", | ||||
|             "can_create_groups", | ||||
|             "can_create_private_channel_group", | ||||
|             "can_create_public_channel_group", | ||||
| @@ -910,7 +911,7 @@ class UserProfile(AbstractBaseUser, PermissionsMixin, UserBaseSettings): | ||||
|         return self.has_permission("edit_topic_policy") | ||||
|  | ||||
|     def can_add_custom_emoji(self) -> bool: | ||||
|         return self.has_permission("add_custom_emoji_policy") | ||||
|         return self.has_permission("can_add_custom_emoji_group") | ||||
|  | ||||
|     def can_delete_any_message(self) -> bool: | ||||
|         return self.has_permission("can_delete_any_message_group") | ||||
|   | ||||
| @@ -4410,6 +4410,20 @@ paths: | ||||
|                                             **Changes**: New in Zulip 10.0 (feature level 280). Previously | ||||
|                                             `realm_create_web_public_stream_policy` field used to control | ||||
|                                             the permission to create web-public channels. | ||||
|                                     can_add_custom_emoji_group: | ||||
|                                       allOf: | ||||
|                                         - description: | | ||||
|                                             A [group-setting value](/api/group-setting-values) defining the set of | ||||
|                                             users who have permission to add custom emoji in the organization. | ||||
| 
 | ||||
|                                             **Changes**: New in Zulip 10.0 (feature level 307). Previously, this | ||||
|                                             permission was controlled by the enum `add_custom_emoji_policy`. Values | ||||
|                                             were 1=Members, 2=Admins, 3=Full members, 4=Moderators. | ||||
| 
 | ||||
|                                             Before Zulip 5.0 (feature level 85), the `realm_add_emoji_by_admins_only` | ||||
|                                             boolean setting controlled this permission; `true` corresponded to `Admins`, | ||||
|                                             and `false` to `Everyone`. | ||||
|                                         - $ref: "#/components/schemas/GroupSettingValue" | ||||
|                                     can_delete_any_message_group: | ||||
|                                       allOf: | ||||
|                                         - description: | | ||||
| @@ -16235,6 +16249,22 @@ paths: | ||||
| 
 | ||||
|                           Whether this organization is configured to allow users to access | ||||
|                           [message edit history](/help/view-a-messages-edit-history). | ||||
|                       realm_can_add_custom_emoji_group: | ||||
|                         allOf: | ||||
|                           - description: | | ||||
|                               Present if `realm` is present in `fetch_event_types`. | ||||
| 
 | ||||
|                               A [group-setting value](/api/group-setting-values) defining the set of | ||||
|                               users who have permission to add custom emoji in the organization. | ||||
| 
 | ||||
|                               **Changes**: New in Zulip 10.0 (feature level 307). Previously, this | ||||
|                               permission was controlled by the enum `add_custom_emoji_policy`. Values | ||||
|                               were 1=Members, 2=Admins, 3=Full members, 4=Moderators. | ||||
| 
 | ||||
|                               Before Zulip 5.0 (feature level 85), the `realm_add_emoji_by_admins_only` | ||||
|                               boolean setting controlled this permission; `true` corresponded to `Admins`, | ||||
|                               and `false` to `Everyone`. | ||||
|                           - $ref: "#/components/schemas/GroupSettingValue" | ||||
|                       realm_can_delete_any_message_group: | ||||
|                         allOf: | ||||
|                           - description: | | ||||
|   | ||||
| @@ -130,6 +130,7 @@ class HomeTest(ZulipTestCase): | ||||
|         "realm_bot_domain", | ||||
|         "realm_bots", | ||||
|         "realm_can_access_all_users_group", | ||||
|         "realm_can_add_custom_emoji_group", | ||||
|         "realm_can_create_groups", | ||||
|         "realm_can_create_private_channel_group", | ||||
|         "realm_can_create_public_channel_group", | ||||
|   | ||||
| @@ -3,15 +3,20 @@ from unittest import mock | ||||
| from zerver.actions.create_realm import do_create_realm | ||||
| from zerver.actions.create_user import do_create_user | ||||
| from zerver.actions.realm_emoji import check_add_realm_emoji | ||||
| from zerver.actions.realm_settings import do_set_realm_property | ||||
| from zerver.actions.realm_settings import ( | ||||
|     do_change_realm_permission_group_setting, | ||||
|     do_set_realm_property, | ||||
| ) | ||||
| from zerver.actions.user_groups import check_add_user_group | ||||
| from zerver.actions.users import do_change_user_role | ||||
| from zerver.lib.emoji import get_emoji_file_name | ||||
| from zerver.lib.exceptions import JsonableError | ||||
| from zerver.lib.test_classes import ZulipTestCase | ||||
| from zerver.lib.test_helpers import get_test_image_file | ||||
| from zerver.lib.thumbnail import BadImageError | ||||
| from zerver.models import Realm, RealmEmoji, UserProfile | ||||
| from zerver.models.realms import CommonPolicyEnum, get_realm | ||||
| from zerver.models import NamedUserGroup, Realm, RealmEmoji, UserProfile | ||||
| from zerver.models.groups import SystemGroups | ||||
| from zerver.models.realms import get_realm | ||||
|  | ||||
|  | ||||
| class RealmEmojiTest(ZulipTestCase): | ||||
| @@ -57,8 +62,15 @@ class RealmEmojiTest(ZulipTestCase): | ||||
|         # having no author are also there in the list. | ||||
|         self.login("othello") | ||||
|         realm = get_realm("zulip") | ||||
|         realm.add_custom_emoji_policy = CommonPolicyEnum.ADMINS_ONLY | ||||
|         realm.save() | ||||
|         administrators_system_group = NamedUserGroup.objects.get( | ||||
|             name=SystemGroups.ADMINISTRATORS, realm=realm, is_system_group=True | ||||
|         ) | ||||
|         do_change_realm_permission_group_setting( | ||||
|             realm, | ||||
|             "can_add_custom_emoji_group", | ||||
|             administrators_system_group, | ||||
|             acting_user=None, | ||||
|         ) | ||||
|         realm_emoji = self.create_test_emoji_with_no_author("my_emoji", realm) | ||||
|  | ||||
|         result = self.client_get("/json/realm/emoji") | ||||
| @@ -165,19 +177,23 @@ class RealmEmojiTest(ZulipTestCase): | ||||
|             result = self.client_post("/json/realm/emoji/%20", info=emoji_data) | ||||
|         self.assert_json_error(result, "Emoji name is missing") | ||||
|  | ||||
|     def test_can_add_custom_emoji(self) -> None: | ||||
|         def validation_func(user_profile: UserProfile) -> bool: | ||||
|             return user_profile.can_add_custom_emoji() | ||||
|  | ||||
|         self.check_has_permission_policies("add_custom_emoji_policy", validation_func) | ||||
|  | ||||
|     def test_user_settings_for_adding_custom_emoji(self) -> None: | ||||
|         othello = self.example_user("othello") | ||||
|         cordelia = self.example_user("cordelia") | ||||
|         iago = self.example_user("iago") | ||||
|  | ||||
|         realm = othello.realm | ||||
|         self.login_user(othello) | ||||
|  | ||||
|         do_change_user_role(othello, UserProfile.ROLE_MODERATOR, acting_user=None) | ||||
|         do_set_realm_property( | ||||
|             othello.realm, "add_custom_emoji_policy", CommonPolicyEnum.ADMINS_ONLY, acting_user=None | ||||
|         administrators_system_group = NamedUserGroup.objects.get( | ||||
|             name=SystemGroups.ADMINISTRATORS, realm=realm, is_system_group=True | ||||
|         ) | ||||
|         do_change_realm_permission_group_setting( | ||||
|             realm, | ||||
|             "can_add_custom_emoji_group", | ||||
|             administrators_system_group, | ||||
|             acting_user=None, | ||||
|         ) | ||||
|         with get_test_image_file("img.png") as fp1: | ||||
|             emoji_data = {"f1": fp1} | ||||
| @@ -190,10 +206,13 @@ class RealmEmojiTest(ZulipTestCase): | ||||
|             result = self.client_post("/json/realm/emoji/my_emoji_1", info=emoji_data) | ||||
|         self.assert_json_success(result) | ||||
|  | ||||
|         do_set_realm_property( | ||||
|             othello.realm, | ||||
|             "add_custom_emoji_policy", | ||||
|             CommonPolicyEnum.MODERATORS_ONLY, | ||||
|         moderators_system_group = NamedUserGroup.objects.get( | ||||
|             name=SystemGroups.MODERATORS, realm=realm, is_system_group=True | ||||
|         ) | ||||
|         do_change_realm_permission_group_setting( | ||||
|             realm, | ||||
|             "can_add_custom_emoji_group", | ||||
|             moderators_system_group, | ||||
|             acting_user=None, | ||||
|         ) | ||||
|         do_change_user_role(othello, UserProfile.ROLE_MEMBER, acting_user=None) | ||||
| @@ -208,10 +227,13 @@ class RealmEmojiTest(ZulipTestCase): | ||||
|             result = self.client_post("/json/realm/emoji/my_emoji_2", info=emoji_data) | ||||
|         self.assert_json_success(result) | ||||
|  | ||||
|         do_set_realm_property( | ||||
|             othello.realm, | ||||
|             "add_custom_emoji_policy", | ||||
|             CommonPolicyEnum.FULL_MEMBERS_ONLY, | ||||
|         full_members_system_group = NamedUserGroup.objects.get( | ||||
|             name=SystemGroups.FULL_MEMBERS, realm=realm, is_system_group=True | ||||
|         ) | ||||
|         do_change_realm_permission_group_setting( | ||||
|             realm, | ||||
|             "can_add_custom_emoji_group", | ||||
|             full_members_system_group, | ||||
|             acting_user=None, | ||||
|         ) | ||||
|         do_set_realm_property(othello.realm, "waiting_period_threshold", 100000, acting_user=None) | ||||
| @@ -228,10 +250,13 @@ class RealmEmojiTest(ZulipTestCase): | ||||
|             result = self.client_post("/json/realm/emoji/my_emoji_3", info=emoji_data) | ||||
|         self.assert_json_success(result) | ||||
|  | ||||
|         do_set_realm_property( | ||||
|             othello.realm, | ||||
|             "add_custom_emoji_policy", | ||||
|             CommonPolicyEnum.MEMBERS_ONLY, | ||||
|         members_system_group = NamedUserGroup.objects.get( | ||||
|             name=SystemGroups.MEMBERS, realm=realm, is_system_group=True | ||||
|         ) | ||||
|         do_change_realm_permission_group_setting( | ||||
|             realm, | ||||
|             "can_add_custom_emoji_group", | ||||
|             members_system_group, | ||||
|             acting_user=None, | ||||
|         ) | ||||
|         do_change_user_role(othello, UserProfile.ROLE_GUEST, acting_user=None) | ||||
| @@ -246,6 +271,61 @@ class RealmEmojiTest(ZulipTestCase): | ||||
|             result = self.client_post("/json/realm/emoji/my_emoji_4", info=emoji_data) | ||||
|         self.assert_json_success(result) | ||||
|  | ||||
|         # Test for checking setting for non-system user group. | ||||
|         user_group = check_add_user_group( | ||||
|             realm, "newgroup", [othello, cordelia], acting_user=othello | ||||
|         ) | ||||
|         do_change_realm_permission_group_setting( | ||||
|             realm, "can_add_custom_emoji_group", user_group, acting_user=None | ||||
|         ) | ||||
|  | ||||
|         # Othello is in the allowed user group, so can add custom emoji. | ||||
|         with get_test_image_file("img.png") as fp1: | ||||
|             emoji_data = {"f1": fp1} | ||||
|             result = self.client_post("/json/realm/emoji/my_emoji_5", info=emoji_data) | ||||
|         self.assert_json_success(result) | ||||
|  | ||||
|         # Iago is not present in the allowed user group, so cannot add custom emoji. | ||||
|         self.login_user(iago) | ||||
|         with get_test_image_file("img.png") as fp1: | ||||
|             emoji_data = {"f1": fp1} | ||||
|             result = self.client_post("/json/realm/emoji/my_emoji_6", info=emoji_data) | ||||
|         self.assert_json_error(result, "Insufficient permission") | ||||
|  | ||||
|         # Test for checking the setting for anonymous user group. | ||||
|         anonymous_user_group = self.create_or_update_anonymous_group_for_setting( | ||||
|             [othello], | ||||
|             [administrators_system_group], | ||||
|         ) | ||||
|         do_change_realm_permission_group_setting( | ||||
|             realm, | ||||
|             "can_add_custom_emoji_group", | ||||
|             anonymous_user_group, | ||||
|             acting_user=None, | ||||
|         ) | ||||
|  | ||||
|         # Iago is present in the `administrators_system_group` subgroup, so can add | ||||
|         # custom emoji. | ||||
|         with get_test_image_file("img.png") as fp1: | ||||
|             emoji_data = {"f1": fp1} | ||||
|             result = self.client_post("/json/realm/emoji/my_emoji_6", info=emoji_data) | ||||
|         self.assert_json_success(result) | ||||
|  | ||||
|         # Othello is the direct member of the allowed anonymous user group, so can add | ||||
|         # custom emoji. | ||||
|         self.login_user(othello) | ||||
|         with get_test_image_file("img.png") as fp1: | ||||
|             emoji_data = {"f1": fp1} | ||||
|             result = self.client_post("/json/realm/emoji/my_emoji_7", info=emoji_data) | ||||
|         self.assert_json_success(result) | ||||
|  | ||||
|         # Cordelia is not present in the anonymous user group, so cannot add custom emoji. | ||||
|         self.login_user(cordelia) | ||||
|         with get_test_image_file("img.png") as fp1: | ||||
|             emoji_data = {"f1": fp1} | ||||
|             result = self.client_post("/json/realm/emoji/my_emoji_6", info=emoji_data) | ||||
|         self.assert_json_error(result, "Insufficient permission") | ||||
|  | ||||
|     def test_delete(self) -> None: | ||||
|         emoji_author = self.example_user("iago") | ||||
|         self.login_user(emoji_author) | ||||
|   | ||||
| @@ -112,6 +112,7 @@ def update_realm( | ||||
|     inline_image_preview: Json[bool] | None = None, | ||||
|     inline_url_embed_preview: Json[bool] | None = None, | ||||
|     add_custom_emoji_policy: Json[CommonPolicyEnum] | None = None, | ||||
|     can_add_custom_emoji_group: Json[GroupSettingChangeRequest] | None = None, | ||||
|     can_delete_any_message_group: Json[GroupSettingChangeRequest] | None = None, | ||||
|     can_delete_own_message_group: Json[GroupSettingChangeRequest] | None = None, | ||||
|     message_content_delete_limit_seconds_raw: Annotated[ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user