users: Send peer_remove on deactivating user.

Tweaked by tabbott to clean up the API changelog.

Fixes #34245.
This commit is contained in:
Shubham Padia
2025-04-01 05:10:09 +00:00
committed by Tim Abbott
parent 2f05bada96
commit 53983c9eb9
5 changed files with 44 additions and 11 deletions

View File

@@ -20,6 +20,12 @@ format used by the Zulip server that they are interacting with.
## Changes in Zulip 11.0
**Feature level 377**
* [`GET /events`](/api/get-events): When a user is deactivate, send
`peer_remove` event to all the subscribers of the streams that the
user was subscribed to.
Feature levels 373-376 reserved for future use in 10.x maintenance
releases.

View File

@@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
# new level means in api_docs/changelog.md, as well as "**Changes**"
# entries in the endpoint's documentation in `zulip.yaml`.
API_FEATURE_LEVEL = 372 # Last bumped to interpret "(no topic)" as empty string.
API_FEATURE_LEVEL = 377 # Last bumped to sending peer_remove on user deactivation.
# 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

View File

@@ -13,6 +13,7 @@ from django.utils.http import urlsafe_base64_encode
from django.utils.timezone import now as timezone_now
from django.utils.translation import get_language
from zerver.actions.streams import send_peer_remove_events
from zerver.actions.user_groups import (
do_send_user_group_members_update_event,
update_users_in_full_members_system_group,
@@ -383,6 +384,19 @@ def send_update_events_for_anonymous_group_settings(
def send_events_for_user_deactivation(user_profile: UserProfile) -> None:
subscribed_streams = get_streams_for_user(
user_profile,
include_public=False,
include_subscribed=True,
)
altered_user_dict: dict[int, set[int]] = defaultdict(set)
streams: list[Stream] = []
for stream in subscribed_streams:
altered_user_dict[stream.id].add(user_profile.id)
streams.append(stream)
send_peer_remove_events(user_profile.realm, streams, altered_user_dict)
event_deactivate_user = dict(
type="realm_user",
op="update",

View File

@@ -916,6 +916,16 @@ paths:
The IDs of the channels from which the users have been
unsubscribed from.
When a user is deactivated, the server will send this event
removing the user's subscriptions before the `realm_user` event
for the user's deactivation.
**Changes**: Before Zulip 10.0 (feature level 377), this event
was not sent on user deactivation. Clients supporting older
server versions and maintaining peer subscriber data need to
remove all channel subscriptions for a user when processing the
`realm_user` event with `op="remove"`.
**Changes**: New in Zulip 4.0 (feature level 35), replacing
the `stream_id` integer.
items:

View File

@@ -1464,7 +1464,7 @@ class NormalActionsTest(BaseAction):
invite_expires_in_minutes=invite_expires_in_minutes,
)
with self.verify_action(num_events=2) as events:
with self.verify_action(num_events=3) as events:
do_deactivate_user(user_profile, acting_user=None)
check_invites_changed("events[0]", events[0])
@@ -3484,9 +3484,10 @@ class NormalActionsTest(BaseAction):
hamletcharacters_group, "can_mention_group", setting_group, acting_user=None
)
with self.verify_action(num_events=1) as events:
with self.verify_action(num_events=2) as events:
do_deactivate_user(user_profile, acting_user=None)
check_realm_user_update("events[0]", events[0], "is_active")
check_subscription_peer_remove("events[0]", events[0])
check_realm_user_update("events[1]", events[1], "is_active")
do_reactivate_user(user_profile, acting_user=None)
self.set_up_db_for_testing_user_access()
@@ -3495,9 +3496,10 @@ class NormalActionsTest(BaseAction):
# Test that users who can access the deactivated user
# do not receive the 'user_group/remove_members' event.
user_profile = self.example_user("cordelia")
with self.verify_action(num_events=1) as events:
with self.verify_action(num_events=2) as events:
do_deactivate_user(user_profile, acting_user=None)
check_realm_user_update("events[0]", events[0], "is_active")
check_subscription_peer_remove("events[0]", events[0])
check_realm_user_update("events[1]", events[1], "is_active")
do_reactivate_user(user_profile, acting_user=None)
@@ -3567,15 +3569,16 @@ class NormalActionsTest(BaseAction):
# Guest loses access to deactivated user if the user
# was not involved in DMs.
user_profile = self.example_user("hamlet")
with self.verify_action(num_events=5) as events:
with self.verify_action(num_events=6) as events:
do_deactivate_user(user_profile, acting_user=None)
check_user_group_remove_members("events[0]", events[0])
check_subscription_peer_remove("events[0]", events[0])
check_user_group_remove_members("events[1]", events[1])
check_user_group_remove_members("events[2]", events[2])
check_user_group_update("events[3]", events[3], {"can_mention_group"})
check_realm_user_remove("events[4]]", events[4])
check_user_group_remove_members("events[3]", events[3])
check_user_group_update("events[4]", events[4], {"can_mention_group"})
check_realm_user_remove("events[5]]", events[5])
self.assertEqual(
events[3]["data"]["can_mention_group"],
events[4]["data"]["can_mention_group"],
UserGroupMembersDict(direct_members=[], direct_subgroups=[members_group.id]),
)