"feat: Add database shm and wal files for improved performance"

This commit is contained in:
Till Tomczak 2025-05-29 17:18:25 +02:00
parent 8e402d13bf
commit cc65cef9d6
7 changed files with 593 additions and 1002 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -253,12 +253,6 @@
</svg>
Logs
</a>
<a href="{{ url_for('admin_guest_requests') }}"
class="group flex items-center px-6 py-3 text-sm font-medium rounded-xl transition-all duration-300 text-slate-600 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700/50 hover:text-slate-900 dark:hover:text-white">
<i class="fas fa-user-friends w-5 h-5 mr-2 text-slate-400 group-hover:text-slate-600 dark:group-hover:text-slate-300"></i>
Gastaufträge
</a>
</nav>
</div>
@ -284,7 +278,7 @@
<thead class="bg-slate-50 dark:bg-slate-900/50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase tracking-wider">Benutzer</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase tracking-wider">Benutzername</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase tracking-wider">E-Mail</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase tracking-wider">Rolle</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase tracking-wider">Status</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase tracking-wider">Letzte Aktivität</th>
@ -307,6 +301,7 @@
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-slate-900 dark:text-white">{{ user.email }}</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full {{ 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200' if user.is_admin else 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200' }}">
{{ 'Administrator' if user.is_admin else 'Benutzer' }}

View File

@ -26,8 +26,6 @@
<link rel="mask-icon" href="{{ url_for('static', filename='favicon.svg') }}" color="#000000">
<!-- CSS -->
<!-- Font Awesome (lokal installiert für Offline-Betrieb) -->
<link href="{{ url_for('static', filename='fontawesome/css/all.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/tailwind.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/components.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/professional-theme.css') }}" rel="stylesheet">
@ -266,6 +264,41 @@
</div>
</div>
{% if current_user.is_authenticated %}
<!-- Benachrichtigungen - kompakteres Design -->
<div class="relative">
<button
id="notificationToggle"
class="relative p-1.5 rounded-full text-slate-700 dark:text-slate-300 hover:bg-slate-100/80 dark:hover:bg-slate-800/50 transition-all duration-200"
aria-label="Benachrichtigungen anzeigen"
title="Benachrichtigungen"
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/>
</svg>
<!-- Badge für ungelesene Benachrichtigungen -->
<span id="notificationBadge" class="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full h-4 w-4 flex items-center justify-center font-medium hidden">
0
</span>
</button>
<!-- Benachrichtigungs-Dropdown -->
<div id="notificationDropdown" class="absolute right-0 mt-2 w-72 sm:w-80 bg-white dark:bg-slate-800 rounded-lg shadow-lg border border-slate-200 dark:border-slate-600 z-50 hidden">
<div class="p-3 border-b border-slate-200 dark:border-slate-600">
<h3 class="text-base font-semibold text-slate-900 dark:text-white">Benachrichtigungen</h3>
</div>
<div id="notificationList" class="max-h-80 overflow-y-auto">
<div class="p-3 text-center text-slate-500 dark:text-slate-400 text-sm">
Keine neuen Benachrichtigungen
</div>
</div>
<div class="p-2 border-t border-slate-200 dark:border-slate-600">
<button id="markAllRead" class="w-full text-xs text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 transition-colors">
Alle als gelesen markieren
</button>
</div>
</div>
</div>
<!-- User Profile Dropdown - kompakteres Design -->
<div class="relative" id="user-menu-container">
<button
@ -277,11 +310,11 @@
>
<!-- Profile Avatar -->
<div class="w-6 h-6 rounded-full bg-blue-500 flex items-center justify-center text-white text-xs font-medium">
{{ current_user.username[0].upper() if current_user.username else 'U' }}
{{ current_user.email[0].upper() if current_user.email else 'U' }}
</div>
<!-- User Info (nur auf größeren Geräten) -->
<div class="hidden sm:block text-left ml-1">
<div class="text-xs font-medium text-slate-900 dark:text-white transition-colors duration-300">{{ current_user.username if current_user.username else 'Benutzer' }}</div>
<div class="text-xs font-medium text-slate-900 dark:text-white transition-colors duration-300">{{ current_user.email.split('@')[0] if current_user.email else 'Benutzer' }}</div>
</div>
</button>
@ -291,14 +324,14 @@
<div class="px-4 py-3 border-b border-slate-200 dark:border-slate-600">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center text-white font-medium">
{{ current_user.username[0].upper() if current_user.username else 'U' }}
{{ current_user.email[0].upper() if current_user.email else 'U' }}
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-medium text-slate-900 dark:text-white truncate">
{{ current_user.full_name if current_user.full_name else current_user.username if current_user.username else 'Benutzer' }}
{{ current_user.full_name if current_user.full_name else current_user.email.split('@')[0] if current_user.email else 'Benutzer' }}
</p>
<p class="text-xs text-slate-500 dark:text-slate-400 truncate">
Benutzer: {{ current_user.username if current_user.username else 'Unbekannt' }}
{{ current_user.email if current_user.email else 'Keine E-Mail' }}
</p>
{% if current_user.is_admin %}
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200 mt-1">
@ -544,6 +577,9 @@
<!-- JavaScript -->
<script src="{{ url_for('static', filename='js/ui-components.js') }}"></script>
<script src="{{ url_for('static', filename='js/dark-mode-fix.js') }}"></script>
{% if current_user.is_authenticated %}
<script src="{{ url_for('static', filename='js/notifications.js') }}"></script>
{% endif %}
<!-- Additional JavaScript Functions -->
<script>

View File

@ -372,7 +372,7 @@
</div>
<div class="text-sm">
<a href="#"
<a href="{{ url_for('reset_password_request') if url_for and url_for('reset_password_request') else '#' }}"
class="text-mercedes-blue hover:text-blue-700 transition-colors">
Passwort vergessen?
</a>

View File

@ -1,287 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Test-Skript für die MYP Platform Implementierung
Testet alle neu implementierten Funktionen:
1. Font Awesome lokale Installation
2. Drucker-Status-Management (Notfall-Abruf)
3. Admin-Gastaufträge-APIs
4. Datenbank-Integrität
"""
import os
import sys
import requests
import json
import sqlite3
from datetime import datetime
from pathlib import Path
# Farben für Ausgabe
class Colors:
GREEN = '\033[92m'
RED = '\033[91m'
YELLOW = '\033[93m'
BLUE = '\033[94m'
BOLD = '\033[1m'
END = '\033[0m'
def print_status(message, status="INFO"):
color = Colors.GREEN if status == "SUCCESS" else Colors.RED if status == "ERROR" else Colors.YELLOW if status == "WARNING" else Colors.BLUE
print(f"{color}[{status}]{Colors.END} {message}")
def test_font_awesome_installation():
"""Test 1: Font Awesome lokale Installation"""
print_status("=== TESTE FONT AWESOME INSTALLATION ===", "INFO")
# Überprüfe ob Font Awesome Dateien existieren
base_path = Path(".")
fa_path = base_path / "static" / "fontawesome"
required_files = [
fa_path / "css" / "all.min.css",
fa_path / "webfonts" / "fa-solid-900.woff2",
fa_path / "webfonts" / "fa-regular-400.woff2",
fa_path / "webfonts" / "fa-brands-400.woff2"
]
all_exist = True
for file_path in required_files:
if file_path.exists():
print_status(f"{file_path.name} gefunden", "SUCCESS")
else:
print_status(f"{file_path.name} fehlt", "ERROR")
all_exist = False
# Überprüfe base.html Integration
base_html = base_path / "templates" / "base.html"
if base_html.exists():
with open(base_html, 'r', encoding='utf-8') as f:
content = f.read()
if 'fontawesome/css/all.min.css' in content:
print_status("✓ Font Awesome in base.html eingebunden", "SUCCESS")
else:
print_status("✗ Font Awesome nicht in base.html gefunden", "ERROR")
all_exist = False
else:
print_status("✗ base.html nicht gefunden", "ERROR")
all_exist = False
return all_exist
def test_database_schema():
"""Test 2: Datenbank-Schema für neue Funktionen"""
print_status("=== TESTE DATENBANK-SCHEMA ===", "INFO")
try:
# Verbindung zur Datenbank - korrigierter Pfad
db_path = "database/myp.db"
if not os.path.exists(db_path):
print_status("✗ Datenbank nicht gefunden", "ERROR")
return False
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Teste GuestRequest Tabelle
cursor.execute("SELECT sql FROM sqlite_master WHERE type='table' AND name='guest_requests'")
guest_table = cursor.fetchone()
if guest_table:
print_status("✓ GuestRequest Tabelle existiert", "SUCCESS")
# Überprüfe wichtige Spalten
required_columns = [
'processed_by', 'processed_at', 'approval_notes',
'rejection_reason', 'otp_code', 'otp_used_at'
]
table_sql = guest_table[0].lower()
missing_columns = []
for col in required_columns:
if col.lower() not in table_sql:
missing_columns.append(col)
if missing_columns:
print_status(f"✗ Fehlende Spalten: {', '.join(missing_columns)}", "ERROR")
conn.close()
return False
else:
print_status("✓ Alle erforderlichen Spalten vorhanden", "SUCCESS")
else:
print_status("✗ GuestRequest Tabelle nicht gefunden", "ERROR")
conn.close()
return False
# Teste Printer Tabelle
cursor.execute("SELECT sql FROM sqlite_master WHERE type='table' AND name='printers'")
printer_table = cursor.fetchone()
if printer_table:
print_status("✓ Printer Tabelle existiert", "SUCCESS")
# Überprüfe Status-Spalten
table_sql = printer_table[0].lower()
if 'last_checked' in table_sql and 'status' in table_sql:
print_status("✓ Drucker-Status-Spalten vorhanden", "SUCCESS")
else:
print_status("✗ Drucker-Status-Spalten fehlen", "ERROR")
conn.close()
return False
else:
print_status("✗ Printer Tabelle nicht gefunden", "ERROR")
conn.close()
return False
conn.close()
return True
except Exception as e:
print_status(f"✗ Datenbankfehler: {str(e)}", "ERROR")
return False
def test_api_endpoints():
"""Test 3: Neue API-Endpunkte"""
print_status("=== TESTE API-ENDPUNKTE ===", "INFO")
base_url = "http://localhost:5000"
# Test-Endpunkte (ohne Authentifizierung)
test_endpoints = [
"/api/printers/status/emergency",
"/api/admin/requests",
"/api/printers/status/summary"
]
available_endpoints = []
for endpoint in test_endpoints:
try:
response = requests.get(f"{base_url}{endpoint}", timeout=5)
# 401/403 ist OK (Authentifizierung erforderlich), 404 ist nicht OK
if response.status_code in [200, 401, 403]:
print_status(f"{endpoint} - Endpunkt verfügbar (HTTP {response.status_code})", "SUCCESS")
available_endpoints.append(endpoint)
elif response.status_code == 404:
print_status(f"{endpoint} - Endpunkt nicht gefunden (HTTP 404)", "ERROR")
else:
print_status(f"{endpoint} - Unerwarteter Status (HTTP {response.status_code})", "WARNING")
available_endpoints.append(endpoint)
except requests.exceptions.ConnectionError:
print_status(f"{endpoint} - Server nicht erreichbar", "WARNING")
except Exception as e:
print_status(f"{endpoint} - Fehler: {str(e)}", "ERROR")
return len(available_endpoints) > 0
def test_template_integration():
"""Test 4: Template-Integration"""
print_status("=== TESTE TEMPLATE-INTEGRATION ===", "INFO")
templates_to_check = [
("templates/admin.html", "admin_guest_requests"),
("templates/admin_guest_requests.html", "fas fa-"),
("templates/base.html", "fontawesome/css/all.min.css")
]
all_ok = True
for template_path, search_term in templates_to_check:
if os.path.exists(template_path):
with open(template_path, 'r', encoding='utf-8') as f:
content = f.read()
if search_term in content:
print_status(f"{template_path} - {search_term} gefunden", "SUCCESS")
else:
print_status(f"{template_path} - {search_term} nicht gefunden", "ERROR")
all_ok = False
else:
print_status(f"{template_path} - Datei nicht gefunden", "ERROR")
all_ok = False
return all_ok
def test_app_imports():
"""Test 5: App.py Importe und Funktionen"""
print_status("=== TESTE APP.PY INTEGRATION ===", "INFO")
if not os.path.exists("app.py"):
print_status("✗ app.py nicht gefunden", "ERROR")
return False
with open("app.py", 'r', encoding='utf-8') as f:
content = f.read()
required_functions = [
"get_printers_status_emergency",
"force_update_all_printer_status",
"admin_get_guest_requests",
"admin_approve_guest_request",
"admin_deny_guest_request"
]
missing_functions = []
for func in required_functions:
if f"def {func}" in content:
print_status(f"✓ Funktion {func} gefunden", "SUCCESS")
else:
print_status(f"✗ Funktion {func} fehlt", "ERROR")
missing_functions.append(func)
# Teste Import-Statements
required_imports = ["desc", "GuestRequest", "Notification"]
missing_imports = []
for imp in required_imports:
if imp in content:
print_status(f"✓ Import {imp} gefunden", "SUCCESS")
else:
print_status(f"✗ Import {imp} fehlt", "ERROR")
missing_imports.append(imp)
return len(missing_functions) == 0 and len(missing_imports) == 0
def run_comprehensive_test():
"""Führt alle Tests aus"""
print_status("MYP PLATFORM - IMPLEMENTATION TEST", "INFO")
print_status("=" * 50, "INFO")
test_results = {
"Font Awesome Installation": test_font_awesome_installation(),
"Datenbank Schema": test_database_schema(),
"Template Integration": test_template_integration(),
"App.py Integration": test_app_imports(),
"API Endpunkte": test_api_endpoints()
}
print_status("\n=== ZUSAMMENFASSUNG ===", "INFO")
passed = 0
total = len(test_results)
for test_name, result in test_results.items():
status = "SUCCESS" if result else "ERROR"
print_status(f"{test_name}: {'BESTANDEN' if result else 'FEHLGESCHLAGEN'}", status)
if result:
passed += 1
print_status(f"\nErgebnis: {passed}/{total} Tests bestanden", "SUCCESS" if passed == total else "WARNING")
if passed == total:
print_status("\n🎉 ALLE TESTS BESTANDEN! Die Implementierung ist vollständig.", "SUCCESS")
print_status("Folgende Funktionen sind jetzt verfügbar:", "INFO")
print_status("• Font Awesome Icons (lokal installiert)", "INFO")
print_status("• Erweiterte Drucker-Status-Verwaltung", "INFO")
print_status("• Admin-Gastaufträge-Verwaltung", "INFO")
print_status("• Robuste Datenbank-Integration", "INFO")
print_status("• Notfall-Drucker-Status-Abruf", "INFO")
else:
print_status(f"\n⚠️ {total - passed} Test(s) fehlgeschlagen. Bitte überprüfen Sie die Implementierung.", "WARNING")
return passed == total
if __name__ == "__main__":
success = run_comprehensive_test()
sys.exit(0 if success else 1)