FIX 3 für Codex

Dieser Commit ist enthalten in:
2025-06-18 01:35:54 +02:00
Ursprung a9cfecc699
Commit 231aa4caed
30 geänderte Dateien mit 573 neuen und 213 gelöschten Zeilen

Datei anzeigen

@@ -11,7 +11,7 @@
<h1 class="display-1">404</h1>
<h2>Seite nicht gefunden</h2>
<p>Die angeforderte Seite konnte nicht gefunden werden.</p>
<a href="/" class="btn btn-primary">Zur Startseite</a>
<a href="{{ url_for('admin.dashboard') }}" class="btn btn-primary">Zur Startseite</a>
</div>
</div>
</div>

Datei anzeigen

@@ -11,7 +11,7 @@
<h1 class="display-1">500</h1>
<h2>Interner Serverfehler</h2>
<p>Es ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.</p>
<a href="/" class="btn btn-primary">Zur Startseite</a>
<a href="{{ url_for('admin.dashboard') }}" class="btn btn-primary">Zur Startseite</a>
</div>
</div>
</div>

Datei anzeigen

@@ -115,12 +115,12 @@
<h1 class="mb-0">Ressourcen hinzufügen</h1>
<p class="text-muted mb-0">Fügen Sie neue Domains, IPs oder Telefonnummern zum Pool hinzu</p>
</div>
<a href="{{ url_for('resources', show_test=show_test) }}" class="btn btn-secondary">
<a href="{{ url_for('resources.resources', show_test=show_test) }}" class="btn btn-secondary">
← Zurück zur Übersicht
</a>
</div>
<form method="post" action="{{ url_for('add_resources', show_test=show_test) }}" id="addResourceForm">
<form method="post" action="{{ url_for('resources.add_resources', show_test=show_test) }}" id="addResourceForm">
<!-- Resource Type Selection -->
<div class="card main-card mb-4">
<div class="card-header bg-white">
@@ -278,7 +278,7 @@ my-website.io</pre>
<!-- Submit Buttons -->
<div class="d-flex justify-content-between">
<button type="button" class="btn btn-secondary" onclick="window.location.href='{{ url_for('resources', show_test=show_test) }}'">
<button type="button" class="btn btn-secondary" onclick="window.location.href='{{ url_for('resources.resources', show_test=show_test) }}'">
<i class="fas fa-times"></i> Abbrechen
</button>
<button type="submit" class="btn btn-success btn-lg" id="submitBtn" disabled>

Datei anzeigen

@@ -5,10 +5,10 @@
{% macro sortable_header(label, field, current_sort, current_order) %}
<th>
{% if current_sort == field %}
<a href="{{ url_for('audit_log', sort=field, order='desc' if current_order == 'asc' else 'asc', user=filter_user, action=filter_action, entity=filter_entity, page=1) }}"
<a href="{{ url_for('admin.audit_log', sort=field, order='desc' if current_order == 'asc' else 'asc', user=filter_user, action=filter_action, entity=filter_entity, page=1) }}"
class="server-sortable">
{% else %}
<a href="{{ url_for('audit_log', sort=field, order='asc', user=filter_user, action=filter_action, entity=filter_entity, page=1) }}"
<a href="{{ url_for('admin.audit_log', sort=field, order='asc', user=filter_user, action=filter_action, entity=filter_entity, page=1) }}"
class="server-sortable">
{% endif %}
{{ label }}
@@ -70,7 +70,7 @@
<!-- Filter -->
<div class="card mb-3">
<div class="card-body">
<form method="get" action="/audit" id="auditFilterForm">
<form method="get" action="{{ url_for('admin.audit_log') }}" id="auditFilterForm">
<div class="row g-3 align-items-end">
<div class="col-md-3">
<label for="user" class="form-label">Benutzer</label>
@@ -114,15 +114,15 @@
</div>
<div class="col-md-3">
<div class="d-flex gap-2">
<a href="/audit" class="btn btn-outline-secondary">Zurücksetzen</a>
<a href="{{ url_for('admin.audit_log') }}" class="btn btn-outline-secondary">Zurücksetzen</a>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
<i class="bi bi-download"></i> Export
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/export/audit?format=excel&user={{ filter_user }}&action={{ filter_action }}&entity={{ filter_entity }}">
<li><a class="dropdown-item" href="{{ url_for('export.export_audit', format='excel', user=filter_user, action=filter_action, entity=filter_entity) }}">
<i class="bi bi-file-earmark-excel text-success"></i> Excel Export</a></li>
<li><a class="dropdown-item" href="/export/audit?format=csv&user={{ filter_user }}&action={{ filter_action }}&entity={{ filter_entity }}">
<li><a class="dropdown-item" href="{{ url_for('export.export_audit', format='csv', user=filter_user, action=filter_action, entity=filter_entity) }}">
<i class="bi bi-file-earmark-text"></i> CSV Export</a></li>
</ul>
</div>
@@ -248,31 +248,31 @@
<ul class="pagination justify-content-center">
<!-- Erste Seite -->
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('audit_log', page=1, user=filter_user, action=filter_action, entity=filter_entity, sort=sort, order=order) }}">Erste</a>
<a class="page-link" href="{{ url_for('admin.audit_log', page=1, user=filter_user, action=filter_action, entity=filter_entity, sort=sort, order=order) }}">Erste</a>
</li>
<!-- Vorherige Seite -->
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('audit_log', page=page-1, user=filter_user, action=filter_action, entity=filter_entity, sort=sort, order=order) }}"></a>
<a class="page-link" href="{{ url_for('admin.audit_log', page=page-1, user=filter_user, action=filter_action, entity=filter_entity, sort=sort, order=order) }}"></a>
</li>
<!-- Seitenzahlen -->
{% for p in range(1, total_pages + 1) %}
{% if p >= page - 2 and p <= page + 2 %}
<li class="page-item {% if p == page %}active{% endif %}">
<a class="page-link" href="{{ url_for('audit_log', page=p, user=filter_user, action=filter_action, entity=filter_entity, sort=sort, order=order) }}">{{ p }}</a>
<a class="page-link" href="{{ url_for('admin.audit_log', page=p, user=filter_user, action=filter_action, entity=filter_entity, sort=sort, order=order) }}">{{ p }}</a>
</li>
{% endif %}
{% endfor %}
<!-- Nächste Seite -->
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('audit_log', page=page+1, user=filter_user, action=filter_action, entity=filter_entity, sort=sort, order=order) }}"></a>
<a class="page-link" href="{{ url_for('admin.audit_log', page=page+1, user=filter_user, action=filter_action, entity=filter_entity, sort=sort, order=order) }}"></a>
</li>
<!-- Letzte Seite -->
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('audit_log', page=total_pages, user=filter_user, action=filter_action, entity=filter_entity, sort=sort, order=order) }}">Letzte</a>
<a class="page-link" href="{{ url_for('admin.audit_log', page=total_pages, user=filter_user, action=filter_action, entity=filter_entity, sort=sort, order=order) }}">Letzte</a>
</li>
</ul>
<p class="text-center text-muted">

Datei anzeigen

@@ -132,7 +132,7 @@
Ich habe die Backup-Codes sicher gespeichert
</label>
</div>
<a href="{{ url_for('profile') }}" class="btn btn-lg btn-success" id="continueBtn" style="display: none;">
<a href="{{ url_for('auth.profile') }}" class="btn btn-lg btn-success" id="continueBtn" style="display: none;">
✅ Weiter zum Profil
</a>
</div>

Datei anzeigen

@@ -120,7 +120,7 @@
<td class="backup-actions">
{% if backup.status == 'success' %}
<div class="btn-group btn-group-sm" role="group">
<a href="/backup/download/{{ backup.id }}"
<a href="{{ url_for('admin.download_backup', backup_id=backup.id) }}"
class="btn btn-outline-primary"
title="Backup herunterladen">
📥 Download
@@ -197,7 +197,7 @@ function createBackup() {
btn.disabled = true;
btn.innerHTML = '⏳ Backup wird erstellt...';
fetch('/backup/create', {
fetch('{{ url_for('admin.create_backup') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -252,7 +252,7 @@ function confirmRestore() {
loadingDiv.innerHTML = '<div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div>';
document.body.appendChild(loadingDiv);
fetch(`/backup/restore/${backupId}`, {
fetch(`{{ url_for('admin.restore_backup', backup_id='') }}${backupId}`, {
method: 'POST',
body: formData
})
@@ -260,7 +260,7 @@ function confirmRestore() {
.then(data => {
if (data.success) {
alert('✅ ' + data.message + '\n\nDie Seite wird neu geladen...');
window.location.href = '/';
window.location.href = '{{ url_for('admin.dashboard') }}';
} else {
alert('❌ ' + data.message);
}
@@ -278,7 +278,7 @@ function deleteBackup(backupId, filename) {
return;
}
fetch(`/backup/delete/${backupId}`, {
fetch(`{{ url_for('admin.delete_backup', backup_id='') }}${backupId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',

Datei anzeigen

@@ -340,7 +340,7 @@
<body class="bg-light">
<nav class="navbar navbar-dark bg-dark navbar-expand-lg">
<div class="container-fluid">
<a href="/" class="navbar-brand text-decoration-none">🎛️ AccountForger - Admin Panel</a>
<a href="{{ url_for('admin.dashboard') }}" class="navbar-brand text-decoration-none">🎛️ AccountForger - Admin Panel</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
@@ -353,8 +353,8 @@
⏱️ <span id="timer-display">5:00</span>
</div>
<span class="text-white me-3">Angemeldet als: {{ username }}</span>
<a href="/profile" class="btn btn-outline-light btn-sm me-2">👤 Profil</a>
<a href="/logout" class="btn btn-outline-light btn-sm">Abmelden</a>
<a href="{{ url_for('auth.profile') }}" class="btn btn-outline-light btn-sm me-2">👤 Profil</a>
<a href="{{ url_for('auth.logout') }}" class="btn btn-outline-light btn-sm">Abmelden</a>
</div>
</div>
</div>
@@ -363,40 +363,40 @@
<!-- Sidebar Navigation -->
<aside class="sidebar" id="sidebar">
<ul class="sidebar-nav">
<li class="nav-item {% if request.endpoint in ['customers_licenses', 'edit_customer', 'create_customer', 'edit_license', 'create_license', 'batch_licenses'] %}has-active-child{% endif %}">
<a class="nav-link has-submenu {% if request.endpoint == 'customers_licenses' %}active{% endif %}" href="/customers-licenses">
<li class="nav-item {% if request.endpoint in ['customers.customers_licenses', 'customers.edit_customer', 'customers.create_customer', 'licenses.edit_license', 'licenses.create_license', 'batch.batch_create'] %}has-active-child{% endif %}">
<a class="nav-link has-submenu {% if request.endpoint == 'customers.customers_licenses' %}active{% endif %}" href="{{ url_for('customers.customers_licenses') }}">
<i class="bi bi-people"></i>
<span>Kunden & Lizenzen</span>
</a>
<ul class="sidebar-submenu">
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'create_customer' %}active{% endif %}" href="/customer/create">
<a class="nav-link {% if request.endpoint == 'customers.create_customer' %}active{% endif %}" href="{{ url_for('customers.create_customer') }}">
<i class="bi bi-person-plus"></i>
<span>Neuer Kunde</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'create_license' %}active{% endif %}" href="/create">
<a class="nav-link {% if request.endpoint == 'licenses.create_license' %}active{% endif %}" href="{{ url_for('licenses.create_license') }}">
<i class="bi bi-plus-circle"></i>
<span>Neue Lizenz</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'batch_licenses' %}active{% endif %}" href="/batch">
<a class="nav-link {% if request.endpoint == 'batch.batch_create' %}active{% endif %}" href="{{ url_for('batch.batch_create') }}">
<i class="bi bi-stack"></i>
<span>Batch-Erstellung</span>
</a>
</li>
</ul>
</li>
<li class="nav-item {% if request.endpoint in ['resources', 'add_resources'] %}has-active-child{% endif %}">
<a class="nav-link has-submenu {% if request.endpoint == 'resources' %}active{% endif %}" href="/resources">
<li class="nav-item {% if request.endpoint in ['resources.resources', 'resources.add_resources'] %}has-active-child{% endif %}">
<a class="nav-link has-submenu {% if request.endpoint == 'resources.resources' %}active{% endif %}" href="{{ url_for('resources.resources') }}">
<i class="bi bi-box-seam"></i>
<span>Resource Pool</span>
</a>
<ul class="sidebar-submenu">
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'add_resources' %}active{% endif %}" href="/resources/add">
<a class="nav-link {% if request.endpoint == 'resources.add_resources' %}active{% endif %}" href="{{ url_for('resources.add_resources') }}">
<i class="bi bi-plus-square"></i>
<span>Ressourcen hinzufügen</span>
</a>
@@ -404,25 +404,25 @@
</ul>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'audit_log' %}active{% endif %}" href="/audit">
<a class="nav-link {% if request.endpoint == 'admin.audit_log' %}active{% endif %}" href="{{ url_for('admin.audit_log') }}">
<i class="bi bi-journal-text"></i>
<span>Audit-Log</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'sessions' %}active{% endif %}" href="/sessions">
<a class="nav-link {% if request.endpoint == 'sessions.sessions' %}active{% endif %}" href="{{ url_for('sessions.sessions') }}">
<i class="bi bi-people"></i>
<span>Sitzungen</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'backups' %}active{% endif %}" href="/backups">
<a class="nav-link {% if request.endpoint == 'admin.backups' %}active{% endif %}" href="{{ url_for('admin.backups') }}">
<i class="bi bi-cloud-download"></i>
<span>Backups</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'blocked_ips' %}active{% endif %}" href="/security/blocked-ips">
<a class="nav-link {% if request.endpoint == 'admin.blocked_ips' %}active{% endif %}" href="{{ url_for('admin.blocked_ips') }}">
<i class="bi bi-shield-lock"></i>
<span>Sicherheit</span>
</a>
@@ -509,7 +509,7 @@
// Session verlängern
function extendSession() {
fetch('/heartbeat', {
fetch('{{ url_for('auth.heartbeat') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
@@ -531,7 +531,7 @@
if (timeRemaining <= 0) {
clearInterval(timerInterval);
window.location.href = '/logout';
window.location.href = '{{ url_for('auth.logout') }}';
}
}

Datei anzeigen

@@ -6,7 +6,7 @@
<div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>🔑 Batch-Lizenzen erstellen</h2>
<a href="/customers-licenses" class="btn btn-secondary">← Zurück zur Übersicht</a>
<a href="{{ url_for('customers.customers_licenses') }}" class="btn btn-secondary">← Zurück zur Übersicht</a>
</div>
<div class="alert alert-info">
@@ -26,7 +26,7 @@
{% endif %}
{% endwith %}
<form method="post" action="/batch" accept-charset="UTF-8">
<form method="post" action="{{ url_for('batch.batch_create') }}" accept-charset="UTF-8">
<div class="row g-3">
<div class="col-md-12">
<label for="customerSelect" class="form-label">Kunde auswählen</label>

Datei anzeigen

@@ -7,7 +7,7 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>✅ Batch-Lizenzen erfolgreich generiert</h2>
<div>
<a href="/batch" class="btn btn-primary">🔑 Weitere Batch erstellen</a>
<a href="{{ url_for('batch.batch_create') }}" class="btn btn-primary">🔑 Weitere Batch erstellen</a>
</div>
</div>
@@ -43,7 +43,7 @@
<div class="card-body">
<p>Exportieren Sie die generierten Lizenzen für den Kunden:</p>
<div class="d-flex gap-2">
<a href="/batch/export" class="btn btn-success">
<a href="{{ url_for('batch.export_batch') }}" class="btn btn-success">
📄 Als CSV exportieren
</a>
<button class="btn btn-outline-primary" onclick="copyAllKeys()">
@@ -102,7 +102,7 @@
<!-- Hinweis -->
<div class="alert alert-info mt-4">
<strong>💡 Tipp:</strong> Die generierten Lizenzen sind sofort aktiv und können verwendet werden.
Sie finden alle Lizenzen auch in der <a href="/licenses?search={{ customer }}">Lizenzübersicht</a>.
Sie finden alle Lizenzen auch in der <a href="{{ url_for('licenses.licenses', search=customer) }}">Lizenzübersicht</a>.
</div>
</div>

Datei anzeigen

@@ -51,7 +51,7 @@
<td>
<div class="btn-group btn-group-sm" role="group">
{% if ip.is_active %}
<form method="post" action="/security/unblock-ip" class="d-inline">
<form method="post" action="{{ url_for('admin.unblock_ip') }}" class="d-inline">
<input type="hidden" name="ip_address" value="{{ ip.ip_address }}">
<button type="submit" class="btn btn-success"
onclick="return confirm('IP {{ ip.ip_address }} wirklich entsperren?')">
@@ -59,7 +59,7 @@
</button>
</form>
{% endif %}
<form method="post" action="/security/clear-attempts" class="d-inline ms-1">
<form method="post" action="{{ url_for('admin.clear_attempts') }}" class="d-inline ms-1">
<input type="hidden" name="ip_address" value="{{ ip.ip_address }}">
<button type="submit" class="btn btn-warning"
onclick="return confirm('Alle Versuche für IP {{ ip.ip_address }} zurücksetzen?')">

Datei anzeigen

@@ -6,12 +6,12 @@
<div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>👤 Neuer Kunde anlegen</h2>
<a href="/customers-licenses" class="btn btn-secondary">← Zurück zur Übersicht</a>
<a href="{{ url_for('customers.customers_licenses') }}" class="btn btn-secondary">← Zurück zur Übersicht</a>
</div>
<div class="card">
<div class="card-body">
<form method="post" action="/customer/create" accept-charset="UTF-8">
<form method="post" action="{{ url_for('customers.create_customer') }}" accept-charset="UTF-8">
<div class="row g-3">
<div class="col-md-6">
<label for="name" class="form-label">Kundenname <span class="text-danger">*</span></label>
@@ -44,7 +44,7 @@
<div class="mt-4">
<button type="submit" class="btn btn-primary">💾 Kunde anlegen</button>
<a href="/customers-licenses" class="btn btn-secondary">Abbrechen</a>
<a href="{{ url_for('customers.customers_licenses') }}" class="btn btn-secondary">Abbrechen</a>
</div>
</form>
</div>

Datei anzeigen

@@ -5,10 +5,10 @@
{% macro sortable_header(label, field, current_sort, current_order) %}
<th>
{% if current_sort == field %}
<a href="{{ url_for('customers', sort=field, order='desc' if current_order == 'asc' else 'asc', search=search, page=1) }}"
<a href="{{ url_for('customers.customers', sort=field, order='desc' if current_order == 'asc' else 'asc', search=search, show_test=show_test, page=1) }}"
class="server-sortable">
{% else %}
<a href="{{ url_for('customers', sort=field, order='asc', search=search, page=1) }}"
<a href="{{ url_for('customers.customers', sort=field, order='asc', search=search, show_test=show_test, page=1) }}"
class="server-sortable">
{% endif %}
{{ label }}
@@ -32,7 +32,7 @@
<!-- Suchformular -->
<div class="card mb-3">
<div class="card-body">
<form method="get" action="/customers" id="customerSearchForm" class="row g-3 align-items-end">
<form method="get" action="{{ url_for('customers.customers') }}" id="customerSearchForm" class="row g-3 align-items-end">
<div class="col-md-8">
<label for="search" class="form-label">🔍 Suchen</label>
<input type="text" class="form-control" id="search" name="search"
@@ -49,13 +49,13 @@
</div>
</div>
<div class="col-md-2">
<a href="/customers" class="btn btn-outline-secondary w-100">Zurücksetzen</a>
<a href="{{ url_for('customers.customers') }}" class="btn btn-outline-secondary w-100">Zurücksetzen</a>
</div>
</form>
{% if search %}
<div class="mt-2">
<small class="text-muted">Suchergebnisse für: <strong>{{ search }}</strong></small>
<a href="/customers" class="btn btn-sm btn-outline-secondary ms-2">✖ Suche zurücksetzen</a>
<a href="{{ url_for('customers.customers') }}" class="btn btn-sm btn-outline-secondary ms-2">✖ Suche zurücksetzen</a>
</div>
{% endif %}
</div>
@@ -92,9 +92,9 @@
</td>
<td>
<div class="btn-group btn-group-sm" role="group">
<a href="/customer/edit/{{ customer.id }}" class="btn btn-outline-primary">✏️ Bearbeiten</a>
<a href="{{ url_for('customers.edit_customer', customer_id=customer.id) }}" class="btn btn-outline-primary">✏️ Bearbeiten</a>
{% if customer.license_count == 0 %}
<form method="post" action="/customer/delete/{{ customer.id }}" style="display: inline;" onsubmit="return confirm('Kunde wirklich löschen?');">
<form method="post" action="{{ url_for('customers.delete_customer', customer_id=customer.id) }}" style="display: inline;" onsubmit="return confirm('Kunde wirklich löschen?');">
<button type="submit" class="btn btn-outline-danger">🗑️ Löschen</button>
</form>
{% else %}
@@ -111,10 +111,10 @@
<div class="text-center py-5">
{% if search %}
<p class="text-muted">Keine Kunden gefunden für: <strong>{{ search }}</strong></p>
<a href="/customers" class="btn btn-secondary">Alle Kunden anzeigen</a>
<a href="{{ url_for('customers.customers') }}" class="btn btn-secondary">Alle Kunden anzeigen</a>
{% else %}
<p class="text-muted">Noch keine Kunden vorhanden.</p>
<a href="/create" class="btn btn-primary">Erste Lizenz erstellen</a>
<a href="{{ url_for('licenses.create_license') }}" class="btn btn-primary">Erste Lizenz erstellen</a>
{% endif %}
</div>
{% endif %}
@@ -126,31 +126,31 @@
<ul class="pagination justify-content-center">
<!-- Erste Seite -->
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('customers', page=1, search=search, sort=sort, order=order) }}">Erste</a>
<a class="page-link" href="{{ url_for('customers.customers', page=1, search=search, sort=sort, order=order, show_test=show_test) }}">Erste</a>
</li>
<!-- Vorherige Seite -->
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('customers', page=page-1, search=search, sort=sort, order=order) }}"></a>
<a class="page-link" href="{{ url_for('customers.customers', page=page-1, search=search, sort=sort, order=order, show_test=show_test) }}"></a>
</li>
<!-- Seitenzahlen -->
{% for p in range(1, total_pages + 1) %}
{% if p >= page - 2 and p <= page + 2 %}
<li class="page-item {% if p == page %}active{% endif %}">
<a class="page-link" href="{{ url_for('customers', page=p, search=search, sort=sort, order=order) }}">{{ p }}</a>
<a class="page-link" href="{{ url_for('customers.customers', page=p, search=search, sort=sort, order=order, show_test=show_test) }}">{{ p }}</a>
</li>
{% endif %}
{% endfor %}
<!-- Nächste Seite -->
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('customers', page=page+1, search=search, sort=sort, order=order) }}"></a>
<a class="page-link" href="{{ url_for('customers.customers', page=page+1, search=search, sort=sort, order=order, show_test=show_test) }}"></a>
</li>
<!-- Letzte Seite -->
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('customers', page=total_pages, search=search, sort=sort, order=order) }}">Letzte</a>
<a class="page-link" href="{{ url_for('customers.customers', page=total_pages, search=search, sort=sort, order=order, show_test=show_test) }}">Letzte</a>
</li>
</ul>
<p class="text-center text-muted">

Datei anzeigen

@@ -13,14 +13,14 @@
<i class="bi bi-download"></i> Export
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/export/customers?format=excel{% if request.args.get('show_test') %}&include_test=true{% endif %}">
<li><a class="dropdown-item" href="{{ url_for('export.export_customers', format='excel', include_test=request.args.get('show_test')) }}">
<i class="bi bi-file-earmark-excel text-success"></i> Kunden (Excel)</a></li>
<li><a class="dropdown-item" href="/export/customers?format=csv{% if request.args.get('show_test') %}&include_test=true{% endif %}">
<li><a class="dropdown-item" href="{{ url_for('export.export_customers', format='csv', include_test=request.args.get('show_test')) }}">
<i class="bi bi-file-earmark-text"></i> Kunden (CSV)</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="/export/licenses?format=excel{% if request.args.get('show_test') %}&include_test=true{% endif %}{% if selected_customer_id %}&customer_id={{ selected_customer_id }}{% endif %}">
<li><a class="dropdown-item" href="{{ url_for('export.export_licenses', format='excel', include_test=request.args.get('show_test'), customer_id=selected_customer_id) }}">
<i class="bi bi-file-earmark-excel text-success"></i> Lizenzen (Excel)</a></li>
<li><a class="dropdown-item" href="/export/licenses?format=csv{% if request.args.get('show_test') %}&include_test=true{% endif %}{% if selected_customer_id %}&customer_id={{ selected_customer_id }}{% endif %}">
<li><a class="dropdown-item" href="{{ url_for('export.export_licenses', format='csv', include_test=request.args.get('show_test'), customer_id=selected_customer_id) }}">
<i class="bi bi-file-earmark-text"></i> Lizenzen (CSV)</a></li>
</ul>
</div>
@@ -83,7 +83,7 @@
<i class="bi bi-inbox" style="font-size: 3rem; opacity: 0.3;"></i>
<p class="mt-3 mb-2">Keine Kunden vorhanden</p>
<small class="d-block mb-3">Erstellen Sie eine neue Lizenz, um automatisch einen Kunden anzulegen.</small>
<a href="/create" class="btn btn-sm btn-primary">
<a href="{{ url_for('licenses.create_license') }}" class="btn btn-sm btn-primary">
<i class="bi bi-plus-circle"></i> Neue Lizenz erstellen
</a>
</div>
@@ -104,7 +104,7 @@
<small class="text-muted">{{ selected_customer[2] }}</small>
</div>
<div>
<a href="/customer/edit/{{ selected_customer[0] }}?ref=customers-licenses{% if request.args.get('show_test') %}&show_test=true{% endif %}" class="btn btn-sm btn-outline-primary">
<a href="{{ url_for('customers.edit_customer', customer_id=selected_customer[0], ref='customers-licenses', show_test=request.args.get('show_test')) }}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-pencil"></i> Bearbeiten
</a>
</div>
@@ -179,7 +179,7 @@
<button class="btn btn-outline-info" onclick="showDeviceManagement({{ license[0] }})" title="Geräte verwalten">
<i class="bi bi-laptop"></i>
</button>
<a href="/license/edit/{{ license[0] }}{% if request.args.get('show_test') %}?ref=customers-licenses&show_test=true{% endif %}" class="btn btn-outline-secondary" title="Bearbeiten">
<a href="{{ url_for('licenses.edit_license', license_id=license[0], ref='customers-licenses', show_test=request.args.get('show_test')) }}" class="btn btn-outline-secondary" title="Bearbeiten">
<i class="bi bi-pencil"></i>
</a>
</div>
@@ -544,7 +544,7 @@ function updateLicenseView(customerId, licenses) {
function toggleLicenseStatus(licenseId, currentStatus) {
const newStatus = !currentStatus;
fetch(`/api/license/${licenseId}/toggle`, {
fetch(`{{ url_for('api.toggle_license', license_id='') }}${licenseId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -565,7 +565,7 @@ function toggleLicenseStatus(licenseId, currentStatus) {
// Direkt zur Lizenzerstellung navigieren
function showNewLicenseModal(customerId) {
window.location.href = `/create?customer_id=${customerId}${window.location.search ? '&' + window.location.search.substring(1) : ''}`;
window.location.href = `{{ url_for('licenses.create_license') }}?customer_id=${customerId}${window.location.search ? '&' + window.location.search.substring(1) : ''}`;
}
// Copy to clipboard
@@ -686,7 +686,7 @@ function showResourceDetails(licenseId, resourceType) {
</td>
<td>${resource.assigned_at}</td>
<td>
<a href="/resources?search=${encodeURIComponent(resource.value)}"
<a href="{{ url_for('resources.resources') }}?search=${encodeURIComponent(resource.value)}"
class="btn btn-sm btn-outline-primary" target="_blank">
<i class="bi bi-box-arrow-up-right"></i> Details
</a>
@@ -1052,7 +1052,7 @@ function saveResourceChanges() {
saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2" role="status"></span>Wird gespeichert...';
// API-Call zum Zuweisen der Ressourcen
fetch('/api/resources/allocate', {
fetch('{{ url_for('api.allocate_resources') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',

Datei anzeigen

@@ -72,7 +72,7 @@
<!-- Statistik-Karten -->
<div class="row g-3 mb-4">
<div class="col-md-4">
<a href="/customers-licenses" class="text-decoration-none">
<a href="{{ url_for('customers.customers_licenses') }}" class="text-decoration-none">
<div class="card stat-card h-100">
<div class="card-body text-center">
<div class="card-icon text-primary">👥</div>
@@ -83,7 +83,7 @@
</a>
</div>
<div class="col-md-4">
<a href="/customers-licenses" class="text-decoration-none">
<a href="{{ url_for('customers.customers_licenses') }}" class="text-decoration-none">
<div class="card stat-card h-100">
<div class="card-body text-center">
<div class="card-icon text-info">📋</div>
@@ -94,7 +94,7 @@
</a>
</div>
<div class="col-md-4">
<a href="/sessions" class="text-decoration-none">
<a href="{{ url_for('sessions.sessions') }}" class="text-decoration-none">
<div class="card stat-card h-100">
<div class="card-body text-center">
<div class="card-icon text-success{% if stats.active_sessions > 0 %} pulse-effect{% endif %}">🟢</div>
@@ -161,7 +161,7 @@
<!-- Backup-Status und Sicherheit nebeneinander -->
<div class="row g-3 mb-4">
<div class="col-md-6">
<a href="/backups" class="text-decoration-none">
<a href="{{ url_for('admin.backups') }}" class="text-decoration-none">
<div class="card stat-card h-100">
<div class="card-body">
<h5 class="card-title">💾 Backup-Status</h5>
@@ -210,7 +210,7 @@
<small class="text-muted">Fehlversuche heute</small>
</div>
</div>
<a href="/security/blocked-ips" class="btn btn-sm btn-outline-danger mt-3">IP-Verwaltung →</a>
<a href="{{ url_for('admin.blocked_ips') }}" class="btn btn-sm btn-outline-danger mt-3">IP-Verwaltung →</a>
</div>
</div>
</div>
@@ -277,14 +277,14 @@
<div class="col-md-4 mb-3">
<div class="d-flex align-items-center">
<div class="me-3">
<a href="/resources?type={{ type }}{{ '&show_test=true' if request.args.get('show_test') == 'true' else '' }}"
<a href="{{ url_for('resources.resources', type=type, show_test=request.args.get('show_test')) }}"
class="text-decoration-none">
<i class="fas fa-{{ 'globe' if type == 'domain' else ('network-wired' if type == 'ipv4' else 'phone') }} fa-2x text-{{ 'success' if data.available_percent > 50 else ('warning' if data.available_percent > 20 else 'danger') }}"></i>
</a>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">
<a href="/resources?type={{ type }}{{ '&show_test=true' if request.args.get('show_test') == 'true' else '' }}"
<a href="{{ url_for('resources.resources', type=type, show_test=request.args.get('show_test')) }}"
class="text-decoration-none text-dark">{{ type|upper }}</a>
</h6>
<div class="d-flex justify-content-between align-items-center">
@@ -303,14 +303,14 @@
</div>
<div class="d-flex justify-content-between mt-1">
<small class="text-muted">
<a href="/resources?type={{ type }}&status=allocated{{ '&show_test=true' if request.args.get('show_test') == 'true' else '' }}"
<a href="{{ url_for('resources.resources', type=type, status='allocated', show_test=request.args.get('show_test')) }}"
class="text-decoration-none text-muted">
{{ data.allocated }} zugeteilt
</a>
</small>
{% if data.quarantine > 0 %}
<small>
<a href="/resources?type={{ type }}&status=quarantine{{ '&show_test=true' if request.args.get('show_test') == 'true' else '' }}"
<a href="{{ url_for('resources.resources', type=type, status='quarantine', show_test=request.args.get('show_test')) }}"
class="text-decoration-none text-warning">
<i class="bi bi-exclamation-triangle"></i> {{ data.quarantine }} in Quarantäne
</a>
@@ -325,7 +325,7 @@
<div class="col-12 text-center text-muted">
<i class="fas fa-inbox fa-3x mb-3"></i>
<p>Keine Ressourcen im Pool vorhanden.</p>
<a href="/resources/add{{ '?show_test=true' if request.args.get('show_test') == 'true' else '' }}" class="btn btn-primary">
<a href="{{ url_for('resources.add_resources', show_test=request.args.get('show_test')) }}" class="btn btn-primary">
<i class="fas fa-plus"></i> Ressourcen hinzufügen
</a>
</div>
@@ -337,7 +337,7 @@
<i class="fas fa-exclamation-triangle"></i>
<strong>Kritisch:</strong> {{ resource_warning }}
</div>
<a href="/resources/add{{ '?show_test=true' if request.args.get('show_test') == 'true' else '' }}"
<a href="{{ url_for('resources.add_resources', show_test=request.args.get('show_test')) }}"
class="btn btn-sm btn-danger">
<i class="bi bi-plus"></i> Ressourcen auffüllen
</a>

Datei anzeigen

@@ -7,13 +7,13 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>Kunde bearbeiten</h2>
<div>
<a href="/customers-licenses{% if request.args.get('show_test') == 'true' %}?show_test=true{% endif %}" class="btn btn-secondary">👥 Zurück zur Übersicht</a>
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">👥 Zurück zur Übersicht</a>
</div>
</div>
<div class="card mb-4">
<div class="card-body">
<form method="post" action="/customer/edit/{{ customer.id }}" accept-charset="UTF-8">
<form method="post" action="{{ url_for('customers.edit_customer', customer_id=customer.id) }}" accept-charset="UTF-8">
{% if request.args.get('show_test') == 'true' %}
<input type="hidden" name="show_test" value="true">
{% endif %}
@@ -42,7 +42,7 @@
<div class="mt-4">
<button type="submit" class="btn btn-primary">💾 Änderungen speichern</button>
<a href="/customers-licenses{% if request.args.get('show_test') == 'true' %}?show_test=true{% endif %}" class="btn btn-secondary">Abbrechen</a>
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">Abbrechen</a>
</div>
</form>
</div>
@@ -87,7 +87,7 @@
{% endif %}
</td>
<td>
<a href="/license/edit/{{ license[0] }}" class="btn btn-outline-primary btn-sm">Bearbeiten</a>
<a href="{{ url_for('licenses.edit_license', license_id=license[0]) }}" class="btn btn-outline-primary btn-sm">Bearbeiten</a>
</td>
</tr>
{% endfor %}

Datei anzeigen

@@ -7,13 +7,13 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>Lizenz bearbeiten</h2>
<div>
<a href="/customers-licenses{% if request.args.get('show_test') == 'true' %}?show_test=true{% endif %}" class="btn btn-secondary">📋 Zurück zur Übersicht</a>
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">📋 Zurück zur Übersicht</a>
</div>
</div>
<div class="card">
<div class="card-body">
<form method="post" action="/license/edit/{{ license.id }}" accept-charset="UTF-8">
<form method="post" action="{{ url_for('licenses.edit_license', license_id=license.id) }}" accept-charset="UTF-8">
{% if request.args.get('show_test') == 'true' %}
<input type="hidden" name="show_test" value="true">
{% endif %}
@@ -75,7 +75,7 @@
<div class="mt-4">
<button type="submit" class="btn btn-primary">💾 Änderungen speichern</button>
<a href="/customers-licenses{% if request.args.get('show_test') == 'true' %}?show_test=true{% endif %}" class="btn btn-secondary">Abbrechen</a>
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">Abbrechen</a>
</div>
</form>
</div>

Datei anzeigen

@@ -6,10 +6,10 @@
<div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>Neue Lizenz erstellen</h2>
<a href="/customers-licenses" class="btn btn-secondary">← Zurück zur Übersicht</a>
<a href="{{ url_for('customers.customers_licenses') }}" class="btn btn-secondary">← Zurück zur Übersicht</a>
</div>
<form method="post" action="/create" accept-charset="UTF-8">
<form method="post" action="{{ url_for('licenses.create_license') }}" accept-charset="UTF-8">
<div class="row g-3">
<div class="col-md-12">
<label for="customerSelect" class="form-label">Kunde auswählen</label>
@@ -197,7 +197,7 @@ function generateLicenseKey() {
button.innerHTML = '⏳ Generiere...';
// API-Call
fetch('/api/generate-license-key', {
fetch('{{ url_for('api.api_generate_key') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -298,7 +298,7 @@ document.addEventListener('DOMContentLoaded', function() {
placeholder: '🔍 Kunde suchen oder neuen Kunden anlegen...',
allowClear: true,
ajax: {
url: '/api/customers',
url: '{{ url_for('api.api_customers') }}',
dataType: 'json',
delay: 250,
data: function (params) {
@@ -339,7 +339,7 @@ document.addEventListener('DOMContentLoaded', function() {
// Vorausgewählten Kunden setzen (falls von kombinierter Ansicht kommend)
{% if preselected_customer_id %}
// Lade Kundendetails und setze Auswahl
fetch('/api/customers?id={{ preselected_customer_id }}')
fetch('{{ url_for('api.api_customers') }}?id={{ preselected_customer_id }}')
.then(response => response.json())
.then(data => {
if (data.results && data.results.length > 0) {
@@ -403,7 +403,7 @@ function checkResourceAvailability() {
const phoneCount = parseInt(document.getElementById('phoneCount').value) || 0;
// API-Call zur Verfügbarkeitsprüfung
fetch(`/api/resources/check-availability?domain=${domainCount}&ipv4=${ipv4Count}&phone=${phoneCount}`)
fetch(`{{ url_for('api.check_resource_availability') }}?domain=${domainCount}&ipv4=${ipv4Count}&phone=${phoneCount}`)
.then(response => response.json())
.then(data => {
// Update der Verfügbarkeitsanzeigen

Datei anzeigen

@@ -5,10 +5,10 @@
{% macro sortable_header(label, field, current_sort, current_order) %}
<th>
{% if current_sort == field %}
<a href="{{ url_for('licenses', sort=field, order='desc' if current_order == 'asc' else 'asc', search=search, type=filter_type, status=filter_status, page=1) }}"
<a href="{{ url_for('licenses.licenses', sort=field, order='desc' if current_order == 'asc' else 'asc', search=search, type=filter_type, status=filter_status, page=1) }}"
class="server-sortable">
{% else %}
<a href="{{ url_for('licenses', sort=field, order='asc', search=search, type=filter_type, status=filter_status, page=1) }}"
<a href="{{ url_for('licenses.licenses', sort=field, order='asc', search=search, type=filter_type, status=filter_status, page=1) }}"
class="server-sortable">
{% endif %}
{{ label }}
@@ -35,7 +35,7 @@
<!-- Such- und Filterformular -->
<div class="card mb-3">
<div class="card-body">
<form method="get" action="/licenses" id="filterForm">
<form method="get" action="{{ url_for('licenses.licenses') }}" id="filterForm">
<div class="row g-3 align-items-end">
<div class="col-md-4">
<label for="search" class="form-label">🔍 Suchen</label>
@@ -64,7 +64,7 @@
</select>
</div>
<div class="col-md-3">
<a href="/licenses" class="btn btn-outline-secondary">Zurücksetzen</a>
<a href="{{ url_for('licenses.licenses') }}" class="btn btn-outline-secondary">Zurücksetzen</a>
</div>
</div>
</form>
@@ -154,8 +154,8 @@
</td>
<td>
<div class="btn-group btn-group-sm" role="group">
<a href="/license/edit/{{ license.id }}" class="btn btn-outline-primary">✏️ Bearbeiten</a>
<form method="post" action="/license/delete/{{ license.id }}" style="display: inline;" onsubmit="return confirm('Wirklich löschen?');">
<a href="{{ url_for('licenses.edit_license', license_id=license.id) }}" class="btn btn-outline-primary">✏️ Bearbeiten</a>
<form method="post" action="{{ url_for('licenses.delete_license', license_id=license.id) }}" style="display: inline;" onsubmit="return confirm('Wirklich löschen?');">
<button type="submit" class="btn btn-outline-danger">🗑️ Löschen</button>
</form>
</div>
@@ -169,10 +169,10 @@
<div class="text-center py-5">
{% if search %}
<p class="text-muted">Keine Lizenzen gefunden für: <strong>{{ search }}</strong></p>
<a href="/licenses" class="btn btn-secondary">Alle Lizenzen anzeigen</a>
<a href="{{ url_for('licenses.licenses') }}" class="btn btn-secondary">Alle Lizenzen anzeigen</a>
{% else %}
<p class="text-muted">Noch keine Lizenzen vorhanden.</p>
<a href="/create" class="btn btn-primary">Erste Lizenz erstellen</a>
<a href="{{ url_for('licenses.create_license') }}" class="btn btn-primary">Erste Lizenz erstellen</a>
{% endif %}
</div>
{% endif %}
@@ -184,31 +184,31 @@
<ul class="pagination justify-content-center">
<!-- Erste Seite -->
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('licenses', page=1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">Erste</a>
<a class="page-link" href="{{ url_for('licenses.licenses', page=1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">Erste</a>
</li>
<!-- Vorherige Seite -->
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('licenses', page=page-1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}"></a>
<a class="page-link" href="{{ url_for('licenses.licenses', page=page-1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}"></a>
</li>
<!-- Seitenzahlen -->
{% for p in range(1, total_pages + 1) %}
{% if p >= page - 2 and p <= page + 2 %}
<li class="page-item {% if p == page %}active{% endif %}">
<a class="page-link" href="{{ url_for('licenses', page=p, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">{{ p }}</a>
<a class="page-link" href="{{ url_for('licenses.licenses', page=p, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">{{ p }}</a>
</li>
{% endif %}
{% endfor %}
<!-- Nächste Seite -->
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('licenses', page=page+1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}"></a>
<a class="page-link" href="{{ url_for('licenses.licenses', page=page+1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}"></a>
</li>
<!-- Letzte Seite -->
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('licenses', page=total_pages, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">Letzte</a>
<a class="page-link" href="{{ url_for('licenses.licenses', page=total_pages, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">Letzte</a>
</li>
</ul>
<p class="text-center text-muted">
@@ -277,7 +277,7 @@ function copyToClipboard(text, button) {
// Toggle License Status
function toggleLicenseStatus(licenseId, isActive) {
fetch(`/api/license/${licenseId}/toggle`, {
fetch(`{{ url_for('api.toggle_license', license_id='') }}${licenseId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -336,21 +336,21 @@ function getSelectedIds() {
function bulkActivate() {
const ids = getSelectedIds();
if (confirm(`${ids.length} Lizenzen aktivieren?`)) {
performBulkAction('/api/licenses/bulk-activate', ids);
performBulkAction('{{ url_for('api.bulk_activate_licenses') }}', ids);
}
}
function bulkDeactivate() {
const ids = getSelectedIds();
if (confirm(`${ids.length} Lizenzen deaktivieren?`)) {
performBulkAction('/api/licenses/bulk-deactivate', ids);
performBulkAction('{{ url_for('api.bulk_deactivate_licenses') }}', ids);
}
}
function bulkDelete() {
const ids = getSelectedIds();
if (confirm(`${ids.length} Lizenzen wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden!`)) {
performBulkAction('/api/licenses/bulk-delete', ids);
performBulkAction('{{ url_for('api.bulk_delete_licenses') }}', ids);
}
}

Datei anzeigen

@@ -94,7 +94,7 @@
Passwort ändern
</h5>
<hr>
<form method="POST" action="{{ url_for('change_password') }}">
<form method="POST" action="{{ url_for('auth.change_password') }}">
<div class="mb-3">
<label for="current_password" class="form-label">Aktuelles Passwort</label>
<input type="password" class="form-control" id="current_password" name="current_password" required>
@@ -131,7 +131,7 @@
</div>
<div class="text-success" style="font-size: 3rem;"></div>
</div>
<form method="POST" action="{{ url_for('disable_2fa') }}" onsubmit="return confirm('Sind Sie sicher, dass Sie 2FA deaktivieren möchten? Dies verringert die Sicherheit Ihres Accounts.');">
<form method="POST" action="{{ url_for('auth.disable_2fa') }}" onsubmit="return confirm('Sind Sie sicher, dass Sie 2FA deaktivieren möchten? Dies verringert die Sicherheit Ihres Accounts.');">
<div class="mb-3">
<label for="password" class="form-label">Passwort zur Bestätigung</label>
<input type="password" class="form-control" id="password" name="password" required placeholder="Ihr aktuelles Passwort">
@@ -150,7 +150,7 @@
Mit 2FA wird bei jeder Anmeldung zusätzlich ein Code aus Ihrer Authenticator-App benötigt.
Dies schützt Ihren Account auch bei kompromittiertem Passwort.
</p>
<a href="{{ url_for('setup_2fa') }}" class="btn btn-success">✨ 2FA einrichten</a>
<a href="{{ url_for('auth.setup_2fa') }}" class="btn btn-success">✨ 2FA einrichten</a>
{% endif %}
</div>
</div>

Datei anzeigen

@@ -158,7 +158,7 @@
<h1 class="mb-0">Resource Historie</h1>
<p class="text-muted mb-0">Detaillierte Aktivitätshistorie</p>
</div>
<a href="{{ url_for('resources') }}" class="btn btn-secondary">
<a href="{{ url_for('resources.resources') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Zurück zur Übersicht
</a>
</div>
@@ -223,7 +223,7 @@
<div class="info-item">
<div class="info-label">Zugewiesen an Lizenz</div>
<div class="info-value">
<a href="{{ url_for('edit_license', license_id=resource.allocated_to_license) }}"
<a href="{{ url_for('licenses.edit_license', license_id=resource.allocated_to_license) }}"
class="text-decoration-none">
{{ license_info.license_key if license_info else 'ID: ' + resource.allocated_to_license|string }}
</a>
@@ -327,7 +327,7 @@
{% if event.license_id %}
&nbsp;&bull;&nbsp;
<i class="fas fa-key"></i>
<a href="{{ url_for('edit_license', license_id=event.license_id) }}">
<a href="{{ url_for('licenses.edit_license', license_id=event.license_id) }}">
Lizenz #{{ event.license_id }}
</a>
{% endif %}

Datei anzeigen

@@ -131,10 +131,10 @@
<p class="text-muted mb-0">Resource Pool Metriken und Analysen</p>
</div>
<div>
<a href="{{ url_for('resources_report') }}" class="btn btn-info">
<a href="{{ url_for('resources.resource_report') }}" class="btn btn-info">
📄 Report generieren
</a>
<a href="{{ url_for('resources') }}" class="btn btn-secondary">
<a href="{{ url_for('resources.resources') }}" class="btn btn-secondary">
← Zurück
</a>
</div>
@@ -262,7 +262,7 @@
<td>
<div class="d-flex align-items-center">
<code class="me-2">{{ resource.resource_value }}</code>
<a href="{{ url_for('resource_history', resource_id=resource.id) }}"
<a href="{{ url_for('resources.resource_history', resource_id=resource.id) }}"
class="resource-link" title="Historie anzeigen">
<i class="fas fa-external-link-alt"></i>
</a>
@@ -325,7 +325,7 @@
<td>
<div class="d-flex align-items-center">
<code class="me-2">{{ resource.resource_value }}</code>
<a href="{{ url_for('resource_history', resource_id=resource.id) }}"
<a href="{{ url_for('resources.resource_history', resource_id=resource.id) }}"
class="resource-link" title="Historie anzeigen">
<i class="fas fa-external-link-alt"></i>
</a>

Datei anzeigen

@@ -6,7 +6,7 @@
<div class="container mt-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>Resource Report Generator</h1>
<a href="{{ url_for('resources') }}" class="btn btn-secondary">
<a href="{{ url_for('resources.resources') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Zurück
</a>
</div>
@@ -18,7 +18,7 @@
<h5 class="mb-0">Report-Einstellungen</h5>
</div>
<div class="card-body">
<form method="get" action="{{ url_for('resources_report') }}">
<form method="get" action="{{ url_for('resources.resource_report') }}">
<div class="row g-3">
<div class="col-md-6">
<label for="report_type" class="form-label">Report-Typ</label>

Datei anzeigen

@@ -267,10 +267,10 @@
{% if data.allocated > 0 %}{{ data.allocated }}{% endif %}
</div>
<div class="progress-bar bg-warning progress-bar-custom"
style="width: {{ (data.quarantine / data.total * 100) if data.total > 0 else 0 }}%"
style="width: {{ (data.quarantined / data.total * 100) if data.total > 0 else 0 }}%"
data-bs-toggle="tooltip"
title="{{ data.quarantine }} in Quarantäne">
{% if data.quarantine > 0 %}{{ data.quarantine }}{% endif %}
title="{{ data.quarantined }} in Quarantäne">
{% if data.quarantined > 0 %}{{ data.quarantined }}{% endif %}
</div>
</div>
@@ -292,7 +292,7 @@
<!-- Filter -->
<div class="card filter-card mb-4">
<div class="card-body">
<form method="get" action="{{ url_for('resources') }}" id="filterForm">
<form method="get" action="{{ url_for('resources.resources') }}" id="filterForm">
<input type="hidden" name="show_test" value="{{ 'true' if show_test else 'false' }}">
<div class="row g-3">
<div class="col-md-3">
@@ -344,9 +344,9 @@
<i class="bi bi-download"></i> Export
</button>
<ul class="dropdown-menu" aria-labelledby="exportDropdown">
<li><a class="dropdown-item" href="/export/resources?format=excel&type={{ resource_type }}&status={{ status_filter }}&search={{ search }}&show_test={{ show_test }}">
<li><a class="dropdown-item" href="{{ url_for('export.resources', format='excel', type=resource_type, status=status_filter, search=search, show_test=show_test) }}">
<i class="bi bi-file-earmark-excel text-success"></i> Excel Export</a></li>
<li><a class="dropdown-item" href="/export/resources?format=csv&type={{ resource_type }}&status={{ status_filter }}&search={{ search }}&show_test={{ show_test }}">
<li><a class="dropdown-item" href="{{ url_for('export.resources', format='csv', type=resource_type, status=status_filter, search=search, show_test=show_test) }}">
<i class="bi bi-file-earmark-text"></i> CSV Export</a></li>
</ul>
</div>
@@ -504,7 +504,7 @@
<td class="text-center">
{% if resource.status == 'quarantine' %}
<!-- Quick Action für Quarantäne -->
<form method="post" action="/resources/release?show_test={{ show_test }}&type={{ resource_type }}&status={{ status_filter }}&search={{ search }}"
<form method="post" action="{{ url_for('resources.release', show_test=show_test, type=resource_type, status=status_filter, search=search) }}"
style="display: inline-block; margin-right: 5px;">
<input type="hidden" name="resource_ids" value="{{ resource.id }}">
<input type="hidden" name="show_test" value="{{ show_test }}">
@@ -528,7 +528,7 @@
<!-- Historie immer verfügbar -->
<li>
<a class="dropdown-item"
href="{{ url_for('resource_history', resource_id=resource.id) }}">
href="{{ url_for('resources.resource_history', resource_id=resource.id) }}">
<i class="bi bi-clock-history text-info"></i> Historie anzeigen
</a>
</li>
@@ -548,7 +548,7 @@
{% if resource.allocated_to_license %}
<li>
<a class="dropdown-item"
href="{{ url_for('edit_license', license_id=resource.allocated_to_license) }}?ref=resources{{ '&show_test=true' if show_test else '' }}">
href="{{ url_for('licenses.edit_license', license_id=resource.allocated_to_license) }}?ref=resources{{ '&show_test=true' if show_test else '' }}">
<i class="bi bi-file-text text-primary"></i> Lizenz bearbeiten
</a>
</li>
@@ -556,7 +556,7 @@
{% if resource.id %}
<li>
<a class="dropdown-item"
href="{{ url_for('customers_licenses', customer_id=resource.id, show_test=show_test) }}">
href="{{ url_for('customers.customers_licenses', customer_id=resource.id, show_test=show_test) }}">
<i class="bi bi-person text-primary"></i> Kunde anzeigen
</a>
</li>
@@ -564,7 +564,7 @@
{% elif resource.status == 'quarantine' %}
<!-- Aktionen für Quarantäne-Ressourcen -->
<li>
<form method="post" action="/resources/release?show_test={{ show_test }}&type={{ resource_type }}&status={{ status_filter }}&search={{ search }}"
<form method="post" action="{{ url_for('resources.release', show_test=show_test, type=resource_type, status=status_filter, search=search) }}"
style="display: contents;">
<input type="hidden" name="resource_ids" value="{{ resource.id }}">
<input type="hidden" name="show_test" value="{{ show_test }}">
@@ -845,7 +845,7 @@ function showQuarantineModal(resourceId) {
// URL mit aktuellen Filtern
const currentUrl = new URL(window.location);
const params = new URLSearchParams(currentUrl.search);
form.setAttribute('action', `/resources/quarantine/${resourceId}?${params.toString()}`);
form.setAttribute('action', `{{ url_for('resources.quarantine', resource_id='') }}${resourceId}?${params.toString()}`);
modal.show();
}

Datei anzeigen

@@ -5,10 +5,10 @@
{% macro active_sortable_header(label, field, current_sort, current_order) %}
<th>
{% if current_sort == field %}
<a href="{{ url_for('sessions', active_sort=field, active_order='desc' if current_order == 'asc' else 'asc', ended_sort=ended_sort, ended_order=ended_order) }}"
<a href="{{ url_for('sessions.sessions', active_sort=field, active_order='desc' if current_order == 'asc' else 'asc', ended_sort=ended_sort, ended_order=ended_order) }}"
class="server-sortable">
{% else %}
<a href="{{ url_for('sessions', active_sort=field, active_order='asc', ended_sort=ended_sort, ended_order=ended_order) }}"
<a href="{{ url_for('sessions.sessions', active_sort=field, active_order='asc', ended_sort=ended_sort, ended_order=ended_order) }}"
class="server-sortable">
{% endif %}
{{ label }}
@@ -26,10 +26,10 @@
{% macro ended_sortable_header(label, field, current_sort, current_order) %}
<th>
{% if current_sort == field %}
<a href="{{ url_for('sessions', active_sort=active_sort, active_order=active_order, ended_sort=field, ended_order='desc' if current_order == 'asc' else 'asc') }}"
<a href="{{ url_for('sessions.sessions', active_sort=active_sort, active_order=active_order, ended_sort=field, ended_order='desc' if current_order == 'asc' else 'asc') }}"
class="server-sortable">
{% else %}
<a href="{{ url_for('sessions', active_sort=active_sort, active_order=active_order, ended_sort=field, ended_order='asc') }}"
<a href="{{ url_for('sessions.sessions', active_sort=active_sort, active_order=active_order, ended_sort=field, ended_order='asc') }}"
class="server-sortable">
{% endif %}
{{ label }}
@@ -62,15 +62,15 @@
</button>
<ul class="dropdown-menu">
<li><h6 class="dropdown-header">Aktive Sessions</h6></li>
<li><a class="dropdown-item" href="/export/sessions?type=active&format=excel">
<li><a class="dropdown-item" href="{{ url_for('export.export_sessions', type='active', format='excel') }}">
<i class="bi bi-file-earmark-excel text-success"></i> Excel Export</a></li>
<li><a class="dropdown-item" href="/export/sessions?type=active&format=csv">
<li><a class="dropdown-item" href="{{ url_for('export.export_sessions', type='active', format='csv') }}">
<i class="bi bi-file-earmark-text"></i> CSV Export</a></li>
<li><hr class="dropdown-divider"></li>
<li><h6 class="dropdown-header">Beendete Sessions</h6></li>
<li><a class="dropdown-item" href="/export/sessions?type=ended&format=excel">
<li><a class="dropdown-item" href="{{ url_for('export.export_sessions', type='ended', format='excel') }}">
<i class="bi bi-file-earmark-excel text-success"></i> Excel Export</a></li>
<li><a class="dropdown-item" href="/export/sessions?type=ended&format=csv">
<li><a class="dropdown-item" href="{{ url_for('export.export_sessions', type='ended', format='csv') }}">
<i class="bi bi-file-earmark-text"></i> CSV Export</a></li>
</ul>
</div>
@@ -114,7 +114,7 @@
{% endif %}
</td>
<td>
<form method="post" action="/session/end/{{ session[0] }}" style="display: inline;">
<form method="post" action="{{ url_for('sessions.end_session', session_id=session[0]) }}" style="display: inline;">
<button type="submit" class="btn btn-sm btn-outline-danger"
onclick="return confirm('Session wirklich beenden?');">
⏹️ Beenden

Datei anzeigen

@@ -60,7 +60,7 @@
<div class="container py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>🔐 2FA einrichten</h1>
<a href="{{ url_for('profile') }}" class="btn btn-secondary">← Zurück zum Profil</a>
<a href="{{ url_for('auth.profile') }}" class="btn btn-secondary">← Zurück zum Profil</a>
</div>
{% with messages = get_flashed_messages(with_categories=true) %}
@@ -167,7 +167,7 @@
</h5>
<p class="ms-5">Geben Sie den 6-stelligen Code aus Ihrer Authenticator-App ein:</p>
<form method="POST" action="{{ url_for('enable_2fa') }}" class="ms-5 me-5">
<form method="POST" action="{{ url_for('auth.enable_2fa') }}" class="ms-5 me-5">
<div class="row align-items-center">
<div class="col-md-6 mb-3">
<input type="text"

Datei anzeigen

@@ -94,7 +94,7 @@
<hr class="my-4">
<div class="text-center">
<a href="/logout" class="text-muted">Abbrechen und zur Anmeldung zurück</a>
<a href="{{ url_for('auth.logout') }}" class="text-muted">Abbrechen und zur Anmeldung zurück</a>
</div>
</form>
</div>