feat: Hinzufügen neuer API-Endpunkte zur erweiterten Drucker-Status-Verwaltung und Verbesserung der Benutzeroberfläche durch optimierte Lade- und Filtermechanismen. Implementierung von Caching für Online-Drucker und Live-Status sowie Auto-Update-Funktionalität zur Echtzeit-Überwachung. Anpassungen in den Templates zur Anzeige von Status-Übersichten und Filteroptionen für eine verbesserte Benutzererfahrung.

This commit is contained in:
2025-05-27 11:38:50 +02:00
parent c39595382c
commit cbe1864678
4 changed files with 985 additions and 142 deletions

View File

@@ -3226,6 +3226,307 @@ def admin_update_printer_form(printer_id):
flash("Fehler beim Aktualisieren des Druckers.", "error")
return redirect(url_for("admin_printer_settings_page", printer_id=printer_id))
# Neue API-Endpunkte für erweiterte Drucker-Status-Verwaltung hinzufügen
@app.route("/api/printers/online", methods=["GET"])
@login_required
def get_online_printers():
"""Gibt nur die online/verfügbaren Drucker zurück - optimiert für schnelle Anzeige."""
db_session = get_db_session()
printers_logger = get_logger("printers")
try:
# Session-Cache für Online-Drucker prüfen
cache_key = f"online_printers_{current_user.id}"
cached_data = session.get(cache_key)
cache_timestamp = session.get(f"{cache_key}_timestamp")
# Cache ist 30 Sekunden gültig
if cached_data and cache_timestamp:
cache_age = (datetime.now() - datetime.fromisoformat(cache_timestamp)).total_seconds()
if cache_age < 30:
printers_logger.info(f"Online-Drucker aus Session-Cache geladen (Alter: {cache_age:.1f}s)")
return jsonify({
"printers": cached_data,
"count": len(cached_data),
"cached": True,
"cache_age": cache_age
})
# Nur verfügbare/online Drucker aus Datenbank laden
printers = db_session.query(Printer).filter(
Printer.status.in_(["available", "online", "idle"]),
Printer.active == True
).all()
current_time = datetime.now()
online_printers = []
for printer in printers:
printer_data = {
"id": printer.id,
"name": printer.name,
"model": printer.model or 'Unbekanntes Modell',
"location": printer.location or 'Unbekannter Standort',
"mac_address": printer.mac_address,
"plug_ip": printer.plug_ip,
"status": printer.status,
"active": printer.active,
"ip_address": printer.plug_ip if printer.plug_ip else getattr(printer, 'ip_address', None),
"created_at": printer.created_at.isoformat() if printer.created_at else current_time.isoformat(),
"last_checked": printer.last_checked.isoformat() if hasattr(printer, 'last_checked') and printer.last_checked else None,
"is_online": True # Alle Drucker in dieser Liste sind online
}
online_printers.append(printer_data)
# In Session-Cache speichern
session[cache_key] = online_printers
session[f"{cache_key}_timestamp"] = current_time.isoformat()
session.permanent = True
db_session.close()
printers_logger.info(f"Online-Drucker geladen: {len(online_printers)} verfügbare Drucker")
return jsonify({
"printers": online_printers,
"count": len(online_printers),
"cached": False,
"message": f"{len(online_printers)} online Drucker gefunden"
})
except Exception as e:
db_session.rollback()
db_session.close()
printers_logger.error(f"Fehler beim Abrufen der Online-Drucker: {str(e)}")
return jsonify({
"error": f"Fehler beim Laden der Online-Drucker: {str(e)}",
"printers": []
}), 500
@app.route("/api/printers/status/live", methods=["GET"])
@login_required
def get_live_printer_status():
"""Gibt Live-Status aller Drucker zurück mit Session-Caching und Echtzeit-Updates."""
db_session = get_db_session()
printers_logger = get_logger("printers")
try:
# Session-Cache für Live-Status prüfen
cache_key = f"live_printer_status_{current_user.id}"
cached_data = session.get(cache_key)
cache_timestamp = session.get(f"{cache_key}_timestamp")
# Cache ist 15 Sekunden gültig für Live-Status
if cached_data and cache_timestamp:
cache_age = (datetime.now() - datetime.fromisoformat(cache_timestamp)).total_seconds()
if cache_age < 15:
printers_logger.info(f"Live-Status aus Session-Cache geladen (Alter: {cache_age:.1f}s)")
return jsonify({
"printers": cached_data,
"cached": True,
"cache_age": cache_age,
"next_update": 15 - cache_age
})
# Alle Drucker aus der Datenbank laden
printers = db_session.query(Printer).all()
if not printers:
return jsonify({
"printers": [],
"count": 0,
"message": "Keine Drucker in der Datenbank gefunden"
})
# Drucker-Daten für Status-Check vorbereiten
printer_data = []
for printer in printers:
printer_data.append({
'id': printer.id,
'name': printer.name,
'ip_address': printer.plug_ip if printer.plug_ip else getattr(printer, 'ip_address', None)
})
# Paralleler Status-Check mit kürzerem Timeout für Live-Updates
try:
status_results = check_multiple_printers_status(printer_data, timeout=3)
except Exception as e:
printers_logger.warning(f"Status-Check fehlgeschlagen, verwende letzte bekannte Status: {str(e)}")
# Fallback: verwende letzte bekannte Status
status_results = {p['id']: (p.get('last_status', 'offline'), False) for p in printer_data}
# Live-Status-Daten zusammenstellen
live_status_data = []
current_time = datetime.now()
online_count = 0
for printer in printers:
if printer.id in status_results:
status, active = status_results[printer.id]
frontend_status = "available" if status == "online" else "offline"
if frontend_status == "available":
online_count += 1
else:
frontend_status = printer.status or "offline"
active = printer.active if hasattr(printer, 'active') else False
# Status in Datenbank aktualisieren (asynchron)
printer.status = frontend_status
printer.active = active
if hasattr(printer, 'last_checked'):
printer.last_checked = current_time
live_status_data.append({
"id": printer.id,
"name": printer.name,
"model": printer.model or 'Unbekanntes Modell',
"location": printer.location or 'Unbekannter Standort',
"mac_address": printer.mac_address,
"plug_ip": printer.plug_ip,
"status": frontend_status,
"active": active,
"ip_address": printer.plug_ip if printer.plug_ip else getattr(printer, 'ip_address', None),
"created_at": printer.created_at.isoformat() if printer.created_at else current_time.isoformat(),
"last_checked": current_time.isoformat(),
"is_online": frontend_status == "available",
"status_changed": True # Für Frontend-Animationen
})
# Änderungen in Datenbank speichern
try:
db_session.commit()
except Exception as e:
printers_logger.warning(f"Fehler beim Speichern der Live-Status-Updates: {str(e)}")
# In Session-Cache speichern
session[cache_key] = live_status_data
session[f"{cache_key}_timestamp"] = current_time.isoformat()
session.permanent = True
# Online-Drucker-Cache invalidieren
online_cache_key = f"online_printers_{current_user.id}"
if online_cache_key in session:
del session[online_cache_key]
del session[f"{online_cache_key}_timestamp"]
db_session.close()
printers_logger.info(f"Live-Status aktualisiert: {online_count} von {len(live_status_data)} Drucker online")
return jsonify({
"printers": live_status_data,
"count": len(live_status_data),
"online_count": online_count,
"offline_count": len(live_status_data) - online_count,
"cached": False,
"timestamp": current_time.isoformat(),
"next_update": 15
})
except Exception as e:
db_session.rollback()
db_session.close()
printers_logger.error(f"Fehler beim Live-Status-Check: {str(e)}")
return jsonify({
"error": f"Fehler beim Live-Status-Check: {str(e)}",
"printers": []
}), 500
@app.route("/api/printers/status/summary", methods=["GET"])
@login_required
def get_printer_status_summary():
"""Gibt eine Zusammenfassung des Drucker-Status zurück - sehr schnell."""
db_session = get_db_session()
try:
# Session-Cache für Status-Zusammenfassung
cache_key = f"printer_summary_{current_user.id}"
cached_data = session.get(cache_key)
cache_timestamp = session.get(f"{cache_key}_timestamp")
# Cache ist 60 Sekunden gültig
if cached_data and cache_timestamp:
cache_age = (datetime.now() - datetime.fromisoformat(cache_timestamp)).total_seconds()
if cache_age < 60:
return jsonify({
**cached_data,
"cached": True,
"cache_age": cache_age
})
# Status-Zusammenfassung aus Datenbank
total_printers = db_session.query(Printer).count()
online_printers = db_session.query(Printer).filter(
Printer.status.in_(["available", "online", "idle"]),
Printer.active == True
).count()
offline_printers = total_printers - online_printers
# Letzte Aktualisierung ermitteln
last_checked = db_session.query(func.max(Printer.last_checked)).scalar()
summary_data = {
"total": total_printers,
"online": online_printers,
"offline": offline_printers,
"percentage_online": round((online_printers / total_printers * 100) if total_printers > 0 else 0, 1),
"last_checked": last_checked.isoformat() if last_checked else None,
"timestamp": datetime.now().isoformat()
}
# In Session-Cache speichern
session[cache_key] = summary_data
session[f"{cache_key}_timestamp"] = datetime.now().isoformat()
session.permanent = True
db_session.close()
return jsonify({
**summary_data,
"cached": False
})
except Exception as e:
db_session.close()
return jsonify({
"error": f"Fehler beim Laden der Status-Zusammenfassung: {str(e)}",
"total": 0,
"online": 0,
"offline": 0
}), 500
# Session-Cache-Management
@app.route("/api/printers/cache/clear", methods=["POST"])
@login_required
def clear_printer_cache():
"""Löscht den Drucker-Cache für den aktuellen Benutzer."""
try:
cache_keys = [
f"online_printers_{current_user.id}",
f"live_printer_status_{current_user.id}",
f"printer_summary_{current_user.id}"
]
cleared_count = 0
for key in cache_keys:
if key in session:
del session[key]
cleared_count += 1
timestamp_key = f"{key}_timestamp"
if timestamp_key in session:
del session[timestamp_key]
return jsonify({
"message": f"Cache erfolgreich geleert ({cleared_count} Einträge)",
"cleared_keys": cleared_count
})
except Exception as e:
return jsonify({
"error": f"Fehler beim Löschen des Cache: {str(e)}"
}), 500
# ===== STARTUP UND MAIN =====
if __name__ == "__main__":
import sys
@@ -3282,4 +3583,4 @@ if __name__ == "__main__":
except Exception as e:
app_logger.error(f"Fehler beim Starten der Anwendung: {str(e)}")
sys.exit(1)
sys.exit(1)