user_groups: Allow updating subgroups and members using same endpoint.

`POST /user_groups/{user_group_id}/members` now allows updating
subgroups as well.
This commit is contained in:
Sahil Batra 2024-10-14 16:09:22 +05:30 committed by Tim Abbott
parent 47a611f989
commit 1e818c4708
5 changed files with 72 additions and 7 deletions

View File

@ -20,6 +20,12 @@ format used by the Zulip server that they are interacting with.
## Changes in Zulip 10.0 ## Changes in Zulip 10.0
**Feature level 311**
* [`POST /user_groups/{user_group_id}/members`](/api/update-user-group-members):
Added `add_subgroups` and `delete_subgroups` parameters to support updating
subgroups of a user group using this endpoint.
**Feature level 310** **Feature level 310**
* `PATCH /realm`, [`GET /events`](/api/get-events), * `PATCH /realm`, [`GET /events`](/api/get-events),

View File

@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
# new level means in api_docs/changelog.md, as well as "**Changes**" # new level means in api_docs/changelog.md, as well as "**Changes**"
# entries in the endpoint's documentation in `zulip.yaml`. # entries in the endpoint's documentation in `zulip.yaml`.
API_FEATURE_LEVEL = 310 # Last bumped for adding `can_move_messages_between_channels_group`. API_FEATURE_LEVEL = 311 # Last bumped for updating subgroups.
# Bump the minor PROVISION_VERSION to indicate that folks should provision # 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 # only when going from an old version of the code to a newer version. Bump

View File

@ -20430,11 +20430,33 @@ paths:
items: items:
type: integer type: integer
example: [12, 13] example: [12, 13]
delete_subgroups:
description: |
The list of user group IDs to be removed from the user group.
**Changes**: New in Zulip 10.0 (feature level 311).
type: array
items:
type: integer
example: [9]
add_subgroups:
description: |
The list of user group IDs to be added to the user group.
**Changes**: New in Zulip 10.0 (feature level 311).
type: array
items:
type: integer
example: [9]
encoding: encoding:
delete: delete:
contentType: application/json contentType: application/json
add: add:
contentType: application/json contentType: application/json
delete_subgroups:
contentType: application/json
add_subgroups:
contentType: application/json
responses: responses:
"200": "200":
$ref: "#/components/responses/SimpleSuccess" $ref: "#/components/responses/SimpleSuccess"
@ -21004,7 +21026,7 @@ paths:
type: array type: array
items: items:
type: integer type: integer
example: [9, 10] example: [10]
encoding: encoding:
delete: delete:
contentType: application/json contentType: application/json

View File

@ -1672,9 +1672,27 @@ class UserGroupAPITestCase(UserGroupTestCase):
# No notification message is sent for removing from user group. # No notification message is sent for removing from user group.
self.assertEqual(self.get_last_message(), initial_last_message) self.assertEqual(self.get_last_message(), initial_last_message)
# Test adding and removing subgroups.
admins_group = NamedUserGroup.objects.get(
name=SystemGroups.ADMINISTRATORS, realm=hamlet.realm, is_system_group=True
)
cordelia = self.example_user("cordelia")
subgroup = check_add_user_group(
hamlet.realm, "leadership", [cordelia], acting_user=cordelia
)
params = {"add_subgroups": orjson.dumps([subgroup.id, admins_group.id]).decode()}
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
self.assert_json_success(result)
self.assert_subgroup_membership(user_group, [subgroup, admins_group])
params = {"delete_subgroups": orjson.dumps([admins_group.id]).decode()}
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
self.assert_json_success(result)
self.assert_subgroup_membership(user_group, [subgroup])
# Test when nothing is provided # Test when nothing is provided
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info={}) result = self.client_post(f"/json/user_groups/{user_group.id}/members", info={})
msg = 'Nothing to do. Specify at least one of "add" or "delete".' msg = 'Nothing to do. Specify at least one of "add", "delete", "add_subgroups" or "delete_subgroups".'
self.assert_json_error(result, msg) self.assert_json_error(result, msg)
self.assert_user_membership(user_group, [hamlet]) self.assert_user_membership(user_group, [hamlet])

View File

@ -212,6 +212,7 @@ def deactivate_user_group(
@require_member_or_admin @require_member_or_admin
@typed_endpoint @typed_endpoint
@transaction.atomic(durable=True)
def update_user_group_backend( def update_user_group_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
@ -219,9 +220,15 @@ def update_user_group_backend(
user_group_id: PathOnly[Json[int]], user_group_id: PathOnly[Json[int]],
delete: Json[list[int]] | None = None, delete: Json[list[int]] | None = None,
add: Json[list[int]] | None = None, add: Json[list[int]] | None = None,
delete_subgroups: Json[list[int]] | None = None,
add_subgroups: Json[list[int]] | None = None,
) -> HttpResponse: ) -> HttpResponse:
if not add and not delete: if not add and not delete and not add_subgroups and not delete_subgroups:
raise JsonableError(_('Nothing to do. Specify at least one of "add" or "delete".')) raise JsonableError(
_(
'Nothing to do. Specify at least one of "add", "delete", "add_subgroups" or "delete_subgroups".'
)
)
thunks = [] thunks = []
if add: if add:
@ -237,6 +244,20 @@ def update_user_group_backend(
) )
) )
if add_subgroups:
thunks.append(
lambda: add_subgroups_to_group_backend(
request, user_profile, user_group_id=user_group_id, subgroup_ids=add_subgroups
)
)
if delete_subgroups:
thunks.append(
lambda: remove_subgroups_from_group_backend(
request, user_profile, user_group_id=user_group_id, subgroup_ids=delete_subgroups
)
)
data = compose_views(thunks) data = compose_views(thunks)
return json_success(request, data) return json_success(request, data)
@ -290,7 +311,6 @@ def notify_for_user_group_subscription_changes(
do_send_messages(notifications) do_send_messages(notifications)
@transaction.atomic
def add_members_to_group_backend( def add_members_to_group_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,
@ -337,7 +357,6 @@ def add_members_to_group_backend(
return json_success(request) return json_success(request)
@transaction.atomic
def remove_members_from_group_backend( def remove_members_from_group_backend(
request: HttpRequest, request: HttpRequest,
user_profile: UserProfile, user_profile: UserProfile,