mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	users: Send stream creation/deletion events on role change.
We now send stream creation and stream deletion events on changing a user's role because a user can gain or lose access to some streams on changing their role.
This commit is contained in:
		@@ -24,6 +24,9 @@ format used by the Zulip server that they are interacting with.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
* [`POST /register`](/api/register-queue): `streams` field in the response
 | 
					* [`POST /register`](/api/register-queue): `streams` field in the response
 | 
				
			||||||
  now included web-public streams as well.
 | 
					  now included web-public streams as well.
 | 
				
			||||||
 | 
					* [`GET /events`](/api/get-events): Events for stream creation and deletion
 | 
				
			||||||
 | 
					  are now sent to the user if they gain or lose access to some streams due
 | 
				
			||||||
 | 
					  to change in their role.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Feature level 204**
 | 
					**Feature level 204**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 = 204
 | 
					API_FEATURE_LEVEL = 205
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# 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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,9 @@ from zerver.lib.cache import bot_dict_fields
 | 
				
			|||||||
from zerver.lib.create_user import create_user
 | 
					from zerver.lib.create_user import create_user
 | 
				
			||||||
from zerver.lib.send_email import clear_scheduled_emails
 | 
					from zerver.lib.send_email import clear_scheduled_emails
 | 
				
			||||||
from zerver.lib.sessions import delete_user_sessions
 | 
					from zerver.lib.sessions import delete_user_sessions
 | 
				
			||||||
 | 
					from zerver.lib.stream_subscription import bulk_get_subscriber_peer_info
 | 
				
			||||||
 | 
					from zerver.lib.stream_traffic import get_streams_traffic
 | 
				
			||||||
 | 
					from zerver.lib.streams import get_streams_for_user, stream_to_dict
 | 
				
			||||||
from zerver.lib.user_counts import realm_user_count_by_role
 | 
					from zerver.lib.user_counts import realm_user_count_by_role
 | 
				
			||||||
from zerver.lib.user_groups import get_system_user_group_for_user
 | 
					from zerver.lib.user_groups import get_system_user_group_for_user
 | 
				
			||||||
from zerver.lib.users import get_active_bots_owned_by_user
 | 
					from zerver.lib.users import get_active_bots_owned_by_user
 | 
				
			||||||
