**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>
98 lines
3.8 KiB
Python
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)
|