📚 Improved backend structure & logs management 🎉

This commit is contained in:
2025-06-11 09:29:15 +02:00
parent 4813e6cc70
commit 6fe5882e7d
17 changed files with 523 additions and 3 deletions

View File

@@ -423,6 +423,342 @@ def stats_page():
"""Zeigt die Statistiken-Seite an"""
return render_template("stats.html", title="Statistiken")
# ===== API-ENDPUNKTE FÜR FRONTEND-KOMPATIBILITÄT =====
@app.route("/api/jobs", methods=["GET"])
@login_required
def api_get_jobs():
"""API-Endpunkt für Jobs - leitet an Jobs-Blueprint weiter"""
from blueprints.jobs import get_jobs
return get_jobs()
@app.route("/api/jobs", methods=["POST"])
@login_required
def api_create_job():
"""API-Endpunkt für Job-Erstellung - leitet an Jobs-Blueprint weiter"""
from blueprints.jobs import create_job
return create_job()
@app.route("/api/jobs/<int:job_id>", methods=["GET"])
@login_required
def api_get_job(job_id):
"""API-Endpunkt für einzelnen Job - leitet an Jobs-Blueprint weiter"""
from blueprints.jobs import get_job
return get_job(job_id)
@app.route("/api/jobs/<int:job_id>", methods=["PUT"])
@login_required
def api_update_job(job_id):
"""API-Endpunkt für Job-Update - leitet an Jobs-Blueprint weiter"""
from blueprints.jobs import update_job
return update_job(job_id)
@app.route("/api/jobs/<int:job_id>", methods=["DELETE"])
@login_required
def api_delete_job(job_id):
"""API-Endpunkt für Job-Löschung - leitet an Jobs-Blueprint weiter"""
from blueprints.jobs import delete_job
return delete_job(job_id)
@app.route("/api/jobs/active", methods=["GET"])
@login_required
def api_get_active_jobs():
"""API-Endpunkt für aktive Jobs - leitet an Jobs-Blueprint weiter"""
from blueprints.jobs import get_active_jobs
return get_active_jobs()
@app.route("/api/jobs/current", methods=["GET"])
@login_required
def api_get_current_job():
"""API-Endpunkt für aktuellen Job - leitet an Jobs-Blueprint weiter"""
from blueprints.jobs import get_current_job
return get_current_job()
@app.route("/api/jobs/<int:job_id>/start", methods=["POST"])
@login_required
def api_start_job(job_id):
"""API-Endpunkt für Job-Start - leitet an Jobs-Blueprint weiter"""
from blueprints.jobs import start_job
return start_job(job_id)
@app.route("/api/jobs/<int:job_id>/pause", methods=["POST"])
@login_required
def api_pause_job(job_id):
"""API-Endpunkt für Job-Pause - leitet an Jobs-Blueprint weiter"""
from blueprints.jobs import pause_job
return pause_job(job_id)
@app.route("/api/jobs/<int:job_id>/resume", methods=["POST"])
@login_required
def api_resume_job(job_id):
"""API-Endpunkt für Job-Resume - leitet an Jobs-Blueprint weiter"""
from blueprints.jobs import resume_job
return resume_job(job_id)
@app.route("/api/jobs/<int:job_id>/finish", methods=["POST"])
@login_required
def api_finish_job(job_id):
"""API-Endpunkt für Job-Finish - leitet an Jobs-Blueprint weiter"""
from blueprints.jobs import finish_job
return finish_job(job_id)
@app.route("/api/printers", methods=["GET"])
@login_required
def api_get_printers():
"""API-Endpunkt für Drucker-Liste"""
try:
from models import get_db_session, Printer
db_session = get_db_session()
printers = db_session.query(Printer).filter(Printer.active == True).all()
printer_list = []
for printer in printers:
printer_dict = {
"id": printer.id,
"name": printer.name,
"model": printer.model,
"location": printer.location,
"status": printer.status,
"ip_address": printer.ip_address,
"plug_ip": printer.plug_ip,
"active": printer.active,
"last_checked": printer.last_checked.isoformat() if printer.last_checked else None
}
printer_list.append(printer_dict)
db_session.close()
app_logger.info(f"✅ API: {len(printer_list)} Drucker abgerufen")
return jsonify({"printers": printer_list})
except Exception as e:
app_logger.error(f"❌ API-Fehler beim Abrufen der Drucker: {str(e)}")
return jsonify({"error": "Fehler beim Laden der Drucker", "details": str(e)}), 500
@app.route("/api/printers/status", methods=["GET"])
@login_required
def api_get_printer_status():
"""API-Endpunkt für Drucker-Status"""
try:
from models import get_db_session, Printer
from utils.tapo_controller import tapo_controller
db_session = get_db_session()
printers = db_session.query(Printer).filter(Printer.active == True).all()
status_list = []
for printer in printers:
# Tapo-Steckdosen-Status prüfen
if printer.plug_ip:
try:
reachable, plug_status = tapo_controller.check_outlet_status(
printer.plug_ip,
printer_id=printer.id
)
status_dict = {
"id": printer.id,
"name": printer.name,
"status": printer.status,
"plug_status": plug_status,
"plug_reachable": reachable,
"plug_ip": printer.plug_ip,
"location": printer.location
}
except Exception as e:
app_logger.warning(f"⚠️ Fehler bei Steckdosen-Status für {printer.name}: {str(e)}")
status_dict = {
"id": printer.id,
"name": printer.name,
"status": "error",
"plug_status": "unknown",
"plug_reachable": False,
"plug_ip": printer.plug_ip,
"location": printer.location,
"error": str(e)
}
else:
status_dict = {
"id": printer.id,
"name": printer.name,
"status": printer.status,
"plug_status": "no_plug",
"plug_reachable": False,
"plug_ip": None,
"location": printer.location
}
status_list.append(status_dict)
db_session.close()
app_logger.info(f"✅ API: Status für {len(status_list)} Drucker abgerufen")
return jsonify({"printers": status_list})
except Exception as e:
app_logger.error(f"❌ API-Fehler beim Abrufen des Drucker-Status: {str(e)}")
return jsonify({"error": "Fehler beim Laden des Drucker-Status", "details": str(e)}), 500
# ===== SESSION-API-ENDPUNKTE =====
@app.route("/api/session/status", methods=["GET"])
@login_required
def api_session_status():
"""API-Endpunkt für Session-Status"""
try:
last_activity = session.get('last_activity')
if last_activity:
last_activity_time = datetime.fromisoformat(last_activity)
time_since_activity = (datetime.now() - last_activity_time).total_seconds()
time_left_seconds = max(0, SESSION_LIFETIME.total_seconds() - time_since_activity)
else:
time_left_seconds = SESSION_LIFETIME.total_seconds()
return jsonify({
"success": True,
"user": {
"id": current_user.id,
"email": current_user.email,
"name": current_user.name,
"is_admin": current_user.is_admin
},
"session": {
"time_left_seconds": int(time_left_seconds),
"max_inactive_minutes": int(SESSION_LIFETIME.total_seconds() / 60),
"last_activity": last_activity or datetime.now().isoformat()
}
})
except Exception as e:
app_logger.error(f"❌ Session-Status-Fehler: {str(e)}")
return jsonify({"success": False, "error": str(e)}), 500
@app.route("/api/session/heartbeat", methods=["POST"])
@login_required
def api_session_heartbeat():
"""API-Endpunkt für Session-Heartbeat"""
try:
# Session-Aktivität aktualisieren
session['last_activity'] = datetime.now().isoformat()
session.permanent = True
# Verbleibende Zeit berechnen
time_left_seconds = SESSION_LIFETIME.total_seconds()
return jsonify({
"success": True,
"time_left_seconds": int(time_left_seconds),
"timestamp": datetime.now().isoformat()
})
except Exception as e:
app_logger.error(f"❌ Session-Heartbeat-Fehler: {str(e)}")
return jsonify({"success": False, "error": str(e)}), 500
@app.route("/api/session/extend", methods=["POST"])
@login_required
def api_session_extend():
"""API-Endpunkt für Session-Verlängerung"""
try:
data = request.get_json() or {}
extend_minutes = data.get('extend_minutes', 30)
# Session verlängern
session['last_activity'] = datetime.now().isoformat()
session.permanent = True
return jsonify({
"success": True,
"extended_minutes": extend_minutes,
"new_expiry": (datetime.now() + SESSION_LIFETIME).isoformat()
})
except Exception as e:
app_logger.error(f"❌ Session-Extend-Fehler: {str(e)}")
return jsonify({"success": False, "error": str(e)}), 500
@app.route("/api/jobs/recent", methods=["GET"])
@login_required
def api_get_recent_jobs():
"""API-Endpunkt für kürzlich erstellte Jobs"""
try:
from models import get_db_session, Job
db_session = get_db_session()
# Letzte 10 Jobs des Benutzers (oder alle für Admin)
query = db_session.query(Job).order_by(Job.created_at.desc())
if not current_user.is_admin:
query = query.filter(Job.user_id == current_user.id)
recent_jobs = query.limit(10).all()
job_list = []
for job in recent_jobs:
job_dict = {
"id": job.id,
"name": job.name,
"status": job.status,
"created_at": job.created_at.isoformat() if job.created_at else None,
"start_at": job.start_at.isoformat() if job.start_at else None,
"duration_minutes": job.duration_minutes,
"printer_name": job.printer.name if job.printer else "Unbekannt"
}
job_list.append(job_dict)
db_session.close()
app_logger.info(f"✅ API: {len(job_list)} kürzliche Jobs abgerufen")
return jsonify({"jobs": job_list})
except Exception as e:
app_logger.error(f"❌ API-Fehler beim Abrufen kürzlicher Jobs: {str(e)}")
return jsonify({"error": "Fehler beim Laden kürzlicher Jobs", "details": str(e)}), 500
@app.route("/api/stats", methods=["GET"])
@login_required
def api_get_stats():
"""API-Endpunkt für System-Statistiken"""
try:
from models import get_db_session, Job, Printer
db_session = get_db_session()
# Grundlegende Statistiken
total_jobs = db_session.query(Job).count()
active_jobs = db_session.query(Job).filter(Job.status.in_(["scheduled", "running"])).count()
completed_jobs = db_session.query(Job).filter(Job.status == "finished").count()
total_printers = db_session.query(Printer).filter(Printer.active == True).count()
# Benutzer-spezifische Statistiken
if not current_user.is_admin:
user_jobs = db_session.query(Job).filter(Job.user_id == current_user.id).count()
user_active_jobs = db_session.query(Job).filter(
Job.user_id == current_user.id,
Job.status.in_(["scheduled", "running"])
).count()
else:
user_jobs = total_jobs
user_active_jobs = active_jobs
db_session.close()
stats = {
"total_jobs": total_jobs,
"active_jobs": active_jobs,
"completed_jobs": completed_jobs,
"total_printers": total_printers,
"user_jobs": user_jobs,
"user_active_jobs": user_active_jobs,
"timestamp": datetime.now().isoformat()
}
app_logger.info(f"✅ API: Statistiken abgerufen")
return jsonify(stats)
except Exception as e:
app_logger.error(f"❌ API-Fehler beim Abrufen der Statistiken: {str(e)}")
return jsonify({"error": "Fehler beim Laden der Statistiken", "details": str(e)}), 500
# Statische Seiten
@app.route("/privacy")
def privacy():