actions: Add function to add and remove subgroups from a user group.

This commit is contained in:
Sahil Batra 2022-03-01 12:22:47 +05:30 committed by Tim Abbott
parent da0b087962
commit b4a9311ef2
6 changed files with 167 additions and 1 deletions

View File

@ -26,6 +26,9 @@ format used by the Zulip server that they are interacting with.
/register`](/api/register-queue): Added `subgroups` field, /register`](/api/register-queue): Added `subgroups` field,
which is a list of IDs of all the subgroups of the user group, to which is a list of IDs of all the subgroups of the user group, to
user group objects. user group objects.
* [`GET /events`](/api/get-events): Added new `user_group` events
operations for live updates to subgroups (`add_subgroups` and
`remove_subgroups`).
**Feature level 126** **Feature level 126**

View File

@ -8,7 +8,14 @@ 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 access_user_group_by_id, create_user_group from zerver.lib.user_groups import access_user_group_by_id, create_user_group
from zerver.models import Realm, UserGroup, UserGroupMembership, UserProfile, active_user_ids from zerver.models import (
GroupGroupMembership,
Realm,
UserGroup,
UserGroupMembership,
UserProfile,
active_user_ids,
)
from zerver.tornado.django_api import send_event from zerver.tornado.django_api import send_event
@ -158,6 +165,36 @@ def remove_members_from_user_group(user_group: UserGroup, user_profile_ids: List
do_send_user_group_members_update_event("remove_members", user_group, user_profile_ids) do_send_user_group_members_update_event("remove_members", user_group, user_profile_ids)
def do_send_subgroups_update_event(
event_name: str, user_group: UserGroup, subgroup_ids: List[int]
) -> None:
event = dict(
type="user_group", op=event_name, group_id=user_group.id, subgroup_ids=subgroup_ids
)
transaction.on_commit(
lambda: send_event(user_group.realm, event, active_user_ids(user_group.realm_id))
)
@transaction.atomic
def add_subgroups_to_user_group(user_group: UserGroup, subgroups: List[UserGroup]) -> None:
group_memberships = [
GroupGroupMembership(supergroup=user_group, subgroup=subgroup) for subgroup in subgroups
]
GroupGroupMembership.objects.bulk_create(group_memberships)
subgroup_ids = [subgroup.id for subgroup in subgroups]
do_send_subgroups_update_event("add_subgroups", user_group, subgroup_ids)
@transaction.atomic
def remove_subgroups_from_user_group(user_group: UserGroup, subgroups: List[UserGroup]) -> None:
GroupGroupMembership.objects.filter(supergroup=user_group, subgroup__in=subgroups).delete()
subgroup_ids = [subgroup.id for subgroup in subgroups]
do_send_subgroups_update_event("remove_subgroups", user_group, subgroup_ids)
def do_send_delete_user_group_event(realm: Realm, user_group_id: int, realm_id: int) -> None: def do_send_delete_user_group_event(realm: Realm, user_group_id: int, realm_id: int) -> None:
event = dict(type="user_group", op="remove", group_id=user_group_id) event = dict(type="user_group", op="remove", group_id=user_group_id)
send_event(realm, event, active_user_ids(realm_id)) send_event(realm, event, active_user_ids(realm_id))

View File

@ -1748,6 +1748,28 @@ def check_user_group_update(var_name: str, event: Dict[str, object], field: str)
assert set(event["data"].keys()) == {field} assert set(event["data"].keys()) == {field}
user_group_add_subgroups_event = event_dict_type(
required_keys=[
("type", Equals("user_group")),
("op", Equals("add_subgroups")),
("group_id", int),
("subgroup_ids", ListType(int)),
]
)
check_user_group_add_subgroups = make_checker(user_group_add_subgroups_event)
user_group_remove_subgroups_event = event_dict_type(
required_keys=[
("type", Equals("user_group")),
("op", Equals("remove_subgroups")),
("group_id", int),
("subgroup_ids", ListType(int)),
]
)
check_user_group_remove_subgroups = make_checker(user_group_remove_subgroups_event)
user_status_event = event_dict_type( user_status_event = event_dict_type(
required_keys=[ required_keys=[
# force vertical # force vertical

View File

@ -1245,6 +1245,17 @@ def apply_event(
members = set(user_group["members"]) members = set(user_group["members"])
user_group["members"] = list(members - set(event["user_ids"])) user_group["members"] = list(members - set(event["user_ids"]))
user_group["members"].sort() user_group["members"].sort()
elif event["op"] == "add_subgroups":
for user_group in state["realm_user_groups"]:
if user_group["id"] == event["group_id"]:
user_group["subgroups"].extend(event["subgroup_ids"])
user_group["subgroups"].sort()
elif event["op"] == "remove_subgroups":
for user_group in state["realm_user_groups"]:
if user_group["id"] == event["group_id"]:
subgroups = set(user_group["subgroups"])
user_group["subgroups"] = list(subgroups - set(event["subgroup_ids"]))
user_group["subgroups"].sort()
elif event["op"] == "remove": elif event["op"] == "remove":
state["realm_user_groups"] = [ state["realm_user_groups"] = [
ug for ug in state["realm_user_groups"] if ug["id"] != event["group_id"] ug for ug in state["realm_user_groups"] if ug["id"] != event["group_id"]

View File

@ -2830,6 +2830,82 @@ paths:
"user_ids": [10], "user_ids": [10],
"id": 0, "id": 0,
} }
- type: object
additionalProperties: false
description: |
Event sent to all users when subgroups have been added to
a user group.
**Changes**: New in Zulip 6.0 (feature level 127).
properties:
id:
$ref: "#/components/schemas/EventIdSchema"
type:
allOf:
- $ref: "#/components/schemas/EventTypeSchema"
- enum:
- user_group
op:
type: string
enum:
- add_subgroups
group_id:
type: integer
description: |
The ID of the user group whose details have changed.
subgroup_ids:
type: array
items:
type: integer
description: |
Array containing the IDs of the subgroups that have been added
to the user group.
example:
{
"type": "user_group",
"op": "add_subgroups",
"group_id": 2,
"subgroup_ids": [10],
"id": 0,
}
- type: object
additionalProperties: false
description: |
Event sent to all users when subgroups have been removed from
a user group.
**Changes**: New in Zulip 6.0 (feature level 127).
properties:
id:
$ref: "#/components/schemas/EventIdSchema"
type:
allOf:
- $ref: "#/components/schemas/EventTypeSchema"
- enum:
- user_group
op:
type: string
enum:
- remove_subgroups
group_id:
type: integer
description: |
The ID of the user group whose details have changed.
subgroup_ids:
type: array
items:
type: integer
description: |
Array containing the IDs of the subgroups that have been
removed from the user group.
example:
{
"type": "user_group",
"op": "remove_subgroups",
"group_id": 2,
"subgroup_ids": [10],
"id": 0,
}
- type: object - type: object
additionalProperties: false additionalProperties: false
description: | description: |

View File

@ -92,12 +92,14 @@ from zerver.actions.streams import (
from zerver.actions.submessage import do_add_submessage from zerver.actions.submessage import do_add_submessage
from zerver.actions.typing import check_send_typing_notification, do_send_stream_typing_notification from zerver.actions.typing import check_send_typing_notification, do_send_stream_typing_notification
from zerver.actions.user_groups import ( from zerver.actions.user_groups import (
add_subgroups_to_user_group,
bulk_add_members_to_user_group, bulk_add_members_to_user_group,
check_add_user_group, check_add_user_group,
check_delete_user_group, check_delete_user_group,
do_update_user_group_description, do_update_user_group_description,
do_update_user_group_name, do_update_user_group_name,
remove_members_from_user_group, remove_members_from_user_group,
remove_subgroups_from_user_group,
) )
from zerver.actions.user_settings import ( from zerver.actions.user_settings import (
do_change_avatar_fields, do_change_avatar_fields,
@ -171,8 +173,10 @@ from zerver.lib.event_schema import (
check_update_message_flags_remove, check_update_message_flags_remove,
check_user_group_add, check_user_group_add,
check_user_group_add_members, check_user_group_add_members,
check_user_group_add_subgroups,
check_user_group_remove, check_user_group_remove,
check_user_group_remove_members, check_user_group_remove_members,
check_user_group_remove_subgroups,
check_user_group_update, check_user_group_update,
check_user_settings_update, check_user_settings_update,
check_user_status, check_user_status,
@ -194,6 +198,7 @@ from zerver.lib.test_helpers import (
stdout_suppressed, stdout_suppressed,
) )
from zerver.lib.topic import TOPIC_NAME from zerver.lib.topic import TOPIC_NAME
from zerver.lib.user_groups import create_user_group
from zerver.lib.user_mutes import get_mute_object from zerver.lib.user_mutes import get_mute_object
from zerver.models import ( from zerver.models import (
Attachment, Attachment,
@ -1225,6 +1230,18 @@ class NormalActionsTest(BaseAction):
events = self.verify_action(lambda: remove_members_from_user_group(backend, [hamlet.id])) events = self.verify_action(lambda: remove_members_from_user_group(backend, [hamlet.id]))
check_user_group_remove_members("events[0]", events[0]) check_user_group_remove_members("events[0]", events[0])
api_design = create_user_group(
"api-design", [hamlet], hamlet.realm, description="API design team"
)
# Test add subgroups
events = self.verify_action(lambda: add_subgroups_to_user_group(backend, [api_design]))
check_user_group_add_subgroups("events[0]", events[0])
# Test remove subgroups
events = self.verify_action(lambda: remove_subgroups_from_user_group(backend, [api_design]))
check_user_group_remove_subgroups("events[0]", events[0])
# Test remove event # Test remove event
events = self.verify_action(lambda: check_delete_user_group(backend.id, othello)) events = self.verify_action(lambda: check_delete_user_group(backend.id, othello))
check_user_group_remove("events[0]", events[0]) check_user_group_remove("events[0]", events[0])