mirror of https://github.com/zulip/zulip.git
user_groups: Add API support for deactivating user groups.
This commit is contained in:
parent
bef7cfe00f
commit
e1cfe61452
|
@ -20,6 +20,16 @@ format used by the Zulip server that they are interacting with.
|
|||
|
||||
## Changes in Zulip 10.0
|
||||
|
||||
**Feature level 290**
|
||||
|
||||
* [`POST /user_groups/{user_group_id}/deactivate`](/api/deactivate-user-group):
|
||||
Added new API endpoint to deactivate a user group.
|
||||
* [`POST /register`](/api/register-queue), [`GET
|
||||
/user_groups`](/api/get-user-groups): Added `deactivated` field in
|
||||
the user group objects to identify deactivated user groups.
|
||||
* [`GET /events`](/api/get-events): When a user group is deactivated,
|
||||
a `user_group` event with `op=update` is sent to clients.
|
||||
|
||||
**Feature level 289**
|
||||
|
||||
* [`POST /users/{user_id}/subscription`](/api/subscribe): In the response,
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
* [Create a user group](/api/create-user-group)
|
||||
* [Update a user group](/api/update-user-group)
|
||||
* [Delete a user group](/api/remove-user-group)
|
||||
* [Deactivate a user group](/api/deactivate-user-group)
|
||||
* [Update user group members](/api/update-user-group-members)
|
||||
* [Update subgroups of a user group](/api/update-user-group-subgroups)
|
||||
* [Get user group membership status](/api/get-is-user-group-member)
|
||||
|
|
|
@ -815,6 +815,7 @@ exports.fixtures = {
|
|||
direct_subgroup_ids: [2],
|
||||
can_manage_group: 16,
|
||||
can_mention_group: 11,
|
||||
deactivated: false,
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
@ -182,6 +182,7 @@ def do_send_create_user_group_event(
|
|||
direct_subgroup_ids=[direct_subgroup.id for direct_subgroup in direct_subgroups],
|
||||
can_manage_group=get_group_setting_value_for_api(user_group.can_manage_group),
|
||||
can_mention_group=get_group_setting_value_for_api(user_group.can_mention_group),
|
||||
deactivated=False,
|
||||
),
|
||||
)
|
||||
send_event_on_commit(user_group.realm, event, active_user_ids(user_group.realm_id))
|
||||
|
@ -436,6 +437,25 @@ def check_delete_user_group(user_group: NamedUserGroup, *, acting_user: UserProf
|
|||
do_send_delete_user_group_event(acting_user.realm, user_group_id, acting_user.realm.id)
|
||||
|
||||
|
||||
@transaction.atomic(savepoint=False)
|
||||
def do_deactivate_user_group(
|
||||
user_group: NamedUserGroup, *, acting_user: UserProfile | None
|
||||
) -> None:
|
||||
user_group.deactivated = True
|
||||
user_group.save(update_fields=["deactivated"])
|
||||
|
||||
now = timezone_now()
|
||||
RealmAuditLog.objects.create(
|
||||
realm=user_group.realm,
|
||||
modified_user_group_id=user_group.id,
|
||||
event_type=AuditLogEventType.USER_GROUP_DEACTIVATED,
|
||||
event_time=now,
|
||||
acting_user=acting_user,
|
||||
)
|
||||
|
||||
do_send_user_group_update_event(user_group, dict(deactivated=True))
|
||||
|
||||
|
||||
@transaction.atomic(savepoint=False)
|
||||
def do_change_user_group_permission_setting(
|
||||
user_group: NamedUserGroup,
|
||||
|
|
|
@ -1817,6 +1817,7 @@ group_type = DictType(
|
|||
("is_system_group", bool),
|
||||
("can_manage_group", group_setting_type),
|
||||
("can_mention_group", group_setting_type),
|
||||
("deactivated", bool),
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -1865,6 +1866,7 @@ user_group_data_type = DictType(
|
|||
("description", str),
|
||||
("can_manage_group", group_setting_type),
|
||||
("can_mention_group", group_setting_type),
|
||||
("deactivated", bool),
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from typing import TypedDict
|
|||
|
||||
from django.conf import settings
|
||||
from django.db import connection, transaction
|
||||
from django.db.models import F, QuerySet
|
||||
from django.db.models import F, Q, QuerySet
|
||||
from django.utils.timezone import now as timezone_now
|
||||
from django.utils.translation import gettext as _
|
||||
from django_cte import With
|
||||
|
@ -53,6 +53,7 @@ class UserGroupDict(TypedDict):
|
|||
is_system_group: bool
|
||||
can_manage_group: int | AnonymousSettingGroupDict
|
||||
can_mention_group: int | AnonymousSettingGroupDict
|
||||
deactivated: bool
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -126,6 +127,70 @@ def access_user_group_by_id(
|
|||
return user_group
|
||||
|
||||
|
||||
def access_user_group_for_deactivation(
|
||||
user_group_id: int, user_profile: UserProfile
|
||||
) -> NamedUserGroup:
|
||||
user_group = access_user_group_by_id(user_group_id, user_profile, for_read=False)
|
||||
|
||||
if (
|
||||
user_group.direct_supergroups.exclude(named_user_group=None)
|
||||
.filter(named_user_group__deactivated=False)
|
||||
.exists()
|
||||
):
|
||||
raise JsonableError(
|
||||
_("You cannot deactivate a user group that is subgroup of any user group.")
|
||||
)
|
||||
|
||||
anonymous_supergroup_ids = user_group.direct_supergroups.filter(
|
||||
named_user_group=None
|
||||
).values_list("id", flat=True)
|
||||
|
||||
# We check both the cases - whether the group is being directly used
|
||||
# as the value of a setting or as a subgroup of an anonymous group
|
||||
# used for a setting.
|
||||
setting_group_ids_using_deactivating_user_group = [
|
||||
*list(anonymous_supergroup_ids),
|
||||
user_group.id,
|
||||
]
|
||||
|
||||
stream_setting_query = Q()
|
||||
for setting_name in Stream.stream_permission_group_settings:
|
||||
stream_setting_query |= Q(
|
||||
**{f"{setting_name}__in": setting_group_ids_using_deactivating_user_group}
|
||||
)
|
||||
|
||||
if (
|
||||
Stream.objects.filter(realm_id=user_group.realm_id, deactivated=False)
|
||||
.filter(stream_setting_query)
|
||||
.exists()
|
||||
):
|
||||
raise JsonableError(_("You cannot deactivate a user group which is used for setting."))
|
||||
|
||||
group_setting_query = Q()
|
||||
for setting_name in NamedUserGroup.GROUP_PERMISSION_SETTINGS:
|
||||
group_setting_query |= Q(
|
||||
**{f"{setting_name}__in": setting_group_ids_using_deactivating_user_group}
|
||||
)
|
||||
|
||||
if (
|
||||
NamedUserGroup.objects.filter(realm_id=user_group.realm_id, deactivated=False)
|
||||
.filter(group_setting_query)
|
||||
.exists()
|
||||
):
|
||||
raise JsonableError(_("You cannot deactivate a user group which is used for setting."))
|
||||
|
||||
realm_setting_query = Q()
|
||||
for setting_name in Realm.REALM_PERMISSION_GROUP_SETTINGS:
|
||||
realm_setting_query |= Q(
|
||||
**{f"{setting_name}__in": setting_group_ids_using_deactivating_user_group}
|
||||
)
|
||||
|
||||
if Realm.objects.filter(id=user_group.realm_id).filter(realm_setting_query).exists():
|
||||
raise JsonableError(_("You cannot deactivate a user group which is used for setting."))
|
||||
|
||||
return user_group
|
||||
|
||||
|
||||
@contextmanager
|
||||
def lock_subgroups_with_respect_to_supergroup(
|
||||
potential_subgroup_ids: Collection[int], potential_supergroup_id: int, acting_user: UserProfile
|
||||
|
@ -430,6 +495,7 @@ def user_groups_in_realm_serialized(realm: Realm) -> list[UserGroupDict]:
|
|||
can_mention_group=get_setting_value_for_user_group_object(
|
||||
user_group.can_mention_group, group_members, group_subgroups
|
||||
),
|
||||
deactivated=user_group.deactivated,
|
||||
)
|
||||
|
||||
for group_dict in group_dicts.values():
|
||||
|
|
|
@ -106,6 +106,7 @@ class AuditLogEventType(IntEnum):
|
|||
USER_GROUP_NAME_CHANGED = 720
|
||||
USER_GROUP_DESCRIPTION_CHANGED = 721
|
||||
USER_GROUP_GROUP_BASED_SETTING_CHANGED = 722
|
||||
USER_GROUP_DEACTIVATED = 723
|
||||
|
||||
# The following values are only for remote server/realm logs.
|
||||
# Values should be exactly 10000 greater than the corresponding
|
||||
|
|
|
@ -275,6 +275,20 @@ def get_temp_user_group_id() -> dict[str, object]:
|
|||
}
|
||||
|
||||
|
||||
@openapi_param_value_generator(["/user_groups/{user_group_id}/deactivate:post"])
|
||||
def get_temp_user_group_id_for_deactivation() -> dict[str, object]:
|
||||
user_group, _ = NamedUserGroup.objects.get_or_create(
|
||||
name="temp-deactivation",
|
||||
realm=get_realm("zulip"),
|
||||
can_manage_group_id=11,
|
||||
can_mention_group_id=11,
|
||||
realm_for_sharding=get_realm("zulip"),
|
||||
)
|
||||
return {
|
||||
"user_group_id": user_group.id,
|
||||
}
|
||||
|
||||
|
||||
@openapi_param_value_generator(["/realm/filters/{filter_id}:delete"])
|
||||
def remove_realm_filters() -> dict[str, object]:
|
||||
filter_id = do_add_linkifier(
|
||||
|
|
|
@ -3228,6 +3228,14 @@ paths:
|
|||
[setting-values]: /api/group-setting-values
|
||||
[system-groups]: /api/group-setting-values#system-groups
|
||||
[mentions]: /help/mention-a-user-or-group
|
||||
deactivated:
|
||||
type: boolean
|
||||
description: |
|
||||
Whether the user group is deactivated. Deactivated groups
|
||||
cannot be used as a subgroup of another group or used for
|
||||
any other purpose.
|
||||
|
||||
**Changes**: New in Zulip 10.0 (feature level 290).
|
||||
example:
|
||||
{
|
||||
"type": "user_group",
|
||||
|
@ -20048,6 +20056,14 @@ paths:
|
|||
[setting-values]: /api/group-setting-values
|
||||
[system-groups]: /api/group-setting-values#system-groups
|
||||
[mentions]: /help/mention-a-user-or-group
|
||||
deactivated:
|
||||
type: boolean
|
||||
description: |
|
||||
Whether the user group is deactivated. Deactivated groups
|
||||
cannot be used as a subgroup of another group or used for
|
||||
any other purpose.
|
||||
|
||||
**Changes**: New in Zulip 10.0 (feature level 290).
|
||||
description: |
|
||||
A list of `user_group` objects.
|
||||
example:
|
||||
|
@ -20211,6 +20227,27 @@ paths:
|
|||
"result": "success",
|
||||
"is_user_group_member": false,
|
||||
}
|
||||
/user_groups/{user_group_id}/deactivate:
|
||||
post:
|
||||
operationId: deactivate-user-group
|
||||
summary: Deactivate a user group
|
||||
tags: ["users"]
|
||||
description: |
|
||||
Deactivate a user group. Deactivated user groups cannot be
|
||||
used for mentions, permissions, or any other purpose, but can
|
||||
be reactivated or renamed.
|
||||
|
||||
Deactivating user groups is preferable to deleting them from
|
||||
the database, since the deactivation model allows audit logs
|
||||
of changes to sensitive group-valued permissions to be
|
||||
maintained.
|
||||
|
||||
**Changes**: New in Zulip 10.0 (feature level 290).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/UserGroupId"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/SimpleSuccess"
|
||||
/real-time:
|
||||
# This entry is a hack; it exists to give us a place to put the text
|
||||
# documenting the parameters for call_on_each_event and friends.
|
||||
|
@ -21268,6 +21305,14 @@ components:
|
|||
[setting-values]: /api/group-setting-values
|
||||
[system-groups]: /api/group-setting-values#system-groups
|
||||
[mentions]: /help/mention-a-user-or-group
|
||||
deactivated:
|
||||
type: boolean
|
||||
description: |
|
||||
Whether the user group is deactivated. Deactivated groups
|
||||
cannot be used as a subgroup of another group or used for
|
||||
any other purpose.
|
||||
|
||||
**Changes**: New in Zulip 10.0 (feature level 290).
|
||||
GroupSettingValue:
|
||||
oneOf:
|
||||
- type: integer
|
||||
|
|
|
@ -52,6 +52,7 @@ from zerver.actions.user_groups import (
|
|||
bulk_remove_members_from_user_groups,
|
||||
check_add_user_group,
|
||||
do_change_user_group_permission_setting,
|
||||
do_deactivate_user_group,
|
||||
do_update_user_group_description,
|
||||
do_update_user_group_name,
|
||||
remove_subgroups_from_user_group,
|
||||
|
@ -1454,3 +1455,25 @@ class TestRealmAuditLog(ZulipTestCase):
|
|||
"property": "can_mention_group",
|
||||
},
|
||||
)
|
||||
|
||||
def test_user_group_deactivation(self) -> None:
|
||||
hamlet = self.example_user("hamlet")
|
||||
cordelia = self.example_user("cordelia")
|
||||
user_group = check_add_user_group(
|
||||
hamlet.realm,
|
||||
"test",
|
||||
[hamlet, cordelia],
|
||||
acting_user=hamlet,
|
||||
)
|
||||
now = timezone_now()
|
||||
do_deactivate_user_group(user_group, acting_user=hamlet)
|
||||
|
||||
audit_log_entries = RealmAuditLog.objects.filter(
|
||||
acting_user=hamlet,
|
||||
realm=hamlet.realm,
|
||||
event_time__gte=now,
|
||||
event_type=AuditLogEventType.USER_GROUP_DEACTIVATED,
|
||||
)
|
||||
self.assert_length(audit_log_entries, 1)
|
||||
self.assertIsNone(audit_log_entries[0].modified_user)
|
||||
self.assertEqual(audit_log_entries[0].modified_user_group, user_group)
|
||||
|
|
|
@ -111,6 +111,7 @@ from zerver.actions.user_groups import (
|
|||
check_add_user_group,
|
||||
check_delete_user_group,
|
||||
do_change_user_group_permission_setting,
|
||||
do_deactivate_user_group,
|
||||
do_update_user_group_description,
|
||||
do_update_user_group_name,
|
||||
remove_subgroups_from_user_group,
|
||||
|
@ -1920,6 +1921,11 @@ class NormalActionsTest(BaseAction):
|
|||
remove_subgroups_from_user_group(backend, [api_design], acting_user=None)
|
||||
check_user_group_remove_subgroups("events[0]", events[0])
|
||||
|
||||
# Test deactivate event
|
||||
with self.verify_action() as events:
|
||||
do_deactivate_user_group(backend, acting_user=None)
|
||||
check_user_group_update("events[0]", events[0], "deactivated")
|
||||
|
||||
# Test remove event
|
||||
with self.verify_action() as events:
|
||||
check_delete_user_group(backend, acting_user=othello)
|
||||
|
|
|
@ -8,7 +8,15 @@ from django.db import transaction
|
|||
from django.utils.timezone import now as timezone_now
|
||||
|
||||
from zerver.actions.create_realm import do_create_realm
|
||||
from zerver.actions.realm_settings import do_set_realm_property
|
||||
from zerver.actions.realm_settings import (
|
||||
do_change_realm_permission_group_setting,
|
||||
do_set_realm_property,
|
||||
)
|
||||
from zerver.actions.streams import (
|
||||
do_change_stream_group_based_setting,
|
||||
do_deactivate_stream,
|
||||
do_unarchive_stream,
|
||||
)
|
||||
from zerver.actions.user_groups import (
|
||||
add_subgroups_to_user_group,
|
||||
bulk_add_members_to_user_groups,
|
||||
|
@ -16,6 +24,7 @@ from zerver.actions.user_groups import (
|
|||
check_add_user_group,
|
||||
create_user_group_in_database,
|
||||
do_change_user_group_permission_setting,
|
||||
do_deactivate_user_group,
|
||||
promote_new_full_members,
|
||||
)
|
||||
from zerver.actions.users import do_deactivate_user
|
||||
|
@ -43,6 +52,7 @@ from zerver.models import (
|
|||
GroupGroupMembership,
|
||||
NamedUserGroup,
|
||||
Realm,
|
||||
Stream,
|
||||
UserGroup,
|
||||
UserGroupMembership,
|
||||
UserProfile,
|
||||
|
@ -83,6 +93,7 @@ class UserGroupTestCase(ZulipTestCase):
|
|||
self.assertEqual(user_groups[0]["direct_subgroup_ids"], [])
|
||||
self.assertEqual(user_groups[0]["can_manage_group"], user_group.id)
|
||||
self.assertEqual(user_groups[0]["can_mention_group"], user_group.id)
|
||||
self.assertFalse(user_groups[0]["deactivated"])
|
||||
|
||||
owners_system_group = NamedUserGroup.objects.get(name=SystemGroups.OWNERS, realm=realm)
|
||||
membership = UserGroupMembership.objects.filter(user_group=owners_system_group).values_list(
|
||||
|
@ -95,6 +106,7 @@ class UserGroupTestCase(ZulipTestCase):
|
|||
self.assertEqual(user_groups[1]["direct_subgroup_ids"], [])
|
||||
self.assertEqual(user_groups[1]["can_manage_group"], user_group.id)
|
||||
self.assertEqual(user_groups[1]["can_mention_group"], user_group.id)
|
||||
self.assertFalse(user_groups[0]["deactivated"])
|
||||
|
||||
admins_system_group = NamedUserGroup.objects.get(
|
||||
name=SystemGroups.ADMINISTRATORS, realm=realm
|
||||
|
@ -112,6 +124,7 @@ class UserGroupTestCase(ZulipTestCase):
|
|||
self.assertEqual(user_groups[9]["members"], [])
|
||||
self.assertEqual(user_groups[9]["can_manage_group"], user_group.id)
|
||||
self.assertEqual(user_groups[9]["can_mention_group"], everyone_group.id)
|
||||
self.assertFalse(user_groups[0]["deactivated"])
|
||||
|
||||
othello = self.example_user("othello")
|
||||
hamletcharacters_group = NamedUserGroup.objects.get(name="hamletcharacters", realm=realm)
|
||||
|
@ -147,6 +160,12 @@ class UserGroupTestCase(ZulipTestCase):
|
|||
user_groups[10]["can_mention_group"].direct_subgroups,
|
||||
[admins_system_group.id, hamletcharacters_group.id],
|
||||
)
|
||||
self.assertFalse(user_groups[0]["deactivated"])
|
||||
|
||||
do_deactivate_user_group(new_user_group, acting_user=None)
|
||||
user_groups = user_groups_in_realm_serialized(realm)
|
||||
self.assertEqual(user_groups[10]["id"], new_user_group.id)
|
||||
self.assertTrue(user_groups[10]["deactivated"])
|
||||
|
||||
def test_get_direct_user_groups(self) -> None:
|
||||
othello = self.example_user("othello")
|
||||
|
@ -1149,6 +1168,238 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|||
result = self.client_delete(f"/json/user_groups/{lear_test_group.id}")
|
||||
self.assert_json_error(result, "Invalid user group")
|
||||
|
||||
def test_user_group_deactivation(self) -> None:
|
||||
support_group = self.create_user_group_for_test("support")
|
||||
leadership_group = self.create_user_group_for_test("leadership")
|
||||
add_subgroups_to_user_group(support_group, [leadership_group], acting_user=None)
|
||||
realm = get_realm("zulip")
|
||||
|
||||
do_set_realm_property(
|
||||
realm, "user_group_edit_policy", CommonPolicyEnum.ADMINS_ONLY, acting_user=None
|
||||
)
|
||||
self.login("othello")
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_error(result, "Insufficient permission")
|
||||
|
||||
do_set_realm_property(
|
||||
realm, "user_group_edit_policy", CommonPolicyEnum.MEMBERS_ONLY, acting_user=None
|
||||
)
|
||||
|
||||
self.login("hamlet")
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_error(result, "Insufficient permission")
|
||||
|
||||
self.login("othello")
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_success(result)
|
||||
support_group = NamedUserGroup.objects.get(name="support", realm=realm)
|
||||
self.assertTrue(support_group.deactivated)
|
||||
|
||||
support_group.deactivated = False
|
||||
support_group.save()
|
||||
|
||||
# Check admins can deactivate groups even if they are not members
|
||||
# of the group.
|
||||
self.login("iago")
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_success(result)
|
||||
support_group = NamedUserGroup.objects.get(name="support", realm=realm)
|
||||
self.assertTrue(support_group.deactivated)
|
||||
|
||||
support_group.deactivated = False
|
||||
support_group.save()
|
||||
|
||||
# Check moderators can deactivate groups if they are allowed by
|
||||
# user_group_edit_policy even when they are not members of the group.
|
||||
do_set_realm_property(
|
||||
realm, "user_group_edit_policy", CommonPolicyEnum.ADMINS_ONLY, acting_user=None
|
||||
)
|
||||
self.login("shiva")
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_error(result, "Insufficient permission")
|
||||
|
||||
do_set_realm_property(
|
||||
realm, "user_group_edit_policy", CommonPolicyEnum.MODERATORS_ONLY, acting_user=None
|
||||
)
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_success(result)
|
||||
support_group = NamedUserGroup.objects.get(name="support", realm=realm)
|
||||
self.assertTrue(support_group.deactivated)
|
||||
|
||||
support_group.deactivated = False
|
||||
support_group.save()
|
||||
|
||||
# Check that group that is subgroup of another group cannot be deactivated.
|
||||
result = self.client_post(f"/json/user_groups/{leadership_group.id}/deactivate")
|
||||
self.assert_json_error(
|
||||
result, "You cannot deactivate a user group that is subgroup of any user group."
|
||||
)
|
||||
|
||||
# If the supergroup is itself deactivated, then subgroup can be deactivated.
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_success(result)
|
||||
result = self.client_post(f"/json/user_groups/{leadership_group.id}/deactivate")
|
||||
self.assert_json_success(result)
|
||||
leadership_group = NamedUserGroup.objects.get(name="leadership", realm=realm)
|
||||
self.assertTrue(leadership_group.deactivated)
|
||||
|
||||
# Check that system groups cannot be deactivated at all.
|
||||
self.login("desdemona")
|
||||
members_system_group = NamedUserGroup.objects.get(
|
||||
name=SystemGroups.MEMBERS, realm=realm, is_system_group=True
|
||||
)
|
||||
result = self.client_post(f"/json/user_groups/{members_system_group.id}/deactivate")
|
||||
self.assert_json_error(result, "Insufficient permission")
|
||||
|
||||
def test_user_group_deactivation_with_group_used_for_settings(self) -> None:
|
||||
support_group = self.create_user_group_for_test("support")
|
||||
realm = get_realm("zulip")
|
||||
moderators_group = NamedUserGroup.objects.get(
|
||||
name=SystemGroups.MODERATORS, realm=realm, is_system_group=True
|
||||
)
|
||||
hamlet = self.example_user("hamlet")
|
||||
self.login("desdemona")
|
||||
|
||||
for setting_name in Realm.REALM_PERMISSION_GROUP_SETTINGS:
|
||||
anonymous_setting_group = self.create_or_update_anonymous_group_for_setting(
|
||||
[hamlet], [moderators_group, support_group]
|
||||
)
|
||||
do_change_realm_permission_group_setting(
|
||||
realm, setting_name, anonymous_setting_group, acting_user=None
|
||||
)
|
||||
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_error(
|
||||
result, "You cannot deactivate a user group which is used for setting."
|
||||
)
|
||||
|
||||
do_change_realm_permission_group_setting(
|
||||
realm, setting_name, support_group, acting_user=None
|
||||
)
|
||||
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_error(
|
||||
result, "You cannot deactivate a user group which is used for setting."
|
||||
)
|
||||
|
||||
# Reset the realm setting to one of the system group so this setting
|
||||
# does not interfere when testing for another setting.
|
||||
do_change_realm_permission_group_setting(
|
||||
realm, setting_name, moderators_group, acting_user=None
|
||||
)
|
||||
|
||||
stream = ensure_stream(realm, "support", acting_user=None)
|
||||
for setting_name in Stream.stream_permission_group_settings:
|
||||
do_change_stream_group_based_setting(
|
||||
stream, setting_name, support_group, acting_user=None
|
||||
)
|
||||
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_error(
|
||||
result, "You cannot deactivate a user group which is used for setting."
|
||||
)
|
||||
|
||||
# Test the group can be deactivated, if the stream which uses
|
||||
# this group for a setting is deactivated.
|
||||
do_deactivate_stream(stream, acting_user=None)
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_success(result)
|
||||
support_group = NamedUserGroup.objects.get(name="support", realm=realm)
|
||||
self.assertTrue(support_group.deactivated)
|
||||
|
||||
support_group.deactivated = False
|
||||
support_group.save()
|
||||
|
||||
do_unarchive_stream(stream, "support", acting_user=None)
|
||||
|
||||
anonymous_setting_group = self.create_or_update_anonymous_group_for_setting(
|
||||
[hamlet], [moderators_group, support_group]
|
||||
)
|
||||
do_change_stream_group_based_setting(
|
||||
stream, setting_name, anonymous_setting_group, acting_user=None
|
||||
)
|
||||
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_error(
|
||||
result, "You cannot deactivate a user group which is used for setting."
|
||||
)
|
||||
|
||||
# Test the group can be deactivated, if the stream which uses
|
||||
# this group for a setting is deactivated.
|
||||
do_deactivate_stream(stream, acting_user=None)
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_success(result)
|
||||
support_group = NamedUserGroup.objects.get(name="support", realm=realm)
|
||||
self.assertTrue(support_group.deactivated)
|
||||
|
||||
# Reactivate the group again for further testing.
|
||||
support_group.deactivated = False
|
||||
support_group.save()
|
||||
|
||||
# Reset the stream setting to one of the system group so this setting
|
||||
# does not interfere when testing for another setting.
|
||||
do_change_stream_group_based_setting(
|
||||
stream, setting_name, moderators_group, acting_user=None
|
||||
)
|
||||
|
||||
leadership_group = self.create_user_group_for_test("leadership")
|
||||
for setting_name in NamedUserGroup.GROUP_PERMISSION_SETTINGS:
|
||||
do_change_user_group_permission_setting(
|
||||
leadership_group, setting_name, support_group, acting_user=None
|
||||
)
|
||||
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_error(
|
||||
result, "You cannot deactivate a user group which is used for setting."
|
||||
)
|
||||
|
||||
# Test the group can be deactivated, if the user group which uses
|
||||
# this group for a setting is deactivated.
|
||||
do_deactivate_user_group(leadership_group, acting_user=None)
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_success(result)
|
||||
support_group = NamedUserGroup.objects.get(name="support", realm=realm)
|
||||
self.assertTrue(support_group.deactivated)
|
||||
|
||||
support_group.deactivated = False
|
||||
support_group.save()
|
||||
|
||||
leadership_group.deactivated = False
|
||||
leadership_group.save()
|
||||
|
||||
anonymous_setting_group = self.create_or_update_anonymous_group_for_setting(
|
||||
[hamlet], [moderators_group, support_group]
|
||||
)
|
||||
do_change_user_group_permission_setting(
|
||||
leadership_group, setting_name, anonymous_setting_group, acting_user=None
|
||||
)
|
||||
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_error(
|
||||
result, "You cannot deactivate a user group which is used for setting."
|
||||
)
|
||||
|
||||
# Test the group can be deactivated, if the user group which uses
|
||||
# this group for a setting is deactivated.
|
||||
do_deactivate_user_group(leadership_group, acting_user=None)
|
||||
result = self.client_post(f"/json/user_groups/{support_group.id}/deactivate")
|
||||
self.assert_json_success(result)
|
||||
support_group = NamedUserGroup.objects.get(name="support", realm=realm)
|
||||
self.assertTrue(support_group.deactivated)
|
||||
|
||||
# Reactivate the group again for further testing.
|
||||
support_group.deactivated = False
|
||||
support_group.save()
|
||||
|
||||
leadership_group.deactivated = False
|
||||
leadership_group.save()
|
||||
|
||||
# Reset the group setting to one of the system group so this setting
|
||||
# does not interfere when testing for another setting.
|
||||
do_change_user_group_permission_setting(
|
||||
leadership_group, setting_name, moderators_group, acting_user=None
|
||||
)
|
||||
|
||||
def test_query_counts(self) -> None:
|
||||
hamlet = self.example_user("hamlet")
|
||||
cordelia = self.example_user("cordelia")
|
||||
|
|
|
@ -13,6 +13,7 @@ from zerver.actions.user_groups import (
|
|||
check_add_user_group,
|
||||
check_delete_user_group,
|
||||
do_change_user_group_permission_setting,
|
||||
do_deactivate_user_group,
|
||||
do_update_user_group_description,
|
||||
do_update_user_group_name,
|
||||
remove_subgroups_from_user_group,
|
||||
|
@ -26,6 +27,7 @@ from zerver.lib.user_groups import (
|
|||
AnonymousSettingGroupDict,
|
||||
GroupSettingChangeRequest,
|
||||
access_user_group_by_id,
|
||||
access_user_group_for_deactivation,
|
||||
access_user_group_for_setting,
|
||||
check_user_group_name,
|
||||
get_direct_memberships_of_users,
|
||||
|
@ -183,6 +185,19 @@ def delete_user_group(
|
|||
return json_success(request)
|
||||
|
||||
|
||||
@typed_endpoint
|
||||
@transaction.atomic
|
||||
def deactivate_user_group(
|
||||
request: HttpRequest,
|
||||
user_profile: UserProfile,
|
||||
*,
|
||||
user_group_id: PathOnly[Json[int]],
|
||||
) -> HttpResponse:
|
||||
user_group = access_user_group_for_deactivation(user_group_id, user_profile)
|
||||
do_deactivate_user_group(user_group, acting_user=user_profile)
|
||||
return json_success(request)
|
||||
|
||||
|
||||
@require_member_or_admin
|
||||
@typed_endpoint
|
||||
def update_user_group_backend(
|
||||
|
|
|
@ -188,6 +188,7 @@ from zerver.views.upload import (
|
|||
)
|
||||
from zerver.views.user_groups import (
|
||||
add_user_group,
|
||||
deactivate_user_group,
|
||||
delete_user_group,
|
||||
edit_user_group,
|
||||
get_is_user_group_member,
|
||||
|
@ -413,6 +414,7 @@ v1_api_and_json_patterns = [
|
|||
rest_path(
|
||||
"user_groups/<int:user_group_id>/members/<int:user_id>", GET=get_is_user_group_member
|
||||
),
|
||||
rest_path("user_groups/<int:user_group_id>/deactivate", POST=deactivate_user_group),
|
||||
# users/me -> zerver.views.user_settings
|
||||
rest_path("users/me/avatar", POST=set_avatar_backend, DELETE=delete_avatar_backend),
|
||||
# users/me/onboarding_steps -> zerver.views.onboarding_steps
|
||||
|
|
Loading…
Reference in New Issue