mirror of
https://github.com/thecyberlearn/quantum-ai-v3.git
synced 2026-08-18 20:32:56 +00:00
BREAKING CHANGES: - Move marketplace and agent discovery views from core to agent_base app - Transfer all wallet functionality from core to dedicated wallet app - Move Stripe webhook handling to wallet app for better organization - Consolidate payment system logic under single responsibility NEW STRUCTURE: - core app: Platform pages only (homepage, pricing) - agent_base app: Complete agent marketplace and catalog system - wallet app: Full payment system with Stripe integration - Individual agent apps: Unchanged, self-contained IMPROVEMENTS: - Clean URL namespacing (agent_base:marketplace, wallet:wallet) - Template organization by app responsibility - Removed deprecated CSS files (header.css) - Added utility classes (.hidden) - Updated all template references to new URL structure - Comprehensive CLAUDE.md documentation updates TECHNICAL CHANGES: - Templates moved: marketplace.html, agent_detail.html → agent_base/ - Templates moved: wallet*.html → wallet/ - New files: agent_base/views.py, agent_base/urls.py, wallet/urls.py - Updated main urls.py routing configuration - Fixed Django system checks and namespace conflicts - Verified all functionality with test suite This reorganization follows Django best practices with single responsibility principle, making the codebase more maintainable and scalable. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
125 lines
4.9 KiB
Python
125 lines
4.9 KiB
Python
from django.core.management.base import BaseCommand
|
|
from django.utils import timezone
|
|
from datetime import timedelta
|
|
from data_analyzer.models import DataAnalysisAgentRequest
|
|
import os
|
|
import glob
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Clean up old uploaded files from data analyzer'
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
'--age-hours',
|
|
type=int,
|
|
default=24,
|
|
help='Delete files older than this many hours (default: 24)'
|
|
)
|
|
parser.add_argument(
|
|
'--dry-run',
|
|
action='store_true',
|
|
help='Show what would be deleted without actually deleting'
|
|
)
|
|
parser.add_argument(
|
|
'--force-orphaned',
|
|
action='store_true',
|
|
help='Also delete orphaned files not associated with database records'
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
age_hours = options['age_hours']
|
|
dry_run = options['dry_run']
|
|
force_orphaned = options['force_orphaned']
|
|
|
|
cutoff_time = timezone.now() - timedelta(hours=age_hours)
|
|
|
|
self.stdout.write(f"Looking for files older than {age_hours} hours ({cutoff_time})")
|
|
|
|
if dry_run:
|
|
self.stdout.write(self.style.WARNING("DRY RUN MODE - No files will be deleted"))
|
|
|
|
# Clean up files associated with old database records
|
|
old_requests = DataAnalysisAgentRequest.objects.filter(
|
|
created_at__lt=cutoff_time
|
|
)
|
|
|
|
deleted_count = 0
|
|
error_count = 0
|
|
|
|
for request in old_requests:
|
|
if request.data_file:
|
|
try:
|
|
file_path = request.data_file.path
|
|
if os.path.exists(file_path):
|
|
if not dry_run:
|
|
os.remove(file_path)
|
|
self.stdout.write(f"Deleted: {file_path}")
|
|
else:
|
|
self.stdout.write(f"Would delete: {file_path}")
|
|
deleted_count += 1
|
|
else:
|
|
self.stdout.write(f"File already gone: {file_path}")
|
|
except Exception as e:
|
|
self.stdout.write(
|
|
self.style.ERROR(f"Error deleting {request.data_file.path}: {e}")
|
|
)
|
|
error_count += 1
|
|
|
|
# Clean up orphaned files if requested
|
|
if force_orphaned:
|
|
self.stdout.write("Checking for orphaned files...")
|
|
|
|
try:
|
|
from django.conf import settings
|
|
upload_path = os.path.join(settings.MEDIA_ROOT, 'uploads/data_analyzer/')
|
|
|
|
if os.path.exists(upload_path):
|
|
# Get all files in upload directory
|
|
all_files = glob.glob(os.path.join(upload_path, '*'))
|
|
|
|
# Get all files currently referenced in database
|
|
db_files = set()
|
|
for request in DataAnalysisAgentRequest.objects.filter(data_file__isnull=False):
|
|
if request.data_file:
|
|
try:
|
|
db_files.add(request.data_file.path)
|
|
except:
|
|
pass
|
|
|
|
# Find orphaned files
|
|
for file_path in all_files:
|
|
if os.path.isfile(file_path) and file_path not in db_files:
|
|
file_age = timezone.now() - timezone.datetime.fromtimestamp(
|
|
os.path.getctime(file_path),
|
|
tz=timezone.get_current_timezone()
|
|
)
|
|
|
|
if file_age > timedelta(hours=age_hours):
|
|
if not dry_run:
|
|
os.remove(file_path)
|
|
self.stdout.write(f"Deleted orphaned file: {file_path}")
|
|
else:
|
|
self.stdout.write(f"Would delete orphaned file: {file_path}")
|
|
deleted_count += 1
|
|
|
|
except Exception as e:
|
|
self.stdout.write(
|
|
self.style.ERROR(f"Error checking orphaned files: {e}")
|
|
)
|
|
error_count += 1
|
|
|
|
# Summary
|
|
if dry_run:
|
|
self.stdout.write(
|
|
self.style.SUCCESS(f"DRY RUN: Would delete {deleted_count} files")
|
|
)
|
|
else:
|
|
self.stdout.write(
|
|
self.style.SUCCESS(f"Successfully deleted {deleted_count} files")
|
|
)
|
|
|
|
if error_count > 0:
|
|
self.stdout.write(
|
|
self.style.ERROR(f"Encountered {error_count} errors")
|
|
) |