mirror of
https://github.com/zulip/zulip.git
synced 2025-10-29 02:53:52 +00:00
event_schema: Add schema check for realm/deactivated event.
This add the schema checker, openapi schema, and also a test for realm/deactivated event. With several block comments by tabbott explaining the logic behind our behavior here. Part of #17568.
This commit is contained in:
@@ -216,6 +216,7 @@ exports.fixtures = {
|
||||
realm__deactivated: {
|
||||
type: "realm",
|
||||
op: "deactivated",
|
||||
realm_id: 2,
|
||||
},
|
||||
|
||||
realm__update__bot_creation_policy: {
|
||||
|
||||
@@ -249,6 +249,13 @@ export function dispatch_normal_event(event) {
|
||||
page_params.realm_night_logo_source = event.data.night_logo_source;
|
||||
realm_logo.rerender();
|
||||
} else if (event.op === "deactivated") {
|
||||
// This handler is likely unnecessary, in that if we
|
||||
// did nothing here, we'd reload and end up at the
|
||||
// same place when we attempt the next `GET /events`
|
||||
// and get an error. Some clients will do that even
|
||||
// with this code, if they didn't have an active
|
||||
// longpoll waiting at the moment the realm was
|
||||
// deactivated.
|
||||
window.location.href = "/accounts/deactivated/";
|
||||
}
|
||||
|
||||
|
||||
@@ -1010,6 +1010,12 @@ def do_deactivate_realm(realm: Realm, acting_user: Optional[UserProfile] = None)
|
||||
# notice when they try to log in.
|
||||
delete_user_sessions(user)
|
||||
|
||||
# This event will only ever be received by clients with an active
|
||||
# longpoll connection, because by this point clients will be
|
||||
# unable to authenticate again to their event queue (triggering an
|
||||
# immediate reload into the page explaining the realm was
|
||||
# deactivated). So the purpose of sending this is to flush all
|
||||
# active longpoll connections for the realm.
|
||||
event = dict(type="realm", op="deactivated", realm_id=realm.id)
|
||||
send_event(realm, event, active_user_ids(realm.id))
|
||||
|
||||
|
||||
@@ -458,6 +458,14 @@ reaction_remove_event = event_dict_type(
|
||||
)
|
||||
check_reaction_remove = make_checker(reaction_remove_event)
|
||||
|
||||
realm_deactivated_event = event_dict_type(
|
||||
required_keys=[
|
||||
("type", Equals("realm")),
|
||||
("op", Equals("deactivated")),
|
||||
("realm_id", int),
|
||||
]
|
||||
)
|
||||
check_realm_deactivated = make_checker(realm_deactivated_event)
|
||||
|
||||
bot_services_outgoing_type = DictType(
|
||||
required_keys=[
|
||||
|
||||
@@ -742,6 +742,15 @@ def apply_event(
|
||||
if key == "authentication_methods":
|
||||
state["realm_password_auth_enabled"] = value["Email"] or value["LDAP"]
|
||||
state["realm_email_auth_enabled"] = value["Email"]
|
||||
elif event["op"] == "deactivated":
|
||||
# The realm has just been deactivated. If our request had
|
||||
# arrived a moment later, we'd have rendered the
|
||||
# deactivation UI; if it'd been a moment sooner, we've
|
||||
# have rendered the app and then immediately got this
|
||||
# event (or actually, more likely, an auth error on GET
|
||||
# /events) and immediately reloaded into the same
|
||||
# deactivation UI. Passing achieves the same result.
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("Unexpected event type {type}/{op}".format(**event))
|
||||
elif event["type"] == "subscription":
|
||||
|
||||
@@ -2773,6 +2773,47 @@ paths:
|
||||
"value": false,
|
||||
"id": 0,
|
||||
}
|
||||
- type: object
|
||||
additionalProperties: false
|
||||
description: |
|
||||
Event sent to all users in a Zulip organization when the
|
||||
organization (realm) is deactivated. Its main purpose is to
|
||||
flush active longpolling connections so clients can immediately
|
||||
show the organization as deactivated.
|
||||
|
||||
Clients cannot rely on receiving this event, because they will
|
||||
no longer be able to authenticate to the Zulip API due to the
|
||||
deactivation, and thus can miss it if they did not have an active
|
||||
longpolling connection at the moment of deactivation.
|
||||
|
||||
Correct handling of realm deactivations requires that clients
|
||||
parse authentication errors from GET /events; if that is done
|
||||
correctly, the client can ignore this event type and rely on its
|
||||
handling of the `GET /events` request it will do immediately
|
||||
after processing this batch of events.
|
||||
properties:
|
||||
id:
|
||||
$ref: "#/components/schemas/EventIdSchema"
|
||||
type:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/EventTypeSchema"
|
||||
- enum:
|
||||
- realm
|
||||
op:
|
||||
type: string
|
||||
enum:
|
||||
- deactivated
|
||||
realm_id:
|
||||
type: integer
|
||||
description: |
|
||||
The ID of the deactivated realm.
|
||||
example:
|
||||
{
|
||||
"type": "realm",
|
||||
"op": "deactivated",
|
||||
"realm_id": 2,
|
||||
"id": 0,
|
||||
}
|
||||
- type: object
|
||||
additionalProperties: false
|
||||
description: |
|
||||
|
||||
@@ -52,6 +52,7 @@ from zerver.lib.actions import (
|
||||
do_create_default_stream_group,
|
||||
do_create_multiuse_invite_link,
|
||||
do_create_user,
|
||||
do_deactivate_realm,
|
||||
do_deactivate_stream,
|
||||
do_deactivate_user,
|
||||
do_delete_messages,
|
||||
@@ -114,6 +115,7 @@ from zerver.lib.event_schema import (
|
||||
check_realm_bot_delete,
|
||||
check_realm_bot_remove,
|
||||
check_realm_bot_update,
|
||||
check_realm_deactivated,
|
||||
check_realm_domains_add,
|
||||
check_realm_domains_change,
|
||||
check_realm_domains_remove,
|
||||
@@ -1477,6 +1479,19 @@ class NormalActionsTest(BaseAction):
|
||||
events = self.verify_action(action, num_events=2)
|
||||
check_realm_bot_add("events[1]", events[1])
|
||||
|
||||
def test_do_deactivate_realm(self) -> None:
|
||||
realm = self.user_profile.realm
|
||||
action = lambda: do_deactivate_realm(realm)
|
||||
|
||||
# We delete sessions of all active users when a realm is
|
||||
# deactivated, and redirect them to a deactivated page in
|
||||
# order to inform that realm/organization has been
|
||||
# deactivated. state_change_expected is False is kinda
|
||||
# correct because were one to somehow compute page_params (as
|
||||
# this test does), but that's not actually possible.
|
||||
events = self.verify_action(action, state_change_expected=False)
|
||||
check_realm_deactivated("events[0]", events[0])
|
||||
|
||||
def test_do_mark_hotspot_as_read(self) -> None:
|
||||
self.user_profile.tutorial_status = UserProfile.TUTORIAL_WAITING
|
||||
self.user_profile.save(update_fields=["tutorial_status"])
|
||||
|
||||
Reference in New Issue
Block a user