feat: Einführung neuer API-Endpunkte zur Verwaltung von Benutzereinstellungen und Druckerstatus. Implementierung von Funktionen zur Überprüfung wartender Jobs und zur Aktualisierung aller Drucker. Verbesserung der Benutzeroberfläche durch optimierte Ladeanzeigen und Warnungen für Offline-Drucker. Anpassungen in den Templates zur Unterstützung neuer Funktionen und zur Verbesserung der Benutzererfahrung.
This commit is contained in:
@@ -773,6 +773,47 @@ def user_update_settings():
|
||||
finally:
|
||||
db_session.close()
|
||||
|
||||
@app.route("/api/user/settings", methods=["GET"])
|
||||
@login_required
|
||||
def get_user_settings():
|
||||
"""Holt die aktuellen Benutzereinstellungen"""
|
||||
try:
|
||||
# Einstellungen aus Session oder Datenbank laden
|
||||
user_settings = session.get('user_settings', {})
|
||||
|
||||
# Standard-Einstellungen falls keine vorhanden
|
||||
default_settings = {
|
||||
"theme": "system",
|
||||
"reduced_motion": False,
|
||||
"contrast": "normal",
|
||||
"notifications": {
|
||||
"new_jobs": True,
|
||||
"job_updates": True,
|
||||
"system": True,
|
||||
"email": False
|
||||
},
|
||||
"privacy": {
|
||||
"activity_logs": True,
|
||||
"two_factor": False,
|
||||
"auto_logout": 60
|
||||
}
|
||||
}
|
||||
|
||||
# Merge mit Standard-Einstellungen
|
||||
settings = {**default_settings, **user_settings}
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"settings": settings
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
user_logger.error(f"Fehler beim Laden der Benutzereinstellungen: {str(e)}")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": "Fehler beim Laden der Einstellungen"
|
||||
}), 500
|
||||
|
||||
@app.route("/user/change-password", methods=["POST"])
|
||||
@login_required
|
||||
def user_change_password():
|
||||
@@ -1461,6 +1502,59 @@ def get_job(job_id):
|
||||
db_session.close()
|
||||
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||
|
||||
@app.route('/api/jobs/check-waiting', methods=['POST'])
|
||||
@login_required
|
||||
def check_waiting_jobs():
|
||||
"""Überprüft wartende Jobs und startet sie, wenn Drucker online gehen."""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
|
||||
# Alle wartenden Jobs finden
|
||||
waiting_jobs = db_session.query(Job).filter(
|
||||
Job.status == "waiting_for_printer"
|
||||
).all()
|
||||
|
||||
if not waiting_jobs:
|
||||
db_session.close()
|
||||
return jsonify({
|
||||
"message": "Keine wartenden Jobs gefunden",
|
||||
"updated_jobs": []
|
||||
})
|
||||
|
||||
updated_jobs = []
|
||||
|
||||
for job in waiting_jobs:
|
||||
# Drucker-Status prüfen
|
||||
printer = db_session.query(Printer).get(job.printer_id)
|
||||
if printer and printer.plug_ip:
|
||||
status, active = check_printer_status(printer.plug_ip)
|
||||
|
||||
if status == "online" and active:
|
||||
# Drucker ist jetzt online - Job kann geplant werden
|
||||
job.status = "scheduled"
|
||||
updated_jobs.append({
|
||||
"id": job.id,
|
||||
"name": job.name,
|
||||
"printer_name": printer.name,
|
||||
"status": "scheduled"
|
||||
})
|
||||
|
||||
jobs_logger.info(f"Job {job.id} von 'waiting_for_printer' zu 'scheduled' geändert - Drucker {printer.name} ist online")
|
||||
|
||||
if updated_jobs:
|
||||
db_session.commit()
|
||||
|
||||
db_session.close()
|
||||
|
||||
return jsonify({
|
||||
"message": f"{len(updated_jobs)} Jobs aktualisiert",
|
||||
"updated_jobs": updated_jobs
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
jobs_logger.error(f"Fehler beim Überprüfen wartender Jobs: {str(e)}")
|
||||
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||
|
||||
@app.route('/api/jobs/active', methods=['GET'])
|
||||
@login_required
|
||||
def get_active_jobs():
|
||||
@@ -1548,6 +1642,15 @@ def create_job():
|
||||
db_session.close()
|
||||
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||
|
||||
# Prüfen, ob der Drucker online ist
|
||||
printer_status, printer_active = check_printer_status(printer.plug_ip if printer.plug_ip else "")
|
||||
|
||||
# Status basierend auf Drucker-Verfügbarkeit setzen
|
||||
if printer_status == "online" and printer_active:
|
||||
job_status = "scheduled"
|
||||
else:
|
||||
job_status = "waiting_for_printer"
|
||||
|
||||
# Neuen Job erstellen
|
||||
new_job = Job(
|
||||
name=name,
|
||||
@@ -1556,7 +1659,7 @@ def create_job():
|
||||
owner_id=current_user.id,
|
||||
start_at=start_at,
|
||||
end_at=end_at,
|
||||
status="scheduled",
|
||||
status=job_status,
|
||||
file_path=file_path,
|
||||
duration_minutes=duration_minutes
|
||||
)
|
||||
@@ -3526,6 +3629,244 @@ def clear_printer_cache():
|
||||
"error": f"Fehler beim Löschen des Cache: {str(e)}"
|
||||
}), 500
|
||||
|
||||
# ===== FEHLENDE ADMIN-API-ENDPUNKTE =====
|
||||
|
||||
@app.route('/api/admin/cache/clear', methods=['POST'])
|
||||
@admin_required
|
||||
def clear_admin_cache():
|
||||
"""Leert den System-Cache"""
|
||||
try:
|
||||
# Cache-Verzeichnisse leeren
|
||||
import shutil
|
||||
import os
|
||||
|
||||
cache_dirs = [
|
||||
os.path.join(os.path.dirname(__file__), 'static', 'cache'),
|
||||
os.path.join(os.path.dirname(__file__), '__pycache__'),
|
||||
]
|
||||
|
||||
cleared_items = 0
|
||||
for cache_dir in cache_dirs:
|
||||
if os.path.exists(cache_dir):
|
||||
for item in os.listdir(cache_dir):
|
||||
item_path = os.path.join(cache_dir, item)
|
||||
try:
|
||||
if os.path.isfile(item_path):
|
||||
os.unlink(item_path)
|
||||
cleared_items += 1
|
||||
elif os.path.isdir(item_path):
|
||||
shutil.rmtree(item_path)
|
||||
cleared_items += 1
|
||||
except Exception as e:
|
||||
app_logger.warning(f"Konnte Cache-Element nicht löschen: {item_path} - {str(e)}")
|
||||
|
||||
# Modell-Cache leeren
|
||||
from models import clear_cache
|
||||
clear_cache()
|
||||
|
||||
app_logger.info(f"System-Cache geleert: {cleared_items} Elemente entfernt")
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": f"Cache erfolgreich geleert ({cleared_items} Elemente)",
|
||||
"cleared_items": cleared_items
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim Leeren des Cache: {str(e)}")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Fehler beim Leeren des Cache: {str(e)}"
|
||||
}), 500
|
||||
|
||||
@app.route('/api/admin/system/restart', methods=['POST'])
|
||||
@admin_required
|
||||
def restart_admin_system():
|
||||
"""Startet das System neu (nur für Entwicklung)"""
|
||||
try:
|
||||
import os
|
||||
import signal
|
||||
|
||||
app_logger.warning("System-Neustart durch Admin angefordert")
|
||||
|
||||
# In Produktionsumgebung sollte dies anders gehandhabt werden
|
||||
if os.environ.get('FLASK_ENV') == 'development':
|
||||
# Graceful shutdown für Development
|
||||
def shutdown_server():
|
||||
func = request.environ.get('werkzeug.server.shutdown')
|
||||
if func is None:
|
||||
raise RuntimeError('Not running with the Werkzeug Server')
|
||||
func()
|
||||
|
||||
shutdown_server()
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "System wird neugestartet..."
|
||||
})
|
||||
else:
|
||||
# Für Produktion - Signal an Parent Process
|
||||
os.kill(os.getpid(), signal.SIGTERM)
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Neustart-Signal gesendet"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim System-Neustart: {str(e)}")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Fehler beim Neustart: {str(e)}"
|
||||
}), 500
|
||||
|
||||
@app.route('/api/admin/printers/update-all', methods=['POST'])
|
||||
@admin_required
|
||||
def update_all_printers():
|
||||
"""Aktualisiert den Status aller Drucker"""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
printers = db_session.query(Printer).all()
|
||||
|
||||
updated_printers = []
|
||||
|
||||
for printer in printers:
|
||||
if printer.plug_ip:
|
||||
try:
|
||||
status, active = check_printer_status(printer.plug_ip)
|
||||
old_status = printer.status
|
||||
|
||||
printer.update_status(status, active)
|
||||
|
||||
updated_printers.append({
|
||||
"id": printer.id,
|
||||
"name": printer.name,
|
||||
"old_status": old_status,
|
||||
"new_status": status,
|
||||
"active": active
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
printers_logger.warning(f"Fehler beim Aktualisieren von Drucker {printer.name}: {str(e)}")
|
||||
|
||||
db_session.commit()
|
||||
db_session.close()
|
||||
|
||||
app_logger.info(f"Status von {len(updated_printers)} Druckern aktualisiert")
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": f"Status von {len(updated_printers)} Druckern aktualisiert",
|
||||
"updated_printers": updated_printers
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim Aktualisieren aller Drucker: {str(e)}")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Fehler beim Aktualisieren: {str(e)}"
|
||||
}), 500
|
||||
|
||||
@app.route('/api/admin/settings', methods=['GET'])
|
||||
@admin_required
|
||||
def get_admin_settings():
|
||||
"""Holt die aktuellen Admin-Einstellungen"""
|
||||
try:
|
||||
from config.settings import (
|
||||
FLASK_HOST, FLASK_PORT, FLASK_DEBUG, SESSION_LIFETIME,
|
||||
SCHEDULER_INTERVAL, SCHEDULER_ENABLED, SSL_ENABLED
|
||||
)
|
||||
|
||||
settings = {
|
||||
"server": {
|
||||
"host": FLASK_HOST,
|
||||
"port": FLASK_PORT,
|
||||
"debug": FLASK_DEBUG,
|
||||
"ssl_enabled": SSL_ENABLED
|
||||
},
|
||||
"session": {
|
||||
"lifetime_minutes": SESSION_LIFETIME.total_seconds() / 60
|
||||
},
|
||||
"scheduler": {
|
||||
"interval_seconds": SCHEDULER_INTERVAL,
|
||||
"enabled": SCHEDULER_ENABLED
|
||||
}
|
||||
}
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"settings": settings
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim Laden der Admin-Einstellungen: {str(e)}")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Fehler beim Laden der Einstellungen: {str(e)}"
|
||||
}), 500
|
||||
|
||||
@app.route('/api/admin/settings', methods=['POST'])
|
||||
@admin_required
|
||||
def update_admin_settings():
|
||||
"""Aktualisiert die Admin-Einstellungen"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
if not data:
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": "Keine Daten empfangen"
|
||||
}), 400
|
||||
|
||||
# Hier würden normalerweise die Einstellungen in einer Konfigurationsdatei gespeichert
|
||||
# Für diese Demo loggen wir nur die Änderungen
|
||||
app_logger.info(f"Admin-Einstellungen aktualisiert: {data}")
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Einstellungen erfolgreich aktualisiert"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim Aktualisieren der Admin-Einstellungen: {str(e)}")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Fehler beim Aktualisieren: {str(e)}"
|
||||
}), 500
|
||||
|
||||
@app.route('/api/admin/logs/export', methods=['GET'])
|
||||
@admin_required
|
||||
def export_admin_logs():
|
||||
"""Exportiert System-Logs"""
|
||||
try:
|
||||
import os
|
||||
import zipfile
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
|
||||
# Temporäre ZIP-Datei erstellen
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
zip_filename = f"myp_logs_{datetime.now().strftime('%Y%m%d_%H%M%S')}.zip"
|
||||
zip_path = os.path.join(temp_dir, zip_filename)
|
||||
|
||||
log_dir = os.path.join(os.path.dirname(__file__), 'logs')
|
||||
|
||||
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
||||
for root, dirs, files in os.walk(log_dir):
|
||||
for file in files:
|
||||
if file.endswith('.log'):
|
||||
file_path = os.path.join(root, file)
|
||||
arcname = os.path.relpath(file_path, log_dir)
|
||||
zipf.write(file_path, arcname)
|
||||
|
||||
app_logger.info("System-Logs exportiert")
|
||||
return send_file(zip_path, as_attachment=True, download_name=zip_filename)
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim Exportieren der Logs: {str(e)}")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Fehler beim Exportieren: {str(e)}"
|
||||
}), 500
|
||||
|
||||
# ===== ENDE FEHLENDE ADMIN-API-ENDPUNKTE =====
|
||||
|
||||
|
||||
# ===== STARTUP UND MAIN =====
|
||||
if __name__ == "__main__":
|
||||
|
Reference in New Issue
Block a user