diff --git a/v2_adminpanel/FEHLERSUCHE.md b/v2_adminpanel/FEHLERSUCHE.md index 50aa743..61c338c 100644 --- a/v2_adminpanel/FEHLERSUCHE.md +++ b/v2_adminpanel/FEHLERSUCHE.md @@ -1,6 +1,6 @@ # Fehlersuche - v2_adminpanel Refactoring -## Aktueller Stand (17.06.2025) +## Aktueller Stand (17.06.2025 - 11:00 Uhr) ### Erfolgreiches Refactoring - Die ursprüngliche 5000+ Zeilen große app.py wurde erfolgreich in Module aufgeteilt: @@ -15,7 +15,10 @@ - ✅ Blueprint-Registrierung funktioniert korrekt - ✅ /test-db Route funktioniert nach Docker-Rebuild - ✅ Kunden-Anzeige funktioniert mit Test-Daten-Filter +- ✅ Lizenzen-Anzeige funktioniert mit erweiterten Filtern - ✅ Batch-Lizenzerstellung funktioniert +- ✅ Ressourcen-Pool funktioniert vollständig +- ✅ Ressourcen hinzufügen funktioniert ### Gelöste Probleme @@ -136,4 +139,128 @@ Folgende Templates wurden von Tuple-Zugriff auf Dictionary-Zugriff umgestellt: ### Status ✅ **Alle bekannten Probleme wurden behoben** ✅ **Admin-Panel ist vollständig funktionsfähig** -✅ **Docker Container läuft stabil** \ No newline at end of file +✅ **Docker Container läuft stabil** + +## Weitere gelöste Probleme (17.06.2025 - 11:00 Uhr) + +### 1. **Test-Daten Checkbox funktioniert nicht** ✅ GELÖST +**Problem**: Die Checkbox zum Anzeigen von Test-Daten in Kunden- und Lizenzansicht funktionierte nicht +**Ursache**: Fehlende Blueprint-Präfixe in Template-URLs +**Lösung**: +- `customers.html`: Alle `url_for('customers')` → `url_for('customer.customers')` +- `licenses.html`: Alle `url_for('licenses')` → `url_for('license.licenses')` +- Formulare senden jetzt korrekt mit `show_test` Parameter + +### 2. **Lizenz-Filter erweitert** ✅ GELÖST +**Problem**: Filter für Test-/Live-Daten fehlte in Lizenzansicht +**Lösung**: `license_routes.py` erweitert mit: +- Typ-Filter: `full`, `test`, `test_data`, `live_data` +- Status-Filter: `active`, `expiring`, `expired`, `inactive` +- Suche über Lizenzschlüssel, Kundenname und E-Mail + +### 3. **Resource Pool Anzeige** ✅ GELÖST +**Problem**: Ressourcen-Pool Seite hatte fehlerhafte Links und Filter funktionierten nicht +**Lösung**: +- `resources.html`: Form-Action korrigiert zu `url_for('resources.resources')` +- JavaScript `toggleTestResources()` arbeitet jetzt mit URL-Parametern +- Alle Sortier- und Paginierungs-Links korrigiert + +### 4. **Ressourcen hinzufügen fehlte** ✅ GELÖST +**Problem**: Route `/resources/add` existierte nicht +**Lösung**: Komplette `add_resources()` Funktion in `resource_routes.py` implementiert: +- Validierung für Domains, IPv4-Adressen und Telefonnummern +- Duplikat-Prüfung +- Bulk-Import mit detailliertem Feedback +- Test/Produktion Unterscheidung + +### 5. **Navigation-Links** ✅ GELÖST +**Problem**: Sidebar-Links für Ressourcen verwendeten hardcodierte URLs +**Lösung**: `base.html` aktualisiert: +- Resource Pool Link: `href="{{ url_for('resources.resources') }}"` +- Add Resources Link: `href="{{ url_for('resources.add_resources') }}"` +- Active-Status Prüfung korrigiert für Blueprint-Endpunkte + +## Routing-Analyse (17.06.2025 - 11:30 Uhr) + +### Identifizierte Routing-Probleme + +Nach systematischer Analyse wurden folgende Routing-Probleme gefunden: + +#### 1. **Fehlende Blueprint-Präfixe** ⚠️ OFFEN +Viele `url_for()` Aufrufe fehlen Blueprint-Präfixe. Dies verursacht 500-Fehler: + +**Betroffene Templates:** +- `profile.html`: 3 fehlerhafte Aufrufe (`change_password`, `disable_2fa`, `setup_2fa`) +- `setup_2fa.html`: 2 fehlerhafte Aufrufe (`profile`, `enable_2fa`) +- `backup_codes.html`: 1 fehlerhafter Aufruf (`profile`) +- `resource_history.html`: 2 fehlerhafte Aufrufe (`resources`, `edit_license`) +- `resource_metrics.html`: 2 fehlerhafte Aufrufe (`resources`, `resources_report`) +- `resource_report.html`: 2 fehlerhafte Aufrufe +- `sessions.html`: Mehrere fehlerhafte Aufrufe +- `audit_log.html`: Mehrere fehlerhafte Aufrufe + +#### 2. **Hardcodierte URLs** ⚠️ OFFEN +Über 50 hardcodierte URLs gefunden, die mit `url_for()` ersetzt werden sollten: + +**Hauptprobleme in `base.html`:** +- `href="/"` → `href="{{ url_for('admin.dashboard') }}"` +- `href="/profile"` → `href="{{ url_for('auth.profile') }}"` +- `href="/logout"` → `href="{{ url_for('auth.logout') }}"` +- `href="/customers-licenses"` → `href="{{ url_for('customer.customers_licenses') }}"` +- `href="/customer/create"` → `href="{{ url_for('customer.create_customer') }}"` +- `href="/create"` → `href="{{ url_for('license.create_license') }}"` +- `href="/batch"` → `href="{{ url_for('batch.batch_create') }}"` +- `href="/audit"` → `href="{{ url_for('admin.audit_log') }}"` +- `href="/sessions"` → `href="{{ url_for('session.sessions') }}"` +- `href="/backups"` → `href="{{ url_for('admin.backups') }}"` + +#### 3. **Doppelte Route-Definitionen** ✅ GELÖST +- Entfernt: Doppelte `add_resource` Funktion in `resource_routes.py` + +#### 4. **Route-Namenskonsistenz** ⚠️ OFFEN +- `resource_report` vs `resources_report` - inkonsistente Benennung + +### Prioritäten für Fixes + +1. **KRITISCH**: Fehlende Blueprint-Präfixe (verursachen 500-Fehler) +2. **HOCH**: Hardcodierte URLs in Navigation (`base.html`) +3. **MITTEL**: Andere hardcodierte URLs +4. **NIEDRIG**: Namenskonsistenz + +### Vollständiger Report +Ein detaillierter Report wurde erstellt: `ROUTING_ISSUES_REPORT.md` + +## Aktuelle Probleme (18.06.2025 - 01:30 Uhr) + +### 1. **Resources Route funktioniert nicht** ❌ NICHT GELÖST +**Problem**: `/resources` Route leitet auf Dashboard um mit Fehlermeldung "Fehler beim Laden der Ressourcen!" +**Fehlermeldungen im Log**: +1. Ursprünglich: `FEHLER: Spalte l.customer_name existiert nicht` +2. Nach Fix: `'dict object' has no attribute 'total'` + +**Versuchte Lösungen**: +1. SQL-Query in `resource_routes.py` korrigiert: + - JOIN mit customers Tabelle hinzugefügt für `c.name as customer_name` + - `l.customer_name` → `c.name` in WHERE-Klausel +2. Stats Dictionary erweitert um `'total': 0` und `stats[res_type]['total'] += count` +3. Template `resources.html` angepasst: `data.quarantine` → `data.quarantined` + +**Status**: Trotz aller Fixes funktioniert die Route weiterhin nicht + +### 2. **URL-Generierungsfehler** ✅ GELÖST +**Problem**: Mehrere `url_for()` Aufrufe mit falschen Endpunkt-Namen +**Gelöste Fehler**: +- `api.generate_license_key` → `api.api_generate_key` +- `api.customers` → `api.api_customers` +- `export.customers` → `export.export_customers` +- `export.licenses` → `export.export_licenses` +- `url_for()` mit leeren Parametern durch hardcodierte URLs ersetzt + +### 3. **Customers-Licenses Route** ❌ NICHT GELÖST +**Problem**: `/customers-licenses` Route leitet auf Dashboard um +**Fehlermeldung im Log**: `ValueError: invalid literal for int() with base 10: ''` +**Ursache**: Template versucht `url_for('licenses.edit_license', license_id='')` mit leerem String aufzurufen +**Versuchte Lösungen**: +- `url_for('licenses.edit_license', license_id='')` durch hardcodierte URL ersetzt: `/license/edit/${license.id}` +- `url_for('customers.edit_customer', customer_id='')` durch hardcodierte URL ersetzt: `/customer/edit/${customerId}` +**Status**: Route funktioniert trotz Fixes nicht \ No newline at end of file diff --git a/v2_adminpanel/ROUTING_ISSUES_REPORT.md b/v2_adminpanel/ROUTING_ISSUES_REPORT.md new file mode 100644 index 0000000..98c4b07 --- /dev/null +++ b/v2_adminpanel/ROUTING_ISSUES_REPORT.md @@ -0,0 +1,118 @@ +# V2 Admin Panel - Routing Issues Report + +Generated: 2025-06-17 + +## Summary of Findings + +After systematically analyzing the v2_adminpanel application, I've identified several routing issues that need to be addressed: + +### 1. Missing Blueprint Prefixes in url_for() Calls + +The following templates have `url_for()` calls that are missing the required blueprint prefix: + +#### In `profile.html`: +- `url_for('change_password')` → Should be `url_for('auth.change_password')` +- `url_for('disable_2fa')` → Should be `url_for('auth.disable_2fa')` +- `url_for('setup_2fa')` → Should be `url_for('auth.setup_2fa')` + +#### In `setup_2fa.html`: +- `url_for('profile')` → Should be `url_for('auth.profile')` +- `url_for('enable_2fa')` → Should be `url_for('auth.enable_2fa')` + +#### In `backup_codes.html`: +- `url_for('profile')` → Should be `url_for('auth.profile')` + +#### In `resource_history.html`: +- `url_for('resources')` → Should be `url_for('resources.resources')` +- `url_for('edit_license', license_id=...)` → Should be `url_for('licenses.edit_license', license_id=...)` + +#### In `resource_metrics.html`: +- `url_for('resources')` → Should be `url_for('resources.resources')` +- `url_for('resources_report')` → Should be `url_for('resources.resource_report')` + +#### In `resource_report.html`: +- `url_for('resources')` → Should be `url_for('resources.resources')` +- `url_for('resources_report')` → Should be `url_for('resources.resource_report')` + +#### In `sessions.html`: +- `url_for('sessions', ...)` → Should be `url_for('sessions.sessions', ...)` + +#### In `audit_log.html`: +- `url_for('audit_log', ...)` → Should be `url_for('admin.audit_log', ...)` + +#### In `licenses.html`: +- `url_for('licenses', ...)` → Should be `url_for('licenses.licenses', ...)` + +#### In `customers.html`: +- `url_for('customers', ...)` → Should be `url_for('customers.customers', ...)` + +#### In `resources.html`: +- Several instances of incorrect references: + - `url_for('customers.customers_licenses', ...)` → Should be `url_for('customers.customers_licenses', ...)` + - `url_for('licenses.edit_license', ...)` → Correct + - `url_for('resource_history', ...)` → Should be `url_for('resources.resource_history', ...)` + - `url_for('edit_license', ...)` → Should be `url_for('licenses.edit_license', ...)` + - `url_for('customers_licenses', ...)` → Should be `url_for('customers.customers_licenses', ...)` + +### 2. Hardcoded URLs That Need Replacement + +Many templates contain hardcoded URLs that should be replaced with `url_for()` calls: + +#### In `base.html`: +- `href="/"` → Should be `href="{{ url_for('admin.index') }}"` +- `href="/profile"` → Should be `href="{{ url_for('auth.profile') }}"` +- `href="/logout"` → Should be `href="{{ url_for('auth.logout') }}"` +- `href="/customers-licenses"` → Should be `href="{{ url_for('customers.customers_licenses') }}"` +- `href="/customer/create"` → Should be `href="{{ url_for('customers.create_customer') }}"` +- `href="/create"` → Should be `href="{{ url_for('licenses.create_license') }}"` +- `href="/batch"` → Should be `href="{{ url_for('batch.batch_licenses') }}"` +- `href="/audit"` → Should be `href="{{ url_for('admin.audit_log') }}"` +- `href="/sessions"` → Should be `href="{{ url_for('sessions.sessions') }}"` +- `href="/backups"` → Should be `href="{{ url_for('admin.backups') }}"` +- `href="/security/blocked-ips"` → Should be `href="{{ url_for('admin.blocked_ips') }}"` + +#### In `customers_licenses.html` and `customers_licenses_old.html`: +- Multiple hardcoded URLs for editing, creating, and exporting that need to be replaced with proper `url_for()` calls + +#### In `edit_license.html`, `create_customer.html`, `index.html`: +- `href="/customers-licenses"` → Should use `url_for()` + +#### In `dashboard.html`: +- Multiple hardcoded URLs that should use `url_for()` + +#### In error pages (`404.html`, `500.html`): +- `href="/"` → Should be `href="{{ url_for('admin.index') }}"` + +### 3. Blueprint Configuration + +Current blueprint configuration: +- `export_bp` has `url_prefix='/export'` +- `api_bp` has `url_prefix='/api'` +- All other blueprints have no url_prefix + +### 4. Route Naming Inconsistencies + +Some routes have inconsistent naming between the route definition and the function name: +- Route `/resources/report` has function name `resource_report` (note the singular vs plural) +- This causes confusion with `url_for()` calls + +### 5. Duplicate Route Risk Areas + +While no exact duplicates were found, there are potential conflicts: +- Both `admin_bp` and `customer_bp` might handle customer-related routes +- API routes in `api_bp` overlap with functionality in other blueprints + +## Recommendations + +1. **Fix all `url_for()` calls** to include the correct blueprint prefix +2. **Replace all hardcoded URLs** with `url_for()` calls +3. **Standardize route naming** to match function names +4. **Add url_prefix to blueprints** where appropriate to avoid conflicts +5. **Create a route mapping document** for developers to reference + +## Priority Actions + +1. **High Priority**: Fix missing blueprint prefixes in `url_for()` calls - these will cause runtime errors +2. **High Priority**: Replace hardcoded URLs in navigation (base.html) - affects site-wide navigation +3. **Medium Priority**: Fix other hardcoded URLs in individual templates +4. **Low Priority**: Refactor route naming for consistency \ No newline at end of file diff --git a/v2_adminpanel/routes/license_routes.py b/v2_adminpanel/routes/license_routes.py index 1e573fd..73318e0 100644 --- a/v2_adminpanel/routes/license_routes.py +++ b/v2_adminpanel/routes/license_routes.py @@ -21,11 +21,73 @@ license_bp = Blueprint('licenses', __name__) @login_required def licenses(): from datetime import datetime, timedelta - show_test = request.args.get('show_test', 'false') == 'true' + + # Get filter parameters + search = request.args.get('search', '').strip() + filter_type = request.args.get('type', '') + filter_status = request.args.get('status', '') + sort = request.args.get('sort', 'created_at') + order = request.args.get('order', 'desc') + page = request.args.get('page', 1, type=int) + per_page = 50 + + # Process type filter to determine show_test + show_test = filter_type in ['test_data', 'test'] + + # Get licenses based on filters licenses_list = get_licenses(show_test=show_test) + + # Additional filtering based on type and status + if filter_type: + if filter_type == 'full': + licenses_list = [l for l in licenses_list if l.get('license_type') == 'full' and not l.get('is_test')] + elif filter_type == 'test': + licenses_list = [l for l in licenses_list if l.get('license_type') == 'test' and not l.get('is_test')] + elif filter_type == 'test_data': + licenses_list = [l for l in licenses_list if l.get('is_test')] + elif filter_type == 'live_data': + licenses_list = [l for l in licenses_list if not l.get('is_test')] + + # Status filtering + if filter_status: + now = datetime.now() + if filter_status == 'active': + licenses_list = [l for l in licenses_list if l.get('is_active') and l.get('valid_until') and l.get('valid_until') > now] + elif filter_status == 'expiring': + expiry_threshold = now + timedelta(days=30) + licenses_list = [l for l in licenses_list if l.get('valid_until') and now < l.get('valid_until') <= expiry_threshold] + elif filter_status == 'expired': + licenses_list = [l for l in licenses_list if l.get('valid_until') and l.get('valid_until') <= now] + elif filter_status == 'inactive': + licenses_list = [l for l in licenses_list if not l.get('is_active')] + + # Search filtering + if search: + search_lower = search.lower() + licenses_list = [l for l in licenses_list if + search_lower in str(l.get('license_key', '')).lower() or + search_lower in str(l.get('customer_name', '')).lower() or + search_lower in str(l.get('customer_email', '')).lower()] + + # Calculate pagination + total = len(licenses_list) + total_pages = (total + per_page - 1) // per_page + start = (page - 1) * per_page + end = start + per_page + licenses_list = licenses_list[start:end] + return render_template("licenses.html", licenses=licenses_list, show_test=show_test, + search=search, + filter_type=filter_type, + filter_status=filter_status, + sort=sort, + order=order, + page=page, + total=total, + total_pages=total_pages, + per_page=per_page, now=datetime.now, timedelta=timedelta) diff --git a/v2_adminpanel/routes/resource_routes.py b/v2_adminpanel/routes/resource_routes.py index dcc43ef..49c6107 100644 --- a/v2_adminpanel/routes/resource_routes.py +++ b/v2_adminpanel/routes/resource_routes.py @@ -1,7 +1,7 @@ import logging from datetime import datetime from zoneinfo import ZoneInfo -from flask import Blueprint, render_template, request, redirect, session, url_for, flash, jsonify +from flask import Blueprint, render_template, request, redirect, session, url_for, flash, jsonify, send_file import config from auth.decorators import login_required @@ -39,10 +39,11 @@ def resources(): rp.created_at, rp.status_changed_at, rp.status_changed_by, - l.customer_name, + c.name as customer_name, l.license_type FROM resource_pools rp LEFT JOIN licenses l ON rp.allocated_to_license = l.id + LEFT JOIN customers c ON l.customer_id = c.id WHERE 1=1 """ @@ -58,7 +59,7 @@ def resources(): params.append(status_filter) if search_query: - query += " AND (rp.resource_value ILIKE %s OR l.customer_name ILIKE %s)" + query += " AND (rp.resource_value ILIKE %s OR c.name ILIKE %s)" params.extend([f'%{search_query}%', f'%{search_query}%']) if not show_test: @@ -103,8 +104,9 @@ def resources(): count = row[3] if res_type not in stats: - stats[res_type] = {'available': 0, 'allocated': 0, 'quarantined': 0, 'test': 0, 'prod': 0} + stats[res_type] = {'total': 0, 'available': 0, 'allocated': 0, 'quarantined': 0, 'test': 0, 'prod': 0} + stats[res_type]['total'] += count stats[res_type][status] = stats[res_type].get(status, 0) + count if is_test: stats[res_type]['test'] += count @@ -128,60 +130,7 @@ def resources(): conn.close() -@resource_bp.route('/resources/add', methods=['GET', 'POST']) -@login_required -def add_resource(): - """Neue Ressource hinzufügen""" - if request.method == 'POST': - try: - with get_db_connection() as conn: - cur = conn.cursor() - try: - resource_type = request.form['resource_type'] - resource_value = request.form['resource_value'].strip() - is_test = 'is_test' in request.form - - # Prüfe ob Ressource bereits existiert - cur.execute(""" - SELECT id FROM resource_pools - WHERE resource_type = %s AND resource_value = %s - """, (resource_type, resource_value)) - - if cur.fetchone(): - flash(f'Ressource {resource_value} existiert bereits!', 'error') - return redirect(url_for('resources.add_resource')) - - # Füge neue Ressource hinzu (ohne created_by) - cur.execute(""" - INSERT INTO resource_pools (resource_type, resource_value, status, is_test, status_changed_by) - VALUES (%s, %s, 'available', %s, %s) - RETURNING id - """, (resource_type, resource_value, is_test, session.get('username', 'system'))) - - resource_id = cur.fetchone()[0] - conn.commit() - - # Audit-Log - log_audit('CREATE', 'resource', resource_id, - new_values={ - 'resource_type': resource_type, - 'resource_value': resource_value, - 'is_test': is_test - }) - - flash(f'Ressource {resource_value} erfolgreich hinzugefügt!', 'success') - return redirect(url_for('resources.resources')) - finally: - cur.close() - - except Exception as e: - import traceback - logging.error(f"Fehler beim Hinzufügen der Ressource: {str(e)}") - logging.error(f"Traceback: {traceback.format_exc()}") - flash(f'Fehler: {str(e)}', 'error') - return redirect(url_for('resources.resources')) - - return render_template('add_resources.html') +# Old add_resource function removed - using add_resources instead @resource_bp.route('/resources/quarantine/', methods=['POST']) @@ -615,4 +564,108 @@ def resource_report(): return redirect(url_for('resources.resources')) finally: cur.close() - conn.close() \ No newline at end of file + conn.close() + + +@resource_bp.route('/resources/add', methods=['GET', 'POST']) +@login_required +def add_resources(): + """Fügt neue Ressourcen zum Pool hinzu""" + if request.method == 'POST': + conn = get_connection() + cur = conn.cursor() + + try: + resource_type = request.form.get('resource_type') + resources_text = request.form.get('resources_text', '') + is_test = request.form.get('is_test', 'false') == 'true' + + if not resource_type or not resources_text.strip(): + flash('Bitte Ressourcentyp und Ressourcen angeben!', 'error') + return redirect(url_for('resources.add_resources')) + + # Parse resources (one per line) + resources = [r.strip() for r in resources_text.strip().split('\n') if r.strip()] + + # Validate resources based on type + valid_resources = [] + invalid_resources = [] + + for resource in resources: + if resource_type == 'domain': + # Basic domain validation + import re + if re.match(r'^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?\.[a-zA-Z]{2,}$', resource): + valid_resources.append(resource) + else: + invalid_resources.append(resource) + elif resource_type == 'ipv4': + # IPv4 validation + parts = resource.split('.') + if len(parts) == 4 and all(p.isdigit() and 0 <= int(p) <= 255 for p in parts): + valid_resources.append(resource) + else: + invalid_resources.append(resource) + elif resource_type == 'phone': + # Phone number validation (basic) + import re + if re.match(r'^\+?[0-9]{7,15}$', resource.replace(' ', '').replace('-', '')): + valid_resources.append(resource) + else: + invalid_resources.append(resource) + else: + invalid_resources.append(resource) + + # Check for duplicates + existing_resources = [] + if valid_resources: + placeholders = ','.join(['%s'] * len(valid_resources)) + cur.execute(f""" + SELECT resource_value + FROM resource_pools + WHERE resource_type = %s + AND resource_value IN ({placeholders}) + """, [resource_type] + valid_resources) + existing_resources = [row[0] for row in cur.fetchall()] + + # Filter out existing resources + new_resources = [r for r in valid_resources if r not in existing_resources] + + # Insert new resources + added_count = 0 + for resource in new_resources: + cur.execute(""" + INSERT INTO resource_pools + (resource_type, resource_value, status, is_test, created_by) + VALUES (%s, %s, 'available', %s, %s) + """, (resource_type, resource, is_test, session['username'])) + added_count += 1 + + conn.commit() + + # Log audit + if added_count > 0: + log_audit('BULK_CREATE', 'resource', + additional_info=f"Added {added_count} {resource_type} resources") + + # Flash messages + if added_count > 0: + flash(f'✅ {added_count} neue Ressourcen erfolgreich hinzugefügt!', 'success') + if existing_resources: + flash(f'⚠️ {len(existing_resources)} Ressourcen existierten bereits und wurden übersprungen.', 'warning') + if invalid_resources: + flash(f'❌ {len(invalid_resources)} ungültige Ressourcen wurden ignoriert.', 'error') + + return redirect(url_for('resources.resources', show_test=request.form.get('show_test', 'false'))) + + except Exception as e: + conn.rollback() + logging.error(f"Fehler beim Hinzufügen von Ressourcen: {str(e)}") + flash('Fehler beim Hinzufügen der Ressourcen!', 'error') + finally: + cur.close() + conn.close() + + # GET request - show form + show_test = request.args.get('show_test', 'false') == 'true' + return render_template('add_resources.html', show_test=show_test) \ No newline at end of file diff --git a/v2_adminpanel/templates/404.html b/v2_adminpanel/templates/404.html index a36c93b..a500061 100644 --- a/v2_adminpanel/templates/404.html +++ b/v2_adminpanel/templates/404.html @@ -11,7 +11,7 @@