@@ -28,6 +31,7 @@ from zerver.models import (
 | 
				
			|||||||
    RealmAuditLog,
 | 
					    RealmAuditLog,
 | 
				
			||||||
    Recipient,
 | 
					    Recipient,
 | 
				
			||||||
    Service,
 | 
					    Service,
 | 
				
			||||||
 | 
					    Stream,
 | 
				
			||||||
    Subscription,
 | 
					    Subscription,
 | 
				
			||||||
    UserGroupMembership,
 | 
					    UserGroupMembership,
 | 
				
			||||||
    UserProfile,
 | 
					    UserProfile,
 | 
				
			||||||
@@ -309,6 +313,59 @@ def do_deactivate_user(
 | 
				
			|||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def send_stream_events_for_role_update(
 | 
				
			||||||
 | 
					    user_profile: UserProfile, old_accessible_streams: List[Stream]
 | 
				
			||||||
 | 
					) -> None:
 | 
				
			||||||
 | 
					    current_accessible_streams = get_streams_for_user(
 | 
				
			||||||
 | 
					        user_profile,
 | 
				
			||||||
 | 
					        include_all_active=user_profile.is_realm_admin,
 | 
				
			||||||
 | 
					        include_web_public=True,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    old_accessible_stream_ids = {stream.id for stream in old_accessible_streams}
 | 
				
			||||||
 | 
					    current_accessible_stream_ids = {stream.id for stream in current_accessible_streams}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    now_accessible_stream_ids = current_accessible_stream_ids - old_accessible_stream_ids
 | 
				
			||||||
 | 
					    if now_accessible_stream_ids:
 | 
				
			||||||
 | 
					        recent_traffic = get_streams_traffic(now_accessible_stream_ids, user_profile.realm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        now_accessible_streams = [
 | 
				
			||||||
 | 
					            stream
 | 
				
			||||||
 | 
					            for stream in current_accessible_streams
 | 
				
			||||||
 | 
					            if stream.id in now_accessible_stream_ids
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        event = dict(
 | 
				
			||||||
 | 
					            type="stream",
 | 
				
			||||||
 | 
					            op="create",
 | 
				
			||||||
 | 
					            streams=[stream_to_dict(stream, recent_traffic) for stream in now_accessible_streams],
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        send_event_on_commit(user_profile.realm, event, [user_profile.id])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subscriber_peer_info = bulk_get_subscriber_peer_info(
 | 
				
			||||||
 | 
					            user_profile.realm, now_accessible_streams
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        for stream_id, stream_subscriber_set in subscriber_peer_info.subscribed_ids.items():
 | 
				
			||||||
 | 
					            peer_add_event = dict(
 | 
				
			||||||
 | 
					                type="subscription",
 | 
				
			||||||
 | 
					                op="peer_add",
 | 
				
			||||||
 | 
					                stream_ids=[stream_id],
 | 
				
			||||||
 | 
					                user_ids=sorted(stream_subscriber_set),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            send_event_on_commit(user_profile.realm, peer_add_event, [user_profile.id])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    now_inaccessible_stream_ids = old_accessible_stream_ids - current_accessible_stream_ids
 | 
				
			||||||
 | 
					    if now_inaccessible_stream_ids:
 | 
				
			||||||
 | 
					        now_inaccessible_streams = [
 | 
				
			||||||
 | 
					            stream for stream in old_accessible_streams if stream.id in now_inaccessible_stream_ids
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        event = dict(
 | 
				
			||||||
 | 
					            type="stream",
 | 
				
			||||||
 | 
					            op="delete",
 | 
				
			||||||
 | 
					            streams=[stream_to_dict(stream) for stream in now_inaccessible_streams],
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        send_event_on_commit(user_profile.realm, event, [user_profile.id])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@transaction.atomic(durable=True)
 | 
					@transaction.atomic(durable=True)
 | 
				
			||||||
def do_change_user_role(
 | 
					def do_change_user_role(
 | 
				
			||||||
    user_profile: UserProfile, value: int, *, acting_user: Optional[UserProfile]
 | 
					    user_profile: UserProfile, value: int, *, acting_user: Optional[UserProfile]
 | 
				
			||||||
@@ -316,6 +373,12 @@ def do_change_user_role(
 | 
				
			|||||||
    old_value = user_profile.role
 | 
					    old_value = user_profile.role
 | 
				
			||||||
    old_system_group = get_system_user_group_for_user(user_profile)
 | 
					    old_system_group = get_system_user_group_for_user(user_profile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    previously_accessible_streams = get_streams_for_user(
 | 
				
			||||||
 | 
					        user_profile,
 | 
				
			||||||
 | 
					        include_web_public=True,
 | 
				
			||||||
 | 
					        include_all_active=user_profile.is_realm_admin,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    user_profile.role = value
 | 
					    user_profile.role = value
 | 
				
			||||||
    user_profile.save(update_fields=["role"])
 | 
					    user_profile.save(update_fields=["role"])
 | 
				
			||||||
    RealmAuditLog.objects.create(
 | 
					    RealmAuditLog.objects.create(
 | 
				
			||||||
@@ -372,6 +435,8 @@ def do_change_user_role(
 | 
				
			|||||||
            user_profile.realm, [user_profile.id], acting_user=acting_user
 | 
					            user_profile.realm, [user_profile.id], acting_user=acting_user
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    send_stream_events_for_role_update(user_profile, previously_accessible_streams)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def do_make_user_billing_admin(user_profile: UserProfile) -> None:
 | 
					def do_make_user_billing_admin(user_profile: UserProfile) -> None:
 | 
				
			||||||
    user_profile.is_billing_admin = True
 | 
					    user_profile.is_billing_admin = True
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -882,26 +882,6 @@ def apply_event(
 | 
				
			|||||||
                    state["can_subscribe_other_users"] = user_profile.can_subscribe_other_users()
 | 
					                    state["can_subscribe_other_users"] = user_profile.can_subscribe_other_users()
 | 
				
			||||||
                    state["can_invite_others_to_realm"] = user_profile.can_invite_others_to_realm()
 | 
					                    state["can_invite_others_to_realm"] = user_profile.can_invite_others_to_realm()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    # TODO: Probably rather than writing the perfect
 | 
					 | 
				
			||||||
                    # live-update code for the case of racing with the
 | 
					 | 
				
			||||||
                    # current user changing roles, we should just do a
 | 
					 | 
				
			||||||
                    # full refetch.
 | 
					 | 
				
			||||||
                    if "never_subscribed" in state:
 | 
					 | 
				
			||||||
                        sub_info = gather_subscriptions_helper(
 | 
					 | 
				
			||||||
                            user_profile,
 | 
					 | 
				
			||||||
                            include_subscribers=include_subscribers,
 | 
					 | 
				
			||||||
                        )
 | 
					 | 
				
			||||||
                        state["subscriptions"] = sub_info.subscriptions
 | 
					 | 
				
			||||||
                        state["unsubscribed"] = sub_info.unsubscribed
 | 
					 | 
				
			||||||
                        state["never_subscribed"] = sub_info.never_subscribed
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if "streams" in state:
 | 
					 | 
				
			||||||
                        state["streams"] = do_get_streams(
 | 
					 | 
				
			||||||
                            user_profile,
 | 
					 | 
				
			||||||
                            include_web_public=True,
 | 
					 | 
				
			||||||
                            include_all_active=user_profile.is_realm_admin,
 | 
					 | 
				
			||||||
                        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if state["is_guest"]:
 | 
					                    if state["is_guest"]:
 | 
				
			||||||
                        state["realm_default_streams"] = []
 | 
					                        state["realm_default_streams"] = []
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1165,12 +1165,16 @@ paths:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                                This event is also sent when a user gains access to a stream they
 | 
					                                This event is also sent when a user gains access to a stream they
 | 
				
			||||||
                                previously [could not access](/help/stream-permissions), such as
 | 
					                                previously [could not access](/help/stream-permissions), such as
 | 
				
			||||||
                                when a private stream is made public, or when a [guest user](/help/roles-and-permissions)
 | 
					                                when a private stream is made public, their role changes or when
 | 
				
			||||||
                                is subscribed to a public (or private) stream.
 | 
					                                a [guest user](/help/roles-and-permissions) is subscribed to a
 | 
				
			||||||
 | 
					                                public (or private) stream.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                Note that organization administrators who are not subscribed will
 | 
					                                Note that organization administrators who are not subscribed will
 | 
				
			||||||
                                not be able to see content on the stream; just that it exists.
 | 
					                                not be able to see content on the stream; just that it exists.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                **Changes**: Prior to Zulip 8.0 (feature level 205), this event was
 | 
				
			||||||
 | 
					                                not sent when a user gained access to a stream due to role change.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                **Changes**: Prior to Zulip 8.0 (feature level 192), this event was
 | 
					                                **Changes**: Prior to Zulip 8.0 (feature level 192), this event was
 | 
				
			||||||
                                not sent when guest users gained access to a public stream by being
 | 
					                                not sent when guest users gained access to a public stream by being
 | 
				
			||||||
                                subscribed.
 | 
					                                subscribed.
 | 
				
			||||||
@@ -1222,6 +1226,13 @@ paths:
 | 
				
			|||||||
                            - type: object
 | 
					                            - type: object
 | 
				
			||||||
                              description: |
 | 
					                              description: |
 | 
				
			||||||
                                Event sent to all users who can see a stream when it is deactivated.
 | 
					                                Event sent to all users who can see a stream when it is deactivated.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                This event is also sent when a user loses access to a stream they
 | 
				
			||||||
 | 
					                                previously [could access](/help/stream-permissions) when their roles
 | 
				
			||||||
 | 
					                                changes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                **Changes**: Prior to Zulip 8.0 (feature level 205), this event was
 | 
				
			||||||
 | 
					                                not sent when a user lost access to a stream due to role change.
 | 
				
			||||||
                              properties:
 | 
					                              properties:
 | 
				
			||||||
                                id:
 | 
					                                id:
 | 
				
			||||||
                                  $ref: "#/components/schemas/EventIdSchema"
 | 
					                                  $ref: "#/components/schemas/EventIdSchema"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1859,10 +1859,19 @@ class NormalActionsTest(BaseAction):
 | 
				
			|||||||
        self.user_profile.refresh_from_db()
 | 
					        self.user_profile.refresh_from_db()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        do_change_user_role(self.user_profile, UserProfile.ROLE_MEMBER, acting_user=None)
 | 
					        do_change_user_role(self.user_profile, UserProfile.ROLE_MEMBER, acting_user=None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.make_stream("Test private stream", invite_only=True)
 | 
				
			||||||
 | 
					        self.subscribe(self.example_user("othello"), "Test private stream")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for role in [UserProfile.ROLE_REALM_ADMINISTRATOR, UserProfile.ROLE_MEMBER]:
 | 
					        for role in [UserProfile.ROLE_REALM_ADMINISTRATOR, UserProfile.ROLE_MEMBER]:
 | 
				
			||||||
 | 
					            if role == UserProfile.ROLE_REALM_ADMINISTRATOR:
 | 
				
			||||||
 | 
					                num_events = 6
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                num_events = 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            events = self.verify_action(
 | 
					            events = self.verify_action(
 | 
				
			||||||
                lambda: do_change_user_role(self.user_profile, role, acting_user=None),
 | 
					                lambda: do_change_user_role(self.user_profile, role, acting_user=None),
 | 
				
			||||||
                num_events=4,
 | 
					                num_events=num_events,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            check_realm_user_update("events[0]", events[0], "role")
 | 
					            check_realm_user_update("events[0]", events[0], "role")
 | 
				
			||||||
            self.assertEqual(events[0]["person"]["role"], role)
 | 
					            self.assertEqual(events[0]["person"]["role"], role)
 | 
				
			||||||
@@ -1872,8 +1881,11 @@ class NormalActionsTest(BaseAction):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if role == UserProfile.ROLE_REALM_ADMINISTRATOR:
 | 
					            if role == UserProfile.ROLE_REALM_ADMINISTRATOR:
 | 
				
			||||||
                check_user_group_remove_members("events[3]", events[3])
 | 
					                check_user_group_remove_members("events[3]", events[3])
 | 
				
			||||||
 | 
					                check_stream_create("events[4]", events[4])
 | 
				
			||||||
 | 
					                check_subscription_peer_add("events[5]", events[5])
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                check_user_group_add_members("events[3]", events[3])
 | 
					                check_user_group_add_members("events[3]", events[3])
 | 
				
			||||||
 | 
					                check_stream_delete("events[4]", events[4])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_change_is_billing_admin(self) -> None:
 | 
					    def test_change_is_billing_admin(self) -> None:
 | 
				
			||||||
        reset_email_visibility_to_everyone_in_zulip_realm()
 | 
					        reset_email_visibility_to_everyone_in_zulip_realm()
 | 
				
			||||||
@@ -1896,10 +1908,18 @@ class NormalActionsTest(BaseAction):
 | 
				
			|||||||
        self.user_profile.refresh_from_db()
 | 
					        self.user_profile.refresh_from_db()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        do_change_user_role(self.user_profile, UserProfile.ROLE_MEMBER, acting_user=None)
 | 
					        do_change_user_role(self.user_profile, UserProfile.ROLE_MEMBER, acting_user=None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.make_stream("Test private stream", invite_only=True)
 | 
				
			||||||
 | 
					        self.subscribe(self.example_user("othello"), "Test private stream")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for role in [UserProfile.ROLE_REALM_OWNER, UserProfile.ROLE_MEMBER]:
 | 
					        for role in [UserProfile.ROLE_REALM_OWNER, UserProfile.ROLE_MEMBER]:
 | 
				
			||||||
 | 
					            if role == UserProfile.ROLE_REALM_OWNER:
 | 
				
			||||||
 | 
					                num_events = 6
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                num_events = 5
 | 
				
			||||||
            events = self.verify_action(
 | 
					            events = self.verify_action(
 | 
				
			||||||
                lambda: do_change_user_role(self.user_profile, role, acting_user=None),
 | 
					                lambda: do_change_user_role(self.user_profile, role, acting_user=None),
 | 
				
			||||||
                num_events=4,
 | 
					                num_events=num_events,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            check_realm_user_update("events[0]", events[0], "role")
 | 
					            check_realm_user_update("events[0]", events[0], "role")
 | 
				
			||||||
            self.assertEqual(events[0]["person"]["role"], role)
 | 
					            self.assertEqual(events[0]["person"]["role"], role)
 | 
				
			||||||
@@ -1909,8 +1929,11 @@ class NormalActionsTest(BaseAction):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if role == UserProfile.ROLE_REALM_OWNER:
 | 
					            if role == UserProfile.ROLE_REALM_OWNER:
 | 
				
			||||||
                check_user_group_remove_members("events[3]", events[3])
 | 
					                check_user_group_remove_members("events[3]", events[3])
 | 
				
			||||||
 | 
					                check_stream_create("events[4]", events[4])
 | 
				
			||||||
 | 
					                check_subscription_peer_add("events[5]", events[5])
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                check_user_group_add_members("events[3]", events[3])
 | 
					                check_user_group_add_members("events[3]", events[3])
 | 
				
			||||||
 | 
					                check_stream_delete("events[4]", events[4])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_change_is_moderator(self) -> None:
 | 
					    def test_change_is_moderator(self) -> None:
 | 
				
			||||||
        reset_email_visibility_to_everyone_in_zulip_realm()
 | 
					        reset_email_visibility_to_everyone_in_zulip_realm()
 | 
				
			||||||
@@ -1950,9 +1973,16 @@ class NormalActionsTest(BaseAction):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        do_change_user_role(self.user_profile, UserProfile.ROLE_MEMBER, acting_user=None)
 | 
					        do_change_user_role(self.user_profile, UserProfile.ROLE_MEMBER, acting_user=None)
 | 
				
			||||||
        for role in [UserProfile.ROLE_GUEST, UserProfile.ROLE_MEMBER]:
 | 
					        for role in [UserProfile.ROLE_GUEST, UserProfile.ROLE_MEMBER]:
 | 
				
			||||||
 | 
					            if role == UserProfile.ROLE_MEMBER:
 | 
				
			||||||
 | 
					                # When changing role from guest to member, peer_add events are also sent
 | 
				
			||||||
 | 
					                # to make sure the subscribers info is provided to the clients for the
 | 
				
			||||||
 | 
					                # streams added by stream creation event.
 | 
				
			||||||
 | 
					                num_events = 7
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                num_events = 5
 | 
				
			||||||
            events = self.verify_action(
 | 
					            events = self.verify_action(
 | 
				
			||||||
                lambda: do_change_user_role(self.user_profile, role, acting_user=None),
 | 
					                lambda: do_change_user_role(self.user_profile, role, acting_user=None),
 | 
				
			||||||
                num_events=4,
 | 
					                num_events=num_events,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            check_realm_user_update("events[0]", events[0], "role")
 | 
					            check_realm_user_update("events[0]", events[0], "role")
 | 
				
			||||||
            self.assertEqual(events[0]["person"]["role"], role)
 | 
					            self.assertEqual(events[0]["person"]["role"], role)
 | 
				
			||||||
@@ -1962,8 +1992,12 @@ class NormalActionsTest(BaseAction):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if role == UserProfile.ROLE_GUEST:
 | 
					            if role == UserProfile.ROLE_GUEST:
 | 
				
			||||||
                check_user_group_remove_members("events[3]", events[3])
 | 
					                check_user_group_remove_members("events[3]", events[3])
 | 
				
			||||||
 | 
					                check_stream_delete("events[4]", events[4])
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                check_user_group_add_members("events[3]", events[3])
 | 
					                check_user_group_add_members("events[3]", events[3])
 | 
				
			||||||
 | 
					                check_stream_create("events[4]", events[4])
 | 
				
			||||||
 | 
					                check_subscription_peer_add("events[5]", events[5])
 | 
				
			||||||
 | 
					                check_subscription_peer_add("events[6]", events[6])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_change_notification_settings(self) -> None:
 | 
					    def test_change_notification_settings(self) -> None:
 | 
				
			||||||
        for notification_setting in self.user_profile.notification_setting_types:
 | 
					        for notification_setting in self.user_profile.notification_setting_types:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -220,7 +220,7 @@ class PermissionTest(ZulipTestCase):
 | 
				
			|||||||
        self.assertFalse(othello_dict["is_owner"])
 | 
					        self.assertFalse(othello_dict["is_owner"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        req = dict(role=UserProfile.ROLE_REALM_OWNER)
 | 
					        req = dict(role=UserProfile.ROLE_REALM_OWNER)
 | 
				
			||||||
        with self.capture_send_event_calls(expected_num_events=4) as events:
 | 
					        with self.capture_send_event_calls(expected_num_events=6) as events:
 | 
				
			||||||
            result = self.client_patch(f"/json/users/{othello.id}", req)
 | 
					            result = self.client_patch(f"/json/users/{othello.id}", req)
 | 
				
			||||||
        self.assert_json_success(result)
 | 
					        self.assert_json_success(result)
 | 
				
			||||||
        owner_users = realm.get_human_owner_users()
 | 
					        owner_users = realm.get_human_owner_users()
 | 
				
			||||||
@@ -230,7 +230,7 @@ class PermissionTest(ZulipTestCase):
 | 
				
			|||||||
        self.assertEqual(person["role"], UserProfile.ROLE_REALM_OWNER)
 | 
					        self.assertEqual(person["role"], UserProfile.ROLE_REALM_OWNER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        req = dict(role=UserProfile.ROLE_MEMBER)
 | 
					        req = dict(role=UserProfile.ROLE_MEMBER)
 | 
				
			||||||
        with self.capture_send_event_calls(expected_num_events=4) as events:
 | 
					        with self.capture_send_event_calls(expected_num_events=5) as events:
 | 
				
			||||||
            result = self.client_patch(f"/json/users/{othello.id}", req)
 | 
					            result = self.client_patch(f"/json/users/{othello.id}", req)
 | 
				
			||||||
        self.assert_json_success(result)
 | 
					        self.assert_json_success(result)
 | 
				
			||||||
        owner_users = realm.get_human_owner_users()
 | 
					        owner_users = realm.get_human_owner_users()
 | 
				
			||||||
@@ -281,7 +281,7 @@ class PermissionTest(ZulipTestCase):
 | 
				
			|||||||
        # Giveth
 | 
					        # Giveth
 | 
				
			||||||
        req = dict(role=orjson.dumps(UserProfile.ROLE_REALM_ADMINISTRATOR).decode())
 | 
					        req = dict(role=orjson.dumps(UserProfile.ROLE_REALM_ADMINISTRATOR).decode())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with self.capture_send_event_calls(expected_num_events=4) as events:
 | 
					        with self.capture_send_event_calls(expected_num_events=6) as events:
 | 
				
			||||||
            result = self.client_patch(f"/json/users/{othello.id}", req)
 | 
					            result = self.client_patch(f"/json/users/{othello.id}", req)
 | 
				
			||||||
        self.assert_json_success(result)
 | 
					        self.assert_json_success(result)
 | 
				
			||||||
        admin_users = realm.get_human_admin_users()
 | 
					        admin_users = realm.get_human_admin_users()
 | 
				
			||||||
@@ -292,7 +292,7 @@ class PermissionTest(ZulipTestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # Taketh away
 | 
					        # Taketh away
 | 
				
			||||||
        req = dict(role=orjson.dumps(UserProfile.ROLE_MEMBER).decode())
 | 
					        req = dict(role=orjson.dumps(UserProfile.ROLE_MEMBER).decode())
 | 
				
			||||||
        with self.capture_send_event_calls(expected_num_events=4) as events:
 | 
					        with self.capture_send_event_calls(expected_num_events=5) as events:
 | 
				
			||||||
            result = self.client_patch(f"/json/users/{othello.id}", req)
 | 
					            result = self.client_patch(f"/json/users/{othello.id}", req)
 | 
				
			||||||
        self.assert_json_success(result)
 | 
					        self.assert_json_success(result)
 | 
				
			||||||
        admin_users = realm.get_human_admin_users()
 | 
					        admin_users = realm.get_human_admin_users()
 | 
				
			||||||
@@ -518,9 +518,42 @@ class PermissionTest(ZulipTestCase):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        req = dict(role=orjson.dumps(new_role).decode())
 | 
					        req = dict(role=orjson.dumps(new_role).decode())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # The basic events sent in all cases on changing role are - one event
 | 
				
			||||||
 | 
					        # for changing role and one event each for adding and removing user
 | 
				
			||||||
 | 
					        # from system user group.
 | 
				
			||||||
        num_events = 3
 | 
					        num_events = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if UserProfile.ROLE_MEMBER in [old_role, new_role]:
 | 
					        if UserProfile.ROLE_MEMBER in [old_role, new_role]:
 | 
				
			||||||
            num_events = 4
 | 
					            # There is one additional event for adding/removing user from
 | 
				
			||||||
 | 
					            # the "Full members" group as well.
 | 
				
			||||||
 | 
					            num_events += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if new_role == UserProfile.ROLE_GUEST:
 | 
				
			||||||
 | 
					            # There is one additional event deleting the unsubscribed public
 | 
				
			||||||
 | 
					            # streams that the user will not able to access after becoming guest.
 | 
				
			||||||
 | 
					            num_events += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if old_role == UserProfile.ROLE_GUEST:
 | 
				
			||||||
 | 
					            # User will receive one event for creation of unsubscribed public
 | 
				
			||||||
 | 
					            # (and private, if the new role is owner or admin) streams that
 | 
				
			||||||
 | 
					            # they did not have access to previously and 3 more peer_add
 | 
				
			||||||
 | 
					            # events for each of the public stream.
 | 
				
			||||||
 | 
					            if new_role in [UserProfile.ROLE_REALM_ADMINISTRATOR, UserProfile.ROLE_REALM_OWNER]:
 | 
				
			||||||
 | 
					                # If the new role is owner or admin, the peer_add event will be
 | 
				
			||||||
 | 
					                # sent for one private stream as well.
 | 
				
			||||||
 | 
					                num_events += 5
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                num_events += 4
 | 
				
			||||||
 | 
					        elif new_role in [
 | 
				
			||||||
 | 
					            UserProfile.ROLE_REALM_ADMINISTRATOR,
 | 
				
			||||||
 | 
					            UserProfile.ROLE_REALM_OWNER,
 | 
				
			||||||
 | 
					        ] and old_role not in [UserProfile.ROLE_REALM_ADMINISTRATOR, UserProfile.ROLE_REALM_OWNER]:
 | 
				
			||||||
 | 
					            # If old_role is not guest and user's role is changed to admin or owner from moderator
 | 
				
			||||||
 | 
					            # or member, then the user gains access to unsubscribed private streams and thus
 | 
				
			||||||
 | 
					            # receives one event for stream creation and one peer_add event for it.
 | 
				
			||||||
 | 
					            num_events += 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with self.capture_send_event_calls(expected_num_events=num_events) as events:
 | 
					        with self.capture_send_event_calls(expected_num_events=num_events) as events:
 | 
				
			||||||
            result = self.client_patch(f"/json/users/{user_profile.id}", req)
 | 
					            result = self.client_patch(f"/json/users/{user_profile.id}", req)
 | 
				
			||||||
        self.assert_json_success(result)
 | 
					        self.assert_json_success(result)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user