diff --git a/zerver/management/commands/delete_realm.py b/zerver/management/commands/delete_realm.py new file mode 100644 index 0000000000..edc49e7e70 --- /dev/null +++ b/zerver/management/commands/delete_realm.py @@ -0,0 +1,49 @@ +import os +import subprocess +from argparse import ArgumentParser +from typing import Any + +from django.conf import settings +from django.core.management.base import CommandError + +from zerver.lib.management import ZulipBaseCommand +from zerver.models import Message, UserProfile + + +class Command(ZulipBaseCommand): + help = """Script to permanently delete a realm. Recommended only for removing +realms used for testing; consider using deactivate_realm instead.""" + + def add_arguments(self, parser: ArgumentParser) -> None: + self.add_realm_args(parser, True) + + def handle(self, *args: Any, **options: str) -> None: + realm = self.get_realm(options) + assert realm is not None # Should be ensured by parser + + user_count = UserProfile.objects.filter( + realm_id=realm.id, + is_active=True, + is_bot=False, + ).count() + + message_count = Message.objects.filter( + sender__realm=realm + ).count() + + print(f"This realm has {user_count} users and {message_count} messages.\n") + + print("This command will \033[91mPERMANENTLY DELETE\033[0m all data for this realm. " + "Most use cases will be better served by scrub_realm and/or deactivate_realm.") + + confirmation = input("Type the name of the realm to confirm: ") + if confirmation != realm.string_id: + raise CommandError("Aborting!") + + # TODO: This approach leaks Recipient and Huddle objects, + # because those don't have a foreign key to the Realm or any + # other model it cascades to (Realm/Stream/UserProfile/etc.). + realm.delete() + subprocess.check_call([os.path.join(settings.DEPLOY_ROOT, "scripts", "setup", "flush-memcached")]) + + print("Realm has been successfully permanently deleted.")