🎉 Feature: Updated project documentation and removed deprecated admin files 🎉
This commit is contained in:
@ -1 +1,332 @@
|
||||
|
||||
# MYP Platform - Mercedes-Benz 3D-Druck-Management-System
|
||||
|
||||
## Projektüberblick
|
||||
|
||||
Dies ist ein umfassendes 3D-Druck-Management-System für Mercedes-Benz TBA Marienfelde, entwickelt als Projektarbeit für die IHK. Das System verwaltet 3D-Drucker, Druckaufträge, Benutzer und bietet erweiterte Features wie Smart-Plug-Steuerung über Tapo-Geräte.
|
||||
|
||||
## Hauptkomponenten
|
||||
|
||||
### 🚀 **Core Application Files**
|
||||
|
||||
#### **backend/app.py** ⭐ (HAUPTEINSTIEGSPUNKT)
|
||||
- **Funktion**: Hauptanwendung und Flask-App-Initialisierung
|
||||
- **Verwendung**: ✅ AKTIV - Startet die gesamte Anwendung
|
||||
- **Features**:
|
||||
- Production/Development-Konfiguration
|
||||
- Blueprint-Registration
|
||||
- Security-Features (CSRF, Session-Management)
|
||||
- Air-Gapped/Offline-Modus für Mercedes-Benz
|
||||
- Aggressive Shutdown-Handler
|
||||
- **Abhängigkeiten**: models.py, alle blueprints, utils/*
|
||||
|
||||
#### **backend/models.py** ⭐ (DATENBANK-CORE)
|
||||
- **Funktion**: SQLAlchemy-Datenbankmodelle und Session-Management
|
||||
- **Verwendung**: ✅ AKTIV - Von allen Modulen verwendet
|
||||
- **Modelle**:
|
||||
- `User` - Benutzerverwaltung mit Mercedes-spezifischen Feldern
|
||||
- `Printer` - 3D-Drucker mit Status und Standort
|
||||
- `Job` - Druckaufträge mit vollständiger Workflow-Unterstützung
|
||||
- `GuestRequest` - Gastanfragen mit OTP-System
|
||||
- `SystemTimer` - Timer-Management für automatische Abläufe
|
||||
- `PlugStatusLog` - Tapo Smart-Plug Logging
|
||||
- `Stats`, `SystemLog`, `Notification` - System-Tracking
|
||||
- **Database**: SQLite mit optimierten Connection-Pooling
|
||||
|
||||
### 🎛️ **Configuration & Settings**
|
||||
|
||||
#### **backend/config/**
|
||||
- **app_config.py** ✅ - Flask-Konfigurationsklassen (Dev/Prod/Test)
|
||||
- **security.py** ✅ - Sicherheitskonfiguration und Headers
|
||||
- **__init__.py** ✅ - Konfiguration-Package-Initialisierung
|
||||
|
||||
#### **backend/utils/settings.py** ⭐
|
||||
- **Funktion**: Zentrale Systemeinstellungen und Pfade
|
||||
- **Verwendung**: ✅ AKTIV - Von allen Modulen importiert
|
||||
- **Inhalt**: DATABASE_PATH, SECRET_KEY, SESSION_LIFETIME, Pfade
|
||||
|
||||
#### **backend/requirements.txt** ⭐
|
||||
- **Funktion**: Python-Abhängigkeiten (130+ Pakete)
|
||||
- **Verwendung**: ✅ AKTIV - Production-optimiert
|
||||
- **Kategorien**: Flask-Ecosystem, Hardware-Integration (PyP100), Security, Monitoring
|
||||
|
||||
### 🔧 **Blueprints (API-Routen)**
|
||||
|
||||
#### **backend/blueprints/jobs.py** ⭐
|
||||
- **Funktion**: Druckauftrags-Management
|
||||
- **Verwendung**: ✅ AKTIV
|
||||
- **Features**: Job-CRUD, Status-Tracking, Timer-Integration
|
||||
|
||||
#### **backend/blueprints/printers.py** ⭐
|
||||
- **Funktion**: Druckerverwaltung und -monitoring
|
||||
- **Verwendung**: ✅ AKTIV
|
||||
- **Features**: Drucker-Status, Wartung, Standort-Management
|
||||
|
||||
#### **backend/blueprints/auth.py** ⭐
|
||||
- **Funktion**: Authentifizierung und Autorisierung
|
||||
- **Verwendung**: ✅ AKTIV
|
||||
- **Features**: Login/Logout, Session-Management, Berechtigungen
|
||||
|
||||
#### **backend/blueprints/admin_unified.py** ⭐
|
||||
- **Funktion**: Einheitliche Admin-Oberfläche
|
||||
- **Verwendung**: ✅ AKTIV - Ersetzt separate Admin-Module
|
||||
- **Features**: Benutzer-/Drucker-/System-Verwaltung
|
||||
|
||||
#### **backend/blueprints/calendar.py** ⭐
|
||||
- **Funktion**: Kalender-Integration und Terminplanung
|
||||
- **Verwendung**: ✅ AKTIV
|
||||
- **Features**: Job-Scheduling, Ressourcenplanung
|
||||
|
||||
#### **backend/blueprints/guest.py** ⭐
|
||||
- **Funktion**: Gastbenutzer-System
|
||||
- **Verwendung**: ✅ AKTIV
|
||||
- **Features**: Gastanfragen, OTP-System, E-Mail-Benachrichtigungen
|
||||
|
||||
#### **backend/blueprints/tapo_control.py** ⭐
|
||||
- **Funktion**: Smart-Plug-Steuerung (TP-Link Tapo)
|
||||
- **Verwendung**: ✅ AKTIV
|
||||
- **Features**: Fernsteuerung, Zeitsteuerung, Status-Monitoring
|
||||
|
||||
#### **backend/blueprints/user_management.py** ⭐
|
||||
- **Funktion**: Erweiterte Benutzerverwaltung
|
||||
- **Verwendung**: ✅ AKTIV
|
||||
- **Features**: Profil-Management, Berechtigungen, API-Endpunkte
|
||||
|
||||
#### **backend/blueprints/uploads.py** ⭐
|
||||
- **Funktion**: Datei-Upload-System
|
||||
- **Verwendung**: ✅ AKTIV
|
||||
- **Features**: G-Code-Upload, Validierung, Speicherverwaltung
|
||||
|
||||
#### **backend/blueprints/api_simple.py** ⭐
|
||||
- **Funktion**: Vereinfachte API-Endpunkte
|
||||
- **Verwendung**: ✅ AKTIV
|
||||
- **Features**: Health-Check, Status-API
|
||||
|
||||
#### **backend/blueprints/sessions.py** ✅
|
||||
- **Funktion**: Session-Management
|
||||
- **Verwendung**: ✅ AKTIV
|
||||
|
||||
#### **backend/blueprints/kiosk.py** ✅
|
||||
- **Funktion**: Kiosk-Modus für öffentliche Terminals
|
||||
- **Verwendung**: ✅ AKTIV
|
||||
|
||||
### 🛠️ **Utility Modules**
|
||||
|
||||
#### **Core System Utilities**
|
||||
- **utils/logging_config.py** ⭐ - Erweiterte Logging-Konfiguration
|
||||
- **utils/database_core.py** ⭐ - Datenbank-Optimierungen und Connection-Management
|
||||
- **utils/database_utils.py** ⭐ - Datenbank-Hilfsfunktionen
|
||||
- **utils/database_cleanup.py** ✅ - Automatische DB-Bereinigung
|
||||
- **utils/database_migration.py** ✅ - Schema-Migrationen
|
||||
|
||||
#### **Hardware Integration**
|
||||
- **utils/tapo_controller.py** ⭐ - TP-Link Tapo Smart-Plug Integration
|
||||
- **utils/printer_monitor.py** ⭐ - 3D-Drucker Monitoring und Status
|
||||
- **utils/debug_drucker_erkennung.py** ✅ - Drucker-Discovery-System
|
||||
|
||||
#### **Job & Timer Management**
|
||||
- **utils/job_scheduler.py** ⭐ - Druckauftrags-Scheduler mit Smart-Plug-Integration
|
||||
- **utils/timer_manager.py** ⭐ - Erweiterte Timer-Verwaltung
|
||||
- **utils/timeout_force_quit_manager.py** ⭐ - Force-Quit mit visueller Anzeige
|
||||
- **utils/queue_manager.py** ⭐ - Job-Warteschlangen-Management
|
||||
- **utils/conflict_manager.py** ⭐ - Konfliktauflösung bei Überschneidungen
|
||||
|
||||
#### **Security & Permissions**
|
||||
- **utils/security.py** ⭐ - Sicherheits-Middleware und Headers
|
||||
- **utils/permissions.py** ⭐ - Rollenbasierte Berechtigungen
|
||||
- **utils/rate_limiter.py** ✅ - Rate-Limiting für API-Schutz
|
||||
|
||||
#### **User Interface & Experience**
|
||||
- **utils/form_validation.py** ⭐ - Formular-Validierung mit Client/Server-Sync
|
||||
- **utils/drag_drop_system.py** ⭐ - Drag & Drop für Datei-Uploads
|
||||
- **utils/advanced_tables.py** ⭐ - Erweiterte Tabellen mit Sortierung/Filtering
|
||||
- **utils/template_helpers.py** ⭐ - Jinja2-Template-Hilfsfunktionen
|
||||
- **utils/realtime_dashboard.py** ⭐ - WebSocket-basiertes Real-time Dashboard
|
||||
|
||||
#### **System Management**
|
||||
- **utils/system_control.py** ⭐ - System-weite Steuerung und Monitoring
|
||||
- **utils/maintenance_system.py** ⭐ - Wartungsplaner für Drucker
|
||||
- **utils/multi_location_system.py** ⭐ - Multi-Standort-Verwaltung
|
||||
- **utils/shutdown_manager.py** ⭐ - Kontrolliertes System-Shutdown
|
||||
- **utils/watchdog_manager.py** ⭐ - System-Überwachung und Recovery
|
||||
- **utils/error_recovery.py** ⭐ - Automatische Fehlerbehandlung
|
||||
|
||||
#### **Reporting & Analytics**
|
||||
- **utils/report_generator.py** ⭐ - PDF/Excel-Report-Generator
|
||||
- **utils/analytics.py** ⭐ - System-Analytics und Metriken
|
||||
- **utils/performance_monitor.py** ✅ - Performance-Tracking
|
||||
|
||||
#### **Communication & Notifications**
|
||||
- **utils/email_notification.py** ✅ - E-Mail-Benachrichtigungen
|
||||
- **utils/offline_config.py** ✅ - Air-Gapped-Modus Konfiguration
|
||||
|
||||
#### **File & Data Management**
|
||||
- **utils/file_manager.py** ⭐ - Erweiterte Dateiverwaltung
|
||||
- **utils/file_utils.py** ⭐ - Datei-Hilfsfunktionen
|
||||
- **utils/backup_manager.py** ✅ - Automatische Backups
|
||||
|
||||
#### **Platform-Specific**
|
||||
- **utils/windows_fixes.py** ⭐ - Windows-spezifische Optimierungen
|
||||
- **utils/ssl_manager.py** ✅ - SSL/TLS-Zertifikat-Management
|
||||
- **utils/ssl_config.py** ✅ - SSL-Konfiguration
|
||||
|
||||
### 🎨 **Frontend Assets**
|
||||
|
||||
#### **backend/templates/** ⭐
|
||||
- **base.html** - Haupt-Template mit responsivem Design
|
||||
- **login.html** - Anmelde-Interface
|
||||
- **dashboard.html** - Hauptdashboard
|
||||
- **jobs.html** - Druckauftrags-Verwaltung
|
||||
- **printers.html** - Drucker-Übersicht
|
||||
- **calendar.html** - Kalender-Ansicht
|
||||
- **admin.html** - Admin-Panel
|
||||
- **guest_request.html** - Gastanfrage-Formular
|
||||
- **settings.html** - Benutzereinstellungen
|
||||
- **profile.html** - Benutzerprofil
|
||||
- **analytics.html** - System-Analytics
|
||||
- **tapo_control.html** - Smart-Plug-Steuerung
|
||||
- **errors/** - Fehlerseiten (404, 500)
|
||||
- **jobs/** - Job-spezifische Templates
|
||||
|
||||
#### **backend/static/** ⭐
|
||||
- **css/** - Stylesheets (responsive, Mercedes-Design)
|
||||
- **js/** - JavaScript (Charts, FullCalendar, Real-time)
|
||||
- **fontawesome/** - Icon-Bibliothek (kompletter Satz)
|
||||
- **icons/** - Projekt-spezifische Icons
|
||||
- **manifest.json** - PWA-Manifest
|
||||
- **offline.html** - Air-Gapped-Modus-Seite
|
||||
|
||||
### 📊 **Database & Data**
|
||||
|
||||
#### **backend/database/**
|
||||
- **myp.db** - Haupt-SQLite-Datenbank
|
||||
- **backups/** - Automatische Datenbank-Backups
|
||||
|
||||
#### **backend/uploads/** ⭐
|
||||
- **assets/**, **avatars/**, **jobs/**, **temp/** - Strukturierte Datei-Organisation
|
||||
- **backups/**, **logs/**, **guests/** - System-Dateien
|
||||
|
||||
### 🔧 **Setup & Deployment**
|
||||
|
||||
#### **backend/setup/**
|
||||
- **setup_https_only.sh** ⭐ - HTTPS-Setup für Production
|
||||
- **systemd/** - Linux-Service-Dateien
|
||||
|
||||
#### **backend/scripts/** ⭐
|
||||
- **screenshot_tool.py** - Automatische Screenshots für Schulungen
|
||||
- **test_protocol_generator.py** - Test-Protokoll-Generator
|
||||
- **requirements_screenshot_tool.txt** - Dependencies für Screenshot-Tool
|
||||
|
||||
### 📝 **Documentation & Legacy**
|
||||
|
||||
#### **docs/** ⭐
|
||||
- **v1-LEGACY/**, **v2-LEGACY/** - Dokumentation alter Versionen
|
||||
- **MYP.dbml**, **MYP.sql** - Datenbank-Schema-Dokumentation
|
||||
|
||||
#### **backend/legacy/**
|
||||
- **app_original.py** - Original-Implementierung (Backup)
|
||||
|
||||
#### **IHK_Projektdokumentation/** ⭐
|
||||
- **Anlagen_und_Screenshots/** - Schulungsmaterialien
|
||||
- **ChatGPT-Data/**, **Gesprächsprotokolle/** - Entwicklungsdokumentation
|
||||
- **IHK_Vorgaben/** - Offizielle IHK-Anforderungen
|
||||
|
||||
#### **dokumentation/**
|
||||
- **berichtshefte/** - Ausbildungsberichte
|
||||
- **kalender/** - Projekt-Zeitplanung
|
||||
|
||||
### 🧪 **Testing & Quality**
|
||||
|
||||
#### **tests/**
|
||||
- Umfassendes Test-Framework (noch zu implementieren)
|
||||
|
||||
#### **Quality Assurance Files**
|
||||
- **utils/test_*.py** - Verschiedene Test-Utilities
|
||||
- **backend/debug/** - Debug-Logs und -Tools
|
||||
- **backend/logs/** - Strukturierte Log-Dateien nach Modulen
|
||||
|
||||
### 🔄 **Deprecated & Backup Files**
|
||||
|
||||
#### **LEGACY-torben_frontend/** ❌
|
||||
- **Funktion**: Alte Next.js-Frontend-Implementation
|
||||
- **Status**: DEPRECATED - Wird nicht verwendet
|
||||
- **Ersetzt durch**: Jinja2-Templates in backend/templates/
|
||||
|
||||
#### **backend/blueprints/deprecated/** ❌
|
||||
- **admin.py** - Alte Admin-Implementation
|
||||
- **Status**: Ersetzt durch admin_unified.py
|
||||
|
||||
#### **utils/deprecated/** ❌
|
||||
- Verschiedene veraltete Utility-Module
|
||||
|
||||
## 📈 **Referenz-Matrix (Wer verwendet was)**
|
||||
|
||||
### Hochfrequent verwendete Module:
|
||||
- **models.py** → Verwendet von: app.py, allen blueprints, 90% der utils
|
||||
- **utils/settings.py** → Verwendet von: app.py, models.py, allen configs
|
||||
- **utils/logging_config.py** → Verwendet von: Praktisch allen .py-Dateien
|
||||
- **utils/permissions.py** → Verwendet von: allen blueprints, auth-relevanten utils
|
||||
|
||||
### Blueprint-Dependencies:
|
||||
- **jobs.py** → models, job_scheduler, timer_manager, printer_monitor
|
||||
- **printers.py** → models, printer_monitor, maintenance_system
|
||||
- **admin_unified.py** → models, alle user/printer/system utils
|
||||
- **tapo_control.py** → tapo_controller, job_scheduler
|
||||
|
||||
### Hardware-Integration:
|
||||
- **utils/tapo_controller.py** → Verwendet von: tapo_control.py, job_scheduler.py
|
||||
- **utils/printer_monitor.py** → Verwendet von: printers.py, jobs.py, system_control.py
|
||||
|
||||
## 🚦 **System-Status-Übersicht**
|
||||
|
||||
### ✅ **Produktiv verwendet** (Core Features):
|
||||
- Hauptanwendung (app.py, models.py)
|
||||
- Alle aktiven Blueprints
|
||||
- Job-Management-System
|
||||
- Smart-Plug-Integration
|
||||
- Benutzer- und Rechteverwaltung
|
||||
- Real-time Dashboard
|
||||
- Gast-System mit OTP
|
||||
|
||||
### 🔧 **Experimentell/In Entwicklung**:
|
||||
- Multi-Location-System
|
||||
- Erweiterte Analytics
|
||||
- Performance-Monitoring
|
||||
- Automatische Wartungsplanung
|
||||
|
||||
### ❌ **Deprecated/Nicht verwendet**:
|
||||
- LEGACY-torben_frontend/
|
||||
- blueprints/deprecated/
|
||||
- utils/deprecated/
|
||||
- Einige Test-/Debug-Scripts
|
||||
|
||||
## 🎯 **Empfehlungen für Wartung**
|
||||
|
||||
### Priorität 1 (Kritisch):
|
||||
- **models.py**: Datenbank-Schema pflegen
|
||||
- **app.py**: Konfiguration aktuell halten
|
||||
- **Alle blueprints**: API-Endpunkte dokumentieren
|
||||
- **utils/tapo_controller.py**: Hardware-Kompatibilität prüfen
|
||||
|
||||
### Priorität 2 (Wichtig):
|
||||
- **templates/**: UI/UX kontinuierlich verbessern
|
||||
- **utils/security.py**: Sicherheitsupdates
|
||||
- **setup/**: Deployment-Scripts aktualisieren
|
||||
|
||||
### Aufräumen:
|
||||
- Deprecated-Ordner entfernen (nach Backup)
|
||||
- Ungenutzte Test-Scripts konsolidieren
|
||||
- Log-Dateien regelmäßig archivieren
|
||||
|
||||
---
|
||||
|
||||
**Gesamtstatistik:**
|
||||
- **~200 Python-Dateien** (Backend-Logik)
|
||||
- **~50 HTML-Templates** (Frontend)
|
||||
- **~130 Dependencies** (requirements.txt)
|
||||
- **~15 Hauptbereiche** (Blueprints, Utils, etc.)
|
||||
- **1 SQLite-Datenbank** mit 12+ Tabellen
|
||||
- **Full-Stack-Anwendung** mit Real-time-Features
|
||||
|
||||
**Entwicklungszeitraum:** 2024-2025 (Laufendes IHK-Projekt)
|
||||
**Zielgruppe:** Mercedes-Benz TBA Marienfelde (Air-Gapped Environment)
|
||||
**Technologie-Stack:** Flask, SQLAlchemy, Jinja2, WebSockets, SQLite
|
@ -107,8 +107,7 @@ python app.py --debug
|
||||
|
||||
```
|
||||
backend/
|
||||
├── app.py # Hauptanwendung mit Development-Support
|
||||
├── app_production.py # Produktions-Anwendung mit HTTPS-Support
|
||||
├── app.py # Haupt-Anwendung mit Production- und Development-Modi
|
||||
├── models.py # Datenbankmodelle
|
||||
├── requirements.txt # Python-Abhängigkeiten
|
||||
├── README.md # Diese Datei
|
||||
|
@ -1,335 +0,0 @@
|
||||
"""
|
||||
Admin-Blueprint für das 3D-Druck-Management-System
|
||||
|
||||
Dieses Modul enthält alle Admin-spezifischen Routen und Funktionen,
|
||||
einschließlich Benutzerverwaltung, Systemüberwachung und Drucker-Administration.
|
||||
"""
|
||||
|
||||
from flask import Blueprint, render_template, request, jsonify, redirect, url_for, flash
|
||||
from flask_login import login_required, current_user
|
||||
from functools import wraps
|
||||
from models import User, Printer, Job, get_db_session, Stats, SystemLog
|
||||
from utils.logging_config import get_logger
|
||||
from datetime import datetime
|
||||
|
||||
# Blueprint erstellen
|
||||
admin_blueprint = Blueprint('admin', __name__, url_prefix='/admin')
|
||||
|
||||
# Logger initialisieren
|
||||
admin_logger = get_logger("admin")
|
||||
|
||||
def admin_required(f):
|
||||
"""Decorator für Admin-Berechtigung"""
|
||||
@wraps(f)
|
||||
@login_required
|
||||
def decorated_function(*args, **kwargs):
|
||||
admin_logger.info(f"Admin-Check für Funktion {f.__name__}: User authenticated: {current_user.is_authenticated}, User ID: {current_user.id if current_user.is_authenticated else 'None'}, Is Admin: {current_user.is_admin if current_user.is_authenticated else 'None'}")
|
||||
if not current_user.is_admin:
|
||||
admin_logger.warning(f"Admin-Zugriff verweigert für User {current_user.id if current_user.is_authenticated else 'Anonymous'} auf Funktion {f.__name__}")
|
||||
return jsonify({"error": "Nur Administratoren haben Zugriff"}), 403
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
@admin_blueprint.route("/")
|
||||
@login_required
|
||||
@admin_required
|
||||
def admin_dashboard():
|
||||
"""Admin-Dashboard-Hauptseite"""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
|
||||
# Grundlegende Statistiken sammeln
|
||||
total_users = db_session.query(User).count()
|
||||
total_printers = db_session.query(Printer).count()
|
||||
total_jobs = db_session.query(Job).count()
|
||||
|
||||
# Aktive Jobs zählen
|
||||
active_jobs = db_session.query(Job).filter(
|
||||
Job.status.in_(['pending', 'printing', 'paused'])
|
||||
).count()
|
||||
|
||||
db_session.close()
|
||||
|
||||
stats = {
|
||||
'total_users': total_users,
|
||||
'total_printers': total_printers,
|
||||
'total_jobs': total_jobs,
|
||||
'active_jobs': active_jobs
|
||||
}
|
||||
|
||||
return render_template('admin/dashboard.html', stats=stats)
|
||||
|
||||
except Exception as e:
|
||||
admin_logger.error(f"Fehler beim Laden des Admin-Dashboards: {str(e)}")
|
||||
flash("Fehler beim Laden der Dashboard-Daten", "error")
|
||||
return render_template('admin/dashboard.html', stats={})
|
||||
|
||||
@admin_blueprint.route("/users")
|
||||
@login_required
|
||||
@admin_required
|
||||
def users_overview():
|
||||
"""Benutzerübersicht für Administratoren"""
|
||||
return render_template('admin/users.html')
|
||||
|
||||
@admin_blueprint.route("/users/add", methods=["GET"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def add_user_page():
|
||||
"""Seite zum Hinzufügen eines neuen Benutzers"""
|
||||
return render_template('admin/add_user.html')
|
||||
|
||||
@admin_blueprint.route("/users/<int:user_id>/edit", methods=["GET"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def edit_user_page(user_id):
|
||||
"""Seite zum Bearbeiten eines Benutzers"""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
|
||||
if not user:
|
||||
db_session.close()
|
||||
flash("Benutzer nicht gefunden", "error")
|
||||
return redirect(url_for('admin.users_overview'))
|
||||
|
||||
db_session.close()
|
||||
return render_template('admin/edit_user.html', user=user)
|
||||
|
||||
except Exception as e:
|
||||
admin_logger.error(f"Fehler beim Laden der Benutzer-Bearbeitung: {str(e)}")
|
||||
flash("Fehler beim Laden der Benutzerdaten", "error")
|
||||
return redirect(url_for('admin.users_overview'))
|
||||
|
||||
@admin_blueprint.route("/printers")
|
||||
@login_required
|
||||
@admin_required
|
||||
def printers_overview():
|
||||
"""Druckerübersicht für Administratoren"""
|
||||
return render_template('admin/printers.html')
|
||||
|
||||
@admin_blueprint.route("/printers/add", methods=["GET"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def add_printer_page():
|
||||
"""Seite zum Hinzufügen eines neuen Druckers"""
|
||||
return render_template('admin/add_printer.html')
|
||||
|
||||
@admin_blueprint.route("/printers/<int:printer_id>/edit", methods=["GET"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def edit_printer_page(printer_id):
|
||||
"""Seite zum Bearbeiten eines Druckers"""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
printer = db_session.query(Printer).filter(Printer.id == printer_id).first()
|
||||
|
||||
if not printer:
|
||||
db_session.close()
|
||||
flash("Drucker nicht gefunden", "error")
|
||||
return redirect(url_for('admin.printers_overview'))
|
||||
|
||||
db_session.close()
|
||||
return render_template('admin/edit_printer.html', printer=printer)
|
||||
|
||||
except Exception as e:
|
||||
admin_logger.error(f"Fehler beim Laden der Drucker-Bearbeitung: {str(e)}")
|
||||
flash("Fehler beim Laden der Druckerdaten", "error")
|
||||
return redirect(url_for('admin.printers_overview'))
|
||||
|
||||
@admin_blueprint.route("/guest-requests")
|
||||
@login_required
|
||||
@admin_required
|
||||
def guest_requests():
|
||||
"""Gäste-Anfragen-Übersicht"""
|
||||
return render_template('admin/guest_requests.html')
|
||||
|
||||
@admin_blueprint.route("/advanced-settings")
|
||||
@login_required
|
||||
@admin_required
|
||||
def advanced_settings():
|
||||
"""Erweiterte Systemeinstellungen"""
|
||||
return render_template('admin/advanced_settings.html')
|
||||
|
||||
@admin_blueprint.route("/system-health")
|
||||
@login_required
|
||||
@admin_required
|
||||
def system_health():
|
||||
"""System-Gesundheitsstatus"""
|
||||
return render_template('admin/system_health.html')
|
||||
|
||||
@admin_blueprint.route("/logs")
|
||||
@login_required
|
||||
@admin_required
|
||||
def logs_overview():
|
||||
"""System-Logs-Übersicht"""
|
||||
return render_template('admin/logs.html')
|
||||
|
||||
@admin_blueprint.route("/maintenance")
|
||||
@login_required
|
||||
@admin_required
|
||||
def maintenance():
|
||||
"""Wartungsseite"""
|
||||
return render_template('admin/maintenance.html')
|
||||
|
||||
# API-Endpunkte für Admin-Funktionen
|
||||
@admin_blueprint.route("/api/users", methods=["POST"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def create_user_api():
|
||||
"""API-Endpunkt zum Erstellen eines neuen Benutzers"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
# Validierung der erforderlichen Felder
|
||||
required_fields = ['username', 'email', 'password', 'name']
|
||||
for field in required_fields:
|
||||
if field not in data or not data[field]:
|
||||
return jsonify({"error": f"Feld '{field}' ist erforderlich"}), 400
|
||||
|
||||
db_session = get_db_session()
|
||||
|
||||
# Überprüfung auf bereits existierende Benutzer
|
||||
existing_user = db_session.query(User).filter(
|
||||
(User.username == data['username']) | (User.email == data['email'])
|
||||
).first()
|
||||
|
||||
if existing_user:
|
||||
db_session.close()
|
||||
return jsonify({"error": "Benutzername oder E-Mail bereits vergeben"}), 400
|
||||
|
||||
# Neuen Benutzer erstellen
|
||||
new_user = User(
|
||||
username=data['username'],
|
||||
email=data['email'],
|
||||
name=data['name'],
|
||||
role=data.get('role', 'user'),
|
||||
department=data.get('department'),
|
||||
position=data.get('position'),
|
||||
phone=data.get('phone'),
|
||||
bio=data.get('bio')
|
||||
)
|
||||
new_user.set_password(data['password'])
|
||||
|
||||
db_session.add(new_user)
|
||||
db_session.commit()
|
||||
|
||||
admin_logger.info(f"Neuer Benutzer erstellt: {new_user.username} von Admin {current_user.username}")
|
||||
|
||||
db_session.close()
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Benutzer erfolgreich erstellt",
|
||||
"user_id": new_user.id
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
admin_logger.error(f"Fehler beim Erstellen des Benutzers: {str(e)}")
|
||||
return jsonify({"error": "Fehler beim Erstellen des Benutzers"}), 500
|
||||
|
||||
@admin_blueprint.route("/api/users/<int:user_id>", methods=["GET"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def get_user_api(user_id):
|
||||
"""API-Endpunkt zum Abrufen von Benutzerdaten"""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
|
||||
if not user:
|
||||
db_session.close()
|
||||
return jsonify({"error": "Benutzer nicht gefunden"}), 404
|
||||
|
||||
user_data = {
|
||||
"id": user.id,
|
||||
"username": user.username,
|
||||
"email": user.email,
|
||||
"name": user.name,
|
||||
"role": user.role,
|
||||
"active": user.active,
|
||||
"created_at": user.created_at.isoformat() if user.created_at else None,
|
||||
"last_login": user.last_login.isoformat() if user.last_login else None,
|
||||
"department": user.department,
|
||||
"position": user.position,
|
||||
"phone": user.phone,
|
||||
"bio": user.bio
|
||||
}
|
||||
|
||||
db_session.close()
|
||||
return jsonify(user_data)
|
||||
|
||||
except Exception as e:
|
||||
admin_logger.error(f"Fehler beim Abrufen der Benutzerdaten: {str(e)}")
|
||||
return jsonify({"error": "Fehler beim Abrufen der Benutzerdaten"}), 500
|
||||
|
||||
@admin_blueprint.route("/api/users/<int:user_id>", methods=["PUT"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def update_user_api(user_id):
|
||||
"""API-Endpunkt zum Aktualisieren von Benutzerdaten"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
db_session = get_db_session()
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
|
||||
if not user:
|
||||
db_session.close()
|
||||
return jsonify({"error": "Benutzer nicht gefunden"}), 404
|
||||
|
||||
# Aktualisierbare Felder
|
||||
updatable_fields = ['username', 'email', 'name', 'role', 'active', 'department', 'position', 'phone', 'bio']
|
||||
|
||||
for field in updatable_fields:
|
||||
if field in data:
|
||||
setattr(user, field, data[field])
|
||||
|
||||
# Passwort separat behandeln
|
||||
if 'password' in data and data['password']:
|
||||
user.set_password(data['password'])
|
||||
|
||||
user.updated_at = datetime.now()
|
||||
db_session.commit()
|
||||
|
||||
admin_logger.info(f"Benutzer {user.username} aktualisiert von Admin {current_user.username}")
|
||||
|
||||
db_session.close()
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Benutzer erfolgreich aktualisiert"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
admin_logger.error(f"Fehler beim Aktualisieren des Benutzers: {str(e)}")
|
||||
return jsonify({"error": "Fehler beim Aktualisieren des Benutzers"}), 500
|
||||
|
||||
@admin_blueprint.route("/api/users/<int:user_id>", methods=["DELETE"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def delete_user_api(user_id):
|
||||
"""API-Endpunkt zum Löschen eines Benutzers"""
|
||||
try:
|
||||
if user_id == current_user.id:
|
||||
return jsonify({"error": "Sie können sich nicht selbst löschen"}), 400
|
||||
|
||||
db_session = get_db_session()
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
|
||||
if not user:
|
||||
db_session.close()
|
||||
return jsonify({"error": "Benutzer nicht gefunden"}), 404
|
||||
|
||||
username = user.username
|
||||
db_session.delete(user)
|
||||
db_session.commit()
|
||||
|
||||
admin_logger.info(f"Benutzer {username} gelöscht von Admin {current_user.username}")
|
||||
|
||||
db_session.close()
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Benutzer erfolgreich gelöscht"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
admin_logger.error(f"Fehler beim Löschen des Benutzers: {str(e)}")
|
||||
return jsonify({"error": "Fehler beim Löschen des Benutzers"}), 500
|
@ -1,489 +0,0 @@
|
||||
"""
|
||||
Admin-API Blueprint für erweiterte Verwaltungsfunktionen
|
||||
|
||||
Dieses Blueprint stellt zusätzliche Admin-API-Endpunkte bereit für:
|
||||
- System-Backups
|
||||
- Datenbank-Optimierung
|
||||
- Cache-Verwaltung
|
||||
|
||||
Autor: MYP Team
|
||||
Datum: 2025-06-01
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import zipfile
|
||||
import sqlite3
|
||||
import glob
|
||||
from datetime import datetime, timedelta
|
||||
from flask import Blueprint, request, jsonify, current_app
|
||||
from flask_login import login_required, current_user
|
||||
from functools import wraps
|
||||
from utils.logging_config import get_logger
|
||||
|
||||
# Blueprint erstellen
|
||||
admin_api_blueprint = Blueprint('admin_api', __name__, url_prefix='/api/admin')
|
||||
|
||||
# Logger initialisieren
|
||||
admin_logger = get_logger("admin_api")
|
||||
|
||||
def admin_required(f):
|
||||
"""Decorator um sicherzustellen, dass nur Admins auf Endpunkte zugreifen können."""
|
||||
@wraps(f)
|
||||
@login_required
|
||||
def decorated_function(*args, **kwargs):
|
||||
if not current_user.is_authenticated or current_user.role != 'admin':
|
||||
admin_logger.warning(f"Unauthorized admin access attempt by user {getattr(current_user, 'id', 'anonymous')}")
|
||||
return jsonify({'error': 'Admin-Berechtigung erforderlich'}), 403
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
@admin_api_blueprint.route('/backup/create', methods=['POST'])
|
||||
@admin_required
|
||||
def create_backup():
|
||||
"""
|
||||
Erstellt ein manuelles System-Backup.
|
||||
|
||||
Erstellt eine Sicherung aller wichtigen Systemdaten einschließlich
|
||||
Datenbank, Konfigurationsdateien und Benutzer-Uploads.
|
||||
|
||||
Returns:
|
||||
JSON: Erfolgs-Status und Backup-Informationen
|
||||
"""
|
||||
try:
|
||||
admin_logger.info(f"Backup-Erstellung angefordert von Admin {current_user.username}")
|
||||
|
||||
# Backup-Verzeichnis sicherstellen
|
||||
backup_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'database', 'backups')
|
||||
os.makedirs(backup_dir, exist_ok=True)
|
||||
|
||||
# Eindeutigen Backup-Namen erstellen
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
backup_name = f"system_backup_{timestamp}.zip"
|
||||
backup_path = os.path.join(backup_dir, backup_name)
|
||||
|
||||
created_files = []
|
||||
backup_size = 0
|
||||
|
||||
with zipfile.ZipFile(backup_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
||||
# 1. Datenbank-Datei hinzufügen
|
||||
try:
|
||||
from utils.settings import DATABASE_PATH
|
||||
if os.path.exists(DATABASE_PATH):
|
||||
zipf.write(DATABASE_PATH, 'database/main.db')
|
||||
created_files.append('database/main.db')
|
||||
admin_logger.debug("✅ Hauptdatenbank zur Sicherung hinzugefügt")
|
||||
|
||||
# WAL- und SHM-Dateien falls vorhanden
|
||||
wal_path = DATABASE_PATH + '-wal'
|
||||
shm_path = DATABASE_PATH + '-shm'
|
||||
|
||||
if os.path.exists(wal_path):
|
||||
zipf.write(wal_path, 'database/main.db-wal')
|
||||
created_files.append('database/main.db-wal')
|
||||
|
||||
if os.path.exists(shm_path):
|
||||
zipf.write(shm_path, 'database/main.db-shm')
|
||||
created_files.append('database/main.db-shm')
|
||||
|
||||
except Exception as db_error:
|
||||
admin_logger.warning(f"Fehler beim Hinzufügen der Datenbank: {str(db_error)}")
|
||||
|
||||
# 2. Konfigurationsdateien
|
||||
try:
|
||||
config_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config')
|
||||
if os.path.exists(config_dir):
|
||||
for root, dirs, files in os.walk(config_dir):
|
||||
for file in files:
|
||||
if file.endswith(('.py', '.json', '.yaml', '.yml', '.toml')):
|
||||
file_path = os.path.join(root, file)
|
||||
arc_path = os.path.relpath(file_path, os.path.dirname(os.path.dirname(__file__)))
|
||||
zipf.write(file_path, arc_path)
|
||||
created_files.append(arc_path)
|
||||
admin_logger.debug("✅ Konfigurationsdateien zur Sicherung hinzugefügt")
|
||||
except Exception as config_error:
|
||||
admin_logger.warning(f"Fehler beim Hinzufügen der Konfiguration: {str(config_error)}")
|
||||
|
||||
# 3. Wichtige User-Uploads (limitiert auf die letzten 1000 Dateien)
|
||||
try:
|
||||
uploads_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'uploads')
|
||||
if os.path.exists(uploads_dir):
|
||||
file_count = 0
|
||||
max_files = 1000 # Limit für Performance
|
||||
|
||||
for root, dirs, files in os.walk(uploads_dir):
|
||||
for file in files[:max_files - file_count]:
|
||||
if file_count >= max_files:
|
||||
break
|
||||
|
||||
file_path = os.path.join(root, file)
|
||||
file_size = os.path.getsize(file_path)
|
||||
|
||||
# Nur Dateien unter 50MB hinzufügen
|
||||
if file_size < 50 * 1024 * 1024:
|
||||
arc_path = os.path.relpath(file_path, os.path.dirname(os.path.dirname(__file__)))
|
||||
zipf.write(file_path, arc_path)
|
||||
created_files.append(arc_path)
|
||||
file_count += 1
|
||||
|
||||
if file_count >= max_files:
|
||||
break
|
||||
|
||||
admin_logger.debug(f"✅ {file_count} Upload-Dateien zur Sicherung hinzugefügt")
|
||||
except Exception as uploads_error:
|
||||
admin_logger.warning(f"Fehler beim Hinzufügen der Uploads: {str(uploads_error)}")
|
||||
|
||||
# 4. System-Logs (nur die letzten 100 Log-Dateien)
|
||||
try:
|
||||
logs_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'logs')
|
||||
if os.path.exists(logs_dir):
|
||||
log_files = []
|
||||
for root, dirs, files in os.walk(logs_dir):
|
||||
for file in files:
|
||||
if file.endswith(('.log', '.txt')):
|
||||
file_path = os.path.join(root, file)
|
||||
log_files.append((file_path, os.path.getmtime(file_path)))
|
||||
|
||||
# Sortiere nach Datum (neueste zuerst) und nimm nur die letzten 100
|
||||
log_files.sort(key=lambda x: x[1], reverse=True)
|
||||
for file_path, _ in log_files[:100]:
|
||||
arc_path = os.path.relpath(file_path, os.path.dirname(os.path.dirname(__file__)))
|
||||
zipf.write(file_path, arc_path)
|
||||
created_files.append(arc_path)
|
||||
|
||||
admin_logger.debug(f"✅ {len(log_files[:100])} Log-Dateien zur Sicherung hinzugefügt")
|
||||
except Exception as logs_error:
|
||||
admin_logger.warning(f"Fehler beim Hinzufügen der Logs: {str(logs_error)}")
|
||||
|
||||
# Backup-Größe bestimmen
|
||||
if os.path.exists(backup_path):
|
||||
backup_size = os.path.getsize(backup_path)
|
||||
|
||||
admin_logger.info(f"✅ System-Backup erfolgreich erstellt: {backup_name} ({backup_size / 1024 / 1024:.2f} MB)")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': f'Backup erfolgreich erstellt: {backup_name}',
|
||||
'backup_info': {
|
||||
'filename': backup_name,
|
||||
'size_bytes': backup_size,
|
||||
'size_mb': round(backup_size / 1024 / 1024, 2),
|
||||
'files_count': len(created_files),
|
||||
'created_at': datetime.now().isoformat(),
|
||||
'path': backup_path
|
||||
}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
admin_logger.error(f"❌ Fehler beim Erstellen des Backups: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Fehler beim Erstellen des Backups: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@admin_api_blueprint.route('/database/optimize', methods=['POST'])
|
||||
@admin_required
|
||||
def optimize_database():
|
||||
"""
|
||||
Führt Datenbank-Optimierung durch.
|
||||
|
||||
Optimiert die SQLite-Datenbank durch VACUUM, ANALYZE und weitere
|
||||
Wartungsoperationen für bessere Performance.
|
||||
|
||||
Returns:
|
||||
JSON: Erfolgs-Status und Optimierungs-Statistiken
|
||||
"""
|
||||
try:
|
||||
admin_logger.info(f"Datenbank-Optimierung angefordert von Admin {current_user.username}")
|
||||
|
||||
from utils.settings import DATABASE_PATH
|
||||
|
||||
optimization_results = {
|
||||
'vacuum_completed': False,
|
||||
'analyze_completed': False,
|
||||
'integrity_check': False,
|
||||
'wal_checkpoint': False,
|
||||
'size_before': 0,
|
||||
'size_after': 0,
|
||||
'space_saved': 0
|
||||
}
|
||||
|
||||
# Datenbankgröße vor Optimierung
|
||||
if os.path.exists(DATABASE_PATH):
|
||||
optimization_results['size_before'] = os.path.getsize(DATABASE_PATH)
|
||||
|
||||
# Verbindung zur Datenbank herstellen
|
||||
conn = sqlite3.connect(DATABASE_PATH, timeout=30.0)
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
# 1. Integritätsprüfung
|
||||
admin_logger.debug("🔍 Führe Integritätsprüfung durch...")
|
||||
cursor.execute("PRAGMA integrity_check")
|
||||
integrity_result = cursor.fetchone()
|
||||
optimization_results['integrity_check'] = integrity_result[0] == 'ok'
|
||||
|
||||
if not optimization_results['integrity_check']:
|
||||
admin_logger.warning(f"⚠️ Integritätsprüfung ergab: {integrity_result[0]}")
|
||||
else:
|
||||
admin_logger.debug("✅ Integritätsprüfung erfolgreich")
|
||||
|
||||
# 2. WAL-Checkpoint (falls WAL-Modus aktiv)
|
||||
try:
|
||||
admin_logger.debug("🔄 Führe WAL-Checkpoint durch...")
|
||||
cursor.execute("PRAGMA wal_checkpoint(TRUNCATE)")
|
||||
optimization_results['wal_checkpoint'] = True
|
||||
admin_logger.debug("✅ WAL-Checkpoint erfolgreich")
|
||||
except Exception as wal_error:
|
||||
admin_logger.debug(f"ℹ️ WAL-Checkpoint nicht möglich: {str(wal_error)}")
|
||||
|
||||
# 3. ANALYZE - Statistiken aktualisieren
|
||||
admin_logger.debug("📊 Aktualisiere Datenbank-Statistiken...")
|
||||
cursor.execute("ANALYZE")
|
||||
optimization_results['analyze_completed'] = True
|
||||
admin_logger.debug("✅ ANALYZE erfolgreich")
|
||||
|
||||
# 4. VACUUM - Datenbank komprimieren und reorganisieren
|
||||
admin_logger.debug("🗜️ Komprimiere und reorganisiere Datenbank...")
|
||||
cursor.execute("VACUUM")
|
||||
optimization_results['vacuum_completed'] = True
|
||||
admin_logger.debug("✅ VACUUM erfolgreich")
|
||||
|
||||
# 5. Performance-Optimierungen
|
||||
try:
|
||||
# Cache-Größe optimieren
|
||||
cursor.execute("PRAGMA cache_size = 10000") # 10MB Cache
|
||||
|
||||
# Journal-Modus auf WAL setzen für bessere Concurrent-Performance
|
||||
cursor.execute("PRAGMA journal_mode = WAL")
|
||||
|
||||
# Synchronous auf NORMAL für Balance zwischen Performance und Sicherheit
|
||||
cursor.execute("PRAGMA synchronous = NORMAL")
|
||||
|
||||
# Page-Größe optimieren (falls noch nicht gesetzt)
|
||||
cursor.execute("PRAGMA page_size = 4096")
|
||||
|
||||
admin_logger.debug("✅ Performance-Optimierungen angewendet")
|
||||
except Exception as perf_error:
|
||||
admin_logger.warning(f"⚠️ Performance-Optimierungen teilweise fehlgeschlagen: {str(perf_error)}")
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
# Datenbankgröße nach Optimierung
|
||||
if os.path.exists(DATABASE_PATH):
|
||||
optimization_results['size_after'] = os.path.getsize(DATABASE_PATH)
|
||||
optimization_results['space_saved'] = optimization_results['size_before'] - optimization_results['size_after']
|
||||
|
||||
# Ergebnisse loggen
|
||||
space_saved_mb = optimization_results['space_saved'] / 1024 / 1024
|
||||
admin_logger.info(f"✅ Datenbank-Optimierung abgeschlossen - {space_saved_mb:.2f} MB Speicher gespart")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'Datenbank erfolgreich optimiert',
|
||||
'results': {
|
||||
'vacuum_completed': optimization_results['vacuum_completed'],
|
||||
'analyze_completed': optimization_results['analyze_completed'],
|
||||
'integrity_check_passed': optimization_results['integrity_check'],
|
||||
'wal_checkpoint_completed': optimization_results['wal_checkpoint'],
|
||||
'size_before_mb': round(optimization_results['size_before'] / 1024 / 1024, 2),
|
||||
'size_after_mb': round(optimization_results['size_after'] / 1024 / 1024, 2),
|
||||
'space_saved_mb': round(space_saved_mb, 2),
|
||||
'optimization_timestamp': datetime.now().isoformat()
|
||||
}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
admin_logger.error(f"❌ Fehler bei Datenbank-Optimierung: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Fehler bei Datenbank-Optimierung: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@admin_api_blueprint.route('/cache/clear', methods=['POST'])
|
||||
@admin_required
|
||||
def clear_cache():
|
||||
"""
|
||||
Leert den System-Cache.
|
||||
|
||||
Entfernt alle temporären Dateien, Cache-Verzeichnisse und
|
||||
Python-Bytecode um Speicher freizugeben und Performance zu verbessern.
|
||||
|
||||
Returns:
|
||||
JSON: Erfolgs-Status und Lösch-Statistiken
|
||||
"""
|
||||
try:
|
||||
admin_logger.info(f"Cache-Leerung angefordert von Admin {current_user.username}")
|
||||
|
||||
cleared_stats = {
|
||||
'files_deleted': 0,
|
||||
'dirs_deleted': 0,
|
||||
'space_freed': 0,
|
||||
'categories': {}
|
||||
}
|
||||
|
||||
app_root = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
# 1. Python-Bytecode-Cache leeren (__pycache__)
|
||||
try:
|
||||
pycache_count = 0
|
||||
pycache_size = 0
|
||||
|
||||
for root, dirs, files in os.walk(app_root):
|
||||
if '__pycache__' in root:
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
pycache_size += os.path.getsize(file_path)
|
||||
os.remove(file_path)
|
||||
pycache_count += 1
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Versuche das __pycache__-Verzeichnis zu löschen
|
||||
try:
|
||||
os.rmdir(root)
|
||||
cleared_stats['dirs_deleted'] += 1
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
cleared_stats['categories']['python_bytecode'] = {
|
||||
'files': pycache_count,
|
||||
'size_mb': round(pycache_size / 1024 / 1024, 2)
|
||||
}
|
||||
cleared_stats['files_deleted'] += pycache_count
|
||||
cleared_stats['space_freed'] += pycache_size
|
||||
|
||||
admin_logger.debug(f"✅ Python-Bytecode-Cache: {pycache_count} Dateien, {pycache_size / 1024 / 1024:.2f} MB")
|
||||
|
||||
except Exception as pycache_error:
|
||||
admin_logger.warning(f"⚠️ Fehler beim Leeren des Python-Cache: {str(pycache_error)}")
|
||||
|
||||
# 2. Temporäre Dateien im uploads/temp Verzeichnis
|
||||
try:
|
||||
temp_count = 0
|
||||
temp_size = 0
|
||||
temp_dir = os.path.join(app_root, 'uploads', 'temp')
|
||||
|
||||
if os.path.exists(temp_dir):
|
||||
for root, dirs, files in os.walk(temp_dir):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
temp_size += os.path.getsize(file_path)
|
||||
os.remove(file_path)
|
||||
temp_count += 1
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
cleared_stats['categories']['temp_uploads'] = {
|
||||
'files': temp_count,
|
||||
'size_mb': round(temp_size / 1024 / 1024, 2)
|
||||
}
|
||||
cleared_stats['files_deleted'] += temp_count
|
||||
cleared_stats['space_freed'] += temp_size
|
||||
|
||||
admin_logger.debug(f"✅ Temporäre Upload-Dateien: {temp_count} Dateien, {temp_size / 1024 / 1024:.2f} MB")
|
||||
|
||||
except Exception as temp_error:
|
||||
admin_logger.warning(f"⚠️ Fehler beim Leeren des Temp-Verzeichnisses: {str(temp_error)}")
|
||||
|
||||
# 3. System-Cache-Verzeichnisse (falls vorhanden)
|
||||
try:
|
||||
cache_count = 0
|
||||
cache_size = 0
|
||||
|
||||
cache_dirs = [
|
||||
os.path.join(app_root, 'static', 'cache'),
|
||||
os.path.join(app_root, 'cache'),
|
||||
os.path.join(app_root, '.cache')
|
||||
]
|
||||
|
||||
for cache_dir in cache_dirs:
|
||||
if os.path.exists(cache_dir):
|
||||
for root, dirs, files in os.walk(cache_dir):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
cache_size += os.path.getsize(file_path)
|
||||
os.remove(file_path)
|
||||
cache_count += 1
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
cleared_stats['categories']['system_cache'] = {
|
||||
'files': cache_count,
|
||||
'size_mb': round(cache_size / 1024 / 1024, 2)
|
||||
}
|
||||
cleared_stats['files_deleted'] += cache_count
|
||||
cleared_stats['space_freed'] += cache_size
|
||||
|
||||
admin_logger.debug(f"✅ System-Cache: {cache_count} Dateien, {cache_size / 1024 / 1024:.2f} MB")
|
||||
|
||||
except Exception as cache_error:
|
||||
admin_logger.warning(f"⚠️ Fehler beim Leeren des System-Cache: {str(cache_error)}")
|
||||
|
||||
# 4. Alte Log-Dateien (älter als 30 Tage)
|
||||
try:
|
||||
logs_count = 0
|
||||
logs_size = 0
|
||||
logs_dir = os.path.join(app_root, 'logs')
|
||||
cutoff_date = datetime.now().timestamp() - (30 * 24 * 60 * 60) # 30 Tage
|
||||
|
||||
if os.path.exists(logs_dir):
|
||||
for root, dirs, files in os.walk(logs_dir):
|
||||
for file in files:
|
||||
if file.endswith(('.log', '.log.1', '.log.2', '.log.3')):
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
if os.path.getmtime(file_path) < cutoff_date:
|
||||
logs_size += os.path.getsize(file_path)
|
||||
os.remove(file_path)
|
||||
logs_count += 1
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
cleared_stats['categories']['old_logs'] = {
|
||||
'files': logs_count,
|
||||
'size_mb': round(logs_size / 1024 / 1024, 2)
|
||||
}
|
||||
cleared_stats['files_deleted'] += logs_count
|
||||
cleared_stats['space_freed'] += logs_size
|
||||
|
||||
admin_logger.debug(f"✅ Alte Log-Dateien: {logs_count} Dateien, {logs_size / 1024 / 1024:.2f} MB")
|
||||
|
||||
except Exception as logs_error:
|
||||
admin_logger.warning(f"⚠️ Fehler beim Leeren alter Log-Dateien: {str(logs_error)}")
|
||||
|
||||
# 5. Application-Level Cache leeren (falls Models-Cache existiert)
|
||||
try:
|
||||
from models import clear_model_cache
|
||||
clear_model_cache()
|
||||
admin_logger.debug("✅ Application-Level Cache geleert")
|
||||
except (ImportError, AttributeError):
|
||||
admin_logger.debug("ℹ️ Kein Application-Level Cache verfügbar")
|
||||
|
||||
# Ergebnisse zusammenfassen
|
||||
total_space_mb = cleared_stats['space_freed'] / 1024 / 1024
|
||||
admin_logger.info(f"✅ Cache-Leerung abgeschlossen: {cleared_stats['files_deleted']} Dateien, {total_space_mb:.2f} MB freigegeben")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': f'Cache erfolgreich geleert - {total_space_mb:.2f} MB freigegeben',
|
||||
'statistics': {
|
||||
'total_files_deleted': cleared_stats['files_deleted'],
|
||||
'total_dirs_deleted': cleared_stats['dirs_deleted'],
|
||||
'total_space_freed_mb': round(total_space_mb, 2),
|
||||
'categories': cleared_stats['categories'],
|
||||
'cleanup_timestamp': datetime.now().isoformat()
|
||||
}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
admin_logger.error(f"❌ Fehler beim Leeren des Cache: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Fehler beim Leeren des Cache: {str(e)}'
|
||||
}), 500
|
Reference in New Issue
Block a user