Files
Projektarbeit-MYP/backend/docs/TAPO_BUTTONS_FIX.md

8.3 KiB

Tapo-Buttons und Benutzer-Erstellung Fehlerbehebung

Datum: 2025-06-19

Status: BEHOBEN

Problembeschreibung

1. Tapo Ein-/Ausschalte-Buttons funktionieren nicht

  • Symptom: Buttons in der Printers-Route reagieren nicht oder geben Fehlermeldungen zurück
  • Ursache: Mehrere kritische Datenbankfehler in der Admin API
  • Betroffene Dateien: blueprints/admin_unified.py, models.py, app.py

2. Benutzer-Erstellung schlägt fehl

  • Symptom: Fehler "Benutzer konnte nicht erstellt werden"
  • Ursache: Session-Management-Probleme und fehlende Validierung
  • Betroffene Dateien: blueprints/admin_unified.py

Hauptprobleme identifiziert

A. SQL-Text-Fehler

Textual SQL expression 'SELECT 1' should be explicitly declared as text('SELECT 1')

B. Database Constraint Fehler

NOT NULL constraint failed: plug_status_logs.printer_id

C. Session-Management-Probleme

'_GeneratorContextManager' object has no attribute 'query'

Implementierte Lösungen

1. SQL-Text-Ausdrücke korrigiert

In blueprints/admin_unified.py:

# VORHER (fehlerhaft):
db_session.execute("SELECT 1")

# NACHHER (korrekt):
from sqlalchemy import text
db_session.execute(text("SELECT 1"))

Betroffene Funktionen:

  • api_admin_system_health()
  • api_admin_error_recovery_status()

2. PlugStatusLog-Validierung hinzugefügt

In models.py:

@classmethod
def log_status_change(cls, printer_id: int, status: str, ...):
    # VALIDIERUNG hinzugefügt
    if printer_id is None:
        error_msg = "printer_id ist erforderlich für PlugStatusLog.log_status_change"
        logger.error(error_msg)
        raise ValueError(error_msg)
    
    # Session-Management verbessert
    db_session = get_db_session()
    try:
        # Drucker-Existenz prüfen
        printer = db_session.query(Printer).filter(Printer.id == printer_id).first()
        if not printer:
            logger.warning(f"Drucker mit ID {printer_id} nicht gefunden")
        
        # Log-Eintrag erstellen mit korrekter printer_id
        log_entry = cls(printer_id=printer_id, ...)
        db_session.add(log_entry)
        db_session.commit()
        
    except Exception as db_error:
        db_session.rollback()
        raise db_error
    finally:
        db_session.close()

3. Toggle-Drucker-Power-Funktion überarbeitet

In blueprints/admin_unified.py:

@admin_api_blueprint.route('/printers/<int:printer_id>/toggle', methods=['POST'])
@admin_required
def toggle_printer_power(printer_id):
    try:
        from models import get_db_session, Printer, PlugStatusLog
        from utils.hardware_integration import get_tapo_controller
        
        # Session-Management korrekt implementiert
        db_session = get_db_session()
        try:
            printer = db_session.query(Printer).filter(Printer.id == printer_id).first()
            
            # Tapo-Controller verwenden
            tapo_controller = get_tapo_controller()
            success = tapo_controller.toggle_plug(printer.plug_ip, new_state)
            
            if success:
                # Status-Änderung protokollieren - MIT korrekter Drucker-ID
                PlugStatusLog.log_status_change(
                    printer_id=printer_id,  # EXPLIZIT übergeben
                    status='on' if new_state else 'off',
                    source='admin',
                    user_id=current_user.id,
                    ip_address=printer.plug_ip,
                    notes=f"Toggle durch Admin {current_user.name}"
                )
        except Exception as db_error:
            db_session.rollback()
            return jsonify({"error": "Datenbankfehler"}), 500
        finally:
            db_session.close()

4. Benutzer-Erstellung API verbessert

In blueprints/admin_unified.py:

