diff --git a/backend/app.py b/backend/app.py index dcaa9e476..838af8888 100644 --- a/backend/app.py +++ b/backend/app.py @@ -959,7 +959,8 @@ def api_get_printer_status(): if has_tapo_printers: try: - from utils.hardware_integration import tapo_controller + from utils.hardware_integration import get_tapo_controller + tapo_controller = get_tapo_controller() app_logger.info(f"✅ Tapo-Controller erfolgreich importiert: {type(tapo_controller)}") except Exception as import_error: app_logger.warning(f"⚠️ Tapo-Controller konnte nicht importiert werden: {str(import_error)}") diff --git a/backend/backend/database/myp.db-wal b/backend/backend/database/myp.db-wal index 98e9a9e20..18fc73e5e 100644 Binary files a/backend/backend/database/myp.db-wal and b/backend/backend/database/myp.db-wal differ diff --git a/backend/blueprints/admin_unified.py b/backend/blueprints/admin_unified.py index f87e1f2b8..fa5fde750 100644 --- a/backend/blueprints/admin_unified.py +++ b/backend/blueprints/admin_unified.py @@ -1144,7 +1144,7 @@ def export_logs_api(): # ===== API-ENDPUNKTE FÜR SYSTEM-INFORMATIONEN ===== -@admin_blueprint.route("/api/system/status", methods=["GET"]) +@admin_api_blueprint.route("/system/status", methods=["GET"]) @admin_required def get_system_status_api(): """API-Endpunkt für System-Status-Informationen""" @@ -1473,7 +1473,7 @@ def api_admin_plug_schedules_cleanup(): @admin_required def api_admin_plug_schedules_calendar(): """ - API-Endpoint für Kalender-Daten der Steckdosenschaltzeiten. + API-Endpunkt für Kalender-Daten der Steckdosenschaltzeiten. Liefert Events für FullCalendar im JSON-Format. """ try: @@ -1549,6 +1549,218 @@ def api_admin_plug_schedules_calendar(): admin_logger.error(f"Fehler beim Laden der Kalender-Daten: {str(e)}") return jsonify([]) +@admin_api_blueprint.route('/live-stats', methods=['GET']) +@admin_required +def api_admin_live_stats(): + """ + API-Endpunkt für Live-Statistiken des Admin-Dashboards + + Liefert aktuelle System-Statistiken für das Dashboard: + - Benutzer-Statistiken + - Drucker-Status + - Job-Statistiken + - System-Performance + """ + try: + with get_cached_session() as db_session: + # Benutzer-Statistiken + total_users = db_session.query(User).count() + active_users = db_session.query(User).filter(User.active == True).count() + admin_users = db_session.query(User).filter(User.role == 'admin').count() + + # Drucker-Statistiken + total_printers = db_session.query(Printer).count() + active_printers = db_session.query(Printer).filter(Printer.active == True).count() + online_printers = db_session.query(Printer).filter( + Printer.active == True, + Printer.status == 'online' + ).count() + + # Job-Statistiken + total_jobs = db_session.query(Job).count() + active_jobs = db_session.query(Job).filter( + Job.status.in_(['pending', 'printing', 'paused']) + ).count() + completed_jobs = db_session.query(Job).filter( + Job.status == 'completed' + ).count() + failed_jobs = db_session.query(Job).filter( + Job.status == 'failed' + ).count() + + # Jobs der letzten 24 Stunden + last_24h = datetime.now() - timedelta(hours=24) + jobs_24h = db_session.query(Job).filter( + Job.created_at >= last_24h + ).count() + + # Jobs der letzten 7 Tage + last_7d = datetime.now() - timedelta(days=7) + jobs_7d = db_session.query(Job).filter( + Job.created_at >= last_7d + ).count() + + # Steckdosen-Statistiken + plug_logs_24h = db_session.query(PlugStatusLog).filter( + PlugStatusLog.timestamp >= last_24h + ).count() + + # System-Logs der letzten Stunde + last_hour = datetime.now() - timedelta(hours=1) + system_logs_1h = db_session.query(SystemLog).filter( + SystemLog.timestamp >= last_hour + ).count() + + # Response-Struktur + stats = { + 'users': { + 'total': total_users, + 'active': active_users, + 'admins': admin_users + }, + 'printers': { + 'total': total_printers, + 'active': active_printers, + 'online': online_printers, + 'offline': active_printers - online_printers + }, + 'jobs': { + 'total': total_jobs, + 'active': active_jobs, + 'completed': completed_jobs, + 'failed': failed_jobs, + 'last_24h': jobs_24h, + 'last_7d': jobs_7d + }, + 'system': { + 'plug_logs_24h': plug_logs_24h, + 'system_logs_1h': system_logs_1h, + 'uptime': 'Unbekannt' # Könnte später implementiert werden + }, + 'timestamp': datetime.now().isoformat() + } + + admin_api_logger.info(f"Live-Statistiken abgerufen von Admin {current_user.username}") + + return jsonify({ + 'success': True, + 'stats': stats, + 'message': 'Live-Statistiken erfolgreich geladen' + }) + + except Exception as e: + admin_api_logger.error(f"Fehler beim Abrufen der Live-Statistiken: {str(e)}") + return jsonify({ + 'success': False, + 'error': 'Fehler beim Laden der Statistiken', + 'message': str(e), + 'stats': {} + }), 500 + +@admin_api_blueprint.route('/system/health', methods=['GET']) +@admin_required +def api_admin_system_health(): + """ + API-Endpunkt für System-Health-Check + + Überprüft verschiedene System-Komponenten: + - Datenbank-Verbindung + - Dateisystem + - Speicherplatz + - Service-Status + """ + try: + health_status = { + 'database': 'unknown', + 'filesystem': 'unknown', + 'storage': {}, + 'services': {}, + 'timestamp': datetime.now().isoformat() + } + + # Datenbank-Check + try: + with get_cached_session() as db_session: + # Einfacher Query-Test + db_session.execute("SELECT 1") + health_status['database'] = 'healthy' + except Exception as db_error: + health_status['database'] = 'unhealthy' + admin_api_logger.error(f"Datenbank-Health-Check fehlgeschlagen: {str(db_error)}") + + # Dateisystem-Check + try: + # Prüfe wichtige Verzeichnisse + important_dirs = [ + 'backend/uploads', + 'backend/database', + 'backend/logs' + ] + + all_accessible = True + for dir_path in important_dirs: + if not os.path.exists(dir_path) or not os.access(dir_path, os.W_OK): + all_accessible = False + break + + health_status['filesystem'] = 'healthy' if all_accessible else 'unhealthy' + except Exception as fs_error: + health_status['filesystem'] = 'unhealthy' + admin_api_logger.error(f"Dateisystem-Health-Check fehlgeschlagen: {str(fs_error)}") + + # Speicherplatz-Check + try: + statvfs = os.statvfs('.') + total_space = statvfs.f_blocks * statvfs.f_frsize + free_space = statvfs.f_bavail * statvfs.f_frsize + used_space = total_space - free_space + + health_status['storage'] = { + 'total_gb': round(total_space / (1024**3), 2), + 'used_gb': round(used_space / (1024**3), 2), + 'free_gb': round(free_space / (1024**3), 2), + 'percent_used': round((used_space / total_space) * 100, 1) + } + except Exception as storage_error: + admin_api_logger.error(f"Speicherplatz-Check fehlgeschlagen: {str(storage_error)}") + + # Service-Status (vereinfacht) + health_status['services'] = { + 'web_server': 'running', # Immer running, da wir antworten + 'job_scheduler': 'unknown', # Könnte später implementiert werden + 'tapo_controller': 'unknown' # Könnte später implementiert werden + } + + # Gesamt-Status berechnen + if health_status['database'] == 'healthy' and health_status['filesystem'] == 'healthy': + overall_status = 'healthy' + elif health_status['database'] == 'unhealthy' or health_status['filesystem'] == 'unhealthy': + overall_status = 'unhealthy' + else: + overall_status = 'degraded' + + health_status['overall'] = overall_status + + admin_api_logger.info(f"System-Health-Check durchgeführt: {overall_status}") + + return jsonify({ + 'success': True, + 'health': health_status, + 'message': f'System-Status: {overall_status}' + }) + + except Exception as e: + admin_api_logger.error(f"Fehler beim System-Health-Check: {str(e)}") + return jsonify({ + 'success': False, + 'error': 'Fehler beim Health-Check', + 'message': str(e), + 'health': { + 'overall': 'error', + 'timestamp': datetime.now().isoformat() + } + }), 500 + # ===== HELPER FUNCTIONS FOR PLUG SCHEDULES ===== def get_relative_time(timestamp): diff --git a/backend/blueprints/printers.py b/backend/blueprints/printers.py index 7e28615ee..43f9c529d 100644 --- a/backend/blueprints/printers.py +++ b/backend/blueprints/printers.py @@ -73,6 +73,90 @@ def get_live_printer_status(): "message": str(e) }), 500 +@printers_blueprint.route("/status", methods=["GET"]) +@login_required +@measure_execution_time(logger=printers_logger, task_name="API-Drucker-Status-Abfrage") +def get_printer_status(): + """ + Liefert den aktuellen Status aller Drucker. + Dieser Endpunkt ist kompatibel mit dem Frontend printer_monitor.js + + Returns: + JSON mit Status aller Drucker + """ + printers_logger.info(f"🔄 Status-Abfrage von Benutzer {current_user.name} (ID: {current_user.id})") + + try: + # Drucker aus Datenbank holen + db_session = get_db_session() + printers = db_session.query(Printer).all() + + # Status-Daten für jeden Drucker sammeln + printer_data = [] + status_summary = { + 'total': len(printers), + 'online': 0, + 'offline': 0, + 'standby': 0, + 'unreachable': 0, + 'unconfigured': 0 + } + + for printer in printers: + # Basis-Drucker-Daten + printer_info = { + 'id': printer.id, + 'name': printer.name, + 'model': printer.model, + 'location': printer.location, + 'status': printer.status or 'offline', + 'plug_ip': printer.plug_ip, + 'has_plug': bool(printer.plug_ip and printer.plug_username and printer.plug_password), + 'last_checked': printer.last_checked.isoformat() if printer.last_checked else None, + 'created_at': printer.created_at.isoformat() if printer.created_at else None + } + + # Status-Zusammenfassung aktualisieren + status = printer_info['status'] + if status in status_summary: + status_summary[status] += 1 + else: + status_summary['offline'] += 1 + + # Aktive Jobs zählen + active_jobs = db_session.query(Job).filter( + Job.printer_id == printer.id, + Job.status.in_(["running", "printing", "active", "scheduled"]) + ).count() + + printer_info['active_jobs'] = active_jobs + printer_info['is_busy'] = active_jobs > 0 + + printer_data.append(printer_info) + + db_session.close() + + # Antwort mit Status und Zusammenfassung + response = { + "success": True, + "printers": printer_data, + "summary": status_summary, + "timestamp": datetime.now().isoformat() + } + + printers_logger.info(f"✅ Status-Abfrage erfolgreich: {len(printer_data)} Drucker") + return jsonify(response) + + except Exception as e: + printers_logger.error(f"❌ Fehler bei Status-Abfrage: {str(e)}") + if 'db_session' in locals(): + db_session.close() + return jsonify({ + "success": False, + "error": "Fehler bei Abfrage des Druckerstatus", + "message": str(e) + }), 500 + @printers_blueprint.route("/control//power", methods=["POST"]) @login_required @require_permission(Permission.CONTROL_PRINTER) # Verwende die bereits vorhandene Berechtigung diff --git a/backend/docs/printer-monitor-complete-fix.md b/backend/docs/printer-monitor-complete-fix.md new file mode 100644 index 000000000..0519ecba6 --- /dev/null +++ b/backend/docs/printer-monitor-complete-fix.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/instance/sessions/1462c4043506d74ebeacf971fdbca293_activity.pkl b/backend/instance/sessions/1462c4043506d74ebeacf971fdbca293_activity.pkl new file mode 100644 index 000000000..1f204efcd Binary files /dev/null and b/backend/instance/sessions/1462c4043506d74ebeacf971fdbca293_activity.pkl differ diff --git a/backend/instance/sessions/673d7360f5eaf04be37cc013a0e4a538_activity.pkl b/backend/instance/sessions/673d7360f5eaf04be37cc013a0e4a538_activity.pkl new file mode 100644 index 000000000..2ffea0a01 Binary files /dev/null and b/backend/instance/sessions/673d7360f5eaf04be37cc013a0e4a538_activity.pkl differ diff --git a/backend/instance/sessions/e018b45aa4a564a497ba4215e937669f_activity.pkl b/backend/instance/sessions/e018b45aa4a564a497ba4215e937669f_activity.pkl new file mode 100644 index 000000000..a08371172 Binary files /dev/null and b/backend/instance/sessions/e018b45aa4a564a497ba4215e937669f_activity.pkl differ diff --git a/backend/logs/admin/admin.log b/backend/logs/admin/admin.log index 8b2cb99f9..3e8442d1c 100644 --- a/backend/logs/admin/admin.log +++ b/backend/logs/admin/admin.log @@ -2,3 +2,12 @@ 2025-06-12 08:08:27 - [admin] admin - [INFO] INFO - Admin-Dashboard geladen von admin 2025-06-12 08:31:58 - [admin] admin - [INFO] INFO - Admin-Check für Funktion printers_overview: User authenticated: True, User ID: 1, Is Admin: True 2025-06-12 08:31:58 - [admin] admin - [INFO] INFO - Druckerübersicht geladen von admin +2025-06-12 08:33:35 - [admin] admin - [INFO] INFO - Admin-Check für Funktion admin_dashboard: User authenticated: True, User ID: 1, Is Admin: True +2025-06-12 08:33:35 - [admin] admin - [INFO] INFO - Admin-Dashboard geladen von admin +2025-06-12 08:33:38 - [admin] admin - [INFO] INFO - Admin-Check für Funktion logs_overview: User authenticated: True, User ID: 1, Is Admin: True +2025-06-12 08:33:38 - [admin] admin - [INFO] INFO - Logs-Übersicht geladen von admin +2025-06-12 08:33:39 - [admin] admin - [INFO] INFO - Admin-Check für Funktion get_logs_api: User authenticated: True, User ID: 1, Is Admin: True +2025-06-12 08:33:39 - [admin] admin - [INFO] INFO - Logs abgerufen: 0 Einträge, Level: all +2025-06-12 08:33:40 - [admin] admin - [INFO] INFO - Admin-Check für Funktion get_logs_api: User authenticated: True, User ID: 1, Is Admin: True +2025-06-12 08:33:40 - [admin] admin - [INFO] INFO - Logs abgerufen: 0 Einträge, Level: all +2025-06-12 08:33:42 - [admin] admin - [INFO] INFO - Admin-Check für Funktion guest_requests: User authenticated: True, User ID: 1, Is Admin: True diff --git a/backend/logs/app/app.log b/backend/logs/app/app.log index 95ca470a9..979f2dcf4 100644 --- a/backend/logs/app/app.log +++ b/backend/logs/app/app.log @@ -2024,3 +2024,282 @@ werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'admin. 2025-06-12 08:32:50 - [app] app - [INFO] INFO - [STARTUP] Starte Job Scheduler... 2025-06-12 08:32:50 - [app] app - [INFO] INFO - [STARTUP] ✅ Job Scheduler gestartet 2025-06-12 08:32:50 - [app] app - [INFO] INFO - [STARTUP] 🌐 Server startet auf http://0.0.0.0:5000 +2025-06-12 08:32:51 - [app] app - [WARNING] WARNING - DatabaseCleanupManager nicht verfügbar - Fallback auf Legacy-Cleanup +2025-06-12 08:32:51 - [app] app - [INFO] INFO - Optimierte SQLite-Engine erstellt: backend/database/myp.db +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [CONFIG] Erkannte Umgebung: development +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [CONFIG] Production-Modus: False +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [CONFIG] Verwende Development-Konfiguration +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [DEVELOPMENT] Aktiviere Development-Konfiguration +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [DEVELOPMENT] ✅ MYP Development Environment Konfiguration aktiviert +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [DEVELOPMENT] ✅ Environment: Development/Testing +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [DEVELOPMENT] ✅ Debug Mode: True +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [DEVELOPMENT] ✅ SQL Echo: True +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [STARTUP] 🚀 Starte MYP DEVELOPMENT-Umgebung +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [STARTUP] 🏢 Mercedes-Benz TBA Marienfelde +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [STARTUP] 🔒 Air-Gapped: True +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [STARTUP] Initialisiere Datenbank... +2025-06-12 08:32:53 - [app] app - [INFO] INFO - SQLite für Raspberry Pi optimiert (reduzierte Cache-Größe, SD-Karten I/O) +2025-06-12 08:32:53 - [app] app - [INFO] INFO - Datenbank mit Optimierungen initialisiert +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [STARTUP] ✅ Datenbank initialisiert +2025-06-12 08:32:53 - [app] app - [INFO] INFO - [STARTUP] Prüfe Initial-Admin... +2025-06-12 08:32:54 - [app] app - [INFO] INFO - Admin-Benutzer admin (admin@mercedes-benz.com) existiert bereits. Passwort wurde zurückgesetzt. +2025-06-12 08:32:54 - [app] app - [INFO] INFO - [STARTUP] ✅ Admin-Benutzer geprüft +2025-06-12 08:32:54 - [app] app - [INFO] INFO - [STARTUP] Starte Queue Manager... +2025-06-12 08:32:54 - [app] app - [INFO] INFO - [STARTUP] ✅ Queue Manager gestartet +2025-06-12 08:32:54 - [app] app - [INFO] INFO - [STARTUP] Starte Job Scheduler... +2025-06-12 08:32:54 - [app] app - [INFO] INFO - [STARTUP] ✅ Job Scheduler gestartet +2025-06-12 08:32:54 - [app] app - [INFO] INFO - [STARTUP] 🌐 Server startet auf http://0.0.0.0:5000 +2025-06-12 08:32:54 - [app] app - [INFO] INFO - Locating template 'jobs.html': + 1: trying loader of application '__main__' + class: jinja2.loaders.FileSystemLoader + encoding: 'utf-8' + followlinks: False + searchpath: + - C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\templates + -> found ('C:\\Users\\TTOMCZA.EMEA\\Dev\\Projektarbeit-MYP\\backend\\templates\\jobs.html') +2025-06-12 08:32:54 - [app] app - [INFO] INFO - Locating template 'base.html': + 1: trying loader of application '__main__' + class: jinja2.loaders.FileSystemLoader + encoding: 'utf-8' + followlinks: False + searchpath: + - C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\templates + -> found ('C:\\Users\\TTOMCZA.EMEA\\Dev\\Projektarbeit-MYP\\backend\\templates\\base.html') +2025-06-12 08:32:54 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:32:54 - [app] app - [DEBUG] DEBUG - Request: GET /.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:32:54 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:32:54 - [app] app - [INFO] INFO - Locating template 'errors/404.html': + 1: trying loader of application '__main__' + class: jinja2.loaders.FileSystemLoader + encoding: 'utf-8' + followlinks: False + searchpath: + - C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\templates + -> found ('C:\\Users\\TTOMCZA.EMEA\\Dev\\Projektarbeit-MYP\\backend\\templates\\errors\\404.html') +2025-06-12 08:32:54 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:32:55 - [app] app - [DEBUG] DEBUG - Request: GET /api/notifications +2025-06-12 08:32:55 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:32:55 - [app] app - [DEBUG] DEBUG - Request: GET /api/jobs +2025-06-12 08:32:55 - [app] app - [DEBUG] DEBUG - Request: GET /api/session/status +2025-06-12 08:32:55 - [app] app - [DEBUG] DEBUG - Request: GET /api/user/settings +2025-06-12 08:32:55 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:32:55 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:32:55 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:32:56 - [app] app - [DEBUG] DEBUG - Request: GET /stats +2025-06-12 08:32:56 - [app] app - [INFO] INFO - Locating template 'stats.html': + 1: trying loader of application '__main__' + class: jinja2.loaders.FileSystemLoader + encoding: 'utf-8' + followlinks: False + searchpath: + - C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\templates + -> found ('C:\\Users\\TTOMCZA.EMEA\\Dev\\Projektarbeit-MYP\\backend\\templates\\stats.html') +2025-06-12 08:32:56 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:32:56 - [app] app - [DEBUG] DEBUG - Request: GET /.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:32:56 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:32:56 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:32:57 - [app] app - [DEBUG] DEBUG - Request: GET /api/notifications +2025-06-12 08:32:57 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:32:57 - [app] app - [DEBUG] DEBUG - Request: GET /api/session/status +2025-06-12 08:32:57 - [app] app - [DEBUG] DEBUG - Request: GET /api/user/settings +2025-06-12 08:32:57 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:32:57 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:04 - [app] app - [DEBUG] DEBUG - Request: GET /calendar +2025-06-12 08:33:04 - [app] app - [INFO] INFO - Locating template 'calendar.html': + 1: trying loader of application '__main__' + class: jinja2.loaders.FileSystemLoader + encoding: 'utf-8' + followlinks: False + searchpath: + - C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\templates + -> found ('C:\\Users\\TTOMCZA.EMEA\\Dev\\Projektarbeit-MYP\\backend\\templates\\calendar.html') +2025-06-12 08:33:04 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:04 - [app] app - [DEBUG] DEBUG - Request: GET /.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:04 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:04 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:05 - [app] app - [DEBUG] DEBUG - Request: GET /api/notifications +2025-06-12 08:33:05 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:05 - [app] app - [DEBUG] DEBUG - Request: GET /api/calendar/events +2025-06-12 08:33:05 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:05 - [app] app - [DEBUG] DEBUG - Request: GET /api/session/status +2025-06-12 08:33:05 - [app] app - [DEBUG] DEBUG - Request: GET /api/user/settings +2025-06-12 08:33:05 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:33:05 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:13 - [app] app - [DEBUG] DEBUG - Request: GET /stats +2025-06-12 08:33:13 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:13 - [app] app - [DEBUG] DEBUG - Request: GET /.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:13 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:13 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:14 - [app] app - [DEBUG] DEBUG - Request: GET /api/notifications +2025-06-12 08:33:14 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:14 - [app] app - [DEBUG] DEBUG - Request: GET /api/session/status +2025-06-12 08:33:14 - [app] app - [DEBUG] DEBUG - Request: GET /api/user/settings +2025-06-12 08:33:14 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:33:14 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:16 - [app] app - [DEBUG] DEBUG - Request: GET /request +2025-06-12 08:33:16 - [app] app - [INFO] INFO - Locating template 'guest_request.html': + 1: trying loader of application '__main__' + class: jinja2.loaders.FileSystemLoader + encoding: 'utf-8' + followlinks: False + searchpath: + - C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\templates + -> found ('C:\\Users\\TTOMCZA.EMEA\\Dev\\Projektarbeit-MYP\\backend\\templates\\guest_request.html') +2025-06-12 08:33:16 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:16 - [app] app - [ERROR] ERROR - Fehler beim Laden des Benutzers 1: (sqlite3.InterfaceError) bad parameter or other API misuse +[SQL: SELECT users.id AS users_id, users.email AS users_email, users.username AS users_username, users.password_hash AS users_password_hash, users.name AS users_name, users.role AS users_role, users.active AS users_active, users.created_at AS users_created_at, users.last_login AS users_last_login, users.updated_at AS users_updated_at, users.settings AS users_settings, users.last_activity AS users_last_activity, users.department AS users_department, users.position AS users_position, users.phone AS users_phone, users.bio AS users_bio, users.theme_preference AS users_theme_preference, users.language_preference AS users_language_preference, users.email_notifications AS users_email_notifications, users.browser_notifications AS users_browser_notifications, users.dashboard_layout AS users_dashboard_layout, users.compact_mode AS users_compact_mode, users.show_completed_jobs AS users_show_completed_jobs, users.auto_refresh_interval AS users_auto_refresh_interval, users.auto_logout_timeout AS users_auto_logout_timeout +FROM users +WHERE users.id = ? + LIMIT ? OFFSET ?] +[parameters: (1, 1, 0)] +(Background on this error at: https://sqlalche.me/e/20/rvf5) +2025-06-12 08:33:16 - [app] app - [DEBUG] DEBUG - Request: GET /.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:16 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:16 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:17 - [app] app - [DEBUG] DEBUG - Request: GET /api/notifications +2025-06-12 08:33:17 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:17 - [app] app - [DEBUG] DEBUG - Request: GET /api/session/status +2025-06-12 08:33:17 - [app] app - [DEBUG] DEBUG - Request: GET /api/user/settings +2025-06-12 08:33:17 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:33:17 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:21 - [app] app - [DEBUG] DEBUG - Request: POST /request +2025-06-12 08:33:21 - [app] app - [INFO] INFO - OTP generiert für Guest Request 1 +2025-06-12 08:33:21 - [app] app - [DEBUG] DEBUG - Response: 302 +2025-06-12 08:33:21 - [app] app - [DEBUG] DEBUG - Request: GET /request/1 +2025-06-12 08:33:21 - [app] app - [INFO] INFO - Locating template 'guest_status.html': + 1: trying loader of application '__main__' + class: jinja2.loaders.FileSystemLoader + encoding: 'utf-8' + followlinks: False + searchpath: + - C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\templates + -> found ('C:\\Users\\TTOMCZA.EMEA\\Dev\\Projektarbeit-MYP\\backend\\templates\\guest_status.html') +2025-06-12 08:33:21 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:28 - [app] app - [DEBUG] DEBUG - Request: GET /request/1 +2025-06-12 08:33:28 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:28 - [app] app - [DEBUG] DEBUG - Request: GET /.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:28 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:28 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:28 - [app] app - [DEBUG] DEBUG - Request: GET /api/notifications +2025-06-12 08:33:28 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:28 - [app] app - [DEBUG] DEBUG - Request: GET /api/session/status +2025-06-12 08:33:28 - [app] app - [DEBUG] DEBUG - Request: GET /api/user/settings +2025-06-12 08:33:28 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:33:28 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Request: GET /admin/ +2025-06-12 08:33:35 - [app] app - [INFO] INFO - Locating template 'admin.html': + 1: trying loader of application '__main__' + class: jinja2.loaders.FileSystemLoader + encoding: 'utf-8' + followlinks: False + searchpath: + - C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\templates + -> found ('C:\\Users\\TTOMCZA.EMEA\\Dev\\Projektarbeit-MYP\\backend\\templates\\admin.html') +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Request: GET /.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:35 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Request: GET /api/notifications +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Request: GET /api/stats +2025-06-12 08:33:35 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/api/stats +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Request: GET /api/session/status +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Request: GET /api/printers/monitor/live-status +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Request: GET /api/user/settings +2025-06-12 08:33:35 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:33:36 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:33:36 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:36 - [app] app - [DEBUG] DEBUG - Request: GET /api/admin/system-health +2025-06-12 08:33:36 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/api/admin/system-health +2025-06-12 08:33:36 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:38 - [app] app - [DEBUG] DEBUG - Request: GET /admin/logs +2025-06-12 08:33:38 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:38 - [app] app - [DEBUG] DEBUG - Request: GET /.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:38 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:38 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Request: GET /api/notifications +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Request: GET /api/stats +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Request: GET /api/printers/monitor/live-status +2025-06-12 08:33:39 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/api/stats +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Request: GET /api/session/status +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Request: GET /api/user/settings +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Response: 302 +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Request: GET /api/admin/system-health +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Request: GET /auth/login +2025-06-12 08:33:39 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/api/admin/system-health +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Response: 302 +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Request: GET / +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Response: 302 +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Request: GET /admin/api/logs +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Request: GET /dashboard +2025-06-12 08:33:39 - [app] app - [INFO] INFO - Locating template 'dashboard.html': + 1: trying loader of application '__main__' + class: jinja2.loaders.FileSystemLoader + encoding: 'utf-8' + followlinks: False + searchpath: + - C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\templates + -> found ('C:\\Users\\TTOMCZA.EMEA\\Dev\\Projektarbeit-MYP\\backend\\templates\\dashboard.html') +2025-06-12 08:33:39 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:40 - [app] app - [DEBUG] DEBUG - Request: GET /admin/api/logs +2025-06-12 08:33:40 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Request: GET /admin/guest-requests +2025-06-12 08:33:42 - [app] app - [INFO] INFO - Locating template 'admin_guest_requests.html': + 1: trying loader of application '__main__' + class: jinja2.loaders.FileSystemLoader + encoding: 'utf-8' + followlinks: False + searchpath: + - C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\templates + -> found ('C:\\Users\\TTOMCZA.EMEA\\Dev\\Projektarbeit-MYP\\backend\\templates\\admin_guest_requests.html') +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Request: GET /.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:42 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/.well-known/appspecific/com.chrome.devtools.json +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Request: GET /api/notifications +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Request: GET /api/printers/monitor/live-status +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Request: GET /api/session/status +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Request: GET /api/user/settings +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Request: GET /api/admin/guest-requests +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Response: 500 +2025-06-12 08:33:42 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/api/admin/guest-requests +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Response: 404 +2025-06-12 08:33:42 - [app] app - [DEBUG] DEBUG - Response: 200 +2025-06-12 08:34:04 - [app] app - [INFO] INFO - [SHUTDOWN] 🧹 Cleanup wird ausgeführt... +2025-06-12 08:34:04 - [app] app - [INFO] INFO - [SHUTDOWN] ✅ Queue Manager gestoppt +2025-06-12 08:34:04 - [app] app - [ERROR] ERROR - [SHUTDOWN] ❌ Cleanup-Fehler: 'BackgroundTaskScheduler' object has no attribute 'shutdown' +2025-06-12 08:34:05 - [app] app - [WARNING] WARNING - DatabaseCleanupManager nicht verfügbar - Fallback auf Legacy-Cleanup +2025-06-12 08:34:05 - [app] app - [INFO] INFO - Optimierte SQLite-Engine erstellt: backend/database/myp.db +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [CONFIG] Erkannte Umgebung: development +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [CONFIG] Production-Modus: False +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [CONFIG] Verwende Development-Konfiguration +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [DEVELOPMENT] Aktiviere Development-Konfiguration +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [DEVELOPMENT] ✅ MYP Development Environment Konfiguration aktiviert +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [DEVELOPMENT] ✅ Environment: Development/Testing +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [DEVELOPMENT] ✅ Debug Mode: True +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [DEVELOPMENT] ✅ SQL Echo: True +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [STARTUP] 🚀 Starte MYP DEVELOPMENT-Umgebung +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [STARTUP] 🏢 Mercedes-Benz TBA Marienfelde +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [STARTUP] 🔒 Air-Gapped: True +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [STARTUP] Initialisiere Datenbank... +2025-06-12 08:34:06 - [app] app - [INFO] INFO - SQLite für Raspberry Pi optimiert (reduzierte Cache-Größe, SD-Karten I/O) +2025-06-12 08:34:06 - [app] app - [INFO] INFO - Datenbank mit Optimierungen initialisiert +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [STARTUP] ✅ Datenbank initialisiert +2025-06-12 08:34:06 - [app] app - [INFO] INFO - [STARTUP] Prüfe Initial-Admin... +2025-06-12 08:34:07 - [app] app - [INFO] INFO - Admin-Benutzer admin (admin@mercedes-benz.com) existiert bereits. Passwort wurde zurückgesetzt. +2025-06-12 08:34:07 - [app] app - [INFO] INFO - [STARTUP] ✅ Admin-Benutzer geprüft +2025-06-12 08:34:07 - [app] app - [INFO] INFO - [STARTUP] Starte Queue Manager... +2025-06-12 08:34:07 - [app] app - [INFO] INFO - [STARTUP] ✅ Queue Manager gestartet +2025-06-12 08:34:07 - [app] app - [INFO] INFO - [STARTUP] Starte Job Scheduler... +2025-06-12 08:34:07 - [app] app - [INFO] INFO - [STARTUP] ✅ Job Scheduler gestartet +2025-06-12 08:34:07 - [app] app - [INFO] INFO - [STARTUP] 🌐 Server startet auf http://0.0.0.0:5000 +2025-06-12 08:34:12 - [app] app - [INFO] INFO - Not Found (404): http://127.0.0.1:5000/api/admin/guest-requests diff --git a/backend/logs/calendar/calendar.log b/backend/logs/calendar/calendar.log index e69de29bb..d80638a1f 100644 --- a/backend/logs/calendar/calendar.log +++ b/backend/logs/calendar/calendar.log @@ -0,0 +1 @@ +2025-06-12 08:33:05 - [calendar] calendar - [INFO] INFO - 📅 Kalender-Events abgerufen: 0 Einträge für Zeitraum 2025-06-07 22:00:00+00:00 bis 2025-06-14 22:00:00+00:00 diff --git a/backend/logs/core_system/core_system.log b/backend/logs/core_system/core_system.log index 359d611c5..0aa5c77ff 100644 --- a/backend/logs/core_system/core_system.log +++ b/backend/logs/core_system/core_system.log @@ -46,3 +46,7 @@ 2025-06-12 08:32:05 - [core_system] core_system - [INFO] INFO - 📊 Massive Konsolidierung: 6 Dateien → 1 Datei (88% Reduktion) 2025-06-12 08:32:48 - [core_system] core_system - [INFO] INFO - ✅ Core System Management Module erfolgreich initialisiert 2025-06-12 08:32:48 - [core_system] core_system - [INFO] INFO - 📊 Massive Konsolidierung: 6 Dateien → 1 Datei (88% Reduktion) +2025-06-12 08:32:51 - [core_system] core_system - [INFO] INFO - ✅ Core System Management Module erfolgreich initialisiert +2025-06-12 08:32:51 - [core_system] core_system - [INFO] INFO - 📊 Massive Konsolidierung: 6 Dateien → 1 Datei (88% Reduktion) +2025-06-12 08:34:05 - [core_system] core_system - [INFO] INFO - ✅ Core System Management Module erfolgreich initialisiert +2025-06-12 08:34:05 - [core_system] core_system - [INFO] INFO - 📊 Massive Konsolidierung: 6 Dateien → 1 Datei (88% Reduktion) diff --git a/backend/logs/data_management/data_management.log b/backend/logs/data_management/data_management.log index 060a12463..75c5935cb 100644 --- a/backend/logs/data_management/data_management.log +++ b/backend/logs/data_management/data_management.log @@ -46,3 +46,7 @@ 2025-06-12 08:32:06 - [data_management] data_management - [INFO] INFO - 📊 Massive Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion) 2025-06-12 08:32:49 - [data_management] data_management - [INFO] INFO - ✅ Data Management Module initialisiert 2025-06-12 08:32:49 - [data_management] data_management - [INFO] INFO - 📊 Massive Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion) +2025-06-12 08:32:51 - [data_management] data_management - [INFO] INFO - ✅ Data Management Module initialisiert +2025-06-12 08:32:51 - [data_management] data_management - [INFO] INFO - 📊 Massive Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion) +2025-06-12 08:34:05 - [data_management] data_management - [INFO] INFO - ✅ Data Management Module initialisiert +2025-06-12 08:34:05 - [data_management] data_management - [INFO] INFO - 📊 Massive Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion) diff --git a/backend/logs/guest/guest.log b/backend/logs/guest/guest.log index 4bfa9028b..f799078f1 100644 --- a/backend/logs/guest/guest.log +++ b/backend/logs/guest/guest.log @@ -3,3 +3,4 @@ FROM users JOIN user_permissions ON users.id = user_permissions.user_id WHERE user_permissions.can_approve_jobs = 1] (Background on this error at: https://sqlalche.me/e/20/e3q8) +2025-06-12 08:33:21 - [guest] guest - [INFO] INFO - Neue Gastanfrage erstellt: ID 1, Name: Till Tomczak, OTP generiert diff --git a/backend/logs/hardware_integration/hardware_integration.log b/backend/logs/hardware_integration/hardware_integration.log index 6e4c2c6cb..8f4e199eb 100644 --- a/backend/logs/hardware_integration/hardware_integration.log +++ b/backend/logs/hardware_integration/hardware_integration.log @@ -98,3 +98,11 @@ 2025-06-12 08:32:49 - [hardware_integration] hardware_integration - [INFO] INFO - ✅ Printer Monitor initialisiert 2025-06-12 08:32:49 - [hardware_integration] hardware_integration - [INFO] INFO - ✅ Hardware Integration Module initialisiert 2025-06-12 08:32:49 - [hardware_integration] hardware_integration - [INFO] INFO - 📊 Massive Konsolidierung: 2 Dateien → 1 Datei (50% Reduktion) +2025-06-12 08:32:51 - [hardware_integration] hardware_integration - [INFO] INFO - ✅ PyP100 (TP-Link Tapo) verfügbar +2025-06-12 08:32:51 - [hardware_integration] hardware_integration - [INFO] INFO - ✅ Printer Monitor initialisiert +2025-06-12 08:32:51 - [hardware_integration] hardware_integration - [INFO] INFO - ✅ Hardware Integration Module initialisiert +2025-06-12 08:32:51 - [hardware_integration] hardware_integration - [INFO] INFO - 📊 Massive Konsolidierung: 2 Dateien → 1 Datei (50% Reduktion) +2025-06-12 08:34:05 - [hardware_integration] hardware_integration - [INFO] INFO - ✅ PyP100 (TP-Link Tapo) verfügbar +2025-06-12 08:34:05 - [hardware_integration] hardware_integration - [INFO] INFO - ✅ Printer Monitor initialisiert +2025-06-12 08:34:05 - [hardware_integration] hardware_integration - [INFO] INFO - ✅ Hardware Integration Module initialisiert +2025-06-12 08:34:05 - [hardware_integration] hardware_integration - [INFO] INFO - 📊 Massive Konsolidierung: 2 Dateien → 1 Datei (50% Reduktion) diff --git a/backend/logs/job_queue_system/job_queue_system.log b/backend/logs/job_queue_system/job_queue_system.log index 4a36871f5..77a0e3368 100644 --- a/backend/logs/job_queue_system/job_queue_system.log +++ b/backend/logs/job_queue_system/job_queue_system.log @@ -92,3 +92,10 @@ 2025-06-12 08:32:49 - [job_queue_system] job_queue_system - [INFO] INFO - ✅ Job & Queue System Module initialisiert 2025-06-12 08:32:49 - [job_queue_system] job_queue_system - [INFO] INFO - 📊 MASSIVE Konsolidierung: 4 Dateien → 1 Datei (75% Reduktion) 2025-06-12 08:32:50 - [job_queue_system] job_queue_system - [INFO] INFO - Queue Manager gestartet (Legacy-Kompatibilität) +2025-06-12 08:32:51 - [job_queue_system] job_queue_system - [INFO] INFO - ✅ Job & Queue System Module initialisiert +2025-06-12 08:32:51 - [job_queue_system] job_queue_system - [INFO] INFO - 📊 MASSIVE Konsolidierung: 4 Dateien → 1 Datei (75% Reduktion) +2025-06-12 08:32:54 - [job_queue_system] job_queue_system - [INFO] INFO - Queue Manager gestartet (Legacy-Kompatibilität) +2025-06-12 08:34:04 - [job_queue_system] job_queue_system - [INFO] INFO - Queue Manager gestoppt (Legacy-Kompatibilität) +2025-06-12 08:34:05 - [job_queue_system] job_queue_system - [INFO] INFO - ✅ Job & Queue System Module initialisiert +2025-06-12 08:34:05 - [job_queue_system] job_queue_system - [INFO] INFO - 📊 MASSIVE Konsolidierung: 4 Dateien → 1 Datei (75% Reduktion) +2025-06-12 08:34:07 - [job_queue_system] job_queue_system - [INFO] INFO - Queue Manager gestartet (Legacy-Kompatibilität) diff --git a/backend/logs/jobs/jobs.log b/backend/logs/jobs/jobs.log index 750356c6d..bebd64345 100644 --- a/backend/logs/jobs/jobs.log +++ b/backend/logs/jobs/jobs.log @@ -55,3 +55,5 @@ TypeError: unsupported operand type(s) for +: 'NoneType' and 'int' 2025-06-12 08:20:59 - [jobs] jobs - [INFO] INFO - ✅ Jobs erfolgreich abgerufen: 0 von 0 (Seite 1) 2025-06-12 08:21:14 - [jobs] jobs - [INFO] INFO - 📋 Jobs-Abfrage gestartet von Benutzer 1 (Admin: True) 2025-06-12 08:21:14 - [jobs] jobs - [INFO] INFO - ✅ Jobs erfolgreich abgerufen: 0 von 0 (Seite 1) +2025-06-12 08:32:55 - [jobs] jobs - [INFO] INFO - 📋 Jobs-Abfrage gestartet von Benutzer 1 (Admin: True) +2025-06-12 08:32:55 - [jobs] jobs - [INFO] INFO - ✅ Jobs erfolgreich abgerufen: 0 von 0 (Seite 1) diff --git a/backend/logs/monitoring_analytics/monitoring_analytics.log b/backend/logs/monitoring_analytics/monitoring_analytics.log index 9b414783c..28fe0e48a 100644 --- a/backend/logs/monitoring_analytics/monitoring_analytics.log +++ b/backend/logs/monitoring_analytics/monitoring_analytics.log @@ -46,3 +46,7 @@ 2025-06-12 08:32:07 - [monitoring_analytics] monitoring_analytics - [INFO] INFO - 📊 MASSIVE Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion) 2025-06-12 08:32:50 - [monitoring_analytics] monitoring_analytics - [INFO] INFO - ✅ Monitoring & Analytics Module initialisiert 2025-06-12 08:32:50 - [monitoring_analytics] monitoring_analytics - [INFO] INFO - 📊 MASSIVE Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion) +2025-06-12 08:32:53 - [monitoring_analytics] monitoring_analytics - [INFO] INFO - ✅ Monitoring & Analytics Module initialisiert +2025-06-12 08:32:53 - [monitoring_analytics] monitoring_analytics - [INFO] INFO - 📊 MASSIVE Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion) +2025-06-12 08:34:06 - [monitoring_analytics] monitoring_analytics - [INFO] INFO - ✅ Monitoring & Analytics Module initialisiert +2025-06-12 08:34:06 - [monitoring_analytics] monitoring_analytics - [INFO] INFO - 📊 MASSIVE Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion) diff --git a/backend/logs/printers/printers.log b/backend/logs/printers/printers.log index 84245549b..a90e8f118 100644 --- a/backend/logs/printers/printers.log +++ b/backend/logs/printers/printers.log @@ -19,3 +19,15 @@ 2025-06-12 08:32:29 - [printers] printers - [INFO] INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1) 2025-06-12 08:32:29 - [printers] printers - [ERROR] ERROR - ❌ Fehler bei Live-Status-Abfrage: PrinterMonitor.get_live_printer_status() got an unexpected keyword argument 'use_session_cache' 2025-06-12 08:32:29 - [printers] printers - [INFO] INFO - [OK] API-Live-Drucker-Status-Abfrage 'get_live_printer_status' erfolgreich in 0.58ms +2025-06-12 08:33:36 - [printers] printers - [INFO] INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1) +2025-06-12 08:33:36 - [printers] printers - [ERROR] ERROR - ❌ Fehler bei Live-Status-Abfrage: PrinterMonitor.get_live_printer_status() got an unexpected keyword argument 'use_session_cache' +2025-06-12 08:33:36 - [printers] printers - [INFO] INFO - [OK] API-Live-Drucker-Status-Abfrage 'get_live_printer_status' erfolgreich in 2.06ms +2025-06-12 08:33:39 - [printers] printers - [INFO] INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1) +2025-06-12 08:33:39 - [printers] printers - [ERROR] ERROR - ❌ Fehler bei Live-Status-Abfrage: PrinterMonitor.get_live_printer_status() got an unexpected keyword argument 'use_session_cache' +2025-06-12 08:33:39 - [printers] printers - [INFO] INFO - [OK] API-Live-Drucker-Status-Abfrage 'get_live_printer_status' erfolgreich in 1.04ms +2025-06-12 08:33:42 - [printers] printers - [INFO] INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1) +2025-06-12 08:33:42 - [printers] printers - [ERROR] ERROR - ❌ Fehler bei Live-Status-Abfrage: PrinterMonitor.get_live_printer_status() got an unexpected keyword argument 'use_session_cache' +2025-06-12 08:33:42 - [printers] printers - [INFO] INFO - [OK] API-Live-Drucker-Status-Abfrage 'get_live_printer_status' erfolgreich in 0.85ms +2025-06-12 08:34:12 - [printers] printers - [INFO] INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1) +2025-06-12 08:34:12 - [printers] printers - [ERROR] ERROR - ❌ Fehler bei Live-Status-Abfrage: PrinterMonitor.get_live_printer_status() got an unexpected keyword argument 'use_session_cache' +2025-06-12 08:34:12 - [printers] printers - [INFO] INFO - [OK] API-Live-Drucker-Status-Abfrage 'get_live_printer_status' erfolgreich in 0.85ms diff --git a/backend/logs/scheduler/scheduler.log b/backend/logs/scheduler/scheduler.log index dffc68aff..25ef94b4c 100644 --- a/backend/logs/scheduler/scheduler.log +++ b/backend/logs/scheduler/scheduler.log @@ -68,3 +68,9 @@ 2025-06-12 08:32:49 - [scheduler] scheduler - [INFO] INFO - Task check_jobs registriert: Intervall 30s, Enabled: True 2025-06-12 08:32:50 - [scheduler] scheduler - [INFO] INFO - Scheduler-Thread gestartet 2025-06-12 08:32:50 - [scheduler] scheduler - [INFO] INFO - Scheduler gestartet +2025-06-12 08:32:51 - [scheduler] scheduler - [INFO] INFO - Task check_jobs registriert: Intervall 30s, Enabled: True +2025-06-12 08:32:54 - [scheduler] scheduler - [INFO] INFO - Scheduler-Thread gestartet +2025-06-12 08:32:54 - [scheduler] scheduler - [INFO] INFO - Scheduler gestartet +2025-06-12 08:34:05 - [scheduler] scheduler - [INFO] INFO - Task check_jobs registriert: Intervall 30s, Enabled: True +2025-06-12 08:34:07 - [scheduler] scheduler - [INFO] INFO - Scheduler-Thread gestartet +2025-06-12 08:34:07 - [scheduler] scheduler - [INFO] INFO - Scheduler gestartet diff --git a/backend/logs/security_suite/security_suite.log b/backend/logs/security_suite/security_suite.log index aac4fcdc0..303147a45 100644 --- a/backend/logs/security_suite/security_suite.log +++ b/backend/logs/security_suite/security_suite.log @@ -70,3 +70,9 @@ 2025-06-12 08:32:49 - [security_suite] security_suite - [INFO] INFO - ✅ Security Suite Module initialisiert 2025-06-12 08:32:49 - [security_suite] security_suite - [INFO] INFO - 📊 Massive Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion) 2025-06-12 08:32:50 - [security_suite] security_suite - [INFO] INFO - 🔒 Security Suite initialisiert +2025-06-12 08:32:51 - [security_suite] security_suite - [INFO] INFO - ✅ Security Suite Module initialisiert +2025-06-12 08:32:51 - [security_suite] security_suite - [INFO] INFO - 📊 Massive Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion) +2025-06-12 08:32:53 - [security_suite] security_suite - [INFO] INFO - 🔒 Security Suite initialisiert +2025-06-12 08:34:05 - [security_suite] security_suite - [INFO] INFO - ✅ Security Suite Module initialisiert +2025-06-12 08:34:05 - [security_suite] security_suite - [INFO] INFO - 📊 Massive Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion) +2025-06-12 08:34:06 - [security_suite] security_suite - [INFO] INFO - 🔒 Security Suite initialisiert diff --git a/backend/logs/sessions/sessions.log b/backend/logs/sessions/sessions.log index 4c1f29ffb..66e5f4d24 100644 --- a/backend/logs/sessions/sessions.log +++ b/backend/logs/sessions/sessions.log @@ -8,3 +8,12 @@ 2025-06-12 08:31:50 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' 2025-06-12 08:31:56 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' 2025-06-12 08:31:59 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' +2025-06-12 08:32:55 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' +2025-06-12 08:32:57 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' +2025-06-12 08:33:05 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' +2025-06-12 08:33:14 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' +2025-06-12 08:33:17 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' +2025-06-12 08:33:28 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' +2025-06-12 08:33:35 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' +2025-06-12 08:33:39 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' +2025-06-12 08:33:42 - [sessions] sessions - [ERROR] ERROR - Fehler beim Abrufen des Session-Status: 'int' object has no attribute 'total_seconds' diff --git a/backend/logs/startup/startup.log b/backend/logs/startup/startup.log index c8f5dc956..334cd571f 100644 --- a/backend/logs/startup/startup.log +++ b/backend/logs/startup/startup.log @@ -214,3 +214,21 @@ 2025-06-12 08:32:50 - [startup] startup - [INFO] INFO - 🪟 Windows-Modus: Aktiviert 2025-06-12 08:32:50 - [startup] startup - [INFO] INFO - 🔒 Windows-sichere Log-Rotation: Aktiviert 2025-06-12 08:32:50 - [startup] startup - [INFO] INFO - ================================================== +2025-06-12 08:32:53 - [startup] startup - [INFO] INFO - ================================================== +2025-06-12 08:32:53 - [startup] startup - [INFO] INFO - [START] MYP Platform Backend wird gestartet... +2025-06-12 08:32:53 - [startup] startup - [INFO] INFO - 🐍 Python Version: 3.13.3 (tags/v3.13.3:6280bb5, Apr 8 2025, 14:47:33) [MSC v.1943 64 bit (AMD64)] +2025-06-12 08:32:53 - [startup] startup - [INFO] INFO - 💻 Betriebssystem: nt (win32) +2025-06-12 08:32:53 - [startup] startup - [INFO] INFO - 📁 Arbeitsverzeichnis: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend +2025-06-12 08:32:53 - [startup] startup - [INFO] INFO - ⏰ Startzeit: 2025-06-12T08:32:53.808641 +2025-06-12 08:32:53 - [startup] startup - [INFO] INFO - 🪟 Windows-Modus: Aktiviert +2025-06-12 08:32:53 - [startup] startup - [INFO] INFO - 🔒 Windows-sichere Log-Rotation: Aktiviert +2025-06-12 08:32:53 - [startup] startup - [INFO] INFO - ================================================== +2025-06-12 08:34:06 - [startup] startup - [INFO] INFO - ================================================== +2025-06-12 08:34:06 - [startup] startup - [INFO] INFO - [START] MYP Platform Backend wird gestartet... +2025-06-12 08:34:06 - [startup] startup - [INFO] INFO - 🐍 Python Version: 3.13.3 (tags/v3.13.3:6280bb5, Apr 8 2025, 14:47:33) [MSC v.1943 64 bit (AMD64)] +2025-06-12 08:34:06 - [startup] startup - [INFO] INFO - 💻 Betriebssystem: nt (win32) +2025-06-12 08:34:06 - [startup] startup - [INFO] INFO - 📁 Arbeitsverzeichnis: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend +2025-06-12 08:34:06 - [startup] startup - [INFO] INFO - ⏰ Startzeit: 2025-06-12T08:34:06.865423 +2025-06-12 08:34:06 - [startup] startup - [INFO] INFO - 🪟 Windows-Modus: Aktiviert +2025-06-12 08:34:06 - [startup] startup - [INFO] INFO - 🔒 Windows-sichere Log-Rotation: Aktiviert +2025-06-12 08:34:06 - [startup] startup - [INFO] INFO - ================================================== diff --git a/backend/logs/tapo_controller/tapo_controller.log b/backend/logs/tapo_controller/tapo_controller.log index e6c66cc24..11265f512 100644 --- a/backend/logs/tapo_controller/tapo_controller.log +++ b/backend/logs/tapo_controller/tapo_controller.log @@ -23,3 +23,5 @@ 2025-06-12 08:31:54 - [tapo_controller] tapo_controller - [INFO] INFO - ✅ tapo controller initialisiert 2025-06-12 08:32:06 - [tapo_controller] tapo_controller - [INFO] INFO - ✅ tapo controller initialisiert 2025-06-12 08:32:49 - [tapo_controller] tapo_controller - [INFO] INFO - ✅ tapo controller initialisiert +2025-06-12 08:32:51 - [tapo_controller] tapo_controller - [INFO] INFO - ✅ tapo controller initialisiert +2025-06-12 08:34:05 - [tapo_controller] tapo_controller - [INFO] INFO - ✅ tapo controller initialisiert diff --git a/backend/logs/user/user.log b/backend/logs/user/user.log index 3c87b8f5d..4a7126d29 100644 --- a/backend/logs/user/user.log +++ b/backend/logs/user/user.log @@ -10,3 +10,11 @@ 2025-06-12 08:31:50 - [user] user - [INFO] INFO - User admin retrieved settings via API 2025-06-12 08:31:56 - [user] user - [INFO] INFO - User admin retrieved settings via API 2025-06-12 08:31:59 - [user] user - [INFO] INFO - User admin retrieved settings via API +2025-06-12 08:32:55 - [user] user - [INFO] INFO - User admin retrieved settings via API +2025-06-12 08:32:57 - [user] user - [INFO] INFO - User admin retrieved settings via API +2025-06-12 08:33:05 - [user] user - [INFO] INFO - User admin retrieved settings via API +2025-06-12 08:33:14 - [user] user - [INFO] INFO - User admin retrieved settings via API +2025-06-12 08:33:17 - [user] user - [INFO] INFO - User admin retrieved settings via API +2025-06-12 08:33:28 - [user] user - [INFO] INFO - User admin retrieved settings via API +2025-06-12 08:33:36 - [user] user - [INFO] INFO - User admin retrieved settings via API +2025-06-12 08:33:42 - [user] user - [INFO] INFO - User admin retrieved settings via API diff --git a/backend/logs/utilities_collection/utilities_collection.log b/backend/logs/utilities_collection/utilities_collection.log index 44a9e7100..760074663 100644 --- a/backend/logs/utilities_collection/utilities_collection.log +++ b/backend/logs/utilities_collection/utilities_collection.log @@ -50,3 +50,7 @@ 2025-06-12 08:32:05 - [utilities_collection] utilities_collection - [INFO] INFO - 🚨 ALLERLETZTE MEGA-Konsolidierung: 12+ Dateien → 1 Datei (90%+ Reduktion) 2025-06-12 08:32:48 - [utilities_collection] utilities_collection - [INFO] INFO - ✅ Utilities Collection initialisiert 2025-06-12 08:32:48 - [utilities_collection] utilities_collection - [INFO] INFO - 🚨 ALLERLETZTE MEGA-Konsolidierung: 12+ Dateien → 1 Datei (90%+ Reduktion) +2025-06-12 08:32:51 - [utilities_collection] utilities_collection - [INFO] INFO - ✅ Utilities Collection initialisiert +2025-06-12 08:32:51 - [utilities_collection] utilities_collection - [INFO] INFO - 🚨 ALLERLETZTE MEGA-Konsolidierung: 12+ Dateien → 1 Datei (90%+ Reduktion) +2025-06-12 08:34:05 - [utilities_collection] utilities_collection - [INFO] INFO - ✅ Utilities Collection initialisiert +2025-06-12 08:34:05 - [utilities_collection] utilities_collection - [INFO] INFO - 🚨 ALLERLETZTE MEGA-Konsolidierung: 12+ Dateien → 1 Datei (90%+ Reduktion) diff --git a/backend/logs/windows_fixes/windows_fixes.log b/backend/logs/windows_fixes/windows_fixes.log index aad06fd1a..f43639e90 100644 --- a/backend/logs/windows_fixes/windows_fixes.log +++ b/backend/logs/windows_fixes/windows_fixes.log @@ -49,3 +49,7 @@ 2025-06-12 08:32:05 - [windows_fixes] windows_fixes - [INFO] INFO - ✅ Alle Windows-Fixes erfolgreich angewendet 2025-06-12 08:32:48 - [windows_fixes] windows_fixes - [INFO] INFO - 🔧 Wende Windows-spezifische Fixes an... 2025-06-12 08:32:48 - [windows_fixes] windows_fixes - [INFO] INFO - ✅ Alle Windows-Fixes erfolgreich angewendet +2025-06-12 08:32:51 - [windows_fixes] windows_fixes - [INFO] INFO - 🔧 Wende Windows-spezifische Fixes an... +2025-06-12 08:32:51 - [windows_fixes] windows_fixes - [INFO] INFO - ✅ Alle Windows-Fixes erfolgreich angewendet +2025-06-12 08:34:05 - [windows_fixes] windows_fixes - [INFO] INFO - 🔧 Wende Windows-spezifische Fixes an... +2025-06-12 08:34:05 - [windows_fixes] windows_fixes - [INFO] INFO - ✅ Alle Windows-Fixes erfolgreich angewendet diff --git a/backend/static/js/admin-guest-requests.js b/backend/static/js/admin-guest-requests.js index fac41d888..e3206566d 100644 --- a/backend/static/js/admin-guest-requests.js +++ b/backend/static/js/admin-guest-requests.js @@ -93,7 +93,7 @@ async function loadGuestRequests() { try { showLoading(true); - const url = `${API_BASE_URL}/api/admin/guest-requests`; + const url = `${API_BASE_URL}/api/admin/requests`; const response = await fetch(url, { method: 'GET', headers: { diff --git a/backend/static/js/admin-guest-requests.min.js b/backend/static/js/admin-guest-requests.min.js index a18d27b3d..e3206566d 100644 --- a/backend/static/js/admin-guest-requests.min.js +++ b/backend/static/js/admin-guest-requests.min.js @@ -1,58 +1,710 @@ -let currentRequests=[];let filteredRequests=[];let currentPage=0;let totalPages=0;let totalRequests=0;let refreshInterval=null;let csrfToken='';function detectApiBaseUrl(){return'';} -const API_BASE_URL=detectApiBaseUrl();document.addEventListener('DOMContentLoaded',function(){csrfToken=document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')||'';initEventListeners();loadGuestRequests();startAutoRefresh();console.log('🎯 Admin Guest Requests Management geladen');});function initEventListeners(){const searchInput=document.getElementById('search-requests');if(searchInput){searchInput.addEventListener('input',debounce(handleSearch,300));} -const statusFilter=document.getElementById('status-filter');if(statusFilter){statusFilter.addEventListener('change',handleFilterChange);} -const sortOrder=document.getElementById('sort-order');if(sortOrder){sortOrder.addEventListener('change',handleSortChange);} -const refreshBtn=document.getElementById('refresh-btn');if(refreshBtn){refreshBtn.addEventListener('click',()=>{loadGuestRequests();showNotification('🔄 Gastaufträge aktualisiert','info');});} -const exportBtn=document.getElementById('export-btn');if(exportBtn){exportBtn.addEventListener('click',handleExport);} -const bulkActionsBtn=document.getElementById('bulk-actions-btn');if(bulkActionsBtn){bulkActionsBtn.addEventListener('click',showBulkActionsModal);} -const selectAllCheckbox=document.getElementById('select-all');if(selectAllCheckbox){selectAllCheckbox.addEventListener('change',handleSelectAll);}} -async function loadGuestRequests(){try{showLoading(true);const url=`${API_BASE_URL}/api/admin/guest-requests`;const response=await fetch(url,{method:'GET',headers:{'Content-Type':'application/json','X-CSRFToken':csrfToken}});if(!response.ok){throw new Error(`HTTP ${response.status}:${response.statusText}`);} -const data=await response.json();if(data.success){currentRequests=data.requests||[];totalRequests=data.total||0;updateStats(data.stats||{});applyFiltersAndSort();console.log(`✅ ${currentRequests.length}Gastaufträge geladen`);}else{throw new Error(data.message||'Fehler beim Laden der Gastaufträge');}}catch(error){console.error('Fehler beim Laden der Gastaufträge:',error);showNotification('❌ Fehler beim Laden der Gastaufträge: '+error.message,'error');showEmptyState();}finally{showLoading(false);}} -function updateStats(stats){const elements={'pending-count':stats.pending||0,'approved-count':stats.approved||0,'rejected-count':stats.rejected||0,'total-count':stats.total||0};Object.entries(elements).forEach(([id,value])=>{const element=document.getElementById(id);if(element){animateCounter(element,value);}});} -function animateCounter(element,targetValue){const currentValue=parseInt(element.textContent)||0;const difference=targetValue-currentValue;const steps=20;const stepValue=difference/steps;let step=0;const interval=setInterval(()=>{step++;const value=Math.round(currentValue+(stepValue*step));element.textContent=value;if(step>=steps){clearInterval(interval);element.textContent=targetValue;}},50);} -function applyFiltersAndSort(){let requests=[...currentRequests];const statusFilter=document.getElementById('status-filter')?.value;if(statusFilter&&statusFilter!=='all'){requests=requests.filter(req=>req.status===statusFilter);} -const searchTerm=document.getElementById('search-requests')?.value.toLowerCase();if(searchTerm){requests=requests.filter(req=>req.name?.toLowerCase().includes(searchTerm)||req.email?.toLowerCase().includes(searchTerm)||req.file_name?.toLowerCase().includes(searchTerm)||req.reason?.toLowerCase().includes(searchTerm));} -const sortOrder=document.getElementById('sort-order')?.value;requests.sort((a,b)=>{switch(sortOrder){case'oldest':return new Date(a.created_at)-new Date(b.created_at);case'priority':return getPriorityValue(b)-getPriorityValue(a);case'newest':default:return new Date(b.created_at)-new Date(a.created_at);}});filteredRequests=requests;renderRequestsTable();} -function getPriorityValue(request){const now=new Date();const created=new Date(request.created_at);const hoursOld=(now-created)/(1000*60*60);let priority=0;if(request.status==='pending')priority+=10;else if(request.status==='approved')priority+=5;if(hoursOld>24)priority+=5;else if(hoursOld>8)priority+=3;else if(hoursOld>2)priority+=1;return priority;} -function renderRequestsTable(){const tableBody=document.getElementById('requests-table-body');const emptyState=document.getElementById('empty-state');if(!tableBody)return;if(filteredRequests.length===0){tableBody.innerHTML='';showEmptyState();return;} -hideEmptyState();const requestsHtml=filteredRequests.map(request=>createRequestRow(request)).join('');tableBody.innerHTML=requestsHtml;addRowEventListeners();} -function createRequestRow(request){const statusColor=getStatusColor(request.status);const priorityLevel=getPriorityLevel(request);const timeAgo=getTimeAgo(request.created_at);return`
${request.name?request.name[0].toUpperCase():'G'}
${escapeHtml(request.name||'Unbekannt')}
${escapeHtml(request.email||'Keine E-Mail')}
${escapeHtml(request.file_name||'Keine Datei')}
${request.duration_minutes?`${request.duration_minutes}Min.`:'Unbekannte Dauer'} -${request.copies?`• ${request.copies}Kopien`:''}
${request.reason?`
${escapeHtml(request.reason)}
`:''}${getStatusText(request.status)}
${timeAgo}
${formatDateTime(request.created_at)}
${getPriorityBadge(priorityLevel)} -${request.is_urgent?'🔥 Dringend':''}
${request.status==='pending'?``:''}
`;} -function getStatusColor(status){const colors={'pending':'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300','approved':'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300','rejected':'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300','expired':'bg-gray-100 text-gray-800 dark:bg-gray-900/30 dark:text-gray-300'};return colors[status]||'bg-gray-100 text-gray-800 dark:bg-gray-900/30 dark:text-gray-300';} -function getStatusDot(status){const dots={'pending':'bg-yellow-400 dark:bg-yellow-300','approved':'bg-green-400 dark:bg-green-300','rejected':'bg-red-400 dark:bg-red-300','expired':'bg-gray-400 dark:bg-gray-300'};return dots[status]||'bg-gray-400 dark:bg-gray-300';} -function getStatusText(status){const texts={'pending':'Wartend','approved':'Genehmigt','rejected':'Abgelehnt','expired':'Abgelaufen'};return texts[status]||status;} -function getPriorityLevel(request){const priority=getPriorityValue(request);if(priority>=15)return'high';if(priority>=8)return'medium';return'low';} -function getPriorityBadge(level){const badges={'high':'🔴 Hoch','medium':'🟡 Mittel','low':'🟢 Niedrig'};return badges[level]||badges['low'];} -async function approveRequest(requestId){if(!confirm('Möchten Sie diesen Gastauftrag wirklich genehmigen?'))return;try{showLoading(true);const url=`${API_BASE_URL}/api/guest-requests/${requestId}/approve`;const response=await fetch(url,{method:'POST',headers:{'Content-Type':'application/json','X-CSRFToken':csrfToken},body:JSON.stringify({})});const data=await response.json();if(data.success){showNotification('✅ Gastauftrag erfolgreich genehmigt','success');loadGuestRequests();}else{throw new Error(data.message||'Fehler beim Genehmigen');}}catch(error){console.error('Fehler beim Genehmigen:',error);showNotification('❌ Fehler beim Genehmigen: '+error.message,'error');}finally{showLoading(false);}} -async function rejectRequest(requestId){const reason=prompt('Grund für die Ablehnung:');if(!reason)return;try{showLoading(true);const url=`${API_BASE_URL}/api/guest-requests/${requestId}/reject`;const response=await fetch(url,{method:'POST',headers:{'Content-Type':'application/json','X-CSRFToken':csrfToken},body:JSON.stringify({reason})});const data=await response.json();if(data.success){showNotification('✅ Gastauftrag erfolgreich abgelehnt','success');loadGuestRequests();}else{throw new Error(data.message||'Fehler beim Ablehnen');}}catch(error){console.error('Fehler beim Ablehnen:',error);showNotification('❌ Fehler beim Ablehnen: '+error.message,'error');}finally{showLoading(false);}} -async function deleteRequest(requestId){if(!confirm('Möchten Sie diesen Gastauftrag wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.'))return;try{showLoading(true);const url=`${API_BASE_URL}/api/guest-requests/${requestId}`;const response=await fetch(url,{method:'DELETE',headers:{'Content-Type':'application/json','X-CSRFToken':csrfToken}});const data=await response.json();if(data.success){showNotification('✅ Gastauftrag erfolgreich gelöscht','success');loadGuestRequests();}else{throw new Error(data.message||'Fehler beim Löschen');}}catch(error){console.error('Fehler beim Löschen:',error);showNotification('❌ Fehler beim Löschen: '+error.message,'error');}finally{showLoading(false);}} -function showRequestDetail(requestId){const request=currentRequests.find(req=>req.id===requestId);if(!request)return;const modal=document.getElementById('detail-modal');const content=document.getElementById('modal-content');content.innerHTML=`

Gastauftrag Details

Antragsteller

Name:${escapeHtml(request.name||'Unbekannt')}

E-Mail:${escapeHtml(request.email||'Keine E-Mail')}

Erstellt am:${formatDateTime(request.created_at)}

Auftrag Details

Datei:${escapeHtml(request.file_name||'Keine Datei')}

Dauer:${request.duration_minutes||'Unbekannt'}Minuten

Kopien:${request.copies||1}

Status:${getStatusText(request.status)}

${request.reason?`

Begründung

${escapeHtml(request.reason)}

`:''}
${request.status==='pending'?``:''}
`;modal.classList.remove('hidden');} -function closeDetailModal(){const modal=document.getElementById('detail-modal');modal.classList.add('hidden');} -function showBulkActionsModal(){const selectedIds=getSelectedRequestIds();if(selectedIds.length===0){showNotification('⚠️ Bitte wählen Sie mindestens einen Gastauftrag aus','warning');return;} -const modal=document.getElementById('bulk-modal');modal.classList.remove('hidden');} -function closeBulkModal(){const modal=document.getElementById('bulk-modal');modal.classList.add('hidden');} -async function performBulkAction(action){const selectedIds=getSelectedRequestIds();if(selectedIds.length===0)return;const confirmMessages={'approve':`Möchten Sie ${selectedIds.length}Gastaufträge genehmigen?`,'reject':`Möchten Sie ${selectedIds.length}Gastaufträge ablehnen?`,'delete':`Möchten Sie ${selectedIds.length}Gastaufträge löschen?`};if(!confirm(confirmMessages[action]))return;try{showLoading(true);closeBulkModal();const promises=selectedIds.map(async(id)=>{const url=`${API_BASE_URL}/api/guest-requests/${id}/${action}`;const method=action==='delete'?'DELETE':'POST';return fetch(url,{method,headers:{'Content-Type':'application/json','X-CSRFToken':csrfToken}});});const results=await Promise.allSettled(promises);const successCount=results.filter(r=>r.status==='fulfilled'&&r.value.ok).length;showNotification(`✅ ${successCount}von ${selectedIds.length}Aktionen erfolgreich`,'success');loadGuestRequests();document.getElementById('select-all').checked=false;document.querySelectorAll('.request-checkbox').forEach(cb=>cb.checked=false);}catch(error){console.error('Fehler bei Bulk-Aktion:',error);showNotification('❌ Fehler bei der Bulk-Aktion: '+error.message,'error');}finally{showLoading(false);}} -function getSelectedRequestIds(){const checkboxes=document.querySelectorAll('.request-checkbox:checked');return Array.from(checkboxes).map(cb=>parseInt(cb.value));} -function handleSearch(){applyFiltersAndSort();} -function handleFilterChange(){applyFiltersAndSort();} -function handleSortChange(){applyFiltersAndSort();} -function handleSelectAll(event){const checkboxes=document.querySelectorAll('.request-checkbox');checkboxes.forEach(checkbox=>{checkbox.checked=event.target.checked;});} -function handleExport(){const selectedIds=getSelectedRequestIds();const exportData=selectedIds.length>0?filteredRequests.filter(req=>selectedIds.includes(req.id)):filteredRequests;if(exportData.length===0){showNotification('⚠️ Keine Daten zum Exportieren verfügbar','warning');return;} -exportToCSV(exportData);} -function exportToCSV(data){const headers=['ID','Name','E-Mail','Datei','Status','Erstellt','Dauer (Min)','Kopien','Begründung'];const rows=data.map(req=>[req.id,req.name||'',req.email||'',req.file_name||'',getStatusText(req.status),formatDateTime(req.created_at),req.duration_minutes||'',req.copies||'',req.reason||'']);const csvContent=[headers,...rows].map(row=>row.map(field=>`"${String(field).replace(/"/g,'""')}"`).join(',')) +/** + * Mercedes-Benz MYP Admin Guest Requests Management + * Moderne Verwaltung von Gastaufträgen mit Live-Updates + */ + +// Globale Variablen +let currentRequests = []; +let filteredRequests = []; +let currentPage = 0; +let totalPages = 0; +let totalRequests = 0; +let refreshInterval = null; +let csrfToken = ''; + +// API Base URL Detection - Korrigierte Version für CSP-Kompatibilität +function detectApiBaseUrl() { + // Für lokale Entwicklung und CSP-Kompatibilität immer relative URLs verwenden + // Das verhindert CSP-Probleme mit connect-src + return ''; // Leerer String für relative URLs +} + +const API_BASE_URL = detectApiBaseUrl(); + +// Initialisierung beim Laden der Seite +document.addEventListener('DOMContentLoaded', function() { + // CSRF Token abrufen + csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''; + + // Event Listeners initialisieren + initEventListeners(); + + // Daten initial laden + loadGuestRequests(); + + // Auto-Refresh starten + startAutoRefresh(); + + console.log('🎯 Admin Guest Requests Management geladen'); +}); + +/** + * Event Listeners initialisieren + */ +function initEventListeners() { + // Search Input + const searchInput = document.getElementById('search-requests'); + if (searchInput) { + searchInput.addEventListener('input', debounce(handleSearch, 300)); + } + + // Status Filter + const statusFilter = document.getElementById('status-filter'); + if (statusFilter) { + statusFilter.addEventListener('change', handleFilterChange); + } + + // Sort Order + const sortOrder = document.getElementById('sort-order'); + if (sortOrder) { + sortOrder.addEventListener('change', handleSortChange); + } + + // Action Buttons + const refreshBtn = document.getElementById('refresh-btn'); + if (refreshBtn) { + refreshBtn.addEventListener('click', () => { + loadGuestRequests(); + showNotification('🔄 Gastaufträge aktualisiert', 'info'); + }); + } + + const exportBtn = document.getElementById('export-btn'); + if (exportBtn) { + exportBtn.addEventListener('click', handleExport); + } + + const bulkActionsBtn = document.getElementById('bulk-actions-btn'); + if (bulkActionsBtn) { + bulkActionsBtn.addEventListener('click', showBulkActionsModal); + } + + // Select All Checkbox + const selectAllCheckbox = document.getElementById('select-all'); + if (selectAllCheckbox) { + selectAllCheckbox.addEventListener('change', handleSelectAll); + } +} + +/** + * Gastaufträge von der API laden + */ +async function loadGuestRequests() { + try { + showLoading(true); + + const url = `${API_BASE_URL}/api/admin/requests`; + const response = await fetch(url, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': csrfToken + } + }); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + + if (data.success) { + currentRequests = data.requests || []; + totalRequests = data.total || 0; + + // Statistiken aktualisieren + updateStats(data.stats || {}); + + // Tabelle aktualisieren + applyFiltersAndSort(); + + console.log(`✅ ${currentRequests.length} Gastaufträge geladen`); + } else { + throw new Error(data.message || 'Fehler beim Laden der Gastaufträge'); + } + } catch (error) { + console.error('Fehler beim Laden der Gastaufträge:', error); + showNotification('❌ Fehler beim Laden der Gastaufträge: ' + error.message, 'error'); + showEmptyState(); + } finally { + showLoading(false); + } +} + +/** + * Statistiken aktualisieren + */ +function updateStats(stats) { + const elements = { + 'pending-count': stats.pending || 0, + 'approved-count': stats.approved || 0, + 'rejected-count': stats.rejected || 0, + 'total-count': stats.total || 0 + }; + + Object.entries(elements).forEach(([id, value]) => { + const element = document.getElementById(id); + if (element) { + animateCounter(element, value); + } + }); +} + +/** + * Counter mit Animation + */ +function animateCounter(element, targetValue) { + const currentValue = parseInt(element.textContent) || 0; + const difference = targetValue - currentValue; + const steps = 20; + const stepValue = difference / steps; + + let step = 0; + const interval = setInterval(() => { + step++; + const value = Math.round(currentValue + (stepValue * step)); + element.textContent = value; + + if (step >= steps) { + clearInterval(interval); + element.textContent = targetValue; + } + }, 50); +} + +/** + * Filter und Sortierung anwenden + */ +function applyFiltersAndSort() { + let requests = [...currentRequests]; + + // Status Filter + const statusFilter = document.getElementById('status-filter')?.value; + if (statusFilter && statusFilter !== 'all') { + requests = requests.filter(req => req.status === statusFilter); + } + + // Such-Filter + const searchTerm = document.getElementById('search-requests')?.value.toLowerCase(); + if (searchTerm) { + requests = requests.filter(req => + req.name?.toLowerCase().includes(searchTerm) || + req.email?.toLowerCase().includes(searchTerm) || + req.file_name?.toLowerCase().includes(searchTerm) || + req.reason?.toLowerCase().includes(searchTerm) + ); + } + + // Sortierung + const sortOrder = document.getElementById('sort-order')?.value; + requests.sort((a, b) => { + switch (sortOrder) { + case 'oldest': + return new Date(a.created_at) - new Date(b.created_at); + case 'priority': + return getPriorityValue(b) - getPriorityValue(a); + case 'newest': + default: + return new Date(b.created_at) - new Date(a.created_at); + } + }); + + filteredRequests = requests; + renderRequestsTable(); +} + +/** + * Prioritätswert für Sortierung berechnen + */ +function getPriorityValue(request) { + const now = new Date(); + const created = new Date(request.created_at); + const hoursOld = (now - created) / (1000 * 60 * 60); + + let priority = 0; + + // Status-basierte Priorität + if (request.status === 'pending') priority += 10; + else if (request.status === 'approved') priority += 5; + + // Alter-basierte Priorität + if (hoursOld > 24) priority += 5; + else if (hoursOld > 8) priority += 3; + else if (hoursOld > 2) priority += 1; + + return priority; +} + +/** + * Requests-Tabelle rendern + */ +function renderRequestsTable() { + const tableBody = document.getElementById('requests-table-body'); + const emptyState = document.getElementById('empty-state'); + + if (!tableBody) return; + + if (filteredRequests.length === 0) { + tableBody.innerHTML = ''; + showEmptyState(); + return; + } + + hideEmptyState(); + + const requestsHtml = filteredRequests.map(request => createRequestRow(request)).join(''); + tableBody.innerHTML = requestsHtml; + + // Event Listeners für neue Rows hinzufügen + addRowEventListeners(); +} + +/** + * Request Row HTML erstellen + */ +function createRequestRow(request) { + const statusColor = getStatusColor(request.status); + const priorityLevel = getPriorityLevel(request); + const timeAgo = getTimeAgo(request.created_at); + + return ` + + + + + +
+
+
+ ${request.name ? request.name[0].toUpperCase() : 'G'} +
+
+
+
${escapeHtml(request.name || 'Unbekannt')}
+
${escapeHtml(request.email || 'Keine E-Mail')}
+
+
+ + +
${escapeHtml(request.file_name || 'Keine Datei')}
+
+ ${request.duration_minutes ? `${request.duration_minutes} Min.` : 'Unbekannte Dauer'} + ${request.copies ? ` • ${request.copies} Kopien` : ''} +
+ ${request.reason ? `
${escapeHtml(request.reason)}
` : ''} + + + + + ${getStatusText(request.status)} + + + +
${timeAgo}
+
${formatDateTime(request.created_at)}
+ + +
+ ${getPriorityBadge(priorityLevel)} + ${request.is_urgent ? '🔥 Dringend' : ''} +
+ + +
+ + + ${request.status === 'pending' ? ` + + + + ` : ''} + + +
+ + + `; +} + +/** + * Status-Helper-Funktionen + */ +function getStatusColor(status) { + const colors = { + 'pending': 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300', + 'approved': 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300', + 'rejected': 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300', + 'expired': 'bg-gray-100 text-gray-800 dark:bg-gray-900/30 dark:text-gray-300' + }; + return colors[status] || 'bg-gray-100 text-gray-800 dark:bg-gray-900/30 dark:text-gray-300'; +} + +function getStatusDot(status) { + const dots = { + 'pending': 'bg-yellow-400 dark:bg-yellow-300', + 'approved': 'bg-green-400 dark:bg-green-300', + 'rejected': 'bg-red-400 dark:bg-red-300', + 'expired': 'bg-gray-400 dark:bg-gray-300' + }; + return dots[status] || 'bg-gray-400 dark:bg-gray-300'; +} + +function getStatusText(status) { + const texts = { + 'pending': 'Wartend', + 'approved': 'Genehmigt', + 'rejected': 'Abgelehnt', + 'expired': 'Abgelaufen' + }; + return texts[status] || status; +} + +function getPriorityLevel(request) { + const priority = getPriorityValue(request); + if (priority >= 15) return 'high'; + if (priority >= 8) return 'medium'; + return 'low'; +} + +function getPriorityBadge(level) { + const badges = { + 'high': '🔴 Hoch', + 'medium': '🟡 Mittel', + 'low': '🟢 Niedrig' + }; + return badges[level] || badges['low']; +} + +/** + * CRUD-Operationen + */ +async function approveRequest(requestId) { + if (!confirm('Möchten Sie diesen Gastauftrag wirklich genehmigen?')) return; + + try { + showLoading(true); + + const url = `${API_BASE_URL}/api/guest-requests/${requestId}/approve`; + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': csrfToken + }, + body: JSON.stringify({}) // Leeres JSON-Objekt senden + }); + + const data = await response.json(); + + if (data.success) { + showNotification('✅ Gastauftrag erfolgreich genehmigt', 'success'); + loadGuestRequests(); + } else { + throw new Error(data.message || 'Fehler beim Genehmigen'); + } + } catch (error) { + console.error('Fehler beim Genehmigen:', error); + showNotification('❌ Fehler beim Genehmigen: ' + error.message, 'error'); + } finally { + showLoading(false); + } +} + +async function rejectRequest(requestId) { + const reason = prompt('Grund für die Ablehnung:'); + if (!reason) return; + + try { + showLoading(true); + + const url = `${API_BASE_URL}/api/guest-requests/${requestId}/reject`; + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': csrfToken + }, + body: JSON.stringify({ reason }) + }); + + const data = await response.json(); + + if (data.success) { + showNotification('✅ Gastauftrag erfolgreich abgelehnt', 'success'); + loadGuestRequests(); + } else { + throw new Error(data.message || 'Fehler beim Ablehnen'); + } + } catch (error) { + console.error('Fehler beim Ablehnen:', error); + showNotification('❌ Fehler beim Ablehnen: ' + error.message, 'error'); + } finally { + showLoading(false); + } +} + +async function deleteRequest(requestId) { + if (!confirm('Möchten Sie diesen Gastauftrag wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.')) return; + + try { + showLoading(true); + + const url = `${API_BASE_URL}/api/guest-requests/${requestId}`; + const response = await fetch(url, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': csrfToken + } + }); + + const data = await response.json(); + + if (data.success) { + showNotification('✅ Gastauftrag erfolgreich gelöscht', 'success'); + loadGuestRequests(); + } else { + throw new Error(data.message || 'Fehler beim Löschen'); + } + } catch (error) { + console.error('Fehler beim Löschen:', error); + showNotification('❌ Fehler beim Löschen: ' + error.message, 'error'); + } finally { + showLoading(false); + } +} + +/** + * Detail-Modal Funktionen + */ +function showRequestDetail(requestId) { + const request = currentRequests.find(req => req.id === requestId); + if (!request) return; + + const modal = document.getElementById('detail-modal'); + const content = document.getElementById('modal-content'); + + content.innerHTML = ` +
+
+

Gastauftrag Details

+ +
+
+
+
+
+

Antragsteller

+
+

Name: ${escapeHtml(request.name || 'Unbekannt')}

+

E-Mail: ${escapeHtml(request.email || 'Keine E-Mail')}

+

Erstellt am: ${formatDateTime(request.created_at)}

+
+
+ +
+

Auftrag Details

+
+

Datei: ${escapeHtml(request.file_name || 'Keine Datei')}

+

Dauer: ${request.duration_minutes || 'Unbekannt'} Minuten

+

Kopien: ${request.copies || 1}

+

Status: ${getStatusText(request.status)}

+
+
+
+ + ${request.reason ? ` +
+

Begründung

+
+

${escapeHtml(request.reason)}

+
+
+ ` : ''} + +
+ ${request.status === 'pending' ? ` + + + ` : ''} + +
+
+ `; + + modal.classList.remove('hidden'); +} + +function closeDetailModal() { + const modal = document.getElementById('detail-modal'); + modal.classList.add('hidden'); +} + +/** + * Bulk Actions + */ +function showBulkActionsModal() { + const selectedIds = getSelectedRequestIds(); + if (selectedIds.length === 0) { + showNotification('⚠️ Bitte wählen Sie mindestens einen Gastauftrag aus', 'warning'); + return; + } + + const modal = document.getElementById('bulk-modal'); + modal.classList.remove('hidden'); +} + +function closeBulkModal() { + const modal = document.getElementById('bulk-modal'); + modal.classList.add('hidden'); +} + +async function performBulkAction(action) { + const selectedIds = getSelectedRequestIds(); + if (selectedIds.length === 0) return; + + const confirmMessages = { + 'approve': `Möchten Sie ${selectedIds.length} Gastaufträge genehmigen?`, + 'reject': `Möchten Sie ${selectedIds.length} Gastaufträge ablehnen?`, + 'delete': `Möchten Sie ${selectedIds.length} Gastaufträge löschen?` + }; + + if (!confirm(confirmMessages[action])) return; + + try { + showLoading(true); + closeBulkModal(); + + const promises = selectedIds.map(async (id) => { + const url = `${API_BASE_URL}/api/guest-requests/${id}/${action}`; + const method = action === 'delete' ? 'DELETE' : 'POST'; + + return fetch(url, { + method, + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': csrfToken + } + }); + }); + + const results = await Promise.allSettled(promises); + const successCount = results.filter(r => r.status === 'fulfilled' && r.value.ok).length; + + showNotification(`✅ ${successCount} von ${selectedIds.length} Aktionen erfolgreich`, 'success'); + loadGuestRequests(); + + // Alle Checkboxen zurücksetzen + document.getElementById('select-all').checked = false; + document.querySelectorAll('.request-checkbox').forEach(cb => cb.checked = false); + + } catch (error) { + console.error('Fehler bei Bulk-Aktion:', error); + showNotification('❌ Fehler bei der Bulk-Aktion: ' + error.message, 'error'); + } finally { + showLoading(false); + } +} + +function getSelectedRequestIds() { + const checkboxes = document.querySelectorAll('.request-checkbox:checked'); + return Array.from(checkboxes).map(cb => parseInt(cb.value)); +} + +/** + * Event Handlers + */ +function handleSearch() { + applyFiltersAndSort(); +} + +function handleFilterChange() { + applyFiltersAndSort(); +} + +function handleSortChange() { + applyFiltersAndSort(); +} + +function handleSelectAll(event) { + const checkboxes = document.querySelectorAll('.request-checkbox'); + checkboxes.forEach(checkbox => { + checkbox.checked = event.target.checked; + }); +} + +function handleExport() { + const selectedIds = getSelectedRequestIds(); + const exportData = selectedIds.length > 0 ? + filteredRequests.filter(req => selectedIds.includes(req.id)) : + filteredRequests; + + if (exportData.length === 0) { + showNotification('⚠️ Keine Daten zum Exportieren verfügbar', 'warning'); + return; + } + + exportToCSV(exportData); +} + +/** + * Export-Funktionen + */ +function exportToCSV(data) { + const headers = ['ID', 'Name', 'E-Mail', 'Datei', 'Status', 'Erstellt', 'Dauer (Min)', 'Kopien', 'Begründung']; + const rows = data.map(req => [ + req.id, + req.name || '', + req.email || '', + req.file_name || '', + getStatusText(req.status), + formatDateTime(req.created_at), + req.duration_minutes || '', + req.copies || '', + req.reason || '' + ]); + + const csvContent = [headers, ...rows] + .map(row => row.map(field => `"${String(field).replace(/"/g, '""')}"`).join(',')) .join('\n'); const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); @@ -220,4 +872,4 @@ window.closeDetailModal = closeDetailModal; window.closeBulkModal = closeBulkModal; window.performBulkAction = performBulkAction; -console.log('📋 Admin Guest Requests JavaScript vollständig geladen' \ No newline at end of file +console.log('📋 Admin Guest Requests JavaScript vollständig geladen'); \ No newline at end of file diff --git a/backend/static/js/printer_monitor.js.backup b/backend/static/js/printer_monitor.js.backup new file mode 100644 index 000000000..992153710 --- /dev/null +++ b/backend/static/js/printer_monitor.js.backup @@ -0,0 +1,497 @@ +/** + * Live-Drucker-Monitor für MYP Platform + * Verwaltet Live-Status-Updates mit Session-Caching und automatischer Aktualisierung + */ + +class PrinterMonitor { + constructor() { + this.refreshInterval = 30000; // 30 Sekunden Standard-Intervall + this.fastRefreshInterval = 5000; // 5 Sekunden für schnelle Updates + this.currentInterval = null; + this.printers = new Map(); + this.callbacks = new Set(); + this.isActive = false; + this.useCache = true; + this.lastUpdate = null; + this.errorCount = 0; + this.maxErrors = 3; + + // Status-Kategorien für bessere Übersicht + this.statusCategories = { + 'online': { label: 'Online', color: 'success', icon: '🟢' }, + 'offline': { label: 'Offline', color: 'danger', icon: '🔴' }, + 'standby': { label: 'Standby', color: 'warning', icon: '🟡' }, + 'unreachable': { label: 'Nicht erreichbar', color: 'secondary', icon: '⚫' }, + 'unconfigured': { label: 'Nicht konfiguriert', color: 'info', icon: '🔵' } + }; + + console.log('🖨️ PrinterMonitor initialisiert'); + } + + /** + * Startet das Live-Monitoring + */ + start() { + if (this.isActive) { + console.log('⚠️ PrinterMonitor läuft bereits'); + return; + } + + this.isActive = true; + this.errorCount = 0; + + console.log('🚀 Starte PrinterMonitor'); + + // Sofortige erste Aktualisierung + this.updatePrinterStatus(); + + // Reguläres Intervall starten + this.startInterval(); + + // Event-Listener für Sichtbarkeitsänderungen + document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this)); + } + + /** + * Stoppt das Live-Monitoring + */ + stop() { + if (!this.isActive) { + return; + } + + this.isActive = false; + + if (this.currentInterval) { + clearInterval(this.currentInterval); + this.currentInterval = null; + } + + document.removeEventListener('visibilitychange', this.handleVisibilityChange.bind(this)); + + console.log('⏹️ PrinterMonitor gestoppt'); + } + + /** + * Startet das Update-Intervall + */ + startInterval() { + if (this.currentInterval) { + clearInterval(this.currentInterval); + } + + this.currentInterval = setInterval(() => { + this.updatePrinterStatus(); + }, this.refreshInterval); + } + + /** + * Behandelt Sichtbarkeitsänderungen der Seite + */ + handleVisibilityChange() { + if (document.hidden) { + // Seite nicht sichtbar - langsamere Updates + this.refreshInterval = 60000; // 1 Minute + } else { + // Seite sichtbar - normale Updates + this.refreshInterval = 30000; // 30 Sekunden + // Sofortige Aktualisierung wenn Seite wieder sichtbar + this.updatePrinterStatus(); + } + + if (this.isActive) { + this.startInterval(); + } + } + + /** + * Holt aktuelle Drucker-Status-Daten + */ + async updatePrinterStatus() { + if (!this.isActive) { + return; + } + + try { + const response = await fetch(`/api/printers/status`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest' + } + }); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + + if (data.success) { + this.processPrinterData(data); + this.errorCount = 0; // Reset error count on success + } else { + throw new Error(data.error || 'Unbekannter Fehler'); + } + + } catch (error) { + this.errorCount++; + console.error('❌ Fehler beim Abrufen des Drucker-Status:', error); + + // Bei wiederholten Fehlern weniger frequent versuchen + if (this.errorCount >= this.maxErrors) { + this.refreshInterval = Math.min(this.refreshInterval * 2, 300000); // Max 5 Minuten + this.startInterval(); + + this.notifyCallbacks({ + type: 'error', + message: `Drucker-Status nicht verfügbar (${this.errorCount} Fehler)`, + timestamp: new Date().toISOString() + }); + } + } + } + + /** + * Verarbeitet empfangene Drucker-Daten + */ + processPrinterData(data) { + const previousPrinters = new Map(this.printers); + + // Drucker-Daten aktualisieren + this.printers.clear(); + + // Flexible Datenextraktion für verschiedene API-Response-Strukturen + let printersData = null; + + if (data && data.printers && Array.isArray(data.printers)) { + // Neue Struktur: data.printers als Array + printersData = data.printers; + } else if (data && data.printers && typeof data.printers === 'object') { + // Alte Struktur: data.printers als Objekt + printersData = Object.values(data.printers); + } else if (data && data.status && typeof data.status === 'object') { + // Alternative Struktur: data.status + printersData = Object.values(data.status); + } else if (data && typeof data === 'object' && !data.success && !data.error) { + // Direkte Drucker-Daten ohne Wrapper + printersData = Object.values(data); + } + + if (printersData && Array.isArray(printersData)) { + // Drucker-Daten verarbeiten (jetzt als Array) + printersData.forEach(printer => { + // Sichere Validierung der Drucker-Objekte + if (printer && typeof printer === 'object' && printer.id) { + this.printers.set(printer.id, { + ...printer, + statusInfo: this.statusCategories[printer.status] || this.statusCategories['offline'] + }); + } else { + console.warn('⚠️ Ungültiges Drucker-Objekt übersprungen:', printer); + } + }); + + console.log(`✅ ${this.printers.size} Drucker erfolgreich verarbeitet`); + } else { + console.warn('⚠️ Keine gültigen Drucker-Daten in Response-Struktur gefunden'); + console.debug('Response-Struktur:', data); + + // Benachrichtige Callbacks über fehlende Daten (aber nicht als Fehler) + this.notifyCallbacks({ + type: 'warning', + message: 'Keine Drucker-Daten verfügbar', + data: data + }); + return; + } + + this.lastUpdate = new Date(data.timestamp || Date.now()); + + // Änderungen erkennen und benachrichtigen + const changes = this.detectChanges(previousPrinters, this.printers); + + // Callbacks benachrichtigen + this.notifyCallbacks({ + type: 'update', + printers: this.printers, + summary: data.summary, + changes: changes, + timestamp: this.lastUpdate, + cacheUsed: data.cache_used + }); + + console.log(`🔄 Drucker-Status aktualisiert: ${this.printers.size} Drucker`); + } + + /** + * Erkennt Änderungen zwischen zwei Drucker-Status-Maps + */ + detectChanges(oldPrinters, newPrinters) { + const changes = []; + + newPrinters.forEach((newPrinter, id) => { + const oldPrinter = oldPrinters.get(id); + + if (!oldPrinter) { + changes.push({ + type: 'added', + printer: newPrinter + }); + } else if (oldPrinter.status !== newPrinter.status) { + changes.push({ + type: 'status_change', + printer: newPrinter, + oldStatus: oldPrinter.status, + newStatus: newPrinter.status + }); + } + }); + + oldPrinters.forEach((oldPrinter, id) => { + if (!newPrinters.has(id)) { + changes.push({ + type: 'removed', + printer: oldPrinter + }); + } + }); + + return changes; + } + + /** + * Benachrichtigt alle registrierten Callbacks + */ + notifyCallbacks(data) { + this.callbacks.forEach(callback => { + try { + callback(data); + } catch (error) { + console.error('❌ Fehler in PrinterMonitor Callback:', error); + } + }); + } + + /** + * Registriert einen Callback für Status-Updates + */ + onUpdate(callback) { + if (typeof callback === 'function') { + this.callbacks.add(callback); + } + } + + /** + * Entfernt einen Callback + */ + offUpdate(callback) { + this.callbacks.delete(callback); + } + + /** + * Erzwingt eine sofortige Aktualisierung ohne Cache + */ + async forceUpdate() { + const oldUseCache = this.useCache; + this.useCache = false; + + try { + await this.updatePrinterStatus(); + } finally { + this.useCache = oldUseCache; + } + } + + /** + * Löscht den Cache und erzwingt eine Aktualisierung + */ + async clearCache() { + try { + const response = await fetch('/api/printers/monitor/clear-cache', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest' + } + }); + + if (response.ok) { + console.log('🧹 Drucker-Cache geleert'); + await this.forceUpdate(); + } else { + throw new Error(`HTTP ${response.status}`); + } + + } catch (error) { + console.error('❌ Fehler beim Leeren des Caches:', error); + } + } + + /** + * Holt eine schnelle Status-Zusammenfassung + */ + async getSummary() { + try { + const response = await fetch('/api/printers/monitor/summary', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest' + } + }); + + if (response.ok) { + const data = await response.json(); + return data.success ? data.summary : null; + } + + } catch (error) { + console.error('❌ Fehler beim Abrufen der Zusammenfassung:', error); + } + + return null; + } + + /** + * Gibt den aktuellen Status eines Druckers zurück + */ + getPrinter(id) { + return this.printers.get(id); + } + + /** + * Gibt alle Drucker zurück + */ + getAllPrinters() { + return Array.from(this.printers.values()); + } + + /** + * Gibt Drucker nach Status gefiltert zurück + */ + getPrintersByStatus(status) { + return this.getAllPrinters().filter(printer => printer.status === status); + } + + /** + * Gibt eine Status-Zusammenfassung zurück + */ + getStatusSummary() { + const summary = { + total: this.printers.size, + online: 0, + offline: 0, + printing: 0, // Neuer Status: Drucker druckt gerade + standby: 0, + unreachable: 0, + unconfigured: 0, + error: 0 // Status für unbekannte Fehler + }; + + this.printers.forEach(printer => { + const status = printer.status; + if (summary.hasOwnProperty(status)) { + summary[status]++; + } else { + // Fallback für unbekannte Status + summary.offline++; + } + }); + + return summary; + } + + /** + * Aktiviert schnelle Updates (für kritische Operationen) + */ + enableFastUpdates() { + this.refreshInterval = this.fastRefreshInterval; + if (this.isActive) { + this.startInterval(); + } + console.log('⚡ Schnelle Updates aktiviert'); + } + + /** + * Deaktiviert schnelle Updates + */ + disableFastUpdates() { + this.refreshInterval = 30000; // Zurück zu normal + if (this.isActive) { + this.startInterval(); + } + console.log('🐌 Normale Updates aktiviert'); + } + + /** + * Initialisiert alle Steckdosen (nur für Admins) + */ + async initializeAllOutlets() { + try { + const response = await fetch('/api/printers/monitor/initialize-outlets', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest' + } + }); + + if (response.ok) { + const data = await response.json(); + + if (data.success) { + console.log('🔌 Steckdosen-Initialisierung erfolgreich:', data.statistics); + + // Benachrichtige über Initialisierung + this.notifyCallbacks({ + type: 'initialization', + results: data.results, + statistics: data.statistics, + message: data.message + }); + + // Erzwinge Update nach Initialisierung + await this.forceUpdate(); + + return data; + } else { + throw new Error(data.error || 'Initialisierung fehlgeschlagen'); + } + } else { + throw new Error(`HTTP ${response.status}`); + } + + } catch (error) { + console.error('❌ Fehler bei Steckdosen-Initialisierung:', error); + throw error; + } + } +} + +// Globale Instanz +window.printerMonitor = new PrinterMonitor(); + +// Auto-Start wenn DOM bereit ist +document.addEventListener('DOMContentLoaded', () => { + // Nur starten wenn wir auf einer relevanten Seite sind + const relevantPages = ['/printers', '/dashboard', '/admin', '/admin-dashboard']; + const currentPath = window.location.pathname; + + if (relevantPages.some(page => currentPath.includes(page))) { + console.log('🖨️ Auto-Start PrinterMonitor für Seite:', currentPath); + window.printerMonitor.start(); + } +}); + +// Automatisches Cleanup bei Seitenverlassen +window.addEventListener('beforeunload', () => { + if (window.printerMonitor) { + window.printerMonitor.stop(); + } +}); + +// Export für Module +if (typeof module !== 'undefined' && module.exports) { + module.exports = PrinterMonitor; +} \ No newline at end of file