404

Seite nicht gefunden

Die angeforderte Seite konnte nicht gefunden werden.

- Zur Startseite + Zur Startseite diff --git a/v2_adminpanel/templates/500.html b/v2_adminpanel/templates/500.html index 0185023..01b48bf 100644 --- a/v2_adminpanel/templates/500.html +++ b/v2_adminpanel/templates/500.html @@ -11,7 +11,7 @@

500

Interner Serverfehler

Es ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.

- Zur Startseite + Zur Startseite diff --git a/v2_adminpanel/templates/add_resources.html b/v2_adminpanel/templates/add_resources.html index 66cafcc..e60fe89 100644 --- a/v2_adminpanel/templates/add_resources.html +++ b/v2_adminpanel/templates/add_resources.html @@ -115,12 +115,12 @@

Ressourcen hinzufügen

Fügen Sie neue Domains, IPs oder Telefonnummern zum Pool hinzu

- + ← Zurück zur Übersicht -
+
@@ -278,7 +278,7 @@ my-website.io
-
@@ -248,31 +248,31 @@

diff --git a/v2_adminpanel/templates/backup_codes.html b/v2_adminpanel/templates/backup_codes.html index f62c4db..17e7616 100644 --- a/v2_adminpanel/templates/backup_codes.html +++ b/v2_adminpanel/templates/backup_codes.html @@ -132,7 +132,7 @@ Ich habe die Backup-Codes sicher gespeichert

-
diff --git a/v2_adminpanel/templates/backups.html b/v2_adminpanel/templates/backups.html index 675842b..8c743fc 100644 --- a/v2_adminpanel/templates/backups.html +++ b/v2_adminpanel/templates/backups.html @@ -120,7 +120,7 @@ {% if backup.status == 'success' %} @@ -363,40 +363,40 @@