@admin_api_blueprint.route("/users", methods=["POST"])
@admin_required
def create_user_api():
    try:
        # Erweiterte Validierung
        if len(data['username']) < 3:
            return jsonify({"error": "Benutzername muss mindestens 3 Zeichen lang sein"}), 400
        
        # Korrekte Session-Verwendung
        db_session = get_db_session()
        try:
            # Prüfung auf existierende Benutzer
            existing_user = db_session.query(User).filter(
                (User.username == data['username']) | (User.email == data['email'])
            ).first()
            
            if existing_user:
                return jsonify({"error": "Benutzername oder E-Mail bereits vergeben"}), 400
            
            # Benutzer erstellen mit allen erforderlichen Feldern
            new_user = User(
                username=data['username'],
                email=data['email'],
                name=data['name'],
                role=data.get('role', 'user'),
                active=True,
                created_at=datetime.now()
            )
            new_user.set_password(data['password'])
            
            db_session.add(new_user)
            db_session.flush()  # ID generieren
            
            # Berechtigungen erstellen
            permissions = UserPermission(user_id=new_user.id, ...)
            db_session.add(permissions)
            db_session.commit()
            
        except Exception as db_error:
            db_session.rollback()
            return jsonify({"error": "Datenbankfehler"}), 500
        finally:
            db_session.close()

5. Windows-kompatible Speicherplatz-Prüfung

Ersetzt os.statvfs() (Unix-only) durch shutil.disk_usage() (plattformübergreifend):

# VORHER (nur Unix):
statvfs = os.statvfs('.')
total_space = statvfs.f_blocks * statvfs.f_frsize

# NACHHER (Windows-kompatibel):
import shutil
disk_usage = shutil.disk_usage('.')
free_space_gb = disk_usage.free / (1024**3)
total_space_gb = disk_usage.total / (1024**3)

Verbessertes Error-Handling

Logging erweitert

admin_logger.info(f"✅ Drucker {printer_id} erfolgreich {'eingeschaltet' if new_state else 'ausgeschaltet'}")
admin_logger.error(f"❌ Status-Protokollierung fehlgeschlagen: {str(log_error)}")
admin_logger.warning(f"Benutzer-Erstellung fehlgeschlagen: Benutzername oder E-Mail bereits vergeben")

Graceful Degradation

  • Bei Tapo-Controller-Problemen: System läuft weiter, aber mit Warnungen
  • Bei Protokollierungs-Fehlern: Hauptfunktion wird trotzdem ausgeführt
  • Bei Speicherplatz-Checks: Fallback auf vereinfachte Prüfung

Getestete Funktionen

Tapo-Buttons

  • Ein-/Ausschalten über Admin-Panel funktioniert
  • Status-Protokollierung in plug_status_logs erfolgreich
  • Korrekte Fehlerbehandlung bei nicht erreichbaren Steckdosen

Benutzer-Erstellung

  • Formular-basierte Erstellung funktioniert
  • JSON-API-Erstellung funktioniert
  • Berechtigungen werden korrekt erstellt
  • Validierung verhindert doppelte Benutzer

System-Health-Checks

  • Datenbank-Prüfungen ohne SQL-Fehler
  • Windows-kompatible Speicherplatz-Prüfung
  • Tapo-Controller-Status wird korrekt geprüft

Vorbeugende Maßnahmen

1. Verbesserte Validierung

  • Alle Database-Operationen haben Rollback-Schutz
  • Pflichtfelder werden vor DB-Zugriff validiert
  • Session-Management mit try/finally-Blöcken

2. Monitoring

  • Alle kritischen Operationen werden geloggt
  • Fehlschläge werden mit Details protokolliert
  • Performance-Metriken für DB-Operationen

3. Fallback-Mechanismen

  • Graceful Degradation bei Teilsystem-Ausfällen
  • Minimale Funktionalität bleibt erhalten
  • Benutzer-freundliche Fehlermeldungen

Datei-Änderungen Zusammenfassung

Datei Änderungstyp Beschreibung
blueprints/admin_unified.py MAJOR SQL-text() fixes, Session-Management, Toggle-Funktion
models.py MAJOR PlugStatusLog-Validierung, Session-Management
app.py MINOR printer_control Route bereits korrekt implementiert

Nächste Schritte

  1. Testen der Fixes in Production-Umgebung
  2. Monitoring der Logs auf weitere Datenbankfehler
  3. Performance-Optimierung der Admin-API-Endpunkte

Fehlerbehebung bestätigt

  • Tapo Ein-/Ausschalte-Buttons funktionieren
  • Benutzer-Erstellung ohne Fehlermeldungen
  • System-Health-Checks stabil
  • Keine SQL-text() Fehler mehr
  • Keine NOT NULL constraint Fehler mehr
  • Windows-Kompatibilität sichergestellt