1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-23 23:09:37 +02:00
AdventureLog/backend/server/adventures/management/commands/image_cleanup.py
Sean Morley c461f7b105
Import and Export Functionality (#698)
* feat(backup): add BackupViewSet for data export and import functionality

* Fixed frontend returning corrupt binary data

* feat(import): enhance import functionality with confirmation check and improved city/region/country handling

* Potential fix for code scanning alert no. 29: Information exposure through an exception

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Refactor response handling to use arrayBuffer instead of bytes

* Refactor image cleanup command to use LocationImage model and update import/export view to include backup and restore functionality

* Update backup export versioning and improve data restore warning message

* Enhance image navigation and localization support in modal components

* Refactor location handling in Immich integration components for consistency

* Enhance backup and restore functionality with improved localization and error handling

* Improve accessibility by adding 'for' attribute to backup file input label

---------

Co-authored-by: Christian Zäske <blitzdose@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-06-26 10:23:37 -04:00

94 lines
3.1 KiB
Python

import os
from django.core.management.base import BaseCommand
from django.conf import settings
from adventures.models import LocationImage, Attachment
from users.models import CustomUser
class Command(BaseCommand):
help = 'Find and prompt for deletion of unused image files and attachments in filesystem'
def add_arguments(self, parser):
parser.add_argument(
'--dry-run',
action='store_true',
help='Show files that would be deleted without actually deleting them',
)
def handle(self, **options):
dry_run = options['dry_run']
# Get all image and attachment file paths from database
used_files = set()
# Get LocationImage file paths
for img in LocationImage.objects.all():
if img.image and img.image.name:
used_files.add(os.path.join(settings.MEDIA_ROOT, img.image.name))
# Get Attachment file paths
for attachment in Attachment.objects.all():
if attachment.file and attachment.file.name:
used_files.add(os.path.join(settings.MEDIA_ROOT, attachment.file.name))
# Get user profile picture file paths
for user in CustomUser.objects.all():
if user.profile_pic and user.profile_pic.name:
used_files.add(os.path.join(settings.MEDIA_ROOT, user.profile_pic.name))
# Find all files in media/images and media/attachments directories
media_root = settings.MEDIA_ROOT
all_files = []
# Scan images directory
images_dir = os.path.join(media_root, 'images')
# Scan attachments directory
attachments_dir = os.path.join(media_root, 'attachments')
if os.path.exists(attachments_dir):
for root, _, files in os.walk(attachments_dir):
for file in files:
all_files.append(os.path.join(root, file))
# Scan profile-pics directory
profile_pics_dir = os.path.join(media_root, 'profile-pics')
if os.path.exists(profile_pics_dir):
for root, _, files in os.walk(profile_pics_dir):
for file in files:
all_files.append(os.path.join(root, file))
attachments_dir = os.path.join(media_root, 'attachments')
if os.path.exists(attachments_dir):
for root, _, files in os.walk(attachments_dir):
for file in files:
all_files.append(os.path.join(root, file))
# Find unused files
unused_files = [f for f in all_files if f not in used_files]
if not unused_files:
self.stdout.write(self.style.SUCCESS('No unused files found.'))
return
self.stdout.write(f'Found {len(unused_files)} unused files:')
for file_path in unused_files:
self.stdout.write(f' {file_path}')
if dry_run:
self.stdout.write(self.style.WARNING('Dry run mode - no files were deleted.'))
return
# Prompt for deletion
confirm = input('\nDo you want to delete these files? (yes/no): ')
if confirm.lower() in ['yes', 'y']:
deleted_count = 0
for file_path in unused_files:
try:
os.remove(file_path)
self.stdout.write(f'Deleted: {file_path}')
deleted_count += 1
except OSError as e:
self.stdout.write(self.style.ERROR(f'Error deleting {file_path}: {e}'))
self.stdout.write(self.style.SUCCESS(f'Successfully deleted {deleted_count} files.'))
else:
self.stdout.write('Operation cancelled.')