🔧 Major System Refactoring & UI Enhancements
- Dark-Mode JavaScript Optimierungen für bessere Performance - Base Template erweitert mit Enhanced UI Components - Dashboard Template modernisiert mit neuen Card-Layouts - Hardware Integration massiv konsolidiert (1771 Zeilen reduziert) - Drucker Steuerung Blueprint hinzugefügt - Legacy Hardware Integration Files bereinigt - System-Architektur vereinfacht und performanter Major Changes: - -2001 Zeilen Code durch Konsolidierung - +451 Zeilen neue optimierte Implementierung - Vollständige Template-System Überarbeitung 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
323
backend/blueprints/drucker_steuerung.py
Normal file
323
backend/blueprints/drucker_steuerung.py
Normal file
@ -0,0 +1,323 @@
|
||||
"""
|
||||
Drucker-Steuerungs-Blueprint - BACKEND DIKTIERT FRONTEND
|
||||
=======================================================
|
||||
|
||||
NEUE PHILOSOPHIE - VOLLSTÄNDIGE Backend-Kontrolle:
|
||||
- Drucker werden NUR über Tapo-Steckdosen gesteuert
|
||||
- KEIN JavaScript - nur Flask/Jinja Templates
|
||||
- Backend sammelt ALLE Daten und übergibt sie an Templates
|
||||
- Frontend zeigt nur an, was Backend vorschreibt
|
||||
|
||||
Autor: Till Tomczak - Mercedes-Benz TBA Marienfelde
|
||||
Datum: 2025-06-19 (Komplett-Neuschreibung für Backend-Kontrolle)
|
||||
"""
|
||||
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, flash
|
||||
from flask_login import login_required, current_user
|
||||
from datetime import datetime
|
||||
|
||||
from utils.hardware_integration import get_drucker_steuerung
|
||||
from utils.logging_config import get_logger
|
||||
from utils.security_suite import require_permission, Permission
|
||||
|
||||
# Logger
|
||||
drucker_logger = get_logger("drucker_steuerung")
|
||||
|
||||
# Blueprint erstellen
|
||||
drucker_blueprint = Blueprint("drucker", __name__, url_prefix="/drucker")
|
||||
|
||||
# ===== FRONTEND-ROUTEN (Nur Templates) =====
|
||||
|
||||
@drucker_blueprint.route("/")
|
||||
@login_required
|
||||
def drucker_uebersicht():
|
||||
"""
|
||||
Drucker-Übersichtsseite - Backend sammelt ALLE Daten für Frontend.
|
||||
KEIN JavaScript - alles über Flask/Jinja!
|
||||
"""
|
||||
drucker_logger.info(f"🖨️ Drucker-Übersicht aufgerufen von {current_user.name}")
|
||||
|
||||
try:
|
||||
# Hardware-Integration holt ALLE Daten
|
||||
drucker_steuerung = get_drucker_steuerung()
|
||||
template_daten = drucker_steuerung.template_daten_sammeln()
|
||||
|
||||
# Zusätzliche UI-Daten
|
||||
ui_daten = {
|
||||
'seiten_titel': 'Drucker-Verwaltung',
|
||||
'benutzer_kann_steuern': current_user.is_admin or hasattr(current_user, 'can_control_printers'),
|
||||
'letztes_update': datetime.now().strftime('%d.%m.%Y %H:%M:%S'),
|
||||
'refresh_url': url_for('drucker.drucker_uebersicht'),
|
||||
}
|
||||
|
||||
# Alle Daten an Template übergeben
|
||||
return render_template(
|
||||
'drucker_steuerung.html',
|
||||
**template_daten,
|
||||
**ui_daten
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
drucker_logger.error(f"❌ Fehler beim Laden der Drucker-Übersicht: {e}")
|
||||
flash(f'Fehler beim Laden der Drucker-Daten: {str(e)}', 'error')
|
||||
|
||||
# Fallback-Template mit Fehlermeldung
|
||||
return render_template(
|
||||
'drucker_steuerung.html',
|
||||
drucker=[],
|
||||
stats={'gesamt_drucker': 0, 'online_drucker': 0, 'offline_drucker': 0},
|
||||
system_status='error',
|
||||
error=str(e),
|
||||
seiten_titel='Drucker-Verwaltung (Fehler)',
|
||||
benutzer_kann_steuern=False
|
||||
)
|
||||
|
||||
@drucker_blueprint.route("/details/<int:drucker_id>")
|
||||
@login_required
|
||||
def drucker_details(drucker_id):
|
||||
"""
|
||||
Detailansicht für einen einzelnen Drucker.
|
||||
Alle Daten kommen vom Backend - Frontend ist passiv!
|
||||
"""
|
||||
drucker_logger.info(f"🔍 Drucker-Details {drucker_id} aufgerufen von {current_user.name}")
|
||||
|
||||
try:
|
||||
# Hardware-Integration holt alle Drucker-Daten
|
||||
drucker_steuerung = get_drucker_steuerung()
|
||||
alle_daten = drucker_steuerung.template_daten_sammeln()
|
||||
|
||||
# Spezifischen Drucker finden
|
||||
drucker_info = None
|
||||
for drucker in alle_daten.get('drucker', []):
|
||||
if drucker['id'] == drucker_id:
|
||||
drucker_info = drucker
|
||||
break
|
||||
|
||||
if not drucker_info:
|
||||
flash(f'Drucker {drucker_id} nicht gefunden', 'error')
|
||||
return redirect(url_for('drucker.drucker_uebersicht'))
|
||||
|
||||
# Zusätzliche Detail-Daten vom Backend
|
||||
detail_daten = {
|
||||
'seiten_titel': f'Details - {drucker_info["name"]}',
|
||||
'zurueck_url': url_for('drucker.drucker_uebersicht'),
|
||||
'benutzer_kann_steuern': current_user.is_admin or hasattr(current_user, 'can_control_printers'),
|
||||
|
||||
# Steuerungs-URLs (Backend-Routes)
|
||||
'einschalten_url': url_for('drucker.drucker_einschalten', drucker_id=drucker_id),
|
||||
'ausschalten_url': url_for('drucker.drucker_ausschalten', drucker_id=drucker_id),
|
||||
'toggle_url': url_for('drucker.drucker_toggle', drucker_id=drucker_id),
|
||||
|
||||
# Erweiterte Drucker-Infos
|
||||
'laufzeit_heute': '3h 45m', # Mock-Daten
|
||||
'jobs_heute': 2,
|
||||
'letzter_job': 'vor 1 Stunde',
|
||||
'geschätzte_kosten_monat': f"{drucker_info.get('monthly_consumption', 0) * 0.30:.2f} €"
|
||||
}
|
||||
|
||||
return render_template(
|
||||
'drucker_details.html',
|
||||
drucker=drucker_info,
|
||||
stats=alle_daten.get('stats', {}),
|
||||
**detail_daten
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
drucker_logger.error(f"❌ Fehler beim Laden der Drucker-Details {drucker_id}: {e}")
|
||||
flash(f'Fehler beim Laden der Drucker-Details: {str(e)}', 'error')
|
||||
return redirect(url_for('drucker.drucker_uebersicht'))
|
||||
|
||||
# ===== STEUERUNGS-ROUTEN (Backend-Aktionen) =====
|
||||
|
||||
@drucker_blueprint.route("/einschalten/<int:drucker_id>", methods=["POST"])
|
||||
@login_required
|
||||
@require_permission(Permission.CAN_CONTROL_PRINTERS)
|
||||
def drucker_einschalten(drucker_id):
|
||||
"""
|
||||
Schaltet einen Drucker über seine Tapo-Steckdose EIN.
|
||||
Komplett Backend-gesteuert - kein JavaScript!
|
||||
"""
|
||||
drucker_logger.info(f"🟢 Benutzer {current_user.name} schaltet Drucker {drucker_id} ein")
|
||||
|
||||
try:
|
||||
# Hardware-Integration ausführen
|
||||
drucker_steuerung = get_drucker_steuerung()
|
||||
ergebnis = drucker_steuerung.drucker_einschalten(
|
||||
drucker_id,
|
||||
grund=f"Manuell von {current_user.name}"
|
||||
)
|
||||
|
||||
if ergebnis['success']:
|
||||
flash(ergebnis['message'], 'success')
|
||||
drucker_logger.info(f"✅ Drucker {drucker_id} erfolgreich eingeschaltet")
|
||||
else:
|
||||
flash(f"Fehler beim Einschalten: {ergebnis['error']}", 'error')
|
||||
drucker_logger.error(f"❌ Drucker {drucker_id} konnte nicht eingeschaltet werden: {ergebnis['error']}")
|
||||
|
||||
except Exception as e:
|
||||
drucker_logger.error(f"❌ Exception beim Einschalten von Drucker {drucker_id}: {e}")
|
||||
flash(f'Technischer Fehler beim Einschalten: {str(e)}', 'error')
|
||||
|
||||
# Zurück zur Übersicht (Backend-Redirect)
|
||||
return redirect(url_for('drucker.drucker_uebersicht'))
|
||||
|
||||
@drucker_blueprint.route("/ausschalten/<int:drucker_id>", methods=["POST"])
|
||||
@login_required
|
||||
@require_permission(Permission.CAN_CONTROL_PRINTERS)
|
||||
def drucker_ausschalten(drucker_id):
|
||||
"""
|
||||
Schaltet einen Drucker über seine Tapo-Steckdose AUS.
|
||||
Komplett Backend-gesteuert - kein JavaScript!
|
||||
"""
|
||||
drucker_logger.info(f"🔴 Benutzer {current_user.name} schaltet Drucker {drucker_id} aus")
|
||||
|
||||
try:
|
||||
# Hardware-Integration ausführen
|
||||
drucker_steuerung = get_drucker_steuerung()
|
||||
ergebnis = drucker_steuerung.drucker_ausschalten(
|
||||
drucker_id,
|
||||
grund=f"Manuell von {current_user.name}"
|
||||
)
|
||||
|
||||
if ergebnis['success']:
|
||||
flash(ergebnis['message'], 'success')
|
||||
drucker_logger.info(f"✅ Drucker {drucker_id} erfolgreich ausgeschaltet")
|
||||
else:
|
||||
flash(f"Fehler beim Ausschalten: {ergebnis['error']}", 'error')
|
||||
drucker_logger.error(f"❌ Drucker {drucker_id} konnte nicht ausgeschaltet werden: {ergebnis['error']}")
|
||||
|
||||
except Exception as e:
|
||||
drucker_logger.error(f"❌ Exception beim Ausschalten von Drucker {drucker_id}: {e}")
|
||||
flash(f'Technischer Fehler beim Ausschalten: {str(e)}', 'error')
|
||||
|
||||
# Zurück zur Übersicht (Backend-Redirect)
|
||||
return redirect(url_for('drucker.drucker_uebersicht'))
|
||||
|
||||
@drucker_blueprint.route("/toggle/<int:drucker_id>", methods=["POST"])
|
||||
@login_required
|
||||
@require_permission(Permission.CAN_CONTROL_PRINTERS)
|
||||
def drucker_toggle(drucker_id):
|
||||
"""
|
||||
Wechselt den Status eines Druckers (Ein <-> Aus).
|
||||
Komplett Backend-gesteuert - kein JavaScript!
|
||||
"""
|
||||
drucker_logger.info(f"🔄 Benutzer {current_user.name} togglet Drucker {drucker_id}")
|
||||
|
||||
try:
|
||||
# Hardware-Integration ausführen
|
||||
drucker_steuerung = get_drucker_steuerung()
|
||||
ergebnis = drucker_steuerung.drucker_toggle(
|
||||
drucker_id,
|
||||
grund=f"Toggle von {current_user.name}"
|
||||
)
|
||||
|
||||
if ergebnis['success']:
|
||||
flash(ergebnis['message'], 'success')
|
||||
drucker_logger.info(f"✅ Drucker {drucker_id} erfolgreich getoggled")
|
||||
else:
|
||||
flash(f"Fehler beim Umschalten: {ergebnis['error']}", 'error')
|
||||
drucker_logger.error(f"❌ Drucker {drucker_id} konnte nicht getoggled werden: {ergebnis['error']}")
|
||||
|
||||
except Exception as e:
|
||||
drucker_logger.error(f"❌ Exception beim Toggle von Drucker {drucker_id}: {e}")
|
||||
flash(f'Technischer Fehler beim Umschalten: {str(e)}', 'error')
|
||||
|
||||
# Zurück zur Übersicht (Backend-Redirect)
|
||||
return redirect(url_for('drucker.drucker_uebersicht'))
|
||||
|
||||
@drucker_blueprint.route("/alle-ausschalten", methods=["POST"])
|
||||
@login_required
|
||||
@require_permission(Permission.ADMIN)
|
||||
def alle_drucker_ausschalten():
|
||||
"""
|
||||
Schaltet ALLE Drucker aus (Notfall-Funktion).
|
||||
Nur für Admins - komplett Backend-gesteuert!
|
||||
"""
|
||||
drucker_logger.warning(f"🚨 NOTFALL: Benutzer {current_user.name} schaltet ALLE Drucker aus")
|
||||
|
||||
try:
|
||||
# Hardware-Integration holt alle Drucker
|
||||
drucker_steuerung = get_drucker_steuerung()
|
||||
alle_daten = drucker_steuerung.template_daten_sammeln()
|
||||
|
||||
erfolge = 0
|
||||
fehler = 0
|
||||
|
||||
# Jeden Drucker ausschalten
|
||||
for drucker in alle_daten.get('drucker', []):
|
||||
if drucker['status'] == 'online' and drucker['kann_gesteuert_werden']:
|
||||
ergebnis = drucker_steuerung.drucker_ausschalten(
|
||||
drucker['id'],
|
||||
grund=f"NOTFALL-SHUTDOWN von {current_user.name}"
|
||||
)
|
||||
|
||||
if ergebnis['success']:
|
||||
erfolge += 1
|
||||
drucker_logger.info(f"✅ Notfall-Shutdown: {drucker['name']} ausgeschaltet")
|
||||
else:
|
||||
fehler += 1
|
||||
drucker_logger.error(f"❌ Notfall-Shutdown: {drucker['name']} Fehler: {ergebnis['error']}")
|
||||
|
||||
# Ergebnis-Meldung
|
||||
if fehler == 0:
|
||||
flash(f'Alle Drucker erfolgreich ausgeschaltet ({erfolge} Geräte)', 'success')
|
||||
else:
|
||||
flash(f'Teilweise erfolgreich: {erfolge} ausgeschaltet, {fehler} Fehler', 'warning')
|
||||
|
||||
except Exception as e:
|
||||
drucker_logger.error(f"❌ Kritischer Fehler beim Notfall-Shutdown: {e}")
|
||||
flash(f'Kritischer Fehler beim Notfall-Shutdown: {str(e)}', 'error')
|
||||
|
||||
# Zurück zur Übersicht
|
||||
return redirect(url_for('drucker.drucker_uebersicht'))
|
||||
|
||||
@drucker_blueprint.route("/status-refresh")
|
||||
@login_required
|
||||
def status_refresh():
|
||||
"""
|
||||
Aktualisiert alle Drucker-Status.
|
||||
Backend sammelt neue Daten und zeigt sie an - kein JavaScript!
|
||||
"""
|
||||
drucker_logger.info(f"🔄 Status-Refresh ausgeführt von {current_user.name}")
|
||||
|
||||
try:
|
||||
# Hardware-Integration aktualisiert alle Status
|
||||
drucker_steuerung = get_drucker_steuerung()
|
||||
template_daten = drucker_steuerung.template_daten_sammeln()
|
||||
|
||||
online_count = template_daten.get('stats', {}).get('online_drucker', 0)
|
||||
total_count = template_daten.get('stats', {}).get('gesamt_drucker', 0)
|
||||
|
||||
flash(f'Status aktualisiert: {online_count}/{total_count} Drucker online', 'info')
|
||||
|
||||
except Exception as e:
|
||||
drucker_logger.error(f"❌ Fehler beim Status-Refresh: {e}")
|
||||
flash(f'Fehler beim Aktualisieren: {str(e)}', 'error')
|
||||
|
||||
# Zurück zur Übersicht mit aktualisierten Daten
|
||||
return redirect(url_for('drucker.drucker_uebersicht'))
|
||||
|
||||
# ===== ERROR HANDLERS =====
|
||||
|
||||
@drucker_blueprint.errorhandler(403)
|
||||
def drucker_forbidden(e):
|
||||
"""Error-Handler für fehlende Berechtigungen"""
|
||||
drucker_logger.warning(f"403 Forbidden in Drucker-Steuerung: {request.path} von User {current_user.name}")
|
||||
flash('Keine Berechtigung für Drucker-Steuerung', 'error')
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
@drucker_blueprint.errorhandler(404)
|
||||
def drucker_not_found(e):
|
||||
"""Error-Handler für nicht gefundene Drucker"""
|
||||
drucker_logger.warning(f"404 Not Found in Drucker-Steuerung: {request.path}")
|
||||
flash('Drucker nicht gefunden', 'error')
|
||||
return redirect(url_for('drucker.drucker_uebersicht'))
|
||||
|
||||
@drucker_blueprint.errorhandler(500)
|
||||
def drucker_server_error(e):
|
||||
"""Error-Handler für Server-Fehler"""
|
||||
drucker_logger.error(f"500 Server Error in Drucker-Steuerung: {request.path} - {str(e)}")
|
||||
flash('Technischer Fehler in der Drucker-Steuerung', 'error')
|
||||
return redirect(url_for('drucker.drucker_uebersicht'))
|
||||
|
||||
drucker_logger.info("🖨️ Drucker-Steuerungs-Blueprint (Backend-Kontrolle) geladen")
|
Reference in New Issue
Block a user