""" ADMIN ROUTES FÜR app.py Diese Routes sollten zu app.py hinzugefügt werden (nach den Error Handlers, vor if __name__) """ # ============================================================================ # ADMIN ROUTES (diese zeilen in app.py hinzufügen!) # ============================================================================ @app.route("/admin", methods=["GET"]) @auth.login_required def admin_dashboard(): """Admin Dashboard - nur für Admin-Benutzer""" user = auth.current_user() if user not in ADMIN_USERS: log_access(user, "/admin", "GET", 403) return jsonify({"error": "Unauthorized - Admin access required"}), 403 log_access(user, "/admin", "GET") return render_template("admin.html") @app.route("/api/admin/stats", methods=["GET"]) @auth.login_required def get_admin_stats(): """Statistiken für Admin Dashboard""" user = auth.current_user() if user not in ADMIN_USERS: log_access(user, "/api/admin/stats", "GET", 403) return jsonify({"error": "Unauthorized"}), 403 log_access(user, "/api/admin/stats", "GET") logs = [] if os.path.exists(LOG_FILE): try: with open(LOG_FILE, "r") as f: logs = json.load(f) except json.JSONDecodeError: logs = [] # Berechne Statistiken total_requests = len(logs) unique_users = len(set(log.get("username", "unknown") for log in logs)) failed_logins = len([l for l in logs if l.get("status") == 401]) return jsonify({ "total_requests": total_requests, "unique_users": unique_users, "failed_logins": failed_logins, "timestamp": datetime.now().isoformat() }), 200 @app.route("/api/admin/logs", methods=["GET"]) @auth.login_required def get_admin_logs(): """Access Logs für Admin Dashboard""" user = auth.current_user() if user not in ADMIN_USERS: log_access(user, "/api/admin/logs", "GET", 403) return jsonify({"error": "Unauthorized"}), 403 log_access(user, "/api/admin/logs", "GET") logs = [] if os.path.exists(LOG_FILE): try: with open(LOG_FILE, "r") as f: logs = json.load(f) except json.JSONDecodeError: logs = [] # Sortiere nach Zeitstempel absteigend (neueste zuerst) logs_sorted = sorted(logs, key=lambda x: x.get("timestamp", ""), reverse=True) # Optionales Limit (letzte 500 Logs) return jsonify({"logs": logs_sorted[-500:]}), 200 @app.route("/api/admin/export", methods=["GET"]) @auth.login_required def export_logs(): """Exportiere Logs als CSV/JSON""" user = auth.current_user() if user not in ADMIN_USERS: return jsonify({"error": "Unauthorized"}), 403 log_access(user, "/api/admin/export", "GET") logs = [] if os.path.exists(LOG_FILE): try: with open(LOG_FILE, "r") as f: logs = json.load(f) except json.JSONDecodeError: logs = [] # Optional: Als CSV exportieren fmt = request.args.get("format", "json") if fmt == "csv": import csv from io import StringIO output = StringIO() writer = csv.DictWriter(output, fieldnames=["timestamp", "username", "endpoint", "method", "status"]) writer.writeheader() writer.writerows(logs) response = app.make_response(output.getvalue()) response.headers["Content-Disposition"] = f"attachment; filename=logs_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" response.headers["Content-Type"] = "text/csv" return response else: response = app.make_response(json.dumps(logs, indent=2)) response.headers["Content-Disposition"] = f"attachment; filename=logs_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json" response.headers["Content-Type"] = "application/json" return response # ============================================================================ # OPTIONAL: Admin-Utility-Routes # ============================================================================ @app.route("/api/admin/clear-logs", methods=["POST"]) @auth.login_required def clear_logs(): """Lösche alle Logs (nur für Admin, mit Bestätigung)""" user = auth.current_user() if user not in ADMIN_USERS: return jsonify({"error": "Unauthorized"}), 403 # Safety: Verlange "confirm=true" Query Parameter confirm = request.args.get("confirm") == "true" if not confirm: return jsonify({"error": "Confirmation required (add ?confirm=true)"}), 400 log_access(user, "/api/admin/clear-logs", "POST") # Backup erstellen vor dem Löschen if os.path.exists(LOG_FILE): backup_file = LOG_FILE + f".backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}" import shutil shutil.copy(LOG_FILE, backup_file) # Logs leeren with open(LOG_FILE, "w") as f: json.dump([], f) return jsonify({ "status": "success", "message": "Alle Logs wurden gelöscht (Backup erstellt)" }), 200 @app.route("/api/admin/system-info", methods=["GET"]) @auth.login_required def get_system_info(): """System-Information für Admin""" user = auth.current_user() if user not in ADMIN_USERS: return jsonify({"error": "Unauthorized"}), 403 log_access(user, "/api/admin/system-info", "GET") import psutil return jsonify({ "environment": os.getenv("FLASK_ENV", "production"), "debug_mode": app.debug, "database_file": LOG_FILE, "database_size_kb": os.path.getsize(LOG_FILE) / 1024 if os.path.exists(LOG_FILE) else 0, "timestamp": datetime.now().isoformat(), # Optional: CPU/RAM Info # "cpu_percent": psutil.cpu_percent(), # "memory_percent": psutil.virtual_memory().percent, }), 200