Initial commit: AegisSight-Monitor (OSINT-Monitoringsystem)
Dieser Commit ist enthalten in:
0
src/migration/__init__.py
Normale Datei
0
src/migration/__init__.py
Normale Datei
177
src/migration/migrate_to_multitenancy.py
Normale Datei
177
src/migration/migrate_to_multitenancy.py
Normale Datei
@@ -0,0 +1,177 @@
|
||||
"""Einmalige Datenmigration zu Multi-Tenancy.
|
||||
|
||||
Dieses Script:
|
||||
1. Erstellt die AegisSight-Organisation
|
||||
2. Erstellt eine permanente Lizenz fuer AegisSight
|
||||
3. Weist bestehende Nutzer (rac00n, ch33tah) der AegisSight-Org zu
|
||||
4. Setzt tenant_id auf alle bestehenden Daten
|
||||
5. Erstellt Portal-Admin-Zugaenge
|
||||
"""
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
|
||||
# Pfade fuer Imports
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
from config import DB_PATH, TIMEZONE
|
||||
from database import init_db, get_db
|
||||
from auth import hash_password
|
||||
|
||||
|
||||
# E-Mail-Adressen fuer bestehende Nutzer
|
||||
USER_EMAILS = {
|
||||
"rac00n": os.environ.get("RACOON_EMAIL", "momohomma@googlemail.com"),
|
||||
"ch33tah": os.environ.get("CHEETAH_EMAIL", "hendrik_gebhardt@gmx.de"),
|
||||
}
|
||||
|
||||
|
||||
async def migrate():
|
||||
"""Fuehrt die Multi-Tenancy-Migration durch."""
|
||||
|
||||
# 1. Backup erstellen
|
||||
if os.path.exists(DB_PATH):
|
||||
backup_path = DB_PATH + f".backup-{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
||||
shutil.copy2(DB_PATH, backup_path)
|
||||
print(f"Backup erstellt: {backup_path}")
|
||||
else:
|
||||
print("Keine bestehende Datenbank gefunden. Frische Installation.")
|
||||
|
||||
# 2. Schema-Migration (init_db erstellt neue Tabellen und fuegt Spalten hinzu)
|
||||
await init_db()
|
||||
print("Schema-Migration abgeschlossen.")
|
||||
|
||||
db = await get_db()
|
||||
try:
|
||||
# 3. Pruefen ob Migration bereits gelaufen ist
|
||||
cursor = await db.execute("SELECT COUNT(*) as cnt FROM organizations")
|
||||
org_count = (await cursor.fetchone())["cnt"]
|
||||
if org_count > 0:
|
||||
print("Migration wurde bereits durchgefuehrt. Abbruch.")
|
||||
return
|
||||
|
||||
# 4. AegisSight-Organisation anlegen
|
||||
now = datetime.now(TIMEZONE).isoformat()
|
||||
cursor = await db.execute(
|
||||
"""INSERT INTO organizations (name, slug, is_active, created_at, updated_at)
|
||||
VALUES (?, ?, 1, ?, ?)""",
|
||||
("AegisSight", "aegissight", now, now),
|
||||
)
|
||||
aegis_org_id = cursor.lastrowid
|
||||
print(f"Organisation AegisSight angelegt (ID: {aegis_org_id})")
|
||||
|
||||
# 5. Permanente Lizenz fuer AegisSight
|
||||
await db.execute(
|
||||
"""INSERT INTO licenses (organization_id, license_type, max_users, valid_from, valid_until, status, notes)
|
||||
VALUES (?, 'permanent', 50, ?, NULL, 'active', 'Interne AegisSight-Lizenz')""",
|
||||
(aegis_org_id, now),
|
||||
)
|
||||
print("Permanente Lizenz fuer AegisSight erstellt")
|
||||
|
||||
# 6. Bestehende Nutzer der AegisSight-Org zuweisen
|
||||
cursor = await db.execute("SELECT id, username FROM users")
|
||||
users = await cursor.fetchall()
|
||||
|
||||
for user in users:
|
||||
username = user["username"]
|
||||
email = USER_EMAILS.get(username, f"{username}@aegis-sight.de")
|
||||
|
||||
await db.execute(
|
||||
"""UPDATE users SET
|
||||
organization_id = ?,
|
||||
role = 'org_admin',
|
||||
is_active = 1,
|
||||
email = ?
|
||||
WHERE id = ?""",
|
||||
(aegis_org_id, email, user["id"]),
|
||||
)
|
||||
print(f"Nutzer '{username}' -> AegisSight (org_admin, email: {email})")
|
||||
|
||||
# 7. tenant_id auf alle bestehenden Incidents setzen
|
||||
await db.execute(
|
||||
"UPDATE incidents SET tenant_id = ? WHERE tenant_id IS NULL",
|
||||
(aegis_org_id,),
|
||||
)
|
||||
cursor = await db.execute("SELECT changes()")
|
||||
changes = (await cursor.fetchone())[0]
|
||||
print(f"{changes} Incidents mit tenant_id versehen")
|
||||
|
||||
# 8. tenant_id auf alle bestehenden Articles setzen
|
||||
await db.execute(
|
||||
"UPDATE articles SET tenant_id = ? WHERE tenant_id IS NULL",
|
||||
(aegis_org_id,),
|
||||
)
|
||||
cursor = await db.execute("SELECT changes()")
|
||||
changes = (await cursor.fetchone())[0]
|
||||
print(f"{changes} Articles mit tenant_id versehen")
|
||||
|
||||
# 9. tenant_id auf alle bestehenden fact_checks setzen
|
||||
await db.execute(
|
||||
"UPDATE fact_checks SET tenant_id = ? WHERE tenant_id IS NULL",
|
||||
(aegis_org_id,),
|
||||
)
|
||||
|
||||
# 10. tenant_id auf alle bestehenden refresh_log setzen
|
||||
await db.execute(
|
||||
"UPDATE refresh_log SET tenant_id = ? WHERE tenant_id IS NULL",
|
||||
(aegis_org_id,),
|
||||
)
|
||||
|
||||
# 11. tenant_id auf alle bestehenden incident_snapshots setzen
|
||||
await db.execute(
|
||||
"UPDATE incident_snapshots SET tenant_id = ? WHERE tenant_id IS NULL",
|
||||
(aegis_org_id,),
|
||||
)
|
||||
|
||||
# 12. tenant_id auf alle bestehenden notifications setzen
|
||||
await db.execute(
|
||||
"UPDATE notifications SET tenant_id = ? WHERE tenant_id IS NULL",
|
||||
(aegis_org_id,),
|
||||
)
|
||||
|
||||
# 13. System-Quellen bleiben global (tenant_id=NULL)
|
||||
# Nur nutzer-erstellte Quellen bekommen tenant_id
|
||||
await db.execute(
|
||||
"UPDATE sources SET tenant_id = ? WHERE added_by != 'system' AND tenant_id IS NULL",
|
||||
(aegis_org_id,),
|
||||
)
|
||||
print("Nutzer-Quellen mit tenant_id versehen (System-Quellen bleiben global)")
|
||||
|
||||
# 14. Portal-Admin-Zugaenge anlegen
|
||||
print("\n--- Portal-Admin-Zugaenge ---")
|
||||
portal_users = ["rac00n", "ch33tah"]
|
||||
for pu in portal_users:
|
||||
# Pruefen ob schon existiert
|
||||
cursor = await db.execute(
|
||||
"SELECT id FROM portal_admins WHERE username = ?", (pu,)
|
||||
)
|
||||
if await cursor.fetchone():
|
||||
print(f"Portal-Admin '{pu}' existiert bereits")
|
||||
continue
|
||||
|
||||
# Passwort generieren
|
||||
import secrets
|
||||
import string
|
||||
password = ''.join(secrets.choice(string.ascii_letters + string.digits + "!@#$%&*") for _ in range(16))
|
||||
pw_hash = hash_password(password)
|
||||
|
||||
await db.execute(
|
||||
"INSERT INTO portal_admins (username, password_hash) VALUES (?, ?)",
|
||||
(pu, pw_hash),
|
||||
)
|
||||
print(f"Portal-Admin '{pu}' erstellt - Passwort: {password}")
|
||||
|
||||
await db.commit()
|
||||
print("\nMigration erfolgreich abgeschlossen!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\nFEHLER bei Migration: {e}")
|
||||
raise
|
||||
finally:
|
||||
await db.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(migrate())
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren