180 lines
5.8 KiB
Python
180 lines
5.8 KiB
Python
"""
|
|
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
|