From 89b085dec99ff8a44854686f6bcc587e8f61fc57 Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Thu, 29 May 2025 12:22:02 +0200 Subject: [PATCH] "feat: Update job templates in frontend" --- backend/app/app.py | 97 +++++++++++++++++--------- backend/app/templates/jobs.html | 116 ++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 30 deletions(-) diff --git a/backend/app/app.py b/backend/app/app.py index b9ca101f..f3d73249 100644 --- a/backend/app/app.py +++ b/backend/app/app.py @@ -1,40 +1,23 @@ import os import sys import logging -import threading -import time -import subprocess -import socket -import json -import secrets -from concurrent.futures import ThreadPoolExecutor, as_completed +import atexit from datetime import datetime, timedelta -from functools import wraps -from typing import Optional, Dict, List, Tuple, Any, Union - -from flask import Flask, render_template, request, redirect, url_for, flash, jsonify, session, send_file, Response, make_response -from flask_login import LoginManager, login_user, logout_user, login_required, current_user, UserMixin -from werkzeug.security import check_password_hash, generate_password_hash +from flask import Flask, render_template, request, jsonify, redirect, url_for, flash, send_file, abort, session +from flask_login import LoginManager, login_user, logout_user, login_required, current_user from werkzeug.utils import secure_filename -import sqlalchemy.exc -import sqlalchemy -from sqlalchemy.orm import joinedload +from sqlalchemy.orm import sessionmaker, joinedload from sqlalchemy import func -from PyP100 import PyP110 -from flask_wtf.csrf import CSRFProtect -from flask_wtf.csrf import CSRFError -from config.settings import ( - SECRET_KEY, TAPO_USERNAME, TAPO_PASSWORD, PRINTERS, - FLASK_HOST, FLASK_PORT, FLASK_DEBUG, SESSION_LIFETIME, - SCHEDULER_INTERVAL, SCHEDULER_ENABLED, get_ssl_context, FLASK_FALLBACK_PORT, - SSL_ENABLED, SSL_CERT_PATH, SSL_KEY_PATH -) -from utils.logging_config import setup_logging, get_logger, log_startup_info, debug_request, debug_response, measure_execution_time -from models import User, Printer, Job, Stats, GuestRequest, UserPermission, Notification, get_db_session, init_database, create_initial_admin -from utils.job_scheduler import scheduler -from utils.template_helpers import register_template_helpers -from utils.database_utils import backup_manager, database_monitor, maintenance_scheduler +# Lokale Imports +from models import init_database, create_initial_admin, User, Printer, Job, Stats, SystemLog, get_db_session, GuestRequest, UserPermission, Notification +from utils.logging_config import setup_logging, get_logger +from utils.printer_status import check_printer_status, check_multiple_printers_status +from utils.decorators import measure_execution_time +from utils.file_manager import FileManager +from utils.job_scheduler import JobScheduler, get_job_scheduler +from utils.queue_manager import start_queue_manager, stop_queue_manager, get_queue_manager +from config.settings import SECRET_KEY, UPLOAD_FOLDER, ALLOWED_EXTENSIONS, ENVIRONMENT # Blueprints importieren from blueprints.guest import guest_blueprint @@ -4067,6 +4050,45 @@ def mark_all_notifications_read(): # ===== ENDE BENACHRICHTIGUNGS-API-ENDPUNKTE ===== +# ===== QUEUE-MANAGER-API-ENDPUNKTE ===== + +@app.route('/api/queue/status', methods=['GET']) +@login_required +def get_queue_status(): + """Gibt den aktuellen Status der Drucker-Warteschlangen zurück.""" + try: + queue_manager = get_queue_manager() + status = queue_manager.get_queue_status() + + return jsonify({ + "success": True, + "queue_status": status + }) + + except Exception as e: + app_logger.error(f"Fehler beim Abrufen des Queue-Status: {str(e)}") + return jsonify({ + "success": False, + "message": f"Fehler beim Abrufen des Queue-Status: {str(e)}" + }), 500 + +@app.route('/api/queue/check-now', methods=['POST']) +@login_required +def trigger_queue_check(): + """Triggert eine sofortige Überprüfung der Warteschlangen.""" + try: + # Bestehende check_waiting_jobs API verwenden + return check_waiting_jobs() + + except Exception as e: + app_logger.error(f"Fehler beim manuellen Queue-Check: {str(e)}") + return jsonify({ + "success": False, + "message": f"Fehler beim manuellen Queue-Check: {str(e)}" + }), 500 + +# ===== ENDE QUEUE-MANAGER-API-ENDPUNKTE ===== + # ===== STARTUP UND MAIN ===== if __name__ == "__main__": import sys @@ -4082,6 +4104,21 @@ if __name__ == "__main__": # Template-Hilfsfunktionen registrieren register_template_helpers(app) + # Queue-Manager für automatische Drucker-Überwachung starten + try: + queue_manager = start_queue_manager() + app_logger.info("✅ Printer Queue Manager erfolgreich gestartet") + + # Shutdown-Handler registrieren + def cleanup_queue_manager(): + app_logger.info("🔄 Beende Queue Manager...") + stop_queue_manager() + + atexit.register(cleanup_queue_manager) + + except Exception as e: + app_logger.error(f"❌ Fehler beim Starten des Queue-Managers: {str(e)}") + # Scheduler starten (falls aktiviert) if SCHEDULER_ENABLED: try: diff --git a/backend/app/templates/jobs.html b/backend/app/templates/jobs.html index 7982815a..ac1ca234 100644 --- a/backend/app/templates/jobs.html +++ b/backend/app/templates/jobs.html @@ -26,6 +26,9 @@

Neue Reservierung anlegen

+ +
+
@@ -569,6 +572,119 @@ function checkWaitingJobs() { }); } +// Queue-Status anzeigen (neue Funktion) +function loadQueueStatus() { + fetch('/api/queue/status') + .then(response => response.json()) + .then(data => { + if (data.success && data.queue_status) { + updateQueueStatusDisplay(data.queue_status); + } + }) + .catch(error => { + console.error('Fehler beim Laden des Queue-Status:', error); + }); +} + +// Queue-Status-Anzeige aktualisieren (neue Funktion) +function updateQueueStatusDisplay(queueStatus) { + const statusContainer = document.getElementById('queue-status-info'); + if (!statusContainer) return; + + const { waiting_jobs, online_printers, total_printers, queue_manager_running } = queueStatus; + + let statusHtml = ''; + + if (waiting_jobs > 0) { + statusHtml = ` +
+
+
+ + + +
+
+

+ 🔄 WARTESCHLANGEN-MODUS AKTIV +

+

+ ${waiting_jobs} Job${waiting_jobs === 1 ? '' : 's'} warten auf offline Drucker +

+

+ 🟢 ${online_printers} von ${total_printers} Druckern online | + ⏰ System prüft alle 2 Minuten automatisch +

+ ${queue_manager_running ? + 'Überwachung aktiv' : + 'Überwachung inaktiv' + } +
+ +
+
+ `; + } else if (online_printers === total_printers && total_printers > 0) { + statusHtml = ` +
+
+
+ + + +
+
+

+ ✅ ALLE DRUCKER ONLINE +

+

+ Alle ${total_printers} Drucker sind verfügbar - Jobs starten sofort +

+
+
+
+ `; + } + + statusContainer.innerHTML = statusHtml; +} + +// Manuelle Queue-Überprüfung triggern (neue Funktion) +function triggerQueueCheck() { + const button = event.target; + const originalText = button.textContent; + + button.disabled = true; + button.textContent = 'Prüfe...'; + + fetch('/api/queue/check-now', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + } + }) + .then(response => response.json()) + .then(data => { + if (data.updated_jobs && data.updated_jobs.length > 0) { + showNotification(`🎉 ${data.updated_jobs.length} Job(s) aktiviert!`, 'success'); + loadActiveJobs(); + } else { + showNotification('✓ Queue-Check abgeschlossen - keine neuen Updates', 'info'); + } + loadQueueStatus(); // Status neu laden + }) + .catch(error => { + console.error('Fehler beim manuellen Queue-Check:', error); + showNotification('Fehler beim Queue-Check', 'error'); + }) + .finally(() => { + button.disabled = false; + button.textContent = originalText; + }); +} + // Initialisierung des Formulars für neue Jobs function initNewJobForm() { const form = document.getElementById('newJobForm');