diff --git a/api_docs/changelog.md b/api_docs/changelog.md index 4ff1285387..32c4f49af8 100644 --- a/api_docs/changelog.md +++ b/api_docs/changelog.md @@ -20,6 +20,14 @@ format used by the Zulip server that they are interacting with. ## Changes in Zulip 10.0 +**Feature level 314** + +* `PATCH /realm`, [`POST /register`](/api/register-queue), + [`GET /events`](/api/get-events): Anonymous groups are now accepted + by `create_multiuse_invite_group` realm setting, which is a now a + [group-setting value](/api/group-setting-values) instead of an + integer ID of the group. + **Feature level 313** * [`PATCH /users/{user_id}`](/api/update-user): Added `new_email` field to diff --git a/version.py b/version.py index 09d0bccc65..ffc95a4a31 100644 --- a/version.py +++ b/version.py @@ -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 = 313 # Last bumped for adding `new_email` to /users/{user_id} and the new PATCH /users/{email} endpoint +API_FEATURE_LEVEL = 314 # Last bumped for create_multiuse_invite_group api changes. # 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 diff --git a/web/src/settings_components.ts b/web/src/settings_components.ts index e9145e1ff5..e4a5f5a79a 100644 --- a/web/src/settings_components.ts +++ b/web/src/settings_components.ts @@ -477,7 +477,6 @@ const dropdown_widget_map = new Map([ ["realm_signup_announcements_stream_id", null], ["realm_zulip_update_announcements_stream_id", null], ["realm_default_code_block_language", null], - ["realm_create_multiuse_invite_group", null], ["can_remove_subscribers_group", null], ["realm_can_access_all_users_group", null], ["realm_can_add_custom_emoji_group", null], @@ -489,6 +488,7 @@ const dropdown_widget_map = new Map([ ["realm_can_delete_own_message_group", null], ["realm_can_manage_all_groups", null], ["realm_can_move_messages_between_channels_group", null], + ["realm_create_multiuse_invite_group", null], ["realm_direct_message_initiator_group", null], ["realm_direct_message_permission_group", null], ]); @@ -1053,6 +1053,7 @@ export function populate_data_for_realm_settings_request( "can_delete_any_message_group", "can_delete_own_message_group", "can_move_messages_between_channels_group", + "create_multiuse_invite_group", "direct_message_initiator_group", "direct_message_permission_group", ]); diff --git a/zerver/lib/event_schema.py b/zerver/lib/event_schema.py index 5297b0566a..72d4cafb9c 100644 --- a/zerver/lib/event_schema.py +++ b/zerver/lib/event_schema.py @@ -1066,7 +1066,7 @@ group_setting_type = UnionType( group_setting_update_data_type = DictType( required_keys=[], optional_keys=[ - ("create_multiuse_invite_group", int), + ("create_multiuse_invite_group", group_setting_type), ("can_access_all_users_group", int), ("can_add_custom_emoji_group", group_setting_type), ("can_create_groups", group_setting_type), diff --git a/zerver/models/realms.py b/zerver/models/realms.py index 43cd87785e..f50e9f6748 100644 --- a/zerver/models/realms.py +++ b/zerver/models/realms.py @@ -682,7 +682,7 @@ class Realm(models.Model): # type: ignore[django-manager-missing] # django-stub REALM_PERMISSION_GROUP_SETTINGS: dict[str, GroupPermissionSetting] = dict( create_multiuse_invite_group=GroupPermissionSetting( - require_system_group=True, + require_system_group=not settings.ALLOW_GROUP_VALUED_SETTINGS, allow_internet_group=False, allow_owners_group=False, allow_nobody_group=True, @@ -808,6 +808,7 @@ class Realm(models.Model): # type: ignore[django-manager-missing] # django-stub ) REALM_PERMISSION_GROUP_SETTINGS_WITH_NEW_API_FORMAT = [ + "create_multiuse_invite_group", "can_add_custom_emoji_group", "can_create_groups", "can_create_private_channel_group", @@ -1195,6 +1196,8 @@ def get_realm_with_settings(realm_id: int) -> Realm: # the setting is used when fetching users in the realm. # * Announcements streams. return Realm.objects.select_related( + "create_multiuse_invite_group", + "create_multiuse_invite_group__named_user_group", "can_access_all_users_group", "can_access_all_users_group__named_user_group", "can_add_custom_emoji_group", diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml index 8d712299ee..e303f5b9ec 100644 --- a/zerver/openapi/zulip.yaml +++ b/zerver/openapi/zulip.yaml @@ -4532,18 +4532,18 @@ paths: [calc-full-member]: /api/roles-and-permissions#determining-if-a-user-is-a-full-member create_multiuse_invite_group: - type: integer - description: | - The ID of the [user group](/api/get-user-groups) whose members are - allowed to create [reusable invitation - links](/help/invite-new-users#create-a-reusable-invitation-link) - to the organization. + allOf: + - $ref: "#/components/schemas/GroupSettingValue" + - description: | + A [group-setting value](/api/group-setting-values) defining the + set of users who are allowed to create [reusable invitation + links](/help/invite-new-users#create-a-reusable-invitation-link) + to the organization. - This setting can currently only be set to user groups that are - system groups, except for the system groups named - `"role:internet"` and `"role:owners"`. + **Changes**: Prior to Zulip 10.0 (feature level 314), this value used + to be of type integer and did not accept anonymous user groups. - **Changes**: New in Zulip 8.0 (feature level 209). + New in Zulip 8.0 (feature level 209). default_code_block_language: type: string description: | @@ -16591,18 +16591,18 @@ paths: [permission-level]: /api/roles-and-permissions#permission-levels [calc-full-member]: /api/roles-and-permissions#determining-if-a-user-is-a-full-member realm_create_multiuse_invite_group: - type: integer - description: | - The ID of the [user group](/api/get-user-groups) whose members are - allowed to create [reusable invitation - links](/help/invite-new-users#create-a-reusable-invitation-link) - to the organization. + allOf: + - $ref: "#/components/schemas/GroupSettingValue" + - description: | + A [group-setting value](/api/group-setting-values) defining the + set of users who are allowed to create [reusable invitation + links](/help/invite-new-users#create-a-reusable-invitation-link) + to the organization. - This setting can currently only be set to user groups that are - system groups, except for the system groups named - `"role:internet"` and `"role:owners"`. + **Changes**: Prior to Zulip 10.0 (feature level 314), this value used + to be of type integer and did not accept anonymous user groups. - **Changes**: New in Zulip 8.0 (feature level 209). + New in Zulip 8.0 (feature level 209). realm_inline_image_preview: type: boolean description: | diff --git a/zerver/tests/test_invite.py b/zerver/tests/test_invite.py index 0071250cda..06d2035439 100644 --- a/zerver/tests/test_invite.py +++ b/zerver/tests/test_invite.py @@ -2834,19 +2834,46 @@ class MultiuseInviteTest(ZulipTestCase): self.login("iago") result = self.client_patch( "/json/realm", - {"create_multiuse_invite_group": orjson.dumps(full_members_system_group.id).decode()}, + { + "create_multiuse_invite_group": orjson.dumps( + {"new": full_members_system_group.id} + ).decode() + }, ) self.assert_json_error(result, "Must be an organization owner") self.login("desdemona") result = self.client_patch( "/json/realm", - {"create_multiuse_invite_group": orjson.dumps(full_members_system_group.id).decode()}, + { + "create_multiuse_invite_group": orjson.dumps( + {"new": full_members_system_group.id} + ).decode() + }, ) self.assert_json_success(result) realm = get_realm("zulip") self.assertEqual(realm.create_multiuse_invite_group_id, full_members_system_group.id) + # Test setting the value to an anonymous group. + iago = self.example_user("iago") + result = self.client_patch( + "/json/realm", + { + "create_multiuse_invite_group": orjson.dumps( + { + "new": { + "direct_members": [iago.id], + "direct_subgroups": [], + } + } + ).decode() + }, + ) + self.assert_json_success(result) + realm = get_realm("zulip") + self.assertCountEqual(realm.create_multiuse_invite_group.direct_members.all(), [iago]) + def test_multiuse_link_for_inviting_as_owner(self) -> None: self.login("iago") result = self.client_post( diff --git a/zerver/views/realm.py b/zerver/views/realm.py index 2f012977cd..8f64a438ba 100644 --- a/zerver/views/realm.py +++ b/zerver/views/realm.py @@ -101,9 +101,7 @@ def update_realm( disallow_disposable_email_addresses: Json[bool] | None = None, invite_required: Json[bool] | None = None, invite_to_realm_policy: Json[InviteToRealmPolicyEnum] | None = None, - create_multiuse_invite_group_id: Annotated[ - Json[int] | None, ApiParamConfig(whence="create_multiuse_invite_group") - ] = None, + create_multiuse_invite_group: Json[GroupSettingChangeRequest] | None = None, require_unique_names: Json[bool] | None = None, name_changes_disabled: Json[bool] | None = None, email_changes_disabled: Json[bool] | None = None, @@ -226,7 +224,7 @@ def update_realm( if ( invite_to_realm_policy is not None or invite_required is not None - or create_multiuse_invite_group_id is not None + or create_multiuse_invite_group is not None or can_create_groups is not None or can_manage_all_groups is not None ) and not user_profile.is_realm_owner: