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
323 lines
13 KiB
Python
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") |