"Feature: Update admin interface and database schema"
This commit is contained in:
parent
cf297e8e16
commit
ca9abadc6a
@ -354,15 +354,18 @@ def login():
|
||||
@app.route("/auth/logout", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def auth_logout():
|
||||
username = current_user.username if hasattr(current_user, "username") else "Unbekannt"
|
||||
"""Meldet den Benutzer ab."""
|
||||
app_logger.info(f"Benutzer {current_user.email} hat sich abgemeldet")
|
||||
logout_user()
|
||||
auth_logger.info(f"Benutzer {username} hat sich abgemeldet")
|
||||
|
||||
# Unterscheiden zwischen JSON-Anfragen und normalen Anfragen
|
||||
if request.is_json or request.headers.get('Content-Type') == 'application/json':
|
||||
return jsonify({"success": True, "redirect_url": url_for("login")})
|
||||
else:
|
||||
return redirect(url_for("login"))
|
||||
flash("Sie wurden erfolgreich abgemeldet.", "info")
|
||||
return redirect(url_for("login"))
|
||||
|
||||
@app.route("/auth/reset-password-request", methods=["GET", "POST"])
|
||||
def reset_password_request():
|
||||
"""Passwort-Reset anfordern (Placeholder)."""
|
||||
# TODO: Implement password reset functionality
|
||||
flash("Passwort-Reset-Funktionalität ist noch nicht implementiert.", "info")
|
||||
return redirect(url_for("login"))
|
||||
|
||||
@app.route("/auth/api/login", methods=["POST"])
|
||||
def api_login():
|
||||
|
Binary file not shown.
@ -518,14 +518,20 @@
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h2 class="text-2xl font-bold text-slate-900 dark:text-white">System Logs</h2>
|
||||
<div class="flex space-x-3">
|
||||
<select class="px-4 py-2 bg-white dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-xl text-slate-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||
<option>Alle Logs</option>
|
||||
<option>Fehler</option>
|
||||
<option>Warnungen</option>
|
||||
<option>Info</option>
|
||||
<option>Debug</option>
|
||||
<select id="log-level-filter" class="px-4 py-2 bg-white dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-xl text-slate-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||
<option value="all">Alle Logs</option>
|
||||
<option value="error">Fehler</option>
|
||||
<option value="warning">Warnungen</option>
|
||||
<option value="info">Info</option>
|
||||
<option value="debug">Debug</option>
|
||||
</select>
|
||||
<button class="inline-flex items-center px-4 py-2 bg-gradient-to-r from-slate-500 to-slate-600 text-white rounded-xl hover:from-slate-600 hover:to-slate-700 transition-all duration-300 shadow-lg hover:shadow-xl">
|
||||
<button id="refresh-logs-btn" class="inline-flex items-center px-4 py-2 bg-gradient-to-r from-green-500 to-green-600 text-white rounded-xl hover:from-green-600 hover:to-green-700 transition-all duration-300 shadow-lg hover:shadow-xl">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
|
||||
</svg>
|
||||
Aktualisieren
|
||||
</button>
|
||||
<button id="export-logs-btn" class="inline-flex items-center px-4 py-2 bg-gradient-to-r from-slate-500 to-slate-600 text-white rounded-xl hover:from-slate-600 hover:to-slate-700 transition-all duration-300 shadow-lg hover:shadow-xl">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
|
||||
</svg>
|
||||
@ -534,29 +540,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Log Entries -->
|
||||
<div class="space-y-2 max-h-96 overflow-y-auto">
|
||||
{% for log in logs %}
|
||||
<div class="bg-white/60 dark:bg-slate-700/60 backdrop-blur-sm rounded-lg border border-slate-200 dark:border-slate-600 p-4 shadow-sm">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex items-start space-x-3">
|
||||
{% set log_colors = {
|
||||
'ERROR': 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200',
|
||||
'WARNING': 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200',
|
||||
'INFO': 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200',
|
||||
'DEBUG': 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-200'
|
||||
} %}
|
||||
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full {{ log_colors.get(log.level, 'bg-gray-100 text-gray-800') }}">
|
||||
{{ log.level }}
|
||||
</span>
|
||||
<div>
|
||||
<p class="text-sm text-slate-900 dark:text-white">{{ log.message }}</p>
|
||||
<p class="text-xs text-slate-500 dark:text-slate-400 mt-1">{{ log.module }} - {{ log.timestamp | format_datetime('%d.%m.%Y %H:%M:%S') if log.timestamp else 'Unbekannt' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Log Entries Container -->
|
||||
<div id="logs-container" class="space-y-2 max-h-96 overflow-y-auto">
|
||||
<!-- Logs werden hier dynamisch geladen -->
|
||||
<div class="flex justify-center items-center py-12">
|
||||
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 dark:border-blue-400"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -690,6 +679,44 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
});
|
||||
|
||||
// Logs-Tab Event-Handlers und Funktionen
|
||||
const refreshLogsBtn = document.getElementById('refresh-logs-btn');
|
||||
if (refreshLogsBtn) {
|
||||
refreshLogsBtn.addEventListener('click', loadLogs);
|
||||
}
|
||||
|
||||
const exportLogsBtn = document.getElementById('export-logs-btn');
|
||||
if (exportLogsBtn) {
|
||||
exportLogsBtn.addEventListener('click', function() {
|
||||
window.location.href = '/api/admin/logs/export';
|
||||
});
|
||||
}
|
||||
|
||||
const logLevelFilter = document.getElementById('log-level-filter');
|
||||
if (logLevelFilter) {
|
||||
logLevelFilter.addEventListener('change', function() {
|
||||
if (window.logsData) {
|
||||
const level = this.value;
|
||||
if (level === 'all') {
|
||||
window.filteredLogs = [...window.logsData];
|
||||
} else {
|
||||
window.filteredLogs = window.logsData.filter(log =>
|
||||
log.level.toLowerCase() === level.toLowerCase()
|
||||
);
|
||||
}
|
||||
renderLogs();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Logs beim Laden des Logs-Tabs automatisch laden
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const activeTab = urlParams.get('tab');
|
||||
if (activeTab === 'logs') {
|
||||
// Kurz warten, damit das DOM vollständig geladen ist
|
||||
setTimeout(loadLogs, 500);
|
||||
}
|
||||
|
||||
// Start Live-Updates
|
||||
startLiveUpdates();
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user