realm_settings: Clear sessions outside transaction.

This fixes a bug introduced in
6f93ab72c0 where deactivating a realm
would fail with an exception that sessions cannot be cleared inside
database transactions.
This commit is contained in:
Tim Abbott 2023-12-12 08:13:51 -08:00
parent 2b37a35f71
commit f60312b2da

View File

@ -339,7 +339,6 @@ def do_set_realm_user_default_setting(
send_event(realm, event, active_user_ids(realm.id))
@transaction.atomic
def do_deactivate_realm(realm: Realm, *, acting_user: Optional[UserProfile]) -> None:
"""
Deactivate this realm. Do NOT deactivate the users -- we need to be able to
@ -350,45 +349,51 @@ def do_deactivate_realm(realm: Realm, *, acting_user: Optional[UserProfile]) ->
if realm.deactivated:
return
realm.deactivated = True
realm.save(update_fields=["deactivated"])
with transaction.atomic():
realm.deactivated = True
realm.save(update_fields=["deactivated"])
if settings.BILLING_ENABLED:
billing_session = RealmBillingSession(user=acting_user, realm=realm)
billing_session.downgrade_now_without_creating_additional_invoices()
if settings.BILLING_ENABLED:
billing_session = RealmBillingSession(user=acting_user, realm=realm)
billing_session.downgrade_now_without_creating_additional_invoices()
event_time = timezone_now()
RealmAuditLog.objects.create(
realm=realm,
event_type=RealmAuditLog.REALM_DEACTIVATED,
event_time=event_time,
acting_user=acting_user,
extra_data={
RealmAuditLog.ROLE_COUNT: realm_user_count_by_role(realm),
},
)
event_time = timezone_now()
RealmAuditLog.objects.create(
realm=realm,
event_type=RealmAuditLog.REALM_DEACTIVATED,
event_time=event_time,
acting_user=acting_user,
extra_data={
RealmAuditLog.ROLE_COUNT: realm_user_count_by_role(realm),
},
)
from zerver.lib.remote_server import maybe_enqueue_audit_log_upload
from zerver.lib.remote_server import maybe_enqueue_audit_log_upload
maybe_enqueue_audit_log_upload(realm)
maybe_enqueue_audit_log_upload(realm)
ScheduledEmail.objects.filter(realm=realm).delete()
ScheduledEmail.objects.filter(realm=realm).delete()
# 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_on_commit(realm, event, active_user_ids(realm.id))
# Don't deactivate the users, as that would lose a lot of state if
# the realm needs to be reactivated, but do delete their sessions
# so they get bumped to the login screen, where they'll get a
# realm deactivation notice when they try to log in.
#
# Note: This is intentionally outside the transaction because it
# is unsafe to modify sessions inside transactions with the
# cached_db session plugin we're using, and our session engine
# declared in zerver/lib/safe_session_cached_db.py enforces this.
delete_realm_user_sessions(realm)
# 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_on_commit(realm, event, active_user_ids(realm.id))
def do_reactivate_realm(realm: Realm) -> None:
if not realm.deactivated: