mirror of https://github.com/zulip/zulip.git
groups: Allow setting anonymous group to settings while editing.
This commit adds support to set can_mention_group setting to anonymous group while editing groups.
This commit is contained in:
parent
23fdb73353
commit
3f80bc1b41
|
@ -26,7 +26,8 @@ format used by the Zulip server that they are interacting with.
|
||||||
/register`](/api/register-queue): `can_mention_group` field can now
|
/register`](/api/register-queue): `can_mention_group` field can now
|
||||||
either be an ID of a named user group with the permission, or an
|
either be an ID of a named user group with the permission, or an
|
||||||
object describing the set of users and groups with the permission.
|
object describing the set of users and groups with the permission.
|
||||||
* [`POST /user_groups/create`](/api/create-user-group): The
|
* [`POST /user_groups/create`](/api/create-user-group), [`PATCH
|
||||||
|
/user_groups/{user_group_id}`](/api/update-user-group): The
|
||||||
`can_mention_group` parameter can now either be an ID of a named
|
`can_mention_group` parameter can now either be an ID of a named
|
||||||
user group or an object describing a set of users and groups.
|
user group or an object describing a set of users and groups.
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
|
||||||
# Changes should be accompanied by documentation explaining what the
|
# Changes should be accompanied by documentation explaining what the
|
||||||
# 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 = 257
|
API_FEATURE_LEVEL = 258
|
||||||
|
|
||||||
# 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
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from dataclasses import asdict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict, List, Mapping, Optional, Sequence, TypedDict, Union
|
from typing import Dict, List, Mapping, Optional, Sequence, TypedDict, Union
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from zerver.lib.exceptions import JsonableError
|
from zerver.lib.exceptions import JsonableError
|
||||||
from zerver.lib.user_groups import (
|
from zerver.lib.user_groups import (
|
||||||
|
AnonymousSettingGroupDict,
|
||||||
get_group_setting_value_for_api,
|
get_group_setting_value_for_api,
|
||||||
get_role_based_system_groups_dict,
|
get_role_based_system_groups_dict,
|
||||||
set_defaults_for_group_settings,
|
set_defaults_for_group_settings,
|
||||||
|
@ -207,7 +209,7 @@ def check_add_user_group(
|
||||||
|
|
||||||
|
|
||||||
def do_send_user_group_update_event(
|
def do_send_user_group_update_event(
|
||||||
user_group: NamedUserGroup, data: Dict[str, Union[str, int]]
|
user_group: NamedUserGroup, data: Dict[str, Union[str, int, AnonymousSettingGroupDict]]
|
||||||
) -> None:
|
) -> None:
|
||||||
event = dict(type="user_group", op="update", group_id=user_group.id, data=data)
|
event = dict(type="user_group", op="update", group_id=user_group.id, data=data)
|
||||||
send_event(user_group.realm, event, active_user_ids(user_group.realm_id))
|
send_event(user_group.realm, event, active_user_ids(user_group.realm_id))
|
||||||
|
@ -431,6 +433,15 @@ 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)
|
do_send_delete_user_group_event(acting_user.realm, user_group_id, acting_user.realm.id)
|
||||||
|
|
||||||
|
|
||||||
|
def get_group_setting_value_for_audit_log_data(
|
||||||
|
setting_value: Union[int, AnonymousSettingGroupDict],
|
||||||
|
) -> Union[int, Dict[str, List[int]]]:
|
||||||
|
if isinstance(setting_value, int):
|
||||||
|
return setting_value
|
||||||
|
|
||||||
|
return asdict(setting_value)
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic(savepoint=False)
|
@transaction.atomic(savepoint=False)
|
||||||
def do_change_user_group_permission_setting(
|
def do_change_user_group_permission_setting(
|
||||||
user_group: NamedUserGroup,
|
user_group: NamedUserGroup,
|
||||||
|
@ -442,6 +453,20 @@ def do_change_user_group_permission_setting(
|
||||||
old_value = getattr(user_group, setting_name)
|
old_value = getattr(user_group, setting_name)
|
||||||
setattr(user_group, setting_name, setting_value_group)
|
setattr(user_group, setting_name, setting_value_group)
|
||||||
user_group.save()
|
user_group.save()
|
||||||
|
|
||||||
|
old_setting_api_value = get_group_setting_value_for_api(old_value)
|
||||||
|
new_setting_api_value = get_group_setting_value_for_api(setting_value_group)
|
||||||
|
|
||||||
|
if not hasattr(old_value, "named_user_group") and hasattr(
|
||||||
|
setting_value_group, "named_user_group"
|
||||||
|
):
|
||||||
|
# We delete the UserGroup which the setting was set to
|
||||||
|
# previously if it does not have any linked NamedUserGroup
|
||||||
|
# object, as it is not used anywhere else. A new UserGroup
|
||||||
|
# object would be created if the setting is later set to
|
||||||
|
# a combination of users and groups.
|
||||||
|
old_value.delete()
|
||||||
|
|
||||||
RealmAuditLog.objects.create(
|
RealmAuditLog.objects.create(
|
||||||
realm=user_group.realm,
|
realm=user_group.realm,
|
||||||
acting_user=acting_user,
|
acting_user=acting_user,
|
||||||
|
@ -449,11 +474,17 @@ def do_change_user_group_permission_setting(
|
||||||
event_time=timezone_now(),
|
event_time=timezone_now(),
|
||||||
modified_user_group=user_group,
|
modified_user_group=user_group,
|
||||||
extra_data={
|
extra_data={
|
||||||
RealmAuditLog.OLD_VALUE: old_value.id,
|
RealmAuditLog.OLD_VALUE: get_group_setting_value_for_audit_log_data(
|
||||||
RealmAuditLog.NEW_VALUE: setting_value_group.id,
|
old_setting_api_value
|
||||||
|
),
|
||||||
|
RealmAuditLog.NEW_VALUE: get_group_setting_value_for_audit_log_data(
|
||||||
|
new_setting_api_value
|
||||||
|
),
|
||||||
"property": setting_name,
|
"property": setting_name,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
event_data_dict: Dict[str, Union[str, int]] = {setting_name: setting_value_group.id}
|
event_data_dict: Dict[str, Union[str, int, AnonymousSettingGroupDict]] = {
|
||||||
|
setting_name: new_setting_api_value
|
||||||
|
}
|
||||||
do_send_user_group_update_event(user_group, event_data_dict)
|
do_send_user_group_update_event(user_group, event_data_dict)
|
||||||
|
|
|
@ -1857,7 +1857,7 @@ user_group_data_type = DictType(
|
||||||
optional_keys=[
|
optional_keys=[
|
||||||
("name", str),
|
("name", str),
|
||||||
("description", str),
|
("description", str),
|
||||||
("can_mention_group", int),
|
("can_mention_group", group_setting_type),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -242,9 +242,7 @@ def update_or_create_user_group_for_setting(
|
||||||
direct_subgroups: List[int],
|
direct_subgroups: List[int],
|
||||||
current_setting_value: Optional[UserGroup],
|
current_setting_value: Optional[UserGroup],
|
||||||
) -> UserGroup:
|
) -> UserGroup:
|
||||||
if current_setting_value is not None and not hasattr(
|
if current_setting_value is not None and not hasattr(current_setting_value, "named_user_group"):
|
||||||
current_setting_value, "named_user_group"
|
|
||||||
): # nocoverage
|
|
||||||
# We do not create a new group if the setting was already set
|
# We do not create a new group if the setting was already set
|
||||||
# to an anonymous group. The memberships of existing group
|
# to an anonymous group. The memberships of existing group
|
||||||
# itself are updated.
|
# itself are updated.
|
||||||
|
|
|
@ -3174,10 +3174,15 @@ paths:
|
||||||
The new description of the group. Only present if the description
|
The new description of the group. Only present if the description
|
||||||
changed.
|
changed.
|
||||||
can_mention_group:
|
can_mention_group:
|
||||||
type: integer
|
allOf:
|
||||||
description: |
|
- $ref: "#/components/schemas/CanMentionGroup"
|
||||||
ID of the new user group whose members are allowed to mention the
|
- description: |
|
||||||
group.
|
Either the ID of a named user group that has permission
|
||||||
|
to mention the group, or an object describing the set of
|
||||||
|
users and groups who have permission mention the group.
|
||||||
|
|
||||||
|
**Changes**: Before Zulip 9.0 (feature level 258), the
|
||||||
|
`can_mention_group` field was always an integer.
|
||||||
|
|
||||||
**Changes**: Before Zulip 8.0 (feature level 198),
|
**Changes**: Before Zulip 8.0 (feature level 198),
|
||||||
the `can_mention_group` setting
|
the `can_mention_group` setting
|
||||||
|
@ -18544,19 +18549,24 @@ paths:
|
||||||
type: string
|
type: string
|
||||||
example: The marketing team.
|
example: The marketing team.
|
||||||
can_mention_group:
|
can_mention_group:
|
||||||
description: |
|
allOf:
|
||||||
ID of the new user group whose members are allowed to mention the
|
- description: |
|
||||||
group.
|
Either the ID of a named user group that has permission to
|
||||||
|
mention the group, or an object describing the set of users
|
||||||
|
and groups who have permission mention the group.
|
||||||
|
|
||||||
This setting cannot be set to `"role:internet"` and `"role:owners"`
|
This setting cannot be set to `"role:internet"` and `"role:owners"`
|
||||||
system groups.
|
system groups.
|
||||||
|
|
||||||
|
**Changes**: Before Zulip 9.0 (feature level 258), the
|
||||||
|
`can_mention_group` this field was always an integer.
|
||||||
|
|
||||||
**Changes**: Before Zulip 8.0 (feature level 198),
|
**Changes**: Before Zulip 8.0 (feature level 198),
|
||||||
the `can_mention_group` setting was named `can_mention_group_id`.
|
the `can_mention_group` setting was named `can_mention_group_id`.
|
||||||
|
|
||||||
New in Zulip 8.0 (feature level 191). Previously, groups
|
New in Zulip 8.0 (feature level 191). Previously, groups
|
||||||
could be mentioned if and only if they were not system groups.
|
could be mentioned if and only if they were not system groups.
|
||||||
type: integer
|
- $ref: "#/components/schemas/CanMentionGroup"
|
||||||
example: 12
|
example: 12
|
||||||
encoding:
|
encoding:
|
||||||
can_mention_group:
|
can_mention_group:
|
||||||
|
|
|
@ -81,6 +81,7 @@ from zerver.models import (
|
||||||
RealmPlayground,
|
RealmPlayground,
|
||||||
Recipient,
|
Recipient,
|
||||||
Subscription,
|
Subscription,
|
||||||
|
UserGroup,
|
||||||
UserProfile,
|
UserProfile,
|
||||||
)
|
)
|
||||||
from zerver.models.groups import SystemGroups
|
from zerver.models.groups import SystemGroups
|
||||||
|
@ -1333,3 +1334,88 @@ class TestRealmAuditLog(ZulipTestCase):
|
||||||
"property": "can_mention_group",
|
"property": "can_mention_group",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
moderators_group = NamedUserGroup.objects.get(
|
||||||
|
name=SystemGroups.MODERATORS, realm=user_group.realm, is_system_group=True
|
||||||
|
)
|
||||||
|
old_group = user_group.can_mention_group
|
||||||
|
new_group = UserGroup.objects.create(realm=user_group.realm)
|
||||||
|
new_group.direct_members.set([hamlet.id])
|
||||||
|
new_group.direct_subgroups.set([moderators_group.id])
|
||||||
|
|
||||||
|
now = timezone_now()
|
||||||
|
do_change_user_group_permission_setting(
|
||||||
|
user_group, "can_mention_group", new_group, acting_user=None
|
||||||
|
)
|
||||||
|
audit_log_entries = RealmAuditLog.objects.filter(
|
||||||
|
event_type=RealmAuditLog.USER_GROUP_GROUP_BASED_SETTING_CHANGED,
|
||||||
|
event_time__gte=now,
|
||||||
|
)
|
||||||
|
self.assert_length(audit_log_entries, 1)
|
||||||
|
self.assertIsNone(audit_log_entries[0].acting_user)
|
||||||
|
self.assertDictEqual(
|
||||||
|
audit_log_entries[0].extra_data,
|
||||||
|
{
|
||||||
|
RealmAuditLog.OLD_VALUE: old_group.id,
|
||||||
|
RealmAuditLog.NEW_VALUE: {
|
||||||
|
"direct_members": [hamlet.id],
|
||||||
|
"direct_subgroups": [moderators_group.id],
|
||||||
|
},
|
||||||
|
"property": "can_mention_group",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
othello = self.example_user("othello")
|
||||||
|
new_group = UserGroup.objects.create(realm=user_group.realm)
|
||||||
|
new_group.direct_members.set([othello.id])
|
||||||
|
new_group.direct_subgroups.set([moderators_group.id])
|
||||||
|
|
||||||
|
now = timezone_now()
|
||||||
|
do_change_user_group_permission_setting(
|
||||||
|
user_group, "can_mention_group", new_group, acting_user=None
|
||||||
|
)
|
||||||
|
audit_log_entries = RealmAuditLog.objects.filter(
|
||||||
|
event_type=RealmAuditLog.USER_GROUP_GROUP_BASED_SETTING_CHANGED,
|
||||||
|
event_time__gte=now,
|
||||||
|
)
|
||||||
|
self.assert_length(audit_log_entries, 1)
|
||||||
|
self.assertIsNone(audit_log_entries[0].acting_user)
|
||||||
|
self.assertDictEqual(
|
||||||
|
audit_log_entries[0].extra_data,
|
||||||
|
{
|
||||||
|
RealmAuditLog.OLD_VALUE: {
|
||||||
|
"direct_members": [hamlet.id],
|
||||||
|
"direct_subgroups": [moderators_group.id],
|
||||||
|
},
|
||||||
|
RealmAuditLog.NEW_VALUE: {
|
||||||
|
"direct_members": [othello.id],
|
||||||
|
"direct_subgroups": [moderators_group.id],
|
||||||
|
},
|
||||||
|
"property": "can_mention_group",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
new_group = NamedUserGroup.objects.get(
|
||||||
|
name=SystemGroups.EVERYONE, realm=user_group.realm, is_system_group=True
|
||||||
|
)
|
||||||
|
now = timezone_now()
|
||||||
|
do_change_user_group_permission_setting(
|
||||||
|
user_group, "can_mention_group", new_group, acting_user=None
|
||||||
|
)
|
||||||
|
audit_log_entries = RealmAuditLog.objects.filter(
|
||||||
|
event_type=RealmAuditLog.USER_GROUP_GROUP_BASED_SETTING_CHANGED,
|
||||||
|
event_time__gte=now,
|
||||||
|
)
|
||||||
|
self.assert_length(audit_log_entries, 1)
|
||||||
|
self.assertIsNone(audit_log_entries[0].acting_user)
|
||||||
|
self.assertDictEqual(
|
||||||
|
audit_log_entries[0].extra_data,
|
||||||
|
{
|
||||||
|
RealmAuditLog.OLD_VALUE: {
|
||||||
|
"direct_members": [othello.id],
|
||||||
|
"direct_subgroups": [moderators_group.id],
|
||||||
|
},
|
||||||
|
RealmAuditLog.NEW_VALUE: new_group.id,
|
||||||
|
"property": "can_mention_group",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
|
@ -1745,6 +1745,22 @@ class NormalActionsTest(BaseAction):
|
||||||
backend, "can_mention_group", moderators_group, acting_user=None
|
backend, "can_mention_group", moderators_group, acting_user=None
|
||||||
)
|
)
|
||||||
check_user_group_update("events[0]", events[0], "can_mention_group")
|
check_user_group_update("events[0]", events[0], "can_mention_group")
|
||||||
|
self.assertEqual(events[0]["data"]["can_mention_group"], moderators_group.id)
|
||||||
|
|
||||||
|
setting_group = UserGroup.objects.create(realm=self.user_profile.realm)
|
||||||
|
setting_group.direct_members.set([othello.id])
|
||||||
|
setting_group.direct_subgroups.set([moderators_group.id])
|
||||||
|
with self.verify_action() as events:
|
||||||
|
do_change_user_group_permission_setting(
|
||||||
|
backend, "can_mention_group", setting_group, acting_user=None
|
||||||
|
)
|
||||||
|
check_user_group_update("events[0]", events[0], "can_mention_group")
|
||||||
|
self.assertEqual(
|
||||||
|
events[0]["data"]["can_mention_group"],
|
||||||
|
AnonymousSettingGroupDict(
|
||||||
|
direct_members=[othello.id], direct_subgroups=[moderators_group.id]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
# Test add members
|
# Test add members
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
|
|
|
@ -671,6 +671,62 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
||||||
support_group = NamedUserGroup.objects.get(name="support", realm=hamlet.realm)
|
support_group = NamedUserGroup.objects.get(name="support", realm=hamlet.realm)
|
||||||
self.assertEqual(support_group.can_mention_group, nobody_group.usergroup_ptr)
|
self.assertEqual(support_group.can_mention_group, nobody_group.usergroup_ptr)
|
||||||
|
|
||||||
|
othello = self.example_user("othello")
|
||||||
|
params = {
|
||||||
|
"can_mention_group": orjson.dumps(
|
||||||
|
{
|
||||||
|
"direct_members": [othello.id],
|
||||||
|
"direct_subgroups": [moderators_group.id, marketing_group.id],
|
||||||
|
}
|
||||||
|
).decode()
|
||||||
|
}
|
||||||
|
result = self.client_patch(f"/json/user_groups/{support_group.id}", info=params)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
support_group = NamedUserGroup.objects.get(name="support", realm=hamlet.realm)
|
||||||
|
self.assertCountEqual(
|
||||||
|
list(support_group.can_mention_group.direct_members.all()),
|
||||||
|
[othello],
|
||||||
|
)
|
||||||
|
self.assertCountEqual(
|
||||||
|
list(support_group.can_mention_group.direct_subgroups.all()),
|
||||||
|
[marketing_group, moderators_group],
|
||||||
|
)
|
||||||
|
|
||||||
|
prospero = self.example_user("prospero")
|
||||||
|
params = {
|
||||||
|
"can_mention_group": orjson.dumps(
|
||||||
|
{
|
||||||
|
"direct_members": [othello.id, prospero.id],
|
||||||
|
"direct_subgroups": [moderators_group.id, marketing_group.id],
|
||||||
|
}
|
||||||
|
).decode()
|
||||||
|
}
|
||||||
|
previous_can_mention_group_id = support_group.can_mention_group_id
|
||||||
|
result = self.client_patch(f"/json/user_groups/{support_group.id}", info=params)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
support_group = NamedUserGroup.objects.get(name="support", realm=hamlet.realm)
|
||||||
|
|
||||||
|
# Test that the existing UserGroup object is updated.
|
||||||
|
self.assertEqual(support_group.can_mention_group_id, previous_can_mention_group_id)
|
||||||
|
self.assertCountEqual(
|
||||||
|
list(support_group.can_mention_group.direct_members.all()),
|
||||||
|
[othello, prospero],
|
||||||
|
)
|
||||||
|
self.assertCountEqual(
|
||||||
|
list(support_group.can_mention_group.direct_subgroups.all()),
|
||||||
|
[marketing_group, moderators_group],
|
||||||
|
)
|
||||||
|
|
||||||
|
params = {"can_mention_group": orjson.dumps(marketing_group.id).decode()}
|
||||||
|
previous_can_mention_group_id = support_group.can_mention_group_id
|
||||||
|
result = self.client_patch(f"/json/user_groups/{support_group.id}", info=params)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
support_group = NamedUserGroup.objects.get(name="support", realm=hamlet.realm)
|
||||||
|
|
||||||
|
# Test that the previous UserGroup object is deleted.
|
||||||
|
self.assertFalse(UserGroup.objects.filter(id=previous_can_mention_group_id).exists())
|
||||||
|
self.assertEqual(support_group.can_mention_group_id, marketing_group.id)
|
||||||
|
|
||||||
owners_group = NamedUserGroup.objects.get(
|
owners_group = NamedUserGroup.objects.get(
|
||||||
name="role:owners", realm=hamlet.realm, is_system_group=True
|
name="role:owners", realm=hamlet.realm, is_system_group=True
|
||||||
)
|
)
|
||||||
|
@ -699,6 +755,28 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
||||||
result = self.client_patch(f"/json/user_groups/{support_group.id}", info=params)
|
result = self.client_patch(f"/json/user_groups/{support_group.id}", info=params)
|
||||||
self.assert_json_error(result, "Invalid user group")
|
self.assert_json_error(result, "Invalid user group")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"can_mention_group": orjson.dumps(
|
||||||
|
{
|
||||||
|
"direct_members": [1111, othello.id],
|
||||||
|
"direct_subgroups": [moderators_group.id, marketing_group.id],
|
||||||
|
}
|
||||||
|
).decode()
|
||||||
|
}
|
||||||
|
result = self.client_patch(f"/json/user_groups/{support_group.id}", info=params)
|
||||||
|
self.assert_json_error(result, "Invalid user ID: 1111")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"can_mention_group": orjson.dumps(
|
||||||
|
{
|
||||||
|
"direct_members": [prospero.id, othello.id],
|
||||||
|
"direct_subgroups": [1111, marketing_group.id],
|
||||||
|
}
|
||||||
|
).decode()
|
||||||
|
}
|
||||||
|
result = self.client_patch(f"/json/user_groups/{support_group.id}", info=params)
|
||||||
|
self.assert_json_error(result, "Invalid user group ID: 1111")
|
||||||
|
|
||||||
def test_user_group_update_to_already_existing_name(self) -> None:
|
def test_user_group_update_to_already_existing_name(self) -> None:
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
self.login_user(hamlet)
|
self.login_user(hamlet)
|
||||||
|
|
|
@ -30,6 +30,7 @@ from zerver.lib.user_groups import (
|
||||||
access_user_group_for_setting,
|
access_user_group_for_setting,
|
||||||
check_user_group_name,
|
check_user_group_name,
|
||||||
get_direct_memberships_of_users,
|
get_direct_memberships_of_users,
|
||||||
|
get_group_setting_value_for_api,
|
||||||
get_subgroup_ids,
|
get_subgroup_ids,
|
||||||
get_user_group_direct_member_ids,
|
get_user_group_direct_member_ids,
|
||||||
get_user_group_member_ids,
|
get_user_group_member_ids,
|
||||||
|
@ -39,7 +40,7 @@ from zerver.lib.user_groups import (
|
||||||
)
|
)
|
||||||
from zerver.lib.users import access_user_by_id, user_ids_to_users
|
from zerver.lib.users import access_user_by_id, user_ids_to_users
|
||||||
from zerver.lib.validator import check_bool, check_dict_only, check_int, check_list, check_union
|
from zerver.lib.validator import check_bool, check_dict_only, check_int, check_list, check_union
|
||||||
from zerver.models import NamedUserGroup, UserProfile
|
from zerver.models import NamedUserGroup, UserGroup, UserProfile
|
||||||
from zerver.models.users import get_system_bot
|
from zerver.models.users import get_system_bot
|
||||||
from zerver.views.streams import compose_views
|
from zerver.views.streams import compose_views
|
||||||
|
|
||||||
|
@ -121,6 +122,34 @@ def get_user_group(request: HttpRequest, user_profile: UserProfile) -> HttpRespo
|
||||||
return json_success(request, data={"user_groups": user_groups})
|
return json_success(request, data={"user_groups": user_groups})
|
||||||
|
|
||||||
|
|
||||||
|
def are_both_setting_values_equal(
|
||||||
|
first_setting_value: Union[int, AnonymousSettingGroupDict],
|
||||||
|
second_setting_value: Union[int, AnonymousSettingGroupDict],
|
||||||
|
) -> bool:
|
||||||
|
if isinstance(first_setting_value, int) and isinstance(second_setting_value, int):
|
||||||
|
return first_setting_value == second_setting_value
|
||||||
|
|
||||||
|
if isinstance(first_setting_value, AnonymousSettingGroupDict) and isinstance(
|
||||||
|
second_setting_value, AnonymousSettingGroupDict
|
||||||
|
):
|
||||||
|
return set(first_setting_value.direct_members) == set(
|
||||||
|
second_setting_value.direct_members
|
||||||
|
) and set(first_setting_value.direct_subgroups) == set(
|
||||||
|
second_setting_value.direct_subgroups
|
||||||
|
)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def check_setting_value_changed(
|
||||||
|
current_value: UserGroup,
|
||||||
|
new_setting_value: Union[int, AnonymousSettingGroupDict],
|
||||||
|
) -> bool:
|
||||||
|
current_setting_api_value = get_group_setting_value_for_api(current_value)
|
||||||
|
|
||||||
|
return not are_both_setting_values_equal(current_setting_api_value, new_setting_value)
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
@require_user_group_edit_permission
|
@require_user_group_edit_permission
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
|
@ -130,11 +159,11 @@ def edit_user_group(
|
||||||
user_group_id: int = REQ(json_validator=check_int, path_only=True),
|
user_group_id: int = REQ(json_validator=check_int, path_only=True),
|
||||||
name: Optional[str] = REQ(default=None),
|
name: Optional[str] = REQ(default=None),
|
||||||
description: Optional[str] = REQ(default=None),
|
description: Optional[str] = REQ(default=None),
|
||||||
can_mention_group_id: Optional[int] = REQ(
|
can_mention_group: Optional[Union[Dict[str, List[int]], int]] = REQ(
|
||||||
"can_mention_group", json_validator=check_int, default=None
|
json_validator=check_group_setting, default=None
|
||||||
),
|
),
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
if name is None and description is None and can_mention_group_id is None:
|
if name is None and description is None and can_mention_group is None:
|
||||||
raise JsonableError(_("No new data supplied"))
|
raise JsonableError(_("No new data supplied"))
|
||||||
|
|
||||||
user_group = access_user_group_by_id(user_group_id, user_profile, for_read=False)
|
user_group = access_user_group_by_id(user_group_id, user_profile, for_read=False)
|
||||||
|
@ -148,20 +177,21 @@ def edit_user_group(
|
||||||
|
|
||||||
request_settings_dict = locals()
|
request_settings_dict = locals()
|
||||||
for setting_name, permission_config in NamedUserGroup.GROUP_PERMISSION_SETTINGS.items():
|
for setting_name, permission_config in NamedUserGroup.GROUP_PERMISSION_SETTINGS.items():
|
||||||
setting_group_id_name = permission_config.id_field_name
|
if setting_name not in request_settings_dict: # nocoverage
|
||||||
|
|
||||||
if setting_group_id_name not in request_settings_dict: # nocoverage
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if request_settings_dict[setting_group_id_name] is not None and request_settings_dict[
|
if request_settings_dict[setting_name] is None:
|
||||||
setting_group_id_name
|
continue
|
||||||
] != getattr(user_group, setting_group_id_name):
|
|
||||||
setting_value_group_id = request_settings_dict[setting_group_id_name]
|
current_value = getattr(user_group, setting_name)
|
||||||
|
new_setting_value = parse_group_setting_value(request_settings_dict[setting_name])
|
||||||
|
if check_setting_value_changed(current_value, new_setting_value):
|
||||||
setting_value_group = access_user_group_for_setting(
|
setting_value_group = access_user_group_for_setting(
|
||||||
setting_value_group_id,
|
new_setting_value,
|
||||||
user_profile,
|
user_profile,
|
||||||
setting_name=setting_name,
|
setting_name=setting_name,
|
||||||
permission_configuration=permission_config,
|
permission_configuration=permission_config,
|
||||||
|
current_setting_value=current_value,
|
||||||
)
|
)
|
||||||
do_change_user_group_permission_setting(
|
do_change_user_group_permission_setting(
|
||||||
user_group, setting_name, setting_value_group, acting_user=user_profile
|
user_group, setting_name, setting_value_group, acting_user=user_profile
|
||||||
|
|
Loading…
Reference in New Issue