diff --git a/scripts/restore-assets-to-minio.py b/scripts/restore-assets-to-minio.py new file mode 100755 index 00000000..0e8e0608 --- /dev/null +++ b/scripts/restore-assets-to-minio.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python3 +""" +Відновлення assets: оновлення URLs в БД та завантаження файлів в MinIO +""" +import os +import sys +import asyncio +import asyncpg +from pathlib import Path +from typing import Optional + +# Додати шлях до city-service для імпорту +sys.path.insert(0, str(Path(__file__).parent.parent / "services" / "city-service")) + +try: + from lib.assets_client import upload_asset, ensure_bucket, settings +except ImportError as e: + print(f"❌ Помилка імпорту: {e}") + print("Переконайтеся що ви в правильній директорії та MinIO клієнт налаштований") + sys.exit(1) + +# Маппінг старих URL на нові (якщо файли існують) +OLD_TO_NEW_MAPPING = { + "/assets/logos/clan.png": "clan", + "/assets/logos/soul.png": "soul", + "/assets/logos/yaromir.png": "yaromir", + "/assets/logos/druid.png": "druid", + "/assets/logos/nutra.png": "nutra", + "/assets/logos/eonarch.png": "eonarch", + "/assets/logos/helion.png": "energy-union", + "/assets/logos/greenfood.png": "greenfood", + "/assets/logos/daarion.png": "daarion", +} + +async def update_database_urls(dry_run: bool = False): + """Оновлює URLs в БД на правильні MinIO URLs""" + database_url = os.getenv( + "DATABASE_URL", + "postgresql://postgres:postgres@localhost:5432/daarion" + ) + + print("🔗 Підключення до БД...") + conn = await asyncpg.connect(database_url) + + try: + # Отримуємо всі MicroDAO зі старими URL + rows = await conn.fetch(""" + SELECT id, slug, logo_url, banner_url + FROM microdaos + WHERE logo_url IS NOT NULL OR banner_url IS NOT NULL + """) + + print(f"📊 Знайдено {len(rows)} MicroDAO з assets") + + updated_count = 0 + + for row in rows: + slug = row['slug'] + logo_url = row['logo_url'] + banner_url = row['banner_url'] + + updates = [] + + # Оновлюємо logo_url якщо потрібно + if logo_url and (logo_url.startswith('/assets/') or not logo_url.startswith('http')): + # Генеруємо новий URL для MinIO + new_logo_url = f"https://assets.daarion.space/daarion-assets/microdao/logo/{slug}.png" + + if not dry_run: + # Спробуємо завантажити файл якщо він існує локально + local_paths = [ + f"/opt/microdao-daarion/services/city-service/static/uploads/{slug}.png", + f"/opt/microdao-daarion/services/city-service/static/logos/{slug}.png", + f"/opt/microdao-daarion/public/assets/logos/{slug}.png", + ] + + uploaded = False + for local_path in local_paths: + if os.path.exists(local_path): + print(f" 📤 Завантажую логотип: {local_path}") + try: + with open(local_path, "rb") as f: + new_logo_url = upload_asset( + f, + "image/png", + "microdao/logo", + filename=f"{slug}.png" + ) + uploaded = True + print(f" ✅ Завантажено: {new_logo_url}") + break + except Exception as e: + print(f" ⚠️ Помилка завантаження {local_path}: {e}") + + if not uploaded: + print(f" ⚠️ Файл логотипу не знайдено для {slug}, використовую placeholder URL") + + updates.append(f"logo_url = '{new_logo_url}'") + print(f" 🔄 {slug}: logo_url -> {new_logo_url}") + + # Оновлюємо banner_url якщо потрібно + if banner_url and (banner_url.startswith('/api/static/') or not banner_url.startswith('http')): + # Генеруємо новий URL для MinIO + new_banner_url = f"https://assets.daarion.space/daarion-assets/microdao/banner/{slug}.png" + + if not dry_run: + # Спробуємо завантажити файл якщо він існує локально + local_paths = [ + f"/opt/microdao-daarion/services/city-service/static/uploads/{slug}_banner.png", + f"/opt/microdao-daarion/services/city-service/static/banners/{slug}.png", + ] + + uploaded = False + for local_path in local_paths: + if os.path.exists(local_path): + print(f" 📤 Завантажую банер: {local_path}") + try: + with open(local_path, "rb") as f: + new_banner_url = upload_asset( + f, + "image/png", + "microdao/banner", + filename=f"{slug}_banner.png" + ) + uploaded = True + print(f" ✅ Завантажено: {new_banner_url}") + break + except Exception as e: + print(f" ⚠️ Помилка завантаження {local_path}: {e}") + + if not uploaded: + print(f" ⚠️ Файл банера не знайдено для {slug}, залишаємо null") + new_banner_url = None + + if new_banner_url: + updates.append(f"banner_url = '{new_banner_url}'") + print(f" 🔄 {slug}: banner_url -> {new_banner_url}") + else: + updates.append("banner_url = NULL") + print(f" 🔄 {slug}: banner_url -> NULL") + + # Оновлюємо БД якщо є зміни + if updates: + if not dry_run: + update_sql = f""" + UPDATE microdaos + SET {', '.join(updates)} + WHERE id = $1 + """ + await conn.execute(update_sql, row['id']) + updated_count += 1 + else: + print(f" [DRY RUN] Would update: {slug}") + + print(f"\n✅ Оновлено {updated_count} записів") + + finally: + await conn.close() + +def main(): + import argparse + + parser = argparse.ArgumentParser(description="Відновлення assets в MinIO та оновлення URLs в БД") + parser.add_argument( + "--dry-run", + action="store_true", + help="Тільки показати що буде зроблено, не змінювати БД" + ) + args = parser.parse_args() + + print("🚀 Відновлення assets") + print(f"🌐 MinIO Endpoint: {settings.minio_endpoint}") + print(f"🪣 Bucket: {settings.assets_bucket}") + print() + + if not args.dry_run: + ensure_bucket() + print(f"✅ Bucket '{settings.assets_bucket}' готовий") + print() + + asyncio.run(update_database_urls(dry_run=args.dry_run)) + + print("\n✅ Відновлення завершено") + print("\n💡 Якщо файли відсутні, потрібно:") + print(" 1. Завантажити логотипи/банери через UI") + print(" 2. Або створити placeholder зображення") + +if __name__ == "__main__": + main() +