Files
Projektarbeit-MYP/backend/blueprints/drucker_steuerung.py
Till Tomczak 78a9f9545f 🎉 Feat: Enhanced Printer Management System
This commit introduces a comprehensive overhaul of the printer management system, enhancing its functionality and user experience. The following changes have been implemented:

- backend/blueprints/__pycache__/admin_unified.cpython-311.pyc: Updated for improved admin interface integration.
- backend/blueprints/__pycache__/drucker_steuerung.cpython-311.pyc
2025-06-19 22:34:54 +02:00

323 lines
13 KiB
Python

"""
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.CONTROL_PRINTER)
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.CONTROL_PRINTER)
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.CONTROL_PRINTER)
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")