mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-31 03:53:50 +00:00 
			
		
		
		
	Groups: Can perform any join, leave, add, remove for deactivated group.
Fixes #33804. We still do not allow permission settings to be set to deactivated groups.
This commit is contained in:
		
				
					committed by
					
						 Tim Abbott
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							74b0d8ff61
						
					
				
				
					commit
					7eb9c9deef
				
			| @@ -20,6 +20,12 @@ format used by the Zulip server that they are interacting with. | |||||||
|  |  | ||||||
| ## Changes in Zulip 11.0 | ## Changes in Zulip 11.0 | ||||||
|  |  | ||||||
|  | **Feature level 391** | ||||||
|  |  | ||||||
|  | * [`POST /user_groups/{user_group_id}/members`](/api/update-user-group-members), | ||||||
|  |   [`POST /user_groups/{user_group_id}/subgroups`](/api/update-user-group-subgroups): | ||||||
|  |   Adding/removing members and subgroups to a deactivated group is now allowed. | ||||||
|  |  | ||||||
| **Feature level 390** | **Feature level 390** | ||||||
|  |  | ||||||
| * [`GET /events`](/api/get-events): Events with `type: "navigation_view"` are | * [`GET /events`](/api/get-events): Events with `type: "navigation_view"` are | ||||||
|   | |||||||
| @@ -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 = 390 | API_FEATURE_LEVEL = 391 | ||||||
|  |  | ||||||
| # 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 | ||||||
|   | |||||||
| @@ -176,10 +176,6 @@ export function can_manage_user_group(group_id: number): boolean { | |||||||
|  |  | ||||||
| export function can_add_members_to_user_group(group_id: number): boolean { | export function can_add_members_to_user_group(group_id: number): boolean { | ||||||
|     const group = user_groups.get_user_group_from_id(group_id); |     const group = user_groups.get_user_group_from_id(group_id); | ||||||
|     // We cannot add members if the group is deactivated. |  | ||||||
|     if (group.deactivated) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|     if ( |     if ( | ||||||
|         user_has_permission_for_group_setting( |         user_has_permission_for_group_setting( | ||||||
|             group.can_add_members_group, |             group.can_add_members_group, | ||||||
| @@ -195,10 +191,6 @@ export function can_add_members_to_user_group(group_id: number): boolean { | |||||||
|  |  | ||||||
| export function can_remove_members_from_user_group(group_id: number): boolean { | export function can_remove_members_from_user_group(group_id: number): boolean { | ||||||
|     const group = user_groups.get_user_group_from_id(group_id); |     const group = user_groups.get_user_group_from_id(group_id); | ||||||
|     // We cannot remove members if the group is deactivated. |  | ||||||
|     if (group.deactivated) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|     if ( |     if ( | ||||||
|         user_has_permission_for_group_setting( |         user_has_permission_for_group_setting( | ||||||
|             group.can_remove_members_group, |             group.can_remove_members_group, | ||||||
| @@ -214,10 +206,6 @@ export function can_remove_members_from_user_group(group_id: number): boolean { | |||||||
|  |  | ||||||
| export function can_join_user_group(group_id: number): boolean { | export function can_join_user_group(group_id: number): boolean { | ||||||
|     const group = user_groups.get_user_group_from_id(group_id); |     const group = user_groups.get_user_group_from_id(group_id); | ||||||
|     // One cannot join a deactivated group. |  | ||||||
|     if (group.deactivated) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|     if (user_has_permission_for_group_setting(group.can_join_group, "can_join_group", "group")) { |     if (user_has_permission_for_group_setting(group.can_join_group, "can_join_group", "group")) { | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @@ -226,11 +214,7 @@ export function can_join_user_group(group_id: number): boolean { | |||||||
| } | } | ||||||
|  |  | ||||||
| export function can_leave_user_group(group_id: number): boolean { | export function can_leave_user_group(group_id: number): boolean { | ||||||
|     // One cannot leave a deactivated group. |  | ||||||
|     const group = user_groups.get_user_group_from_id(group_id); |     const group = user_groups.get_user_group_from_id(group_id); | ||||||
|     if (group.deactivated) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|     if (user_has_permission_for_group_setting(group.can_leave_group, "can_leave_group", "group")) { |     if (user_has_permission_for_group_setting(group.can_leave_group, "can_leave_group", "group")) { | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -164,9 +164,9 @@ function update_add_members_elements(group: UserGroup): void { | |||||||
|         $button_element.prop("disabled", true); |         $button_element.prop("disabled", true); | ||||||
|         $add_members_container.addClass("add_members_disabled"); |         $add_members_container.addClass("add_members_disabled"); | ||||||
|  |  | ||||||
|         const disable_hint = group.deactivated |         const disable_hint = $t({ | ||||||
|             ? $t({defaultMessage: "Can't add members to a deactivated group"}) |             defaultMessage: "You are not allowed to add members to this group", | ||||||
|             : $t({defaultMessage: "You are not allowed to add members to this group"}); |         }); | ||||||
|         settings_components.initialize_disable_button_hint_popover( |         settings_components.initialize_disable_button_hint_popover( | ||||||
|             $add_members_container, |             $add_members_container, | ||||||
|             disable_hint, |             disable_hint, | ||||||
| @@ -309,13 +309,8 @@ function initialize_tooltip_for_membership_button(group_id: number): void { | |||||||
|         ".join_leave_button_wrapper", |         ".join_leave_button_wrapper", | ||||||
|     ); |     ); | ||||||
|     const is_member = user_groups.is_user_in_group(group_id, people.my_current_user_id()); |     const is_member = user_groups.is_user_in_group(group_id, people.my_current_user_id()); | ||||||
|     const is_deactivated = user_groups.get_user_group_from_id(group_id).deactivated; |  | ||||||
|     let tooltip_message; |     let tooltip_message; | ||||||
|     if (is_deactivated && is_member) { |     if (is_member) { | ||||||
|         tooltip_message = $t({defaultMessage: "You cannot leave a deactivated user group."}); |  | ||||||
|     } else if (is_deactivated) { |  | ||||||
|         tooltip_message = $t({defaultMessage: "You cannot join a deactivated user group."}); |  | ||||||
|     } else if (is_member) { |  | ||||||
|         tooltip_message = $t({defaultMessage: "You do not have permission to leave this group."}); |         tooltip_message = $t({defaultMessage: "You do not have permission to leave this group."}); | ||||||
|     } else { |     } else { | ||||||
|         tooltip_message = $t({defaultMessage: "You do not have permission to join this group."}); |         tooltip_message = $t({defaultMessage: "You do not have permission to join this group."}); | ||||||
|   | |||||||
| @@ -110,6 +110,8 @@ const deactivated_group = { | |||||||
|     members: new Set([1, 2, 3]), |     members: new Set([1, 2, 3]), | ||||||
|     is_system_group: false, |     is_system_group: false, | ||||||
|     direct_subgroup_ids: new Set([4, 5, 6]), |     direct_subgroup_ids: new Set([4, 5, 6]), | ||||||
|  |     can_add_members_group: 4, | ||||||
|  |     can_remove_members_group: 4, | ||||||
|     can_join_group: 1, |     can_join_group: 1, | ||||||
|     can_leave_group: 1, |     can_leave_group: 1, | ||||||
|     can_manage_group: 1, |     can_manage_group: 1, | ||||||
| @@ -436,8 +438,8 @@ function test_user_group_permission_setting(override, setting_name, permission_f | |||||||
|     override(current_user, "user_id", 2); |     override(current_user, "user_id", 2); | ||||||
|     assert.ok(permission_func(students.id)); |     assert.ok(permission_func(students.id)); | ||||||
|  |  | ||||||
|     // Cannot perform any join, leave, add, remove if group is deactivated |     // Can perform any join, leave, add, remove even if the group is deactivated | ||||||
|     assert.ok(!permission_func(deactivated_group.id)); |     assert.ok(permission_func(deactivated_group.id)); | ||||||
| } | } | ||||||
|  |  | ||||||
| run_test("can_join_user_group", ({override}) => { | run_test("can_join_user_group", ({override}) => { | ||||||
|   | |||||||
| @@ -326,7 +326,10 @@ def lock_subgroups_with_respect_to_supergroup( | |||||||
|         else: |         else: | ||||||
|             assert permission_setting is not None |             assert permission_setting is not None | ||||||
|             potential_supergroup = access_user_group_for_update( |             potential_supergroup = access_user_group_for_update( | ||||||
|                 potential_supergroup_id, acting_user, permission_setting=permission_setting |                 potential_supergroup_id, | ||||||
|  |                 acting_user, | ||||||
|  |                 permission_setting=permission_setting, | ||||||
|  |                 allow_deactivated=True, | ||||||
|             ) |             ) | ||||||
|         # 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. | ||||||
|   | |||||||
| @@ -22518,6 +22518,9 @@ paths: | |||||||
|         Update the members of a [user group](/help/user-groups). The |         Update the members of a [user group](/help/user-groups). The | ||||||
|         user IDs must correspond to non-deactivated users. |         user IDs must correspond to non-deactivated users. | ||||||
| 
 | 
 | ||||||
|  |         **Changes**: Prior to Zulip 11.0 (feature level 391), members | ||||||
|  |         could not be added or removed from a deactivated group. | ||||||
|  | 
 | ||||||
|         **Changes**: Prior to Zulip 10.0 (feature level 303), group memberships of |         **Changes**: Prior to Zulip 10.0 (feature level 303), group memberships of | ||||||
|         deactivated users were visible to the API and could be edited via this endpoint. |         deactivated users were visible to the API and could be edited via this endpoint. | ||||||
|       x-curl-examples-parameters: |       x-curl-examples-parameters: | ||||||
| @@ -23111,6 +23114,9 @@ paths: | |||||||
|       description: | |       description: | | ||||||
|         Update the subgroups of a [user group](/help/user-groups). |         Update the subgroups of a [user group](/help/user-groups). | ||||||
| 
 | 
 | ||||||
|  |         **Changes**: Prior to Zulip 11.0 (feature level 391), subgroups | ||||||
|  |         could not be added or removed from a deactivated group. | ||||||
|  | 
 | ||||||
|         **Changes**: New in Zulip 6.0 (feature level 127). |         **Changes**: New in Zulip 6.0 (feature level 127). | ||||||
|       x-curl-examples-parameters: |       x-curl-examples-parameters: | ||||||
|         oneOf: |         oneOf: | ||||||
|   | |||||||
| @@ -2122,12 +2122,12 @@ class UserGroupAPITestCase(UserGroupTestCase): | |||||||
|  |  | ||||||
|         params = {"delete": orjson.dumps([hamlet.id]).decode()} |         params = {"delete": orjson.dumps([hamlet.id]).decode()} | ||||||
|         result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params) |         result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params) | ||||||
|         self.assert_json_error(result, "User group is deactivated.") |         self.assert_json_success(result) | ||||||
|         self.assert_user_membership(user_group, [hamlet]) |         self.assert_member_not_in_group(user_group, hamlet) | ||||||
|  |  | ||||||
|         params = {"add": orjson.dumps([iago.id]).decode()} |         params = {"add": orjson.dumps([hamlet.id]).decode()} | ||||||
|         result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params) |         result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params) | ||||||
|         self.assert_json_error(result, "User group is deactivated.") |         self.assert_json_success(result) | ||||||
|         self.assert_user_membership(user_group, [hamlet]) |         self.assert_user_membership(user_group, [hamlet]) | ||||||
|  |  | ||||||
|     def test_mentions(self) -> None: |     def test_mentions(self) -> None: | ||||||
| @@ -3317,12 +3317,12 @@ class UserGroupAPITestCase(UserGroupTestCase): | |||||||
|  |  | ||||||
|         params = {"delete": orjson.dumps([leadership_group.id]).decode()} |         params = {"delete": orjson.dumps([leadership_group.id]).decode()} | ||||||
|         result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) |         result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) | ||||||
|         self.assert_json_error(result, "User group is deactivated.") |         self.assert_json_success(result) | ||||||
|         self.assert_subgroup_membership(support_group, [leadership_group]) |         self.assert_subgroup_membership(support_group, []) | ||||||
|  |  | ||||||
|         params = {"add": orjson.dumps([test_group.id]).decode()} |         params = {"add": orjson.dumps([leadership_group.id]).decode()} | ||||||
|         result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) |         result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) | ||||||
|         self.assert_json_error(result, "User group is deactivated.") |         self.assert_json_success(result) | ||||||
|         self.assert_subgroup_membership(support_group, [leadership_group]) |         self.assert_subgroup_membership(support_group, [leadership_group]) | ||||||
|  |  | ||||||
|         # Test that a deactivated group cannot be used as a subgroup. |         # Test that a deactivated group cannot be used as a subgroup. | ||||||
|   | |||||||
| @@ -334,17 +334,26 @@ def add_members_to_group_backend( | |||||||
|     if len(members) == 1 and user_profile.id == members[0]: |     if len(members) == 1 and user_profile.id == members[0]: | ||||||
|         try: |         try: | ||||||
|             user_group = access_user_group_for_update( |             user_group = access_user_group_for_update( | ||||||
|                 user_group_id, user_profile, permission_setting="can_join_group" |                 user_group_id, | ||||||
|  |                 user_profile, | ||||||
|  |                 permission_setting="can_join_group", | ||||||
|  |                 allow_deactivated=True, | ||||||
|             ) |             ) | ||||||
|         except JsonableError: |         except JsonableError: | ||||||
|             # User can still join the group if user has permission to add |             # User can still join the group if user has permission to add | ||||||
|             # anyone in the group. |             # anyone in the group. | ||||||
|             user_group = access_user_group_for_update( |             user_group = access_user_group_for_update( | ||||||
|                 user_group_id, user_profile, permission_setting="can_add_members_group" |                 user_group_id, | ||||||
|  |                 user_profile, | ||||||
|  |                 permission_setting="can_add_members_group", | ||||||
|  |                 allow_deactivated=True, | ||||||
|             ) |             ) | ||||||
|     else: |     else: | ||||||
|         user_group = access_user_group_for_update( |         user_group = access_user_group_for_update( | ||||||
|             user_group_id, user_profile, permission_setting="can_add_members_group" |             user_group_id, | ||||||
|  |             user_profile, | ||||||
|  |             permission_setting="can_add_members_group", | ||||||
|  |             allow_deactivated=True, | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|     member_users = user_ids_to_users(members, user_profile.realm, allow_deactivated=False) |     member_users = user_ids_to_users(members, user_profile.realm, allow_deactivated=False) | ||||||
| @@ -381,17 +390,26 @@ def remove_members_from_group_backend( | |||||||
|     if len(members) == 1 and user_profile.id == members[0]: |     if len(members) == 1 and user_profile.id == members[0]: | ||||||
|         try: |         try: | ||||||
|             user_group = access_user_group_for_update( |             user_group = access_user_group_for_update( | ||||||
|                 user_group_id, user_profile, permission_setting="can_leave_group" |                 user_group_id, | ||||||
|  |                 user_profile, | ||||||
|  |                 permission_setting="can_leave_group", | ||||||
|  |                 allow_deactivated=True, | ||||||
|             ) |             ) | ||||||
|         except JsonableError: |         except JsonableError: | ||||||
|             # User can still leave the group if user has permission to remove |             # User can still leave the group if user has permission to remove | ||||||
|             # anyone from the group. |             # anyone from the group. | ||||||
|             user_group = access_user_group_for_update( |             user_group = access_user_group_for_update( | ||||||
|                 user_group_id, user_profile, permission_setting="can_remove_members_group" |                 user_group_id, | ||||||
|  |                 user_profile, | ||||||
|  |                 permission_setting="can_remove_members_group", | ||||||
|  |                 allow_deactivated=True, | ||||||
|             ) |             ) | ||||||
|     else: |     else: | ||||||
|         user_group = access_user_group_for_update( |         user_group = access_user_group_for_update( | ||||||
|             user_group_id, user_profile, permission_setting="can_remove_members_group" |             user_group_id, | ||||||
|  |             user_profile, | ||||||
|  |             permission_setting="can_remove_members_group", | ||||||
|  |             allow_deactivated=True, | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|     group_member_ids = get_user_group_direct_member_ids(user_group) |     group_member_ids = get_user_group_direct_member_ids(user_group) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user