- Add NGINX reverse proxy config for assets.daarion.space - Add script to migrate assets from /static/uploads to MinIO - Add script to update asset URLs in database after migration
196 lines
6.8 KiB
Python
Executable File
196 lines
6.8 KiB
Python
Executable File
#!/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()
|
|
|