mirror of https://github.com/zulip/zulip.git
user_groups: Add API support to add subgroups during group creation.
This commit adds support to add subgroups to a group while creating it. User can add the subgroups to group irrespective of permissions like user can add members during creating it.
This commit is contained in:
parent
1e818c4708
commit
e5043b991a
|
@ -25,6 +25,8 @@ format used by the Zulip server that they are interacting with.
|
||||||
* [`POST /user_groups/{user_group_id}/members`](/api/update-user-group-members):
|
* [`POST /user_groups/{user_group_id}/members`](/api/update-user-group-members):
|
||||||
Added `add_subgroups` and `delete_subgroups` parameters to support updating
|
Added `add_subgroups` and `delete_subgroups` parameters to support updating
|
||||||
subgroups of a user group using this endpoint.
|
subgroups of a user group using this endpoint.
|
||||||
|
* [`POST /user_groups/create`](/api/create-user-group): Added `subgroups`
|
||||||
|
parameter to support setting subgroups of a user group during its creation.
|
||||||
|
|
||||||
**Feature level 310**
|
**Feature level 310**
|
||||||
|
|
||||||
|
|
|
@ -275,7 +275,8 @@ def lock_subgroups_with_respect_to_supergroup(
|
||||||
potential_supergroup_id: int,
|
potential_supergroup_id: int,
|
||||||
acting_user: UserProfile,
|
acting_user: UserProfile,
|
||||||
*,
|
*,
|
||||||
permission_setting: str,
|
permission_setting: str | None,
|
||||||
|
creating_group: bool = False,
|
||||||
) -> Iterator[LockedUserGroupContext]:
|
) -> Iterator[LockedUserGroupContext]:
|
||||||
"""This locks the user groups with the given potential_subgroup_ids, as well
|
"""This locks the user groups with the given potential_subgroup_ids, as well
|
||||||
as their indirect subgroups, followed by the potential supergroup. It
|
as their indirect subgroups, followed by the potential supergroup. It
|
||||||
|
@ -305,9 +306,17 @@ def lock_subgroups_with_respect_to_supergroup(
|
||||||
# the transaction with a JsonableError by handling the DatabaseError.
|
# the transaction with a JsonableError by handling the DatabaseError.
|
||||||
# But at the current scale of concurrent requests, we rely on
|
# But at the current scale of concurrent requests, we rely on
|
||||||
# Postgres's deadlock detection when it occurs.
|
# Postgres's deadlock detection when it occurs.
|
||||||
potential_supergroup = access_user_group_for_update(
|
if creating_group:
|
||||||
potential_supergroup_id, acting_user, permission_setting=permission_setting
|
# User can add subgroups to the group while creating it irrespective
|
||||||
)
|
# of whether the user has other permissions for that group.
|
||||||
|
potential_supergroup = get_user_group_by_id_in_realm(
|
||||||
|
potential_supergroup_id, acting_user.realm, for_read=False
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
assert permission_setting is not None
|
||||||
|
potential_supergroup = access_user_group_for_update(
|
||||||
|
potential_supergroup_id, acting_user, permission_setting=permission_setting
|
||||||
|
)
|
||||||
# We avoid making a separate query for user_group_ids because the
|
# We avoid making a separate query for user_group_ids because the
|
||||||
# recursive query already returns those user groups.
|
# recursive query already returns those user groups.
|
||||||
potential_subgroups = [
|
potential_subgroups = [
|
||||||
|
|
|
@ -20279,6 +20279,19 @@ paths:
|
||||||
items:
|
items:
|
||||||
type: integer
|
type: integer
|
||||||
example: [1, 2, 3, 4]
|
example: [1, 2, 3, 4]
|
||||||
|
subgroups:
|
||||||
|
description: |
|
||||||
|
An array containing the IDs of the initial subgroups for the new
|
||||||
|
user group.
|
||||||
|
|
||||||
|
User can add subgroups to the new group irrespective of other
|
||||||
|
permissions for the new group.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 10.0 (feature level 311).
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: integer
|
||||||
|
example: [11]
|
||||||
can_add_members_group:
|
can_add_members_group:
|
||||||
allOf:
|
allOf:
|
||||||
- description: |
|
- description: |
|
||||||
|
@ -20362,6 +20375,8 @@ paths:
|
||||||
encoding:
|
encoding:
|
||||||
members:
|
members:
|
||||||
contentType: application/json
|
contentType: application/json
|
||||||
|
subgroups:
|
||||||
|
contentType: application/json
|
||||||
can_add_members_group:
|
can_add_members_group:
|
||||||
contentType: application/json
|
contentType: application/json
|
||||||
can_join_group:
|
can_join_group:
|
||||||
|
|
|
@ -531,6 +531,47 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
||||||
self.assert_json_error(result, "User group name cannot start with 'channel:'.")
|
self.assert_json_error(result, "User group name cannot start with 'channel:'.")
|
||||||
self.assert_length(NamedUserGroup.objects.filter(realm=hamlet.realm), 10)
|
self.assert_length(NamedUserGroup.objects.filter(realm=hamlet.realm), 10)
|
||||||
|
|
||||||
|
def test_creating_groups_with_subgroups(self) -> None:
|
||||||
|
realm = get_realm("zulip")
|
||||||
|
hamlet = self.example_user("hamlet")
|
||||||
|
subgroup = check_add_user_group(realm, "support", [hamlet], acting_user=hamlet)
|
||||||
|
self.login("desdemona")
|
||||||
|
|
||||||
|
othello = self.example_user("othello")
|
||||||
|
params = {
|
||||||
|
"name": "Troubleshooting",
|
||||||
|
"members": orjson.dumps([othello.id]).decode(),
|
||||||
|
"description": "Troubleshooting team",
|
||||||
|
"subgroups": orjson.dumps([subgroup.id]).decode(),
|
||||||
|
}
|
||||||
|
result = self.client_post("/json/user_groups/create", info=params)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
self.assert_length(NamedUserGroup.objects.filter(realm=hamlet.realm), 11)
|
||||||
|
user_group = NamedUserGroup.objects.get(name="Troubleshooting", realm=hamlet.realm)
|
||||||
|
self.assert_subgroup_membership(user_group, [subgroup])
|
||||||
|
|
||||||
|
# User can add subgroups to a group while creating it even if
|
||||||
|
# settings are set to not allow adding subgroups after creating
|
||||||
|
# the group.
|
||||||
|
self.login("othello")
|
||||||
|
self.assertEqual(realm.can_manage_all_groups.named_user_group.name, SystemGroups.OWNERS)
|
||||||
|
|
||||||
|
admins_group = NamedUserGroup.objects.get(
|
||||||
|
name=SystemGroups.ADMINISTRATORS, realm=realm, is_system_group=True
|
||||||
|
)
|
||||||
|
params = {
|
||||||
|
"name": "Backend",
|
||||||
|
"members": orjson.dumps([othello.id]).decode(),
|
||||||
|
"description": "Backend team",
|
||||||
|
"subgroups": orjson.dumps([subgroup.id]).decode(),
|
||||||
|
"can_manage_group": orjson.dumps(admins_group.id).decode(),
|
||||||
|
"can_add_members_group": orjson.dumps(admins_group.id).decode(),
|
||||||
|
}
|
||||||
|
result = self.client_post("/json/user_groups/create", info=params)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
user_group = NamedUserGroup.objects.get(name="Troubleshooting", realm=realm)
|
||||||
|
self.assert_subgroup_membership(user_group, [subgroup])
|
||||||
|
|
||||||
def do_test_set_group_setting_during_user_group_creation(self, setting_name: str) -> None:
|
def do_test_set_group_setting_during_user_group_creation(self, setting_name: str) -> None:
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
|
|
|
@ -57,6 +57,7 @@ def add_user_group(
|
||||||
name: str,
|
name: str,
|
||||||
members: Json[list[int]],
|
members: Json[list[int]],
|
||||||
description: str,
|
description: str,
|
||||||
|
subgroups: Json[list[int]] | None = None,
|
||||||
can_add_members_group: Json[int | AnonymousSettingGroupDict] | None = None,
|
can_add_members_group: Json[int | AnonymousSettingGroupDict] | None = None,
|
||||||
can_join_group: Json[int | AnonymousSettingGroupDict] | None = None,
|
can_join_group: Json[int | AnonymousSettingGroupDict] | None = None,
|
||||||
can_leave_group: Json[int | AnonymousSettingGroupDict] | None = None,
|
can_leave_group: Json[int | AnonymousSettingGroupDict] | None = None,
|
||||||
|
@ -84,7 +85,7 @@ def add_user_group(
|
||||||
)
|
)
|
||||||
group_settings_map[setting_name] = setting_value_group
|
group_settings_map[setting_name] = setting_value_group
|
||||||
|
|
||||||
check_add_user_group(
|
user_group = check_add_user_group(
|
||||||
user_profile.realm,
|
user_profile.realm,
|
||||||
name,
|
name,
|
||||||
user_profiles,
|
user_profiles,
|
||||||
|
@ -92,6 +93,15 @@ def add_user_group(
|
||||||
group_settings_map=group_settings_map,
|
group_settings_map=group_settings_map,
|
||||||
acting_user=user_profile,
|
acting_user=user_profile,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if subgroups is not None and len(subgroups) != 0:
|
||||||
|
with lock_subgroups_with_respect_to_supergroup(
|
||||||
|
subgroups, user_group.id, user_profile, permission_setting=None, creating_group=True
|
||||||
|
) as context:
|
||||||
|
add_subgroups_to_user_group(
|
||||||
|
context.supergroup, context.direct_subgroups, acting_user=user_profile
|
||||||
|
)
|
||||||
|
|
||||||
return json_success(request)
|
return json_success(request)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue