spawner/migrate_container_blocking.py
XPS\Micro a4f85df93c feat: Phase 7 - Container-Level Blocking mit Admin-Dashboard UI und Cascading
**Neue Features:**
1. Container-Level Blocking: Admin kann einzelne Container blockieren/entsperren
2. User-Block Cascading: Wenn User gesperrt wird, werden automatisch alle seine Container blockiert
3. Launch-Protection: Blockierte Container können vom User nicht gestartet werden
4. Container-Verwaltungs-Tab im Admin-Dashboard mit Block/Unblock UI
5. Blocked-Status auf User-Dashboard mit visueller Markierung (rot)
6. Bulk-Operations für Container (Block/Unblock)

**Backend-Änderungen (admin_api.py):**
- GET /api/admin/users: Liefert nun auch Container-Liste mit is_blocked Status
- POST /api/admin/containers/<id>/block: Blockiert einzelnen Container
- POST /api/admin/containers/<id>/unblock: Entsperrt einzelnen Container
- POST /api/admin/containers/bulk-block: Blockiert mehrere Container
- POST /api/admin/containers/bulk-unblock: Entsperrt mehrere Container
- POST /api/admin/users/<id>/block: Cascade-Blockade aller Container (Phase 7)

**Backend-Änderungen (api.py):**
- GET /api/user/containers: Liefert is_blocked und blocked_at Felder
- POST /api/container/launch/<type>: Launch-Protection prüft is_blocked Flag

**Database-Änderungen (models.py):**
- UserContainer: Füge is_blocked, blocked_at, blocked_by Spalten hinzu
- Relationships für Blocker-Admin

**Frontend-Änderungen:**
- Admin-Dashboard: Neuer "Container-Verwaltung" Tab mit Grid-View
- Admin-Dashboard: Block/Unblock Buttons pro Container
- Admin-Dashboard: Bulk-Operations für Container-Selection
- User-Dashboard: Blocked-Badge und Blocked-Beschreibung in Container-Cards
- User-Dashboard: Disabled Button wenn Container blockiert
- User-Dashboard: Toast-Benachrichtigung bei Launch-Protection

**Migration:**
- Neue Datei: migrate_container_blocking.py für Database-Setup
  Verwendung: python migrate_container_blocking.py

**Sicherheit:**
- Blockierte Container werden mit stop_container() gestoppt
- Lazy-Init des ContainerManager für robuste Error-Handling
- Separate Admin-Endpoints mit @admin_required() Decorator
- Audit-Logging aller Block/Unblock-Operationen

**Testing-Punkte:**
- User-Block blockiert alle Container? ✓ Cascading
- Container-Block wird auf User-Dashboard angezeigt? ✓ is_blocked prüfen
- Launch-Protection funktioniert? ✓ 403 Error bei is_blocked
- Admin-Container-Tab funktioniert? ✓ Grid-View mit Search
- Bulk-Operations funktionieren? ✓ Multiple Selection + Confirm

Fixes: #0 (Phase 7 Implementation)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-02-04 22:44:06 +01:00

98 lines
3.8 KiB
Python

#!/usr/bin/env python3
"""
Migration Script: Container Blocking Fields hinzufügen
Fügt folgende Spalten zur user_container Tabelle hinzu:
- is_blocked (BOOLEAN DEFAULT 0)
- blocked_at (DATETIME)
- blocked_by (INTEGER, Foreign Key zu user.id)
Verwendung:
python migrate_container_blocking.py
Fallback (SQLite):
sqlite3 spawner.db < migration.sql
"""
from app import app, db
import sys
def migrate():
"""Führt die Migration durch"""
try:
with app.app_context():
print("[MIGRATION] Starte Container Blocking Migration...")
# Prüfe ob Spalten bereits existieren
inspector = db.inspect(db.engine)
columns = [col['name'] for col in inspector.get_columns('user_container')]
if 'is_blocked' in columns:
print("[INFO] Spalte 'is_blocked' existiert bereits")
else:
print("[ADD] Füge Spalte 'is_blocked' hinzu...")
with db.engine.connect() as conn:
try:
conn.execute(db.text("""
ALTER TABLE user_container
ADD COLUMN is_blocked BOOLEAN DEFAULT 0 NOT NULL
"""))
conn.commit()
print("✅ Spalte 'is_blocked' erstellt")
except Exception as e:
print(f"⚠️ Fehler bei 'is_blocked': {e}")
# Könnte bereits existieren (MySQL)
if 'blocked_at' in columns:
print("[INFO] Spalte 'blocked_at' existiert bereits")
else:
print("[ADD] Füge Spalte 'blocked_at' hinzu...")
with db.engine.connect() as conn:
try:
conn.execute(db.text("""
ALTER TABLE user_container
ADD COLUMN blocked_at DATETIME
"""))
conn.commit()
print("✅ Spalte 'blocked_at' erstellt")
except Exception as e:
print(f"⚠️ Fehler bei 'blocked_at': {e}")
if 'blocked_by' in columns:
print("[INFO] Spalte 'blocked_by' existiert bereits")
else:
print("[ADD] Füge Spalte 'blocked_by' hinzu...")
with db.engine.connect() as conn:
try:
conn.execute(db.text("""
ALTER TABLE user_container
ADD COLUMN blocked_by INTEGER
REFERENCES user(id) ON DELETE SET NULL
"""))
conn.commit()
print("✅ Spalte 'blocked_by' erstellt")
except Exception as e:
print(f"⚠️ Fehler bei 'blocked_by': {e}")
print("\n[SUCCESS] Migration abgeschlossen!")
print("[INFO] Folgende Änderungen wurden durchgeführt:")
print(" - is_blocked BOOLEAN DEFAULT 0")
print(" - blocked_at DATETIME")
print(" - blocked_by INTEGER FK zu user(id)")
print("\n[NEXT] Starte die Application mit: docker-compose up -d")
return True
except Exception as e:
print(f"\n[ERROR] Migration fehlgeschlagen: {str(e)}")
print("[HELP] Versuche manuelle Migration:")
print(" sqlite3 spawner.db")
print(" > ALTER TABLE user_container ADD COLUMN is_blocked BOOLEAN DEFAULT 0;")
print(" > ALTER TABLE user_container ADD COLUMN blocked_at DATETIME;")
print(" > ALTER TABLE user_container ADD COLUMN blocked_by INTEGER;")
return False
if __name__ == '__main__':
success = migrate()
sys.exit(0 if success else 1)