diff --git a/zerver/actions/user_groups.py b/zerver/actions/user_groups.py index c74a58257c..256b67609c 100644 --- a/zerver/actions/user_groups.py +++ b/zerver/actions/user_groups.py @@ -448,6 +448,16 @@ def add_subgroups_to_user_group( *, acting_user: UserProfile | None, ) -> None: + if len(subgroups) == 0: + return + + realm = user_group.realm + supergroups = get_recursive_supergroups_union_for_groups([user_group.id]) + streams = list( + get_metadata_access_streams_via_group_ids([group.id for group in supergroups], realm) + ) + old_stream_metadata_user_ids = bulk_can_access_stream_metadata_user_ids(streams) + group_memberships = [ GroupGroupMembership(supergroup=user_group, subgroup=subgroup) for subgroup in subgroups ] @@ -478,8 +488,36 @@ def add_subgroups_to_user_group( ] RealmAuditLog.objects.bulk_create(audit_log_entries) + subscriber_ids_for_streams = get_user_ids_for_streams({stream.id for stream in streams}) + new_stream_metadata_user_ids = bulk_can_access_stream_metadata_user_ids(streams) + recent_traffic = get_streams_traffic({stream.id for stream in streams}, realm) + anonymous_group_membership = get_anonymous_group_membership_dict_for_streams(streams) + do_send_subgroups_update_event("add_subgroups", user_group, subgroup_ids) + for stream in streams: + user_ids_gaining_metadata_access = ( + new_stream_metadata_user_ids[stream.id] - old_stream_metadata_user_ids[stream.id] + ) + send_stream_creation_event( + realm, + stream, + list(user_ids_gaining_metadata_access), + recent_traffic, + anonymous_group_membership, + ) + peer_add_event = dict( + type="subscription", + op="peer_add", + stream_ids=[stream.id], + user_ids=sorted(subscriber_ids_for_streams[stream.id]), + ) + send_event_on_commit( + realm, + peer_add_event, + user_ids_gaining_metadata_access, + ) + @transaction.atomic(savepoint=False) def remove_subgroups_from_user_group( diff --git a/zerver/tests/test_events.py b/zerver/tests/test_events.py index a64fb887b2..dc5022dede 100644 --- a/zerver/tests/test_events.py +++ b/zerver/tests/test_events.py @@ -2232,7 +2232,11 @@ class NormalActionsTest(BaseAction): check_user_group_update("events[0]", events[0], {"name"}) def do_test_user_group_events_on_stream_metadata_access_change( - self, setting_name: str, stream: Stream, user_group: NamedUserGroup + self, + setting_name: str, + stream: Stream, + user_group: NamedUserGroup, + hamlet_group: NamedUserGroup, ) -> None: othello = self.example_user("othello") hamlet = self.example_user("hamlet") @@ -2249,6 +2253,15 @@ class NormalActionsTest(BaseAction): bulk_remove_members_from_user_groups([user_group], [hamlet.id], acting_user=None) check_user_group_remove_members("events[0]", events[0]) check_stream_delete("events[1]", events[1]) + + with self.verify_action(num_events=3) as events: + add_subgroups_to_user_group(user_group, [hamlet_group], acting_user=None) + check_user_group_add_subgroups("events[0]", events[0]) + check_stream_create("events[1]", events[1]) + check_subscription_peer_add("events[2]", events[2]) + + # Remove subgroup for next test. + remove_subgroups_from_user_group(user_group, [hamlet_group], acting_user=None) else: with self.verify_action() as events: bulk_add_members_to_user_groups([user_group], [hamlet.id], acting_user=None) @@ -2258,6 +2271,13 @@ class NormalActionsTest(BaseAction): bulk_remove_members_from_user_groups([user_group], [hamlet.id], acting_user=None) check_user_group_remove_members("events[0]", events[0]) + with self.verify_action() as events: + add_subgroups_to_user_group(user_group, [hamlet_group], acting_user=None) + check_user_group_add_subgroups("events[0]", events[0]) + + # Remove subgroup for next test. + remove_subgroups_from_user_group(user_group, [hamlet_group], acting_user=None) + nobody_group = NamedUserGroup.objects.get( name=SystemGroups.NOBODY, realm=othello.realm, is_system_group=True ) @@ -2273,10 +2293,17 @@ class NormalActionsTest(BaseAction): "Test group", acting_user=self.example_user("othello"), ) + hamlet_group = check_add_user_group( + self.user_profile.realm, + "hamlet_group", + [self.example_user("hamlet")], + "Hamlet group", + acting_user=self.example_user("othello"), + ) private_stream = self.make_stream("private_stream", invite_only=True) for setting_name in Stream.stream_permission_group_settings: self.do_test_user_group_events_on_stream_metadata_access_change( - setting_name, private_stream, test_group + setting_name, private_stream, test_group, hamlet_group ) def test_default_stream_groups_events(self) -> None: diff --git a/zerver/tests/test_user_groups.py b/zerver/tests/test_user_groups.py index 7f112c4294..5d5eac86c7 100644 --- a/zerver/tests/test_user_groups.py +++ b/zerver/tests/test_user_groups.py @@ -571,6 +571,7 @@ class UserGroupTestCase(ZulipTestCase): bulk_add_members_to_user_groups([test_group], [], acting_user=None) bulk_remove_members_from_user_groups([], [hamlet.id], acting_user=None) bulk_remove_members_from_user_groups([test_group], [], acting_user=None) + add_subgroups_to_user_group(test_group, [], acting_user=None) class UserGroupAPITestCase(UserGroupTestCase):