mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-31 20:13:46 +00:00 
			
		
		
		
	user_groups: Add API endpoint to get members of a user group.
This commit adds 'GET /user_groups/{user_group_id}/members'
endpoint to get members of a user group. "direct_member_only"
parameter can be passed as True to the endpoint to get only
direct members of the user group and not the members of
subgroup.
			
			
This commit is contained in:
		| @@ -34,6 +34,8 @@ format used by the Zulip server that they are interacting with. | |||||||
| * [`GET /user_groups/{user_group_id}/members/{user_id}`](/api/get-is-user-group-member): | * [`GET /user_groups/{user_group_id}/members/{user_id}`](/api/get-is-user-group-member): | ||||||
|   Added new endpoint for checking whether a given user is member of a |   Added new endpoint for checking whether a given user is member of a | ||||||
|   given user group. |   given user group. | ||||||
|  | * [`GET /user_groups/{user_group_id}/members`](/api/get-user-group-members): | ||||||
|  |   Added new endpoint to get members of a user group. | ||||||
|  |  | ||||||
| **Feature level 126** | **Feature level 126** | ||||||
|  |  | ||||||
|   | |||||||
| @@ -63,6 +63,7 @@ | |||||||
| * [Update user group members](/api/update-user-group-members) | * [Update user group members](/api/update-user-group-members) | ||||||
| * [Update user group subgroups](/api/update-user-group-subgroups) | * [Update user group subgroups](/api/update-user-group-subgroups) | ||||||
| * [Get user group membership status](/api/get-is-user-group-member) | * [Get user group membership status](/api/get-is-user-group-member) | ||||||
|  | * [Get user group members](/api/get-user-group-members) | ||||||
| * [Mute a user](/api/mute-user) | * [Mute a user](/api/mute-user) | ||||||
| * [Unmute a user](/api/unmute-user) | * [Unmute a user](/api/unmute-user) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -168,6 +168,17 @@ def is_user_in_group( | |||||||
|     return get_recursive_group_members(user_group=user_group).filter(id=user.id).exists() |     return get_recursive_group_members(user_group=user_group).filter(id=user.id).exists() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_user_group_member_ids( | ||||||
|  |     user_group: UserGroup, *, direct_member_only: bool = False | ||||||
|  | ) -> List[int]: | ||||||
|  |     if direct_member_only: | ||||||
|  |         member_ids = get_user_group_direct_members(user_group) | ||||||
|  |     else: | ||||||
|  |         member_ids = get_recursive_group_members(user_group).values_list("id", flat=True) | ||||||
|  |  | ||||||
|  |     return list(member_ids) | ||||||
|  |  | ||||||
|  |  | ||||||
| def create_system_user_groups_for_realm(realm: Realm) -> Dict[int, UserGroup]: | def create_system_user_groups_for_realm(realm: Realm) -> Dict[int, UserGroup]: | ||||||
|     """Any changes to this function likely require a migration to adjust |     """Any changes to this function likely require a migration to adjust | ||||||
|     existing realms.  See e.g. migration 0375_create_role_based_system_groups.py, |     existing realms.  See e.g. migration 0375_create_role_based_system_groups.py, | ||||||
|   | |||||||
| @@ -13756,6 +13756,40 @@ paths: | |||||||
|       responses: |       responses: | ||||||
|         "200": |         "200": | ||||||
|           $ref: "#/components/responses/SimpleSuccess" |           $ref: "#/components/responses/SimpleSuccess" | ||||||
|  |     get: | ||||||
|  |       operationId: get-user-group-members | ||||||
|  |       summary: Get user group members | ||||||
|  |       tags: ["users"] | ||||||
|  |       description: | | ||||||
|  |         Get the members of a [user group](/help/user-groups). | ||||||
|  |  | ||||||
|  |         `GET {{ api_url }}/v1/user_groups/{user_group_id}/members` | ||||||
|  |  | ||||||
|  |         **Changes**: New in Zulip 6.0 (feature level 127). | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/components/parameters/UserGroupId" | ||||||
|  |         - $ref: "#/components/parameters/DirectMemberOnly" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: Success | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 allOf: | ||||||
|  |                   - $ref: "#/components/schemas/JsonSuccessBase" | ||||||
|  |                   - $ref: "#/components/schemas/SuccessDescription" | ||||||
|  |                   - additionalProperties: false | ||||||
|  |                     properties: | ||||||
|  |                       result: {} | ||||||
|  |                       msg: {} | ||||||
|  |                       members: | ||||||
|  |                         type: array | ||||||
|  |                         items: | ||||||
|  |                           type: integer | ||||||
|  |                         description: | | ||||||
|  |                           A list containing the user IDs of members of the user group. | ||||||
|  |                     example: | ||||||
|  |                       {"msg": "", "result": "success", "members": [10, 12]} | ||||||
|   /user_groups/{user_group_id}: |   /user_groups/{user_group_id}: | ||||||
|     patch: |     patch: | ||||||
|       operationId: update-user-group |       operationId: update-user-group | ||||||
|   | |||||||
| @@ -941,3 +941,41 @@ class UserGroupAPITestCase(UserGroupTestCase): | |||||||
|             self.client_get(f"/json/user_groups/{admins_group.id}/members/{othello.id}").content |             self.client_get(f"/json/user_groups/{admins_group.id}/members/{othello.id}").content | ||||||
|         ) |         ) | ||||||
|         self.assertFalse(result_dict["is_user_group_member"]) |         self.assertFalse(result_dict["is_user_group_member"]) | ||||||
|  |  | ||||||
|  |     def test_get_user_group_members(self) -> None: | ||||||
|  |         realm = get_realm("zulip") | ||||||
|  |         iago = self.example_user("iago") | ||||||
|  |         desdemona = self.example_user("desdemona") | ||||||
|  |         shiva = self.example_user("shiva") | ||||||
|  |         moderators_group = UserGroup.objects.get( | ||||||
|  |             name="@role:moderators", realm=realm, is_system_group=True | ||||||
|  |         ) | ||||||
|  |         self.login("iago") | ||||||
|  |  | ||||||
|  |         # Test invalid user group id | ||||||
|  |         result = self.client_get("/json/user_groups/25/members") | ||||||
|  |         self.assert_json_error(result, "Invalid user group") | ||||||
|  |  | ||||||
|  |         result_dict = orjson.loads( | ||||||
|  |             self.client_get(f"/json/user_groups/{moderators_group.id}/members").content | ||||||
|  |         ) | ||||||
|  |         self.assertCountEqual(result_dict["members"], [desdemona.id, iago.id, shiva.id]) | ||||||
|  |  | ||||||
|  |         params = {"direct_member_only": orjson.dumps(True).decode()} | ||||||
|  |         result_dict = orjson.loads( | ||||||
|  |             self.client_get(f"/json/user_groups/{moderators_group.id}/members", info=params).content | ||||||
|  |         ) | ||||||
|  |         self.assertCountEqual(result_dict["members"], [shiva.id]) | ||||||
|  |  | ||||||
|  |         # User not part of a group can also get its members. | ||||||
|  |         self.login("hamlet") | ||||||
|  |         result_dict = orjson.loads( | ||||||
|  |             self.client_get(f"/json/user_groups/{moderators_group.id}/members").content | ||||||
|  |         ) | ||||||
|  |         self.assertCountEqual(result_dict["members"], [desdemona.id, iago.id, shiva.id]) | ||||||
|  |  | ||||||
|  |         params = {"direct_member_only": orjson.dumps(True).decode()} | ||||||
|  |         result_dict = orjson.loads( | ||||||
|  |             self.client_get(f"/json/user_groups/{moderators_group.id}/members", info=params).content | ||||||
|  |         ) | ||||||
|  |         self.assertCountEqual(result_dict["members"], [shiva.id]) | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ from zerver.lib.user_groups import ( | |||||||
|     access_user_groups_as_potential_subgroups, |     access_user_groups_as_potential_subgroups, | ||||||
|     get_direct_memberships_of_users, |     get_direct_memberships_of_users, | ||||||
|     get_user_group_direct_members, |     get_user_group_direct_members, | ||||||
|  |     get_user_group_member_ids, | ||||||
|     is_user_in_group, |     is_user_in_group, | ||||||
|     user_groups_in_realm_serialized, |     user_groups_in_realm_serialized, | ||||||
| ) | ) | ||||||
| @@ -240,3 +241,21 @@ def get_is_user_group_member( | |||||||
|             ) |             ) | ||||||
|         }, |         }, | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @require_member_or_admin | ||||||
|  | @has_request_variables | ||||||
|  | def get_user_group_members( | ||||||
|  |     request: HttpRequest, | ||||||
|  |     user_profile: UserProfile, | ||||||
|  |     user_group_id: int = REQ(json_validator=check_int, path_only=True), | ||||||
|  |     direct_member_only: bool = REQ(json_validator=check_bool, default=False), | ||||||
|  | ) -> HttpResponse: | ||||||
|  |     user_group = access_user_group_by_id(user_group_id, user_profile, for_read=True) | ||||||
|  |  | ||||||
|  |     return json_success( | ||||||
|  |         request, | ||||||
|  |         data={ | ||||||
|  |             "members": get_user_group_member_ids(user_group, direct_member_only=direct_member_only) | ||||||
|  |         }, | ||||||
|  |     ) | ||||||
|   | |||||||
| @@ -178,6 +178,7 @@ from zerver.views.user_groups import ( | |||||||
|     edit_user_group, |     edit_user_group, | ||||||
|     get_is_user_group_member, |     get_is_user_group_member, | ||||||
|     get_user_group, |     get_user_group, | ||||||
|  |     get_user_group_members, | ||||||
|     update_subgroups_of_user_group, |     update_subgroups_of_user_group, | ||||||
|     update_user_group_backend, |     update_user_group_backend, | ||||||
| ) | ) | ||||||
| @@ -373,7 +374,11 @@ v1_api_and_json_patterns = [ | |||||||
|     rest_path("user_groups", GET=get_user_group), |     rest_path("user_groups", GET=get_user_group), | ||||||
|     rest_path("user_groups/create", POST=add_user_group), |     rest_path("user_groups/create", POST=add_user_group), | ||||||
|     rest_path("user_groups/<int:user_group_id>", PATCH=edit_user_group, DELETE=delete_user_group), |     rest_path("user_groups/<int:user_group_id>", PATCH=edit_user_group, DELETE=delete_user_group), | ||||||
|     rest_path("user_groups/<int:user_group_id>/members", POST=update_user_group_backend), |     rest_path( | ||||||
|  |         "user_groups/<int:user_group_id>/members", | ||||||
|  |         GET=get_user_group_members, | ||||||
|  |         POST=update_user_group_backend, | ||||||
|  |     ), | ||||||
|     rest_path("user_groups/<int:user_group_id>/subgroups", POST=update_subgroups_of_user_group), |     rest_path("user_groups/<int:user_group_id>/subgroups", POST=update_subgroups_of_user_group), | ||||||
|     rest_path( |     rest_path( | ||||||
|         "user_groups/<int:user_group_id>/members/<int:user_id>", GET=get_is_user_group_member |         "user_groups/<int:user_group_id>/members/<int:user_id>", GET=get_is_user_group_member | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user