mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 22:13:26 +00:00
demo-orgs: Delete expired demo orgs in archive_messages cron job.
Adds delete_expired_demo_organizations to the archive_messages management command, which is run as a cron job. Adds "demo_expired" as a `RealmDeactivationReasonType` to be used for this specific case of calling do_deactivate_realm. The function loops through non-deactivated realms that have a demo organization scheduled deletion datetime set that is less than the current datetime.
This commit is contained in:
committed by
Tim Abbott
parent
0fa5b158df
commit
c797c481b3
@@ -16,6 +16,7 @@ from zerver.actions.custom_profile_fields import do_remove_realm_custom_profile_
|
|||||||
from zerver.actions.message_delete import do_delete_messages_by_sender
|
from zerver.actions.message_delete import do_delete_messages_by_sender
|
||||||
from zerver.actions.user_groups import update_users_in_full_members_system_group
|
from zerver.actions.user_groups import update_users_in_full_members_system_group
|
||||||
from zerver.actions.user_settings import do_delete_avatar_image
|
from zerver.actions.user_settings import do_delete_avatar_image
|
||||||
|
from zerver.lib.demo_organizations import demo_organization_owner_email_exists
|
||||||
from zerver.lib.exceptions import JsonableError
|
from zerver.lib.exceptions import JsonableError
|
||||||
from zerver.lib.message import parse_message_time_limit_setting, update_first_visible_message_id
|
from zerver.lib.message import parse_message_time_limit_setting, update_first_visible_message_id
|
||||||
from zerver.lib.queue import queue_json_publish_rollback_unsafe
|
from zerver.lib.queue import queue_json_publish_rollback_unsafe
|
||||||
@@ -533,6 +534,7 @@ RealmDeactivationReasonType = Literal[
|
|||||||
"tos_violation",
|
"tos_violation",
|
||||||
"inactivity",
|
"inactivity",
|
||||||
"self_hosting_migration",
|
"self_hosting_migration",
|
||||||
|
"demo_expired",
|
||||||
# When we change the subdomain of a realm, we leave
|
# When we change the subdomain of a realm, we leave
|
||||||
# behind a deactivated gravestone realm.
|
# behind a deactivated gravestone realm.
|
||||||
"subdomain_change",
|
"subdomain_change",
|
||||||
@@ -625,6 +627,26 @@ def do_deactivate_realm(
|
|||||||
do_send_realm_deactivation_email(realm, acting_user, deletion_delay_days)
|
do_send_realm_deactivation_email(realm, acting_user, deletion_delay_days)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_expired_demo_organizations() -> None:
|
||||||
|
demo_organizations_to_delete = Realm.objects.filter(
|
||||||
|
deactivated=False, demo_organization_scheduled_deletion_date__lte=timezone_now()
|
||||||
|
)
|
||||||
|
for demo_organization in demo_organizations_to_delete:
|
||||||
|
email_owners = False
|
||||||
|
if demo_organization_owner_email_exists(demo_organization):
|
||||||
|
email_owners = True
|
||||||
|
# By setting deletion_delay_days to zero, we send an event to
|
||||||
|
# the deferred work queue to scrub the realm data when
|
||||||
|
# deactivating the realm.
|
||||||
|
do_deactivate_realm(
|
||||||
|
realm=demo_organization,
|
||||||
|
acting_user=None,
|
||||||
|
deactivation_reason="demo_expired",
|
||||||
|
deletion_delay_days=0,
|
||||||
|
email_owners=email_owners,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def do_reactivate_realm(realm: Realm) -> None:
|
def do_reactivate_realm(realm: Realm) -> None:
|
||||||
if not realm.deactivated:
|
if not realm.deactivated:
|
||||||
logging.warning("Realm %s cannot be reactivated because it is already active.", realm.id)
|
logging.warning("Realm %s cannot be reactivated because it is already active.", realm.id)
|
||||||
|
|||||||
@@ -4,10 +4,14 @@ from zerver.lib.exceptions import JsonableError
|
|||||||
from zerver.models.realms import Realm
|
from zerver.models.realms import Realm
|
||||||
|
|
||||||
|
|
||||||
|
def demo_organization_owner_email_exists(realm: Realm) -> bool:
|
||||||
|
human_owner_emails = set(realm.get_human_owner_users().values_list("delivery_email", flat=True))
|
||||||
|
return human_owner_emails != {""}
|
||||||
|
|
||||||
|
|
||||||
def check_demo_organization_has_set_email(realm: Realm) -> None:
|
def check_demo_organization_has_set_email(realm: Realm) -> None:
|
||||||
# This should be called after checking that the realm has
|
# This should be called after checking that the realm has
|
||||||
# a demo_organization_scheduled_deletion_date set.
|
# a demo_organization_scheduled_deletion_date set.
|
||||||
assert realm.demo_organization_scheduled_deletion_date is not None
|
assert realm.demo_organization_scheduled_deletion_date is not None
|
||||||
human_owner_emails = set(realm.get_human_owner_users().values_list("delivery_email", flat=True))
|
if not demo_organization_owner_email_exists(realm):
|
||||||
if "" in human_owner_emails:
|
|
||||||
raise JsonableError(_("Configure owner account email address."))
|
raise JsonableError(_("Configure owner account email address."))
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ from typing import Any
|
|||||||
|
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
from zerver.actions.realm_settings import clean_deactivated_realm_data
|
from zerver.actions.realm_settings import (
|
||||||
|
clean_deactivated_realm_data,
|
||||||
|
delete_expired_demo_organizations,
|
||||||
|
)
|
||||||
from zerver.lib.management import ZulipBaseCommand, abort_unless_locked
|
from zerver.lib.management import ZulipBaseCommand, abort_unless_locked
|
||||||
from zerver.lib.retention import archive_messages, clean_archived_data
|
from zerver.lib.retention import archive_messages, clean_archived_data
|
||||||
|
|
||||||
@@ -13,4 +16,12 @@ class Command(ZulipBaseCommand):
|
|||||||
def handle(self, *args: Any, **options: str) -> None:
|
def handle(self, *args: Any, **options: str) -> None:
|
||||||
clean_archived_data()
|
clean_archived_data()
|
||||||
archive_messages()
|
archive_messages()
|
||||||
|
scrub_realms()
|
||||||
|
|
||||||
|
|
||||||
|
def scrub_realms() -> None:
|
||||||
|
# First, scrub currently deactivated realms that have an expired
|
||||||
|
# scheduled deletion date. Then, deactivate and scrub realms with
|
||||||
|
# an expired scheduled demo organization deletion date.
|
||||||
clean_deactivated_realm_data()
|
clean_deactivated_realm_data()
|
||||||
|
delete_expired_demo_organizations()
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ from zerver.actions.message_send import (
|
|||||||
)
|
)
|
||||||
from zerver.actions.realm_settings import (
|
from zerver.actions.realm_settings import (
|
||||||
clean_deactivated_realm_data,
|
clean_deactivated_realm_data,
|
||||||
|
delete_expired_demo_organizations,
|
||||||
do_add_deactivated_redirect,
|
do_add_deactivated_redirect,
|
||||||
do_change_realm_max_invites,
|
do_change_realm_max_invites,
|
||||||
do_change_realm_org_type,
|
do_change_realm_org_type,
|
||||||
@@ -1225,6 +1226,64 @@ class RealmTest(ZulipTestCase):
|
|||||||
clean_deactivated_realm_data()
|
clean_deactivated_realm_data()
|
||||||
mock_scrub_realm.assert_called_once_with(zephyr, acting_user=None)
|
mock_scrub_realm.assert_called_once_with(zephyr, acting_user=None)
|
||||||
|
|
||||||
|
def test_delete_expired_demo_organizations(self) -> None:
|
||||||
|
zulip = get_realm("zulip")
|
||||||
|
assert not zulip.deactivated
|
||||||
|
assert zulip.demo_organization_scheduled_deletion_date is None
|
||||||
|
|
||||||
|
with mock.patch(
|
||||||
|
"zerver.actions.realm_settings.do_deactivate_realm"
|
||||||
|
) as mock_deactivate_realm:
|
||||||
|
delete_expired_demo_organizations()
|
||||||
|
mock_deactivate_realm.assert_not_called()
|
||||||
|
|
||||||
|
# Add scheduled demo organization deletion date
|
||||||
|
zulip.demo_organization_scheduled_deletion_date = timezone_now() + timedelta(days=4)
|
||||||
|
zulip.save()
|
||||||
|
|
||||||
|
# Before deletion date
|
||||||
|
with mock.patch(
|
||||||
|
"zerver.actions.realm_settings.do_deactivate_realm"
|
||||||
|
) as mock_deactivate_realm:
|
||||||
|
delete_expired_demo_organizations()
|
||||||
|
mock_deactivate_realm.assert_not_called()
|
||||||
|
|
||||||
|
# After deletion date, when owner email is set.
|
||||||
|
with (
|
||||||
|
time_machine.travel(timezone_now() + timedelta(days=5), tick=False),
|
||||||
|
mock.patch(
|
||||||
|
"zerver.actions.realm_settings.do_deactivate_realm"
|
||||||
|
) as mock_deactivate_realm,
|
||||||
|
):
|
||||||
|
delete_expired_demo_organizations()
|
||||||
|
mock_deactivate_realm.assert_called_once_with(
|
||||||
|
realm=zulip,
|
||||||
|
acting_user=None,
|
||||||
|
deactivation_reason="demo_expired",
|
||||||
|
deletion_delay_days=0,
|
||||||
|
email_owners=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# After deletion date, when owner email is not set.
|
||||||
|
desdemona = self.example_user("desdemona")
|
||||||
|
desdemona.delivery_email = ""
|
||||||
|
desdemona.save()
|
||||||
|
|
||||||
|
with (
|
||||||
|
time_machine.travel(timezone_now() + timedelta(days=5), tick=False),
|
||||||
|
mock.patch(
|
||||||
|
"zerver.actions.realm_settings.do_deactivate_realm"
|
||||||
|
) as mock_deactivate_realm,
|
||||||
|
):
|
||||||
|
delete_expired_demo_organizations()
|
||||||
|
mock_deactivate_realm.assert_called_once_with(
|
||||||
|
realm=zulip,
|
||||||
|
acting_user=None,
|
||||||
|
deactivation_reason="demo_expired",
|
||||||
|
deletion_delay_days=0,
|
||||||
|
email_owners=False,
|
||||||
|
)
|
||||||
|
|
||||||
def test_initial_plan_type(self) -> None:
|
def test_initial_plan_type(self) -> None:
|
||||||
with self.settings(BILLING_ENABLED=True):
|
with self.settings(BILLING_ENABLED=True):
|
||||||
self.assertEqual(do_create_realm("hosted", "hosted").plan_type, Realm.PLAN_TYPE_LIMITED)
|
self.assertEqual(do_create_realm("hosted", "hosted").plan_type, Realm.PLAN_TYPE_LIMITED)
|
||||||
|
|||||||
Reference in New Issue
Block a user