diff --git a/frontend_tests/node_tests/message_edit.js b/frontend_tests/node_tests/message_edit.js index 6c87d639f3..31a59f1609 100644 --- a/frontend_tests/node_tests/message_edit.js +++ b/frontend_tests/node_tests/message_edit.js @@ -116,9 +116,13 @@ run_test("is_topic_editable", ({override}) => { message.sent_by_me = false; page_params.is_admin = true; - assert.equal(message_edit.is_topic_editable(message), true); + override(settings_data, "user_can_edit_topic_of_any_message", () => false); + assert.equal(message_edit.is_topic_editable(message), false); page_params.is_admin = false; + message.sent_by_me = false; + assert.equal(message_edit.is_topic_editable(message), false); + message.topic = "translated: (no topic)"; assert.equal(message_edit.is_topic_editable(message), true); diff --git a/frontend_tests/node_tests/settings_data.js b/frontend_tests/node_tests/settings_data.js index 103f4d361b..eb01afba58 100644 --- a/frontend_tests/node_tests/settings_data.js +++ b/frontend_tests/node_tests/settings_data.js @@ -248,6 +248,14 @@ test_message_policy( settings_data.user_can_edit_topic_of_any_message, ); +run_test("user_can_edit_topic_of_any_message_nobody_case", () => { + page_params.is_admin = true; + page_params.is_guest = false; + page_params.realm_edit_topic_policy = + settings_config.edit_topic_policy_values.nobody.code; + assert.equal(settings_data.user_can_edit_topic_of_any_message(), false); +}); + test_message_policy( "user_can_delete_own_message", "realm_delete_own_message_policy", diff --git a/static/js/message_edit.js b/static/js/message_edit.js index ec39323211..9cfc9b2365 100644 --- a/static/js/message_edit.js +++ b/static/js/message_edit.js @@ -65,10 +65,8 @@ export function is_topic_editable(message, edit_limit_seconds_buffer = 0) { // If message editing is disabled, so is topic editing. return false; } - // Organization admins and message senders can edit message topics indefinitely. - if (page_params.is_admin) { - return true; - } + + // message senders can edit message topics indefinitely. if (message.sent_by_me) { return true; } @@ -81,9 +79,10 @@ export function is_topic_editable(message, edit_limit_seconds_buffer = 0) { return false; } - // moderators can edit the topic if edit_topic_policy allows them to do so, - // irrespective of the topic editing deadline. - if (page_params.is_moderator) { + // Organization admins and moderators can edit message topics indefinitely, + // irrespective of the topic editing deadline, if edit_topic_policy allows + // them to do so. + if (page_params.is_admin || page_params.is_moderator) { return true; } diff --git a/static/js/settings_config.ts b/static/js/settings_config.ts index 92740c8f3f..9c83200ab4 100644 --- a/static/js/settings_config.ts +++ b/static/js/settings_config.ts @@ -290,6 +290,15 @@ export const common_message_policy_values = { }, }; +export const edit_topic_policy_values = { + ...common_message_policy_values, + nobody: { + order: 6, + code: 6, + description: $t({defaultMessage: "Nobody"}), + }, +}; + export const time_limit_dropdown_values = [ { text: $t({defaultMessage: "Any time"}), diff --git a/static/js/settings_org.js b/static/js/settings_org.js index fe520f0329..2d5fd73cbf 100644 --- a/static/js/settings_org.js +++ b/static/js/settings_org.js @@ -114,6 +114,9 @@ export function get_organization_settings_options() { options.invite_to_realm_policy_values = get_sorted_options_list( settings_config.invite_to_realm_policy_values, ); + options.edit_topic_policy_values = get_sorted_options_list( + settings_config.edit_topic_policy_values, + ); return options; } diff --git a/static/templates/settings/organization_permissions_admin.hbs b/static/templates/settings/organization_permissions_admin.hbs index 917217c57f..34951cf050 100644 --- a/static/templates/settings/organization_permissions_admin.hbs +++ b/static/templates/settings/organization_permissions_admin.hbs @@ -177,7 +177,7 @@
diff --git a/templates/zerver/api/changelog.md b/templates/zerver/api/changelog.md index 784d804c40..a8b680b817 100644 --- a/templates/zerver/api/changelog.md +++ b/templates/zerver/api/changelog.md @@ -20,6 +20,12 @@ format used by the Zulip server that they are interacting with. ## Changes in Zulip 7.0 +**Feature level 159** + +* [`POST /register`](/api/register-queue), [`GET /events`](/api/get-events), + `PATCH /realm`: Nobody added as an option for the realm setting + `edit_topic_policy`. + Feature levels 157-158 are reserved for future use in 6.x maintenance releases. diff --git a/zerver/models.py b/zerver/models.py index 80f88601d8..3a7384fcf9 100644 --- a/zerver/models.py +++ b/zerver/models.py @@ -365,6 +365,15 @@ class Realm(models.Model): # type: ignore[django-manager-missing] # django-stub POLICY_NOBODY, ] + EDIT_TOPIC_POLICY_TYPES = [ + POLICY_MEMBERS_ONLY, + POLICY_ADMINS_ONLY, + POLICY_FULL_MEMBERS_ONLY, + POLICY_MODERATORS_ONLY, + POLICY_EVERYONE, + POLICY_NOBODY, + ] + DEFAULT_COMMUNITY_TOPIC_EDITING_LIMIT_SECONDS = 259200 # Who in the organization is allowed to add custom emojis. diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml index eb237223a3..14e188f7b8 100644 --- a/zerver/openapi/zulip.yaml +++ b/zerver/openapi/zulip.yaml @@ -3890,9 +3890,11 @@ paths: - 3 = [full members][calc-full-member] only - 4 = moderators only - 5 = everyone + - 6 = nobody **Changes**: New in Zulip 5.0 (feature level 75), replacing the - previous `allow_community_topic_editing` boolean. + previous `allow_community_topic_editing` boolean. Nobody added + as an option in Zulip 7.0 (feature level 159). [permission-level]: /api/roles-and-permissions#permission-levels [calc-full-member]: /api/roles-and-permissions#determining-if-a-user-is-a-full-member @@ -12155,9 +12157,11 @@ paths: - 3 = [full members][calc-full-member] only - 4 = moderators only - 5 = everyone + - 6 = nobody **Changes**: New in Zulip 5.0 (feature level 75), replacing the - previous `allow_community_topic_editing` boolean. + previous `allow_community_topic_editing` boolean. Nobody added as + an option in Zulip 7.0 (feature level 159). [permission-level]: /api/roles-and-permissions#permission-levels [calc-full-member]: /api/roles-and-permissions#determining-if-a-user-is-a-full-member diff --git a/zerver/tests/test_message_edit.py b/zerver/tests/test_message_edit.py index 87621ce598..a0c2988ebc 100644 --- a/zerver/tests/test_message_edit.py +++ b/zerver/tests/test_message_edit.py @@ -1153,6 +1153,15 @@ class EditMessageTest(EditMessageTestCase): ) do_edit_message_assert_success(id_, "E", "iago") + # even owners and admins cannot edit the topics of messages + set_message_editing_params(True, "unlimited", Realm.POLICY_NOBODY) + do_edit_message_assert_error( + id_, "H", "You don't have permission to edit this message", "desdemona" + ) + do_edit_message_assert_error( + id_, "H", "You don't have permission to edit this message", "iago" + ) + # users cannot edit topics if allow_message_editing is False set_message_editing_params(False, "unlimited", Realm.POLICY_EVERYONE) do_edit_message_assert_error( diff --git a/zerver/tests/test_realm.py b/zerver/tests/test_realm.py index 4149cfd978..187a8e4dbf 100644 --- a/zerver/tests/test_realm.py +++ b/zerver/tests/test_realm.py @@ -1176,7 +1176,7 @@ class RealmAPITest(ZulipTestCase): move_messages_between_streams_policy=Realm.COMMON_POLICY_TYPES, add_custom_emoji_policy=Realm.COMMON_POLICY_TYPES, delete_own_message_policy=Realm.COMMON_MESSAGE_POLICY_TYPES, - edit_topic_policy=Realm.COMMON_MESSAGE_POLICY_TYPES, + edit_topic_policy=Realm.EDIT_TOPIC_POLICY_TYPES, message_content_edit_limit_seconds=[1000, 1100, 1200], ) diff --git a/zerver/views/realm.py b/zerver/views/realm.py index 1375c57f78..54e73be14b 100644 --- a/zerver/views/realm.py +++ b/zerver/views/realm.py @@ -78,7 +78,7 @@ def update_realm( ), allow_message_editing: Optional[bool] = REQ(json_validator=check_bool, default=None), edit_topic_policy: Optional[int] = REQ( - json_validator=check_int_in(Realm.COMMON_MESSAGE_POLICY_TYPES), default=None + json_validator=check_int_in(Realm.EDIT_TOPIC_POLICY_TYPES), default=None ), mandatory_topics: Optional[bool] = REQ(json_validator=check_bool, default=None), message_content_edit_limit_seconds_raw: Optional[Union[int, str]] = REQ(