mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 02:31:08 -05:00
165 lines
6.0 KiB
Python
165 lines
6.0 KiB
Python
"""
|
|
Django management command to delete a user while preserving their submissions.
|
|
|
|
Usage:
|
|
uv run manage.py delete_user <username>
|
|
uv run manage.py delete_user --user-id <user_id>
|
|
uv run manage.py delete_user <username> --dry-run
|
|
"""
|
|
|
|
from django.core.management.base import BaseCommand, CommandError
|
|
from apps.accounts.models import User
|
|
from apps.accounts.services import UserDeletionService
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = "Delete a user while preserving all their submissions"
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
"username", nargs="?", type=str, help="Username of the user to delete"
|
|
)
|
|
parser.add_argument(
|
|
"--user-id",
|
|
type=str,
|
|
help="User ID of the user to delete (alternative to username)",
|
|
)
|
|
parser.add_argument(
|
|
"--dry-run",
|
|
action="store_true",
|
|
help="Show what would be deleted without actually deleting",
|
|
)
|
|
parser.add_argument(
|
|
"--force", action="store_true", help="Skip confirmation prompt"
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
username = options.get("username")
|
|
user_id = options.get("user_id")
|
|
dry_run = options.get("dry_run", False)
|
|
force = options.get("force", False)
|
|
|
|
# Validate arguments
|
|
if not username and not user_id:
|
|
raise CommandError("You must provide either a username or --user-id")
|
|
|
|
if username and user_id:
|
|
raise CommandError("You cannot provide both username and --user-id")
|
|
|
|
# Find the user
|
|
try:
|
|
if username:
|
|
user = User.objects.get(username=username)
|
|
else:
|
|
user = User.objects.get(user_id=user_id)
|
|
except User.DoesNotExist:
|
|
identifier = username or user_id
|
|
raise CommandError(f'User "{identifier}" does not exist')
|
|
|
|
# Check if user can be deleted
|
|
can_delete, reason = UserDeletionService.can_delete_user(user)
|
|
if not can_delete:
|
|
raise CommandError(f"Cannot delete user: {reason}")
|
|
|
|
# Count submissions
|
|
submission_counts = {
|
|
"park_reviews": getattr(
|
|
user, "park_reviews", user.__class__.objects.none()
|
|
).count(),
|
|
"ride_reviews": getattr(
|
|
user, "ride_reviews", user.__class__.objects.none()
|
|
).count(),
|
|
"uploaded_park_photos": getattr(
|
|
user, "uploaded_park_photos", user.__class__.objects.none()
|
|
).count(),
|
|
"uploaded_ride_photos": getattr(
|
|
user, "uploaded_ride_photos", user.__class__.objects.none()
|
|
).count(),
|
|
"top_lists": getattr(
|
|
user, "top_lists", user.__class__.objects.none()
|
|
).count(),
|
|
"edit_submissions": getattr(
|
|
user, "edit_submissions", user.__class__.objects.none()
|
|
).count(),
|
|
"photo_submissions": getattr(
|
|
user, "photo_submissions", user.__class__.objects.none()
|
|
).count(),
|
|
}
|
|
|
|
total_submissions = sum(submission_counts.values())
|
|
|
|
# Display user information
|
|
self.stdout.write(self.style.WARNING("\nUser Information:"))
|
|
self.stdout.write(f" Username: {user.username}")
|
|
self.stdout.write(f" User ID: {user.user_id}")
|
|
self.stdout.write(f" Email: {user.email}")
|
|
self.stdout.write(f" Date Joined: {user.date_joined}")
|
|
self.stdout.write(f" Role: {user.role}")
|
|
|
|
# Display submission counts
|
|
self.stdout.write(self.style.WARNING("\nSubmissions to preserve:"))
|
|
for submission_type, count in submission_counts.items():
|
|
if count > 0:
|
|
self.stdout.write(
|
|
f' {submission_type.replace("_", " ").title()}: {count}'
|
|
)
|
|
|
|
self.stdout.write(f"\nTotal submissions: {total_submissions}")
|
|
|
|
if total_submissions > 0:
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f'\nAll {total_submissions} submissions will be transferred to the "deleted_user" placeholder.'
|
|
)
|
|
)
|
|
else:
|
|
self.stdout.write(
|
|
self.style.WARNING("\nNo submissions found for this user.")
|
|
)
|
|
|
|
if dry_run:
|
|
self.stdout.write(self.style.SUCCESS("\n[DRY RUN] No changes were made."))
|
|
return
|
|
|
|
# Confirmation prompt
|
|
if not force:
|
|
self.stdout.write(
|
|
self.style.WARNING(
|
|
f'\nThis will permanently delete the user "{user.username}" '
|
|
f"but preserve all {total_submissions} submissions."
|
|
)
|
|
)
|
|
confirm = input("Are you sure you want to continue? (yes/no): ")
|
|
if confirm.lower() not in ["yes", "y"]:
|
|
self.stdout.write(self.style.ERROR("Operation cancelled."))
|
|
return
|
|
|
|
# Perform the deletion
|
|
try:
|
|
result = UserDeletionService.delete_user_preserve_submissions(user)
|
|
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f'\nSuccessfully deleted user "{result["deleted_user"]["username"]}"'
|
|
)
|
|
)
|
|
|
|
preserved_count = sum(result["preserved_submissions"].values())
|
|
if preserved_count > 0:
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f'Preserved {preserved_count} submissions under user "{result["transferred_to"]["username"]}"'
|
|
)
|
|
)
|
|
|
|
# Show detailed preservation summary
|
|
self.stdout.write(self.style.WARNING("\nPreservation Summary:"))
|
|
for submission_type, count in result["preserved_submissions"].items():
|
|
if count > 0:
|
|
self.stdout.write(
|
|
f' {submission_type.replace("_", " ").title()}: {count}'
|
|
)
|
|
|
|
except Exception as e:
|
|
raise CommandError(f"Error deleting user: {str(e)}")
|