#!/usr/bin/env python3 """ Оновлює URLs assets в базі даних після міграції в MinIO """ import json import sys import asyncio from pathlib import Path # Додати шлях до city-service sys.path.insert(0, str(Path(__file__).parent.parent / "services" / "city-service")) try: import asyncpg from dotenv import load_dotenv import os load_dotenv() except ImportError as e: print(f"❌ Помилка імпорту: {e}") sys.exit(1) async def update_database(mapping_file: str, dry_run: bool = False): """ Оновлює URLs в базі даних на основі маппінгу """ # Читаємо маппінг with open(mapping_file, "r") as f: mapping = json.load(f) print(f"📖 Завантажено {len(mapping)} маппінгів") # Підключаємося до БД database_url = os.getenv("DATABASE_URL", "postgresql://postgres:postgres@localhost:5432/daarion") conn = await asyncpg.connect(database_url) try: updates = { "microdaos": {"logo_url": 0, "banner_url": 0}, "agents": {"avatar_url": 0}, "city_rooms": {"logo_url": 0, "banner_url": 0}, } # Створюємо зворотний маппінг: старий URL -> новий URL reverse_mapping = {} for old_path, new_url in mapping.items(): # Витягуємо відносний шлях з старого шляху if "/static/uploads" in old_path: relative_path = old_path.split("/static/uploads/")[-1] # Створюємо старий URL як він міг бути в БД old_urls = [ f"/static/uploads/{relative_path}", f"/api/static/{relative_path}", f"static/uploads/{relative_path}", relative_path, ] for old_url in old_urls: reverse_mapping[old_url] = new_url print(f"🔄 Створено {len(reverse_mapping)} зворотних маппінгів") # Оновлюємо microdaos for old_url, new_url in reverse_mapping.items(): # Logo URLs result = await conn.execute( """ UPDATE microdaos SET logo_url = $1 WHERE logo_url = $2 OR logo_url LIKE $3 """, new_url, old_url, f"%{old_url}%", ) if result != "UPDATE 0": updates["microdaos"]["logo_url"] += int(result.split()[-1]) if not dry_run: print(f" ✅ Updated microdao logo: {old_url} -> {new_url}") # Banner URLs result = await conn.execute( """ UPDATE microdaos SET banner_url = $1 WHERE banner_url = $2 OR banner_url LIKE $3 """, new_url, old_url, f"%{old_url}%", ) if result != "UPDATE 0": updates["microdaos"]["banner_url"] += int(result.split()[-1]) if not dry_run: print(f" ✅ Updated microdao banner: {old_url} -> {new_url}") # Оновлюємо agents for old_url, new_url in reverse_mapping.items(): result = await conn.execute( """ UPDATE agents SET avatar_url = $1 WHERE avatar_url = $2 OR avatar_url LIKE $3 """, new_url, old_url, f"%{old_url}%", ) if result != "UPDATE 0": updates["agents"]["avatar_url"] += int(result.split()[-1]) if not dry_run: print(f" ✅ Updated agent avatar: {old_url} -> {new_url}") # Оновлюємо city_rooms (якщо таблиця існує) try: for old_url, new_url in reverse_mapping.items(): # Logo result = await conn.execute( """ UPDATE city_rooms SET logo_url = $1 WHERE logo_url = $2 OR logo_url LIKE $3 """, new_url, old_url, f"%{old_url}%", ) if result != "UPDATE 0": updates["city_rooms"]["logo_url"] += int(result.split()[-1]) # Banner result = await conn.execute( """ UPDATE city_rooms SET banner_url = $1 WHERE banner_url = $2 OR banner_url LIKE $3 """, new_url, old_url, f"%{old_url}%", ) if result != "UPDATE 0": updates["city_rooms"]["banner_url"] += int(result.split()[-1]) except Exception as e: print(f" ⚠️ city_rooms update skipped: {e}") print() print("=" * 60) print("📊 Статистика оновлень:") for table, fields in updates.items(): total = sum(fields.values()) if total > 0: print(f" {table}:") for field, count in fields.items(): if count > 0: print(f" - {field}: {count}") print("=" * 60) if dry_run: print("🔍 DRY RUN - зміни не збережені") else: print("✅ База даних оновлена") finally: await conn.close() def main(): import argparse parser = argparse.ArgumentParser(description="Оновлення URLs assets в БД") parser.add_argument( "--mapping", default="scripts/assets_migration_mapping.json", help="Файл з маппінгом старих -> нових URLs" ) parser.add_argument( "--dry-run", action="store_true", help="Тільки показати що буде оновлено" ) args = parser.parse_args() if not Path(args.mapping).exists(): print(f"❌ Файл маппінгу не знайдено: {args.mapping}") print("Спочатку запустіть migrate_assets_to_minio.py") sys.exit(1) print("🔄 Оновлення URLs в базі даних") print(f"📄 Mapping file: {args.mapping}") print() asyncio.run(update_database(args.mapping, dry_run=args.dry_run)) if __name__ == "__main__": main()