mirror of https://github.com/zulip/zulip.git
realm-deactivation: Send email to owners as part of deactivation.
Creates a new "realm_deactivated" email that can be sent to realm owners as part of `do_deactivate_realm`, via a boolean flag, `email_owners`. This flag is set to `False` when `do_deactivate_realm` is used for realm exports or changing a realm's subdomain, so that the active organization owners are not emailed in those cases. This flag is optional for the `deactivate_realm` management command, but as there is no active user passed in that case, then the email is sent without referencing who deactivated the realm. It is passed as `True` for the support analytics view, but the email that is generated does not include information about the support admin user who completed the request for organization deactivation. When an active organization owner deactivates the organization, then the flag is `True` and an email is sent to them as well as any other active organization owners, with a slight variation in the email text for those two cases. Adds specific tests for when `email_owners` is passed as `True`. All existing tests for other functionality of `do_deactivate_user` pass the flag as `False`. Adds `localize` from django.util.formats as a jinja env filter so that the dates in these emails are internationlized for the owner's default language setting in the "realm_deactivated" email templates. Fixes #24685.
This commit is contained in:
parent
2eaf098c5d
commit
673a01ea0c
|
@ -4319,7 +4319,10 @@ class StripeTest(StripeTestCase):
|
|||
self.assertEqual(last_ledger_entry.licenses_at_next_renewal, 20)
|
||||
|
||||
do_deactivate_realm(
|
||||
get_realm("zulip"), acting_user=None, deactivation_reason="owner_request"
|
||||
get_realm("zulip"),
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
|
||||
plan.refresh_from_db()
|
||||
|
@ -4355,7 +4358,10 @@ class StripeTest(StripeTestCase):
|
|||
)
|
||||
|
||||
do_deactivate_realm(
|
||||
get_realm("zulip"), acting_user=None, deactivation_reason="owner_request"
|
||||
get_realm("zulip"),
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
self.assertTrue(get_realm("zulip").deactivated)
|
||||
do_reactivate_realm(get_realm("zulip"))
|
||||
|
|
|
@ -1426,6 +1426,7 @@ class TestSupportEndpoint(ZulipTestCase):
|
|||
lear_realm,
|
||||
acting_user=self.example_user("iago"),
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=True,
|
||||
)
|
||||
self.assert_in_success_response(["lear deactivated"], result)
|
||||
|
||||
|
|
|
@ -444,7 +444,10 @@ def support(
|
|||
# TODO: Add support for deactivation reason in the support UI that'll be passed
|
||||
# here.
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=acting_user, deactivation_reason="owner_request"
|
||||
realm,
|
||||
acting_user=acting_user,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=True,
|
||||
)
|
||||
context["success_message"] = f"{realm.string_id} deactivated."
|
||||
elif scrub_realm:
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
{% extends "zerver/emails/email_base_default.html" %}
|
||||
{% set localized_date = event_date|localize %}
|
||||
|
||||
{% block illustration %}
|
||||
<img src="{{ email_images_base_url }}/email_logo.png" alt=""/>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
{% if acting_user and initiated_deactivation %}
|
||||
{% trans %}You have deactivated your Zulip organization, {{ realm_name }}, on {{ localized_date }}.{% endtrans %}
|
||||
{% elif acting_user %}
|
||||
{% trans %}Your Zulip organization, {{ realm_name }}, was deactivated by {{ deactivating_owner }} on {{ localized_date }}.{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}Your Zulip organization, {{ realm_name }}, was deactivated on {{ localized_date }}.{% endtrans %}
|
||||
{% endif %}
|
||||
</p>
|
||||
<p>
|
||||
{% trans %}If you have any questions or concerns, please reply to this email as soon as possible.{% endtrans %}
|
||||
</p>
|
||||
{% endblock %}
|
|
@ -0,0 +1 @@
|
|||
{% trans %}Your Zulip organization {{ realm_name }} has been deactivated{% endtrans %}
|
|
@ -0,0 +1,10 @@
|
|||
{% set localized_date = event_date|localize %}
|
||||
{% if acting_user and initiated_deactivation %}
|
||||
{% trans %}You have deactivated your Zulip organization, {{ realm_name }}, on {{ localized_date }}.{% endtrans %}
|
||||
{% elif acting_user %}
|
||||
{% trans %}Your Zulip organization, {{ realm_name }}, was deactivated by {{ deactivating_owner }} on {{ localized_date }}.{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}Your Zulip organization, {{ realm_name }}, was deactivated on {{ localized_date }}.{% endtrans %}
|
||||
{% endif %}
|
||||
|
||||
{% trans%}If you have any questions or concerns, please reply to this email as soon as possible.{% endtrans %}
|
|
@ -116,7 +116,9 @@ with test_server_running(
|
|||
do_reactivate_user(guest_user, acting_user=None)
|
||||
|
||||
# Test realm deactivated error
|
||||
do_deactivate_realm(guest_user.realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
guest_user.realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
|
||||
client = Client(
|
||||
email=email,
|
||||
|
|
|
@ -98,7 +98,10 @@ def do_change_realm_subdomain(
|
|||
if add_deactivated_redirect:
|
||||
placeholder_realm = do_create_realm(old_subdomain, realm.name)
|
||||
do_deactivate_realm(
|
||||
placeholder_realm, acting_user=None, deactivation_reason="subdomain_change"
|
||||
placeholder_realm,
|
||||
acting_user=None,
|
||||
deactivation_reason="subdomain_change",
|
||||
email_owners=False,
|
||||
)
|
||||
do_add_deactivated_redirect(placeholder_realm, realm.url)
|
||||
|
||||
|
|
|
@ -2,8 +2,10 @@ import logging
|
|||
from email.headerregistry import Address
|
||||
from typing import Any, Dict, Literal, Optional, Tuple, Union
|
||||
|
||||
import zoneinfo
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.utils.timezone import get_current_timezone_name as timezone_get_current_timezone_name
|
||||
from django.utils.timezone import now as timezone_now
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
@ -15,9 +17,10 @@ from zerver.actions.user_settings import do_delete_avatar_image
|
|||
from zerver.lib.exceptions import JsonableError
|
||||
from zerver.lib.message import parse_message_time_limit_setting, update_first_visible_message_id
|
||||
from zerver.lib.retention import move_messages_to_archive
|
||||
from zerver.lib.send_email import FromAddress, send_email_to_admins
|
||||
from zerver.lib.send_email import FromAddress, send_email, send_email_to_admins
|
||||
from zerver.lib.sessions import delete_realm_user_sessions
|
||||
from zerver.lib.timestamp import datetime_to_timestamp, timestamp_to_datetime
|
||||
from zerver.lib.timezone import canonicalize_timezone
|
||||
from zerver.lib.upload import delete_message_attachments
|
||||
from zerver.lib.user_counts import realm_user_count_by_role
|
||||
from zerver.lib.user_groups import (
|
||||
|
@ -501,6 +504,7 @@ def do_deactivate_realm(
|
|||
*,
|
||||
acting_user: Optional[UserProfile],
|
||||
deactivation_reason: RealmDeactivationReasonType,
|
||||
email_owners: bool,
|
||||
) -> None:
|
||||
"""
|
||||
Deactivate this realm. Do NOT deactivate the users -- we need to be able to
|
||||
|
@ -557,6 +561,12 @@ def do_deactivate_realm(
|
|||
# declared in zerver/lib/safe_session_cached_db.py enforces this.
|
||||
delete_realm_user_sessions(realm)
|
||||
|
||||
# Flag to send deactivated realm email to organization owners; is false
|
||||
# for realm exports and realm subdomain changes so that those actions
|
||||
# do not email active organization owners.
|
||||
if email_owners:
|
||||
do_send_realm_deactivation_email(realm, acting_user)
|
||||
|
||||
|
||||
def do_reactivate_realm(realm: Realm) -> None:
|
||||
if not realm.deactivated:
|
||||
|
@ -800,3 +810,64 @@ def do_send_realm_reactivation_email(realm: Realm, *, acting_user: Optional[User
|
|||
language=language,
|
||||
context=context,
|
||||
)
|
||||
|
||||
|
||||
def do_send_realm_deactivation_email(realm: Realm, acting_user: Optional[UserProfile]) -> None:
|
||||
shared_context: Dict[str, Any] = {
|
||||
"realm_name": realm.name,
|
||||
}
|
||||
deactivation_time = timezone_now()
|
||||
owners = set(realm.get_human_owner_users())
|
||||
anonymous_deactivation = False
|
||||
|
||||
# The realm was deactivated via the deactivate_realm management command.
|
||||
if acting_user is None:
|
||||
anonymous_deactivation = True
|
||||
|
||||
# This realm was deactivated from the support panel; we do not share the
|
||||
# deactivating user's information in this case.
|
||||
if acting_user is not None and acting_user not in owners:
|
||||
anonymous_deactivation = True
|
||||
|
||||
for owner in owners:
|
||||
owner_tz = owner.timezone
|
||||
if owner_tz == "":
|
||||
owner_tz = timezone_get_current_timezone_name()
|
||||
local_date = deactivation_time.astimezone(
|
||||
zoneinfo.ZoneInfo(canonicalize_timezone(owner_tz))
|
||||
).date()
|
||||
|
||||
if anonymous_deactivation:
|
||||
context = dict(
|
||||
acting_user=False,
|
||||
initiated_deactivation=False,
|
||||
event_date=local_date,
|
||||
**shared_context,
|
||||
)
|
||||
else:
|
||||
assert acting_user is not None
|
||||
if owner == acting_user:
|
||||
context = dict(
|
||||
acting_user=True,
|
||||
initiated_deactivation=True,
|
||||
event_date=local_date,
|
||||
**shared_context,
|
||||
)
|
||||
else:
|
||||
context = dict(
|
||||
acting_user=True,
|
||||
initiated_deactivation=False,
|
||||
deactivating_owner=acting_user.full_name,
|
||||
event_date=local_date,
|
||||
**shared_context,
|
||||
)
|
||||
|
||||
send_email(
|
||||
"zerver/emails/realm_deactivated",
|
||||
to_emails=[owner.delivery_email],
|
||||
from_name=FromAddress.security_email_from_name(language=owner.default_language),
|
||||
from_address=FromAddress.SUPPORT,
|
||||
language=owner.default_language,
|
||||
context=context,
|
||||
realm=realm,
|
||||
)
|
||||
|
|
|
@ -21,10 +21,15 @@ class Command(ZulipBaseCommand):
|
|||
help="Reason for deactivation",
|
||||
required=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--email_owners",
|
||||
action="store_true",
|
||||
help="Whether to email organization owners about realm deactivation",
|
||||
)
|
||||
self.add_realm_args(parser, required=True)
|
||||
|
||||
@override
|
||||
def handle(self, *args: Any, **options: str) -> None:
|
||||
def handle(self, *args: Any, **options: Any) -> None:
|
||||
realm = self.get_realm(options)
|
||||
deactivation_reason = options["deactivation_reason"]
|
||||
|
||||
|
@ -38,8 +43,12 @@ class Command(ZulipBaseCommand):
|
|||
print("The realm", options["realm_id"], "is already deactivated.")
|
||||
return
|
||||
|
||||
send_realm_deactivation_email = options["email_owners"]
|
||||
print("Deactivating", options["realm_id"])
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason=cast(Any, deactivation_reason)
|
||||
realm,
|
||||
acting_user=None,
|
||||
deactivation_reason=cast(Any, deactivation_reason),
|
||||
email_owners=send_realm_deactivation_email,
|
||||
)
|
||||
print("Done!")
|
||||
|
|
|
@ -203,7 +203,10 @@ class Command(ZulipBaseCommand):
|
|||
if options["deactivate_realm"]:
|
||||
print(f"\033[94mDeactivating realm\033[0m: {realm.string_id}")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="self_hosting_migration"
|
||||
realm,
|
||||
acting_user=None,
|
||||
deactivation_reason="self_hosting_migration",
|
||||
email_owners=False,
|
||||
)
|
||||
|
||||
def percent_callback(bytes_transferred: Any) -> None:
|
||||
|
|
|
@ -420,7 +420,9 @@ class TestRealmAuditLog(ZulipTestCase):
|
|||
def test_realm_activation(self) -> None:
|
||||
realm = get_realm("zulip")
|
||||
user = self.example_user("desdemona")
|
||||
do_deactivate_realm(realm, acting_user=user, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=user, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
log_entry = RealmAuditLog.objects.get(
|
||||
realm=realm, event_type=RealmAuditLog.REALM_DEACTIVATED, acting_user=user
|
||||
)
|
||||
|
|
|
@ -215,7 +215,10 @@ class AuthBackendTest(ZulipTestCase):
|
|||
|
||||
# Verify auth fails with a deactivated realm
|
||||
do_deactivate_realm(
|
||||
user_profile.realm, acting_user=None, deactivation_reason="owner_request"
|
||||
user_profile.realm,
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
result = backend.authenticate(**good_kwargs)
|
||||
|
||||
|
@ -4992,7 +4995,10 @@ class FetchAPIKeyTest(ZulipTestCase):
|
|||
|
||||
def test_deactivated_realm(self) -> None:
|
||||
do_deactivate_realm(
|
||||
self.user_profile.realm, acting_user=None, deactivation_reason="owner_request"
|
||||
self.user_profile.realm,
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
result = self.client_post(
|
||||
"/api/v1/fetch_api_key",
|
||||
|
@ -5056,7 +5062,10 @@ class DevFetchAPIKeyTest(ZulipTestCase):
|
|||
|
||||
def test_deactivated_realm(self) -> None:
|
||||
do_deactivate_realm(
|
||||
self.user_profile.realm, acting_user=None, deactivation_reason="owner_request"
|
||||
self.user_profile.realm,
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
result = self.client_post("/api/v1/dev_fetch_api_key", dict(username=self.email))
|
||||
self.assert_json_error_contains(result, "This organization has been deactivated", 401)
|
||||
|
@ -6350,7 +6359,10 @@ class TestLDAP(ZulipLDAPTestCase):
|
|||
backend = self.backend
|
||||
email = "nonexisting@zulip.com"
|
||||
do_deactivate_realm(
|
||||
backend._realm, acting_user=None, deactivation_reason="owner_request"
|
||||
backend._realm,
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
with self.assertRaisesRegex(Exception, "Realm has been deactivated"):
|
||||
backend.get_or_build_user(email, _LDAPUser())
|
||||
|
@ -7473,7 +7485,10 @@ class JWTFetchAPIKeyTest(ZulipTestCase):
|
|||
def test_inactive_realm_failure(self) -> None:
|
||||
payload = {"email": self.email}
|
||||
do_deactivate_realm(
|
||||
self.user_profile.realm, acting_user=None, deactivation_reason="owner_request"
|
||||
self.user_profile.realm,
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
with self.settings(JWT_AUTH_KEYS={"zulip": {"key": "key1", "algorithms": ["HS256"]}}):
|
||||
key = settings.JWT_AUTH_KEYS["zulip"]["key"]
|
||||
|
|
|
@ -583,7 +583,10 @@ class DeactivatedRealmTest(ZulipTestCase):
|
|||
"""
|
||||
realm = get_realm("zulip")
|
||||
do_deactivate_realm(
|
||||
get_realm("zulip"), acting_user=None, deactivation_reason="owner_request"
|
||||
get_realm("zulip"),
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
|
||||
result = self.client_post(
|
||||
|
@ -652,7 +655,10 @@ class DeactivatedRealmTest(ZulipTestCase):
|
|||
|
||||
"""
|
||||
do_deactivate_realm(
|
||||
get_realm("zulip"), acting_user=None, deactivation_reason="owner_request"
|
||||
get_realm("zulip"),
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
user_profile = self.example_user("hamlet")
|
||||
api_key = get_api_key(user_profile)
|
||||
|
|
|
@ -161,7 +161,10 @@ class EmailChangeTestCase(ZulipTestCase):
|
|||
activation_url = self.generate_email_change_link(new_email)
|
||||
|
||||
do_deactivate_realm(
|
||||
user_profile.realm, acting_user=None, deactivation_reason="owner_request"
|
||||
user_profile.realm,
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
|
||||
response = self.client_get(activation_url)
|
||||
|
|
|
@ -1283,7 +1283,10 @@ class TestMissedMessageEmailMessages(ZulipTestCase):
|
|||
mm_address = create_missed_message_address(user_profile, message)
|
||||
|
||||
do_deactivate_realm(
|
||||
user_profile.realm, acting_user=None, deactivation_reason="owner_request"
|
||||
user_profile.realm,
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
|
||||
incoming_valid_message = EmailMessage()
|
||||
|
|
|
@ -3007,7 +3007,9 @@ class NormalActionsTest(BaseAction):
|
|||
# correct because were one to somehow compute page_params (as
|
||||
# this test does), but that's not actually possible.
|
||||
with self.verify_action(state_change_expected=False) as events:
|
||||
do_deactivate_realm(realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
check_realm_deactivated("events[0]", events[0])
|
||||
|
||||
def test_do_mark_onboarding_step_as_read(self) -> None:
|
||||
|
|
|
@ -1670,7 +1670,9 @@ class AnalyticsBouncerTest(BouncerTestCase):
|
|||
do_set_realm_authentication_methods(zephyr_realm, new_auth_method_dict, acting_user=user)
|
||||
|
||||
# Deactivation is synced.
|
||||
do_deactivate_realm(zephyr_realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
zephyr_realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
|
||||
send_server_data_to_push_bouncer()
|
||||
check_counts(5, 5, 1, 1, 7)
|
||||
|
|
|
@ -9,6 +9,7 @@ from unittest import mock, skipUnless
|
|||
|
||||
import orjson
|
||||
from django.conf import settings
|
||||
from django.core import mail
|
||||
from django.test import override_settings
|
||||
from django.utils.timezone import now as timezone_now
|
||||
from typing_extensions import override
|
||||
|
@ -314,7 +315,9 @@ class RealmTest(ZulipTestCase):
|
|||
hamlet_id = self.example_user("hamlet").id
|
||||
get_user_profile_by_id(hamlet_id)
|
||||
realm = get_realm("zulip")
|
||||
do_deactivate_realm(realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
user = get_user_profile_by_id(hamlet_id)
|
||||
self.assertTrue(user.realm.deactivated)
|
||||
|
||||
|
@ -361,7 +364,9 @@ class RealmTest(ZulipTestCase):
|
|||
delay=timedelta(hours=1),
|
||||
)
|
||||
self.assertEqual(ScheduledEmail.objects.count(), 1)
|
||||
do_deactivate_realm(user.realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
user.realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
self.assertEqual(ScheduledEmail.objects.count(), 0)
|
||||
|
||||
def test_do_change_realm_description_clears_cached_descriptions(self) -> None:
|
||||
|
@ -385,10 +390,14 @@ class RealmTest(ZulipTestCase):
|
|||
realm = get_realm("zulip")
|
||||
self.assertFalse(realm.deactivated)
|
||||
|
||||
do_deactivate_realm(realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
self.assertTrue(realm.deactivated)
|
||||
|
||||
do_deactivate_realm(realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
self.assertTrue(realm.deactivated)
|
||||
|
||||
def test_do_set_deactivated_redirect_on_deactivated_realm(self) -> None:
|
||||
|
@ -396,7 +405,9 @@ class RealmTest(ZulipTestCase):
|
|||
realm = get_realm("zulip")
|
||||
|
||||
redirect_url = "new_server.zulip.com"
|
||||
do_deactivate_realm(realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
self.assertTrue(realm.deactivated)
|
||||
do_add_deactivated_redirect(realm, redirect_url)
|
||||
self.assertEqual(realm.deactivated_redirect, redirect_url)
|
||||
|
@ -408,7 +419,9 @@ class RealmTest(ZulipTestCase):
|
|||
|
||||
def test_do_reactivate_realm(self) -> None:
|
||||
realm = get_realm("zulip")
|
||||
do_deactivate_realm(realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
self.assertTrue(realm.deactivated)
|
||||
|
||||
do_reactivate_realm(realm)
|
||||
|
@ -438,7 +451,9 @@ class RealmTest(ZulipTestCase):
|
|||
|
||||
def test_realm_reactivation_link(self) -> None:
|
||||
realm = get_realm("zulip")
|
||||
do_deactivate_realm(realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
self.assertTrue(realm.deactivated)
|
||||
|
||||
obj = RealmReactivationStatus.objects.create(realm=realm)
|
||||
|
@ -451,13 +466,17 @@ class RealmTest(ZulipTestCase):
|
|||
self.assertFalse(realm.deactivated)
|
||||
|
||||
# Make sure the link can't be reused.
|
||||
do_deactivate_realm(realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
response = self.client_get(confirmation_url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_realm_reactivation_confirmation_object(self) -> None:
|
||||
realm = get_realm("zulip")
|
||||
do_deactivate_realm(realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
self.assertTrue(realm.deactivated)
|
||||
obj = RealmReactivationStatus.objects.create(realm=realm)
|
||||
create_confirmation_link(obj, Confirmation.REALM_REACTIVATION)
|
||||
|
@ -466,22 +485,80 @@ class RealmTest(ZulipTestCase):
|
|||
self.assertEqual(confirmation.content_object, obj)
|
||||
self.assertEqual(confirmation.realm, realm)
|
||||
|
||||
def test_do_send_realm_deactivation_email_no_acting_user(self) -> None:
|
||||
realm = get_realm("zulip")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="owner_request", email_owners=True
|
||||
)
|
||||
self.assertEqual(realm.deactivated, True)
|
||||
self.assert_length(mail.outbox, 1)
|
||||
self.assertIn(
|
||||
"Your Zulip organization Zulip Dev has been deactivated", mail.outbox[0].subject
|
||||
)
|
||||
self.assertIn("Your Zulip organization, Zulip Dev, was deactivated on", mail.outbox[0].body)
|
||||
|
||||
def test_do_send_realm_deactivation_email_by_support(self) -> None:
|
||||
realm = get_realm("lear")
|
||||
king = self.lear_user("king")
|
||||
king.role = UserProfile.ROLE_REALM_OWNER
|
||||
king.save()
|
||||
iago = self.example_user("iago")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=iago, deactivation_reason="owner_request", email_owners=True
|
||||
)
|
||||
self.assertEqual(realm.deactivated, True)
|
||||
self.assert_length(mail.outbox, 1)
|
||||
self.assertIn(
|
||||
"Your Zulip organization Lear & Co. has been deactivated", mail.outbox[0].subject
|
||||
)
|
||||
self.assertIn(
|
||||
"Your Zulip organization, Lear & Co., was deactivated on",
|
||||
mail.outbox[0].body,
|
||||
)
|
||||
|
||||
def test_do_send_realm_deactivation_email_by_owner(self) -> None:
|
||||
realm = get_realm("zulip")
|
||||
iago = self.example_user("iago")
|
||||
iago.role = UserProfile.ROLE_REALM_OWNER
|
||||
iago.save(update_fields=["role"])
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=iago, deactivation_reason="owner_request", email_owners=True
|
||||
)
|
||||
self.assertEqual(realm.deactivated, True)
|
||||
self.assert_length(mail.outbox, 2)
|
||||
for email in mail.outbox:
|
||||
if email.to[0] == "iago@zulip.com":
|
||||
self.assertIn(
|
||||
"Your Zulip organization Zulip Dev has been deactivated", email.subject
|
||||
)
|
||||
self.assertIn(
|
||||
"You have deactivated your Zulip organization, Zulip Dev, on", email.body
|
||||
)
|
||||
else:
|
||||
self.assertIn(
|
||||
"Your Zulip organization Zulip Dev has been deactivated", email.subject
|
||||
)
|
||||
self.assertIn(
|
||||
"Your Zulip organization, Zulip Dev, was deactivated by Iago on", email.body
|
||||
)
|
||||
|
||||
def test_do_send_realm_reactivation_email(self) -> None:
|
||||
realm = get_realm("zulip")
|
||||
do_deactivate_realm(realm, acting_user=None, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=None, deactivation_reason="owner_request", email_owners=False
|
||||
)
|
||||
self.assertEqual(realm.deactivated, True)
|
||||
iago = self.example_user("iago")
|
||||
do_send_realm_reactivation_email(realm, acting_user=iago)
|
||||
from django.core.mail import outbox
|
||||
|
||||
self.assert_length(outbox, 1)
|
||||
self.assertEqual(self.email_envelope_from(outbox[0]), settings.NOREPLY_EMAIL_ADDRESS)
|
||||
self.assert_length(mail.outbox, 1)
|
||||
self.assertEqual(self.email_envelope_from(mail.outbox[0]), settings.NOREPLY_EMAIL_ADDRESS)
|
||||
self.assertRegex(
|
||||
self.email_display_from(outbox[0]),
|
||||
self.email_display_from(mail.outbox[0]),
|
||||
rf"^testserver account security <{self.TOKENIZED_NOREPLY_REGEX}>\Z",
|
||||
)
|
||||
self.assertIn("Reactivate your Zulip organization", outbox[0].subject)
|
||||
self.assertIn("Dear former administrators", outbox[0].body)
|
||||
self.assertIn("Reactivate your Zulip organization", mail.outbox[0].subject)
|
||||
self.assertIn("Dear former administrators", mail.outbox[0].body)
|
||||
admins = realm.get_human_admin_users()
|
||||
confirmation_url = self.get_confirmation_url_from_outbox(admins[0].delivery_email)
|
||||
response = self.client_get(confirmation_url)
|
||||
|
|
|
@ -557,7 +557,10 @@ class PasswordResetTest(ZulipTestCase):
|
|||
user_profile = self.example_user("hamlet")
|
||||
email = user_profile.delivery_email
|
||||
do_deactivate_realm(
|
||||
user_profile.realm, acting_user=None, deactivation_reason="owner_request"
|
||||
user_profile.realm,
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
|
||||
# start the password reset process by supplying an email address
|
||||
|
@ -4353,7 +4356,10 @@ class TestFindMyTeam(ZulipTestCase):
|
|||
|
||||
def test_find_team_deactivated_realm(self) -> None:
|
||||
do_deactivate_realm(
|
||||
get_realm("zulip"), acting_user=None, deactivation_reason="owner_request"
|
||||
get_realm("zulip"),
|
||||
acting_user=None,
|
||||
deactivation_reason="owner_request",
|
||||
email_owners=False,
|
||||
)
|
||||
data = {"emails": self.example_email("hamlet")}
|
||||
result = self.client_post("/accounts/find/", data)
|
||||
|
|
|
@ -494,7 +494,9 @@ def update_realm(
|
|||
@has_request_variables
|
||||
def deactivate_realm(request: HttpRequest, user: UserProfile) -> HttpResponse:
|
||||
realm = user.realm
|
||||
do_deactivate_realm(realm, acting_user=user, deactivation_reason="owner_request")
|
||||
do_deactivate_realm(
|
||||
realm, acting_user=user, deactivation_reason="owner_request", email_owners=True
|
||||
)
|
||||
return json_success(request)
|
||||
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ from django.contrib.staticfiles.storage import staticfiles_storage
|
|||
from django.template.defaultfilters import pluralize, slugify
|
||||
from django.urls import reverse
|
||||
from django.utils import translation
|
||||
from django.utils.formats import localize
|
||||
from django.utils.timesince import timesince
|
||||
from jinja2 import Environment
|
||||
from two_factor.plugins.phonenumber.templatetags.phonenumber import device_action
|
||||
|
@ -39,6 +40,7 @@ def environment(**options: Any) -> Environment:
|
|||
env.filters["display_list"] = display_list
|
||||
env.filters["device_action"] = device_action
|
||||
env.filters["timesince"] = timesince
|
||||
env.filters["localize"] = localize
|
||||
|
||||
env.policies["json.dumps_function"] = json_dumps
|
||||
env.policies["json.dumps_kwargs"] = {}
|
||||
|
|
Loading…
Reference in New Issue