ich geh behindert
This commit is contained in:
Binary file not shown.
BIN
backend/blueprints/__pycache__/kiosk.cpython-313.pyc
Normal file
BIN
backend/blueprints/__pycache__/kiosk.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/blueprints/__pycache__/sessions.cpython-313.pyc
Normal file
BIN
backend/blueprints/__pycache__/sessions.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/blueprints/__pycache__/uploads.cpython-313.pyc
Normal file
BIN
backend/blueprints/__pycache__/uploads.cpython-313.pyc
Normal file
Binary file not shown.
@@ -68,7 +68,7 @@ def create_backup():
|
||||
with zipfile.ZipFile(backup_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
||||
# 1. Datenbank-Datei hinzufügen
|
||||
try:
|
||||
from config.settings import DATABASE_PATH
|
||||
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')
|
||||
@@ -196,7 +196,7 @@ def optimize_database():
|
||||
try:
|
||||
admin_logger.info(f"Datenbank-Optimierung angefordert von Admin {current_user.username}")
|
||||
|
||||
from config.settings import DATABASE_PATH
|
||||
from utils.settings import DATABASE_PATH
|
||||
|
||||
optimization_results = {
|
||||
'vacuum_completed': False,
|
||||
|
203
backend/blueprints/kiosk.py
Normal file
203
backend/blueprints/kiosk.py
Normal file
@@ -0,0 +1,203 @@
|
||||
"""
|
||||
Kiosk-Blueprint für das 3D-Druck-Management-System
|
||||
|
||||
Dieses Modul enthält alle Routen und Funktionen für den Kiosk-Modus.
|
||||
"""
|
||||
|
||||
from flask import Blueprint, jsonify, request, redirect, url_for
|
||||
from flask_login import login_required, current_user, logout_user
|
||||
from werkzeug.security import generate_password_hash
|
||||
from models import User, SystemLog, get_db_session
|
||||
from utils.logging_config import get_logger
|
||||
from datetime import datetime
|
||||
import os
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
|
||||
# Blueprint erstellen
|
||||
kiosk_blueprint = Blueprint('kiosk', __name__, url_prefix='/api/kiosk')
|
||||
|
||||
# Logger initialisieren
|
||||
kiosk_logger = get_logger("kiosk")
|
||||
|
||||
# Kiosk-Status
|
||||
kiosk_status = {
|
||||
"active": False,
|
||||
"user_id": None,
|
||||
"start_time": None,
|
||||
"countdown_active": False,
|
||||
"countdown_minutes": 0,
|
||||
"countdown_start": None
|
||||
}
|
||||
|
||||
@kiosk_blueprint.route('/status', methods=['GET'])
|
||||
def get_status():
|
||||
"""Gibt den aktuellen Kiosk-Status zurück"""
|
||||
try:
|
||||
# Berechne verbleibende Zeit wenn Countdown aktiv
|
||||
remaining_time = 0
|
||||
if kiosk_status["countdown_active"] and kiosk_status["countdown_start"]:
|
||||
elapsed = (datetime.now() - kiosk_status["countdown_start"]).total_seconds()
|
||||
total_seconds = kiosk_status["countdown_minutes"] * 60
|
||||
remaining_time = max(0, total_seconds - elapsed)
|
||||
|
||||
return jsonify({
|
||||
"active": kiosk_status["active"],
|
||||
"user_id": kiosk_status["user_id"],
|
||||
"start_time": kiosk_status["start_time"].isoformat() if kiosk_status["start_time"] else None,
|
||||
"countdown_active": kiosk_status["countdown_active"],
|
||||
"countdown_minutes": kiosk_status["countdown_minutes"],
|
||||
"remaining_seconds": int(remaining_time)
|
||||
})
|
||||
except Exception as e:
|
||||
kiosk_logger.error(f"Fehler beim Abrufen des Kiosk-Status: {str(e)}")
|
||||
return jsonify({"error": "Fehler beim Abrufen des Status"}), 500
|
||||
|
||||
@kiosk_blueprint.route('/deactivate', methods=['POST'])
|
||||
def deactivate():
|
||||
"""
|
||||
Deaktiviert den Kiosk-Modus
|
||||
|
||||
Diese Route kann sowohl von angemeldeten Benutzern als auch
|
||||
ohne Anmeldung aufgerufen werden (für den Force-Logout).
|
||||
"""
|
||||
try:
|
||||
kiosk_logger.info("Kiosk-Modus wird deaktiviert")
|
||||
|
||||
# SystemLog erstellen
|
||||
with get_db_session() as db_session:
|
||||
user_id = current_user.id if current_user.is_authenticated else None
|
||||
SystemLog.log_system_event(
|
||||
level="INFO",
|
||||
message="Kiosk-Modus deaktiviert",
|
||||
module="kiosk",
|
||||
user_id=user_id
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
# Benutzer abmelden wenn angemeldet
|
||||
if current_user.is_authenticated:
|
||||
logout_user()
|
||||
|
||||
# Kiosk-Status zurücksetzen
|
||||
kiosk_status.update({
|
||||
"active": False,
|
||||
"user_id": None,
|
||||
"start_time": None,
|
||||
"countdown_active": False,
|
||||
"countdown_minutes": 0,
|
||||
"countdown_start": None
|
||||
})
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Kiosk-Modus wurde deaktiviert"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
kiosk_logger.error(f"Fehler beim Deaktivieren des Kiosk-Modus: {str(e)}")
|
||||
return jsonify({
|
||||
"error": "Fehler beim Deaktivieren des Kiosk-Modus"
|
||||
}), 500
|
||||
|
||||
@kiosk_blueprint.route('/activate', methods=['POST'])
|
||||
@login_required
|
||||
def activate():
|
||||
"""Aktiviert den Kiosk-Modus für einen temporären Benutzer"""
|
||||
try:
|
||||
if not current_user.is_admin:
|
||||
return jsonify({"error": "Nur Administratoren können den Kiosk-Modus aktivieren"}), 403
|
||||
|
||||
data = request.get_json() or {}
|
||||
countdown_minutes = data.get('countdown_minutes', 30)
|
||||
|
||||
# Kiosk-Benutzer erstellen oder aktualisieren
|
||||
with get_db_session() as db_session:
|
||||
kiosk_user = db_session.query(User).filter_by(username="kiosk").first()
|
||||
|
||||
if not kiosk_user:
|
||||
# Neuen Kiosk-Benutzer erstellen
|
||||
kiosk_user = User(
|
||||
username="kiosk",
|
||||
email="kiosk@local",
|
||||
name="Kiosk-Benutzer",
|
||||
role="user"
|
||||
)
|
||||
kiosk_user.set_password(generate_password_hash("kiosk_temp_password"))
|
||||
db_session.add(kiosk_user)
|
||||
|
||||
db_session.commit()
|
||||
|
||||
# Kiosk-Status aktivieren
|
||||
kiosk_status.update({
|
||||
"active": True,
|
||||
"user_id": kiosk_user.id,
|
||||
"start_time": datetime.now(),
|
||||
"countdown_active": True,
|
||||
"countdown_minutes": countdown_minutes,
|
||||
"countdown_start": datetime.now()
|
||||
})
|
||||
|
||||
# SystemLog erstellen
|
||||
SystemLog.log_system_event(
|
||||
level="INFO",
|
||||
message=f"Kiosk-Modus aktiviert für {countdown_minutes} Minuten",
|
||||
module="kiosk",
|
||||
user_id=current_user.id
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
kiosk_logger.info(f"Kiosk-Modus aktiviert für {countdown_minutes} Minuten")
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": f"Kiosk-Modus wurde für {countdown_minutes} Minuten aktiviert",
|
||||
"kiosk_user_id": kiosk_user.id
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
kiosk_logger.error(f"Fehler beim Aktivieren des Kiosk-Modus: {str(e)}")
|
||||
return jsonify({"error": "Fehler beim Aktivieren des Kiosk-Modus"}), 500
|
||||
|
||||
@kiosk_blueprint.route('/restart', methods=['POST'])
|
||||
def restart_system():
|
||||
"""
|
||||
Startet das System neu (nur für Kiosk-Modus).
|
||||
Diese Route ist öffentlich zugänglich für den Kiosk-Neustart.
|
||||
"""
|
||||
try:
|
||||
kiosk_logger.warning("System-Neustart wird vom Kiosk-Modus ausgelöst")
|
||||
|
||||
# SystemLog erstellen
|
||||
with get_db_session() as db_session:
|
||||
SystemLog.log_system_event(
|
||||
level="WARNING",
|
||||
message="System-Neustart vom Kiosk-Modus ausgelöst",
|
||||
module="kiosk"
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
# Neustart in separatem Thread nach kurzer Verzögerung
|
||||
def delayed_restart():
|
||||
time.sleep(2)
|
||||
try:
|
||||
if os.name == 'nt': # Windows
|
||||
subprocess.run(["shutdown", "/r", "/t", "0"], check=True)
|
||||
else: # Linux/Unix
|
||||
subprocess.run(["sudo", "reboot"], check=True)
|
||||
except Exception as e:
|
||||
kiosk_logger.error(f"Fehler beim System-Neustart: {str(e)}")
|
||||
|
||||
restart_thread = threading.Thread(target=delayed_restart)
|
||||
restart_thread.daemon = True
|
||||
restart_thread.start()
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "System wird in Kürze neu gestartet"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
kiosk_logger.error(f"Fehler beim System-Neustart: {str(e)}")
|
||||
return jsonify({"error": "Fehler beim System-Neustart"}), 500
|
136
backend/blueprints/sessions.py
Normal file
136
backend/blueprints/sessions.py
Normal file
@@ -0,0 +1,136 @@
|
||||
"""
|
||||
Session-Blueprint für das 3D-Druck-Management-System
|
||||
|
||||
Dieses Modul enthält alle Routen und Funktionen für Session-Management.
|
||||
"""
|
||||
|
||||
from flask import Blueprint, jsonify, request, session
|
||||
from flask_login import login_required, current_user
|
||||
from datetime import datetime, timedelta
|
||||
from models import User, get_db_session, SystemLog
|
||||
from utils.logging_config import get_logger
|
||||
from utils.settings import SESSION_LIFETIME
|
||||
|
||||
# Blueprint erstellen
|
||||
sessions_blueprint = Blueprint('sessions', __name__, url_prefix='/api/session')
|
||||
|
||||
# Logger initialisieren
|
||||
sessions_logger = get_logger("sessions")
|
||||
|
||||
@sessions_blueprint.route('/heartbeat', methods=['POST'])
|
||||
@login_required
|
||||
def heartbeat():
|
||||
"""
|
||||
Session-Heartbeat zum Aktualisieren der letzten Aktivität.
|
||||
Verhindert automatischen Logout bei aktiven Benutzern.
|
||||
"""
|
||||
try:
|
||||
# Session-Aktivität aktualisieren
|
||||
session['last_activity'] = datetime.now().isoformat()
|
||||
session.permanent = True
|
||||
|
||||
# Benutzer-Aktivität in Datenbank aktualisieren
|
||||
with get_db_session() as db_session:
|
||||
user = db_session.query(User).filter_by(id=current_user.id).first()
|
||||
if user:
|
||||
user.last_activity = datetime.now()
|
||||
db_session.commit()
|
||||
|
||||
# Verbleibende Session-Zeit berechnen
|
||||
session_start = session.get('session_start')
|
||||
if session_start:
|
||||
elapsed = (datetime.now() - datetime.fromisoformat(session_start)).total_seconds()
|
||||
remaining = max(0, SESSION_LIFETIME.total_seconds() - elapsed)
|
||||
else:
|
||||
remaining = SESSION_LIFETIME.total_seconds()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'remaining_seconds': int(remaining),
|
||||
'session_lifetime': int(SESSION_LIFETIME.total_seconds())
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
sessions_logger.error(f"Fehler beim Session-Heartbeat: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Aktualisieren der Session'}), 500
|
||||
|
||||
@sessions_blueprint.route('/status', methods=['GET'])
|
||||
@login_required
|
||||
def status():
|
||||
"""Gibt den aktuellen Session-Status zurück"""
|
||||
try:
|
||||
# Session-Informationen sammeln
|
||||
session_start = session.get('session_start')
|
||||
last_activity = session.get('last_activity')
|
||||
|
||||
# Verbleibende Zeit berechnen
|
||||
if session_start:
|
||||
elapsed = (datetime.now() - datetime.fromisoformat(session_start)).total_seconds()
|
||||
remaining = max(0, SESSION_LIFETIME.total_seconds() - elapsed)
|
||||
else:
|
||||
remaining = SESSION_LIFETIME.total_seconds()
|
||||
|
||||
# Inaktivitätszeit berechnen
|
||||
if last_activity:
|
||||
inactive_seconds = (datetime.now() - datetime.fromisoformat(last_activity)).total_seconds()
|
||||
else:
|
||||
inactive_seconds = 0
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'user': {
|
||||
'id': current_user.id,
|
||||
'username': current_user.username,
|
||||
'email': current_user.email,
|
||||
'name': current_user.name,
|
||||
'is_admin': current_user.is_admin
|
||||
},
|
||||
'session': {
|
||||
'start_time': session_start,
|
||||
'last_activity': last_activity,
|
||||
'remaining_seconds': int(remaining),
|
||||
'inactive_seconds': int(inactive_seconds),
|
||||
'lifetime_seconds': int(SESSION_LIFETIME.total_seconds()),
|
||||
'is_permanent': session.permanent
|
||||
}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
sessions_logger.error(f"Fehler beim Abrufen des Session-Status: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Abrufen des Session-Status'}), 500
|
||||
|
||||
@sessions_blueprint.route('/extend', methods=['POST'])
|
||||
@login_required
|
||||
def extend():
|
||||
"""Verlängert die aktuelle Session"""
|
||||
try:
|
||||
# Nur Admins können Sessions verlängern
|
||||
if not current_user.is_admin:
|
||||
return jsonify({'error': 'Keine Berechtigung zum Verlängern der Session'}), 403
|
||||
|
||||
# Session-Start zurücksetzen
|
||||
session['session_start'] = datetime.now().isoformat()
|
||||
session['last_activity'] = datetime.now().isoformat()
|
||||
session.permanent = True
|
||||
|
||||
# SystemLog erstellen
|
||||
with get_db_session() as db_session:
|
||||
SystemLog.log_system_event(
|
||||
level="INFO",
|
||||
message=f"Session verlängert für Benutzer {current_user.username}",
|
||||
module="sessions",
|
||||
user_id=current_user.id
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
sessions_logger.info(f"Session verlängert für Benutzer {current_user.id}")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'Session wurde verlängert',
|
||||
'new_lifetime_seconds': int(SESSION_LIFETIME.total_seconds())
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
sessions_logger.error(f"Fehler beim Verlängern der Session: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Verlängern der Session'}), 500
|
462
backend/blueprints/uploads.py
Normal file
462
backend/blueprints/uploads.py
Normal file
@@ -0,0 +1,462 @@
|
||||
"""
|
||||
Upload-Blueprint für das 3D-Druck-Management-System
|
||||
|
||||
Dieses Modul enthält alle Routen und Funktionen für Datei-Uploads.
|
||||
"""
|
||||
|
||||
from flask import Blueprint, jsonify, request, send_file, abort
|
||||
from flask_login import login_required, current_user
|
||||
from werkzeug.utils import secure_filename
|
||||
from functools import wraps
|
||||
import os
|
||||
from typing import Dict, Any
|
||||
from datetime import datetime
|
||||
|
||||
from models import get_db_session, SystemLog
|
||||
from utils.logging_config import get_logger
|
||||
from utils.file_manager import file_manager, save_job_file, save_guest_file, save_avatar_file, save_asset_file, save_log_file, save_backup_file, save_temp_file, delete_file as delete_file_safe
|
||||
from utils.settings import UPLOAD_FOLDER, ALLOWED_EXTENSIONS
|
||||
|
||||
# Blueprint erstellen
|
||||
uploads_blueprint = Blueprint('uploads', __name__, url_prefix='/api')
|
||||
|
||||
# Logger initialisieren
|
||||
uploads_logger = get_logger("uploads")
|
||||
|
||||
def admin_required(f):
|
||||
"""Decorator für Admin-geschützte Routen"""
|
||||
@wraps(f)
|
||||
@login_required
|
||||
def decorated_function(*args, **kwargs):
|
||||
if not current_user.is_admin:
|
||||
abort(403)
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
def allowed_file(filename: str) -> bool:
|
||||
"""Prüft ob die Dateiendung erlaubt ist"""
|
||||
return '.' in filename and \
|
||||
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
||||
|
||||
@uploads_blueprint.route('/upload/job', methods=['POST'])
|
||||
@login_required
|
||||
def upload_job_file():
|
||||
"""Lädt eine Job-Datei hoch"""
|
||||
try:
|
||||
if 'file' not in request.files:
|
||||
return jsonify({'error': 'Keine Datei hochgeladen'}), 400
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||
|
||||
if not allowed_file(file.filename):
|
||||
return jsonify({'error': 'Dateityp nicht erlaubt'}), 400
|
||||
|
||||
# Datei speichern
|
||||
result = save_job_file(file, user_id=current_user.id)
|
||||
|
||||
if result['success']:
|
||||
# SystemLog erstellen
|
||||
with get_db_session() as db_session:
|
||||
SystemLog.log_system_event(
|
||||
level="INFO",
|
||||
message=f"Job-Datei hochgeladen: {result['filename']}",
|
||||
module="uploads",
|
||||
user_id=current_user.id
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
uploads_logger.info(f"Job-Datei erfolgreich hochgeladen: {result['filename']} von User {current_user.id}")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'filename': result['filename'],
|
||||
'path': result['path'],
|
||||
'url': result['url'],
|
||||
'size': result['size']
|
||||
})
|
||||
else:
|
||||
return jsonify({'error': result.get('error', 'Upload fehlgeschlagen')}), 500
|
||||
|
||||
except Exception as e:
|
||||
uploads_logger.error(f"Fehler beim Job-Upload: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Hochladen der Datei'}), 500
|
||||
|
||||
@uploads_blueprint.route('/upload/guest', methods=['POST'])
|
||||
def upload_guest_file():
|
||||
"""Lädt eine Gast-Datei hoch (ohne Login)"""
|
||||
try:
|
||||
if 'file' not in request.files:
|
||||
return jsonify({'error': 'Keine Datei hochgeladen'}), 400
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||
|
||||
if not allowed_file(file.filename):
|
||||
return jsonify({'error': 'Dateityp nicht erlaubt'}), 400
|
||||
|
||||
# Gast-ID aus Request holen
|
||||
guest_id = request.form.get('guest_id', 'anonymous')
|
||||
|
||||
# Datei speichern
|
||||
result = save_guest_file(file, guest_id=guest_id)
|
||||
|
||||
if result['success']:
|
||||
uploads_logger.info(f"Gast-Datei erfolgreich hochgeladen: {result['filename']} für Gast {guest_id}")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'filename': result['filename'],
|
||||
'path': result['path'],
|
||||
'url': result['url'],
|
||||
'size': result['size']
|
||||
})
|
||||
else:
|
||||
return jsonify({'error': result.get('error', 'Upload fehlgeschlagen')}), 500
|
||||
|
||||
except Exception as e:
|
||||
uploads_logger.error(f"Fehler beim Gast-Upload: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Hochladen der Datei'}), 500
|
||||
|
||||
@uploads_blueprint.route('/upload/avatar', methods=['POST'])
|
||||
@login_required
|
||||
def upload_avatar():
|
||||
"""Lädt ein Avatar-Bild hoch"""
|
||||
try:
|
||||
if 'file' not in request.files:
|
||||
return jsonify({'error': 'Keine Datei hochgeladen'}), 400
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||
|
||||
# Prüfe Dateityp (nur Bilder)
|
||||
allowed_image_extensions = {'png', 'jpg', 'jpeg', 'gif', 'webp'}
|
||||
if not ('.' in file.filename and file.filename.rsplit('.', 1)[1].lower() in allowed_image_extensions):
|
||||
return jsonify({'error': 'Nur Bilddateien erlaubt'}), 400
|
||||
|
||||
# Datei speichern
|
||||
result = save_avatar_file(file, user_id=current_user.id)
|
||||
|
||||
if result['success']:
|
||||
# Altes Avatar löschen (optional)
|
||||
# TODO: Implementiere Avatar-Verwaltung in User-Model
|
||||
|
||||
uploads_logger.info(f"Avatar erfolgreich hochgeladen: {result['filename']} für User {current_user.id}")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'filename': result['filename'],
|
||||
'path': result['path'],
|
||||
'url': result['url'],
|
||||
'size': result['size']
|
||||
})
|
||||
else:
|
||||
return jsonify({'error': result.get('error', 'Upload fehlgeschlagen')}), 500
|
||||
|
||||
except Exception as e:
|
||||
uploads_logger.error(f"Fehler beim Avatar-Upload: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Hochladen des Avatars'}), 500
|
||||
|
||||
@uploads_blueprint.route('/upload/asset', methods=['POST'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def upload_asset():
|
||||
"""Lädt ein Asset hoch (nur für Admins)"""
|
||||
try:
|
||||
if 'file' not in request.files:
|
||||
return jsonify({'error': 'Keine Datei hochgeladen'}), 400
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||
|
||||
# Asset-Typ aus Request
|
||||
asset_type = request.form.get('type', 'general')
|
||||
|
||||
# Datei speichern
|
||||
result = save_asset_file(file, asset_type=asset_type, user_id=current_user.id)
|
||||
|
||||
if result['success']:
|
||||
# SystemLog erstellen
|
||||
with get_db_session() as db_session:
|
||||
SystemLog.log_system_event(
|
||||
level="INFO",
|
||||
message=f"Asset hochgeladen: {result['filename']} (Typ: {asset_type})",
|
||||
module="uploads",
|
||||
user_id=current_user.id
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
uploads_logger.info(f"Asset erfolgreich hochgeladen: {result['filename']} (Typ: {asset_type})")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'filename': result['filename'],
|
||||
'path': result['path'],
|
||||
'url': result['url'],
|
||||
'size': result['size'],
|
||||
'type': asset_type
|
||||
})
|
||||
else:
|
||||
return jsonify({'error': result.get('error', 'Upload fehlgeschlagen')}), 500
|
||||
|
||||
except Exception as e:
|
||||
uploads_logger.error(f"Fehler beim Asset-Upload: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Hochladen des Assets'}), 500
|
||||
|
||||
@uploads_blueprint.route('/upload/log', methods=['POST'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def upload_log():
|
||||
"""Lädt eine Log-Datei hoch (nur für Admins)"""
|
||||
try:
|
||||
if 'file' not in request.files:
|
||||
return jsonify({'error': 'Keine Datei hochgeladen'}), 400
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||
|
||||
# Log-Typ aus Request
|
||||
log_type = request.form.get('type', 'general')
|
||||
|
||||
# Datei speichern
|
||||
result = save_log_file(file, log_type=log_type, user_id=current_user.id)
|
||||
|
||||
if result['success']:
|
||||
uploads_logger.info(f"Log-Datei erfolgreich hochgeladen: {result['filename']} (Typ: {log_type})")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'filename': result['filename'],
|
||||
'path': result['path'],
|
||||
'url': result['url'],
|
||||
'size': result['size'],
|
||||
'type': log_type
|
||||
})
|
||||
else:
|
||||
return jsonify({'error': result.get('error', 'Upload fehlgeschlagen')}), 500
|
||||
|
||||
except Exception as e:
|
||||
uploads_logger.error(f"Fehler beim Log-Upload: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Hochladen der Log-Datei'}), 500
|
||||
|
||||
@uploads_blueprint.route('/upload/backup', methods=['POST'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def upload_backup():
|
||||
"""Lädt eine Backup-Datei hoch (nur für Admins)"""
|
||||
try:
|
||||
if 'file' not in request.files:
|
||||
return jsonify({'error': 'Keine Datei hochgeladen'}), 400
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||
|
||||
# Backup-Typ aus Request
|
||||
backup_type = request.form.get('type', 'database')
|
||||
|
||||
# Datei speichern
|
||||
result = save_backup_file(file, backup_type=backup_type, user_id=current_user.id)
|
||||
|
||||
if result['success']:
|
||||
# SystemLog erstellen
|
||||
with get_db_session() as db_session:
|
||||
SystemLog.log_system_event(
|
||||
level="INFO",
|
||||
message=f"Backup hochgeladen: {result['filename']} (Typ: {backup_type})",
|
||||
module="uploads",
|
||||
user_id=current_user.id
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
uploads_logger.info(f"Backup erfolgreich hochgeladen: {result['filename']} (Typ: {backup_type})")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'filename': result['filename'],
|
||||
'path': result['path'],
|
||||
'url': result['url'],
|
||||
'size': result['size'],
|
||||
'type': backup_type
|
||||
})
|
||||
else:
|
||||
return jsonify({'error': result.get('error', 'Upload fehlgeschlagen')}), 500
|
||||
|
||||
except Exception as e:
|
||||
uploads_logger.error(f"Fehler beim Backup-Upload: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Hochladen des Backups'}), 500
|
||||
|
||||
@uploads_blueprint.route('/upload/temp', methods=['POST'])
|
||||
@login_required
|
||||
def upload_temp_file():
|
||||
"""Lädt eine temporäre Datei hoch"""
|
||||
try:
|
||||
if 'file' not in request.files:
|
||||
return jsonify({'error': 'Keine Datei hochgeladen'}), 400
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||
|
||||
# Datei speichern
|
||||
result = save_temp_file(file, user_id=current_user.id)
|
||||
|
||||
if result['success']:
|
||||
uploads_logger.info(f"Temporäre Datei erfolgreich hochgeladen: {result['filename']}")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'filename': result['filename'],
|
||||
'path': result['path'],
|
||||
'url': result['url'],
|
||||
'size': result['size'],
|
||||
'ttl': 3600 # 1 Stunde TTL für temporäre Dateien
|
||||
})
|
||||
else:
|
||||
return jsonify({'error': result.get('error', 'Upload fehlgeschlagen')}), 500
|
||||
|
||||
except Exception as e:
|
||||
uploads_logger.error(f"Fehler beim Temp-Upload: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Hochladen der temporären Datei'}), 500
|
||||
|
||||
@uploads_blueprint.route('/files/<path:file_path>', methods=['GET'])
|
||||
@login_required
|
||||
def serve_uploaded_file(file_path):
|
||||
"""Gibt eine hochgeladene Datei zurück"""
|
||||
try:
|
||||
# Sicherheitsprüfung: Pfad-Traversal verhindern
|
||||
safe_path = os.path.normpath(file_path)
|
||||
if '..' in safe_path or safe_path.startswith('/'):
|
||||
abort(403)
|
||||
|
||||
# Vollständiger Pfad
|
||||
full_path = os.path.join(UPLOAD_FOLDER, safe_path)
|
||||
|
||||
# Prüfe ob Datei existiert
|
||||
if not os.path.exists(full_path) or not os.path.isfile(full_path):
|
||||
abort(404)
|
||||
|
||||
# Prüfe Zugriffsrechte (je nach Dateityp)
|
||||
# TODO: Implementiere detaillierte Zugriffskontrolle
|
||||
|
||||
# Datei zurückgeben
|
||||
return send_file(full_path, as_attachment=True)
|
||||
|
||||
except Exception as e:
|
||||
uploads_logger.error(f"Fehler beim Abrufen der Datei {file_path}: {str(e)}")
|
||||
abort(500)
|
||||
|
||||
@uploads_blueprint.route('/files/<path:file_path>', methods=['DELETE'])
|
||||
@login_required
|
||||
def delete_uploaded_file(file_path):
|
||||
"""Löscht eine hochgeladene Datei"""
|
||||
try:
|
||||
# Sicherheitsprüfung: Pfad-Traversal verhindern
|
||||
safe_path = os.path.normpath(file_path)
|
||||
if '..' in safe_path or safe_path.startswith('/'):
|
||||
return jsonify({'error': 'Ungültiger Dateipfad'}), 403
|
||||
|
||||
# Vollständiger Pfad
|
||||
full_path = os.path.join(UPLOAD_FOLDER, safe_path)
|
||||
|
||||
# Prüfe ob Datei existiert
|
||||
if not os.path.exists(full_path) or not os.path.isfile(full_path):
|
||||
return jsonify({'error': 'Datei nicht gefunden'}), 404
|
||||
|
||||
# Prüfe Zugriffsrechte
|
||||
# TODO: Implementiere detaillierte Zugriffskontrolle
|
||||
# Aktuell: Nur eigene Dateien oder Admin
|
||||
|
||||
# Datei löschen
|
||||
if delete_file_safe(full_path):
|
||||
# SystemLog erstellen
|
||||
with get_db_session() as db_session:
|
||||
SystemLog.log_system_event(
|
||||
level="INFO",
|
||||
message=f"Datei gelöscht: {safe_path}",
|
||||
module="uploads",
|
||||
user_id=current_user.id
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
uploads_logger.info(f"Datei erfolgreich gelöscht: {safe_path} von User {current_user.id}")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'Datei erfolgreich gelöscht'
|
||||
})
|
||||
else:
|
||||
return jsonify({'error': 'Fehler beim Löschen der Datei'}), 500
|
||||
|
||||
except Exception as e:
|
||||
uploads_logger.error(f"Fehler beim Löschen der Datei {file_path}: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Löschen der Datei'}), 500
|
||||
|
||||
@uploads_blueprint.route('/admin/files/stats', methods=['GET'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def get_file_stats():
|
||||
"""Gibt Statistiken über hochgeladene Dateien zurück"""
|
||||
try:
|
||||
stats = file_manager.get_storage_stats()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'stats': {
|
||||
'total_files': stats.get('total_files', 0),
|
||||
'total_size': stats.get('total_size', 0),
|
||||
'by_type': stats.get('by_type', {}),
|
||||
'by_user': stats.get('by_user', {}),
|
||||
'storage_path': UPLOAD_FOLDER
|
||||
}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
uploads_logger.error(f"Fehler beim Abrufen der Datei-Statistiken: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Abrufen der Statistiken'}), 500
|
||||
|
||||
@uploads_blueprint.route('/admin/files/cleanup', methods=['POST'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def cleanup_temp_files():
|
||||
"""Bereinigt temporäre Dateien"""
|
||||
try:
|
||||
# Cleanup-Optionen aus Request
|
||||
data = request.get_json() or {}
|
||||
older_than_hours = data.get('older_than_hours', 24)
|
||||
dry_run = data.get('dry_run', False)
|
||||
|
||||
# Cleanup durchführen
|
||||
result = file_manager.cleanup_temp_files(
|
||||
older_than_hours=older_than_hours,
|
||||
dry_run=dry_run
|
||||
)
|
||||
|
||||
if not dry_run:
|
||||
# SystemLog erstellen
|
||||
with get_db_session() as db_session:
|
||||
SystemLog.log_system_event(
|
||||
level="INFO",
|
||||
message=f"Temporäre Dateien bereinigt: {result['deleted_count']} Dateien, {result['freed_space']} Bytes",
|
||||
module="uploads",
|
||||
user_id=current_user.id
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
uploads_logger.info(f"Cleanup durchgeführt: {result['deleted_count']} Dateien gelöscht")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'deleted_count': result['deleted_count'],
|
||||
'freed_space': result['freed_space'],
|
||||
'dry_run': dry_run
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
uploads_logger.error(f"Fehler beim Cleanup: {str(e)}")
|
||||
return jsonify({'error': 'Fehler beim Bereinigen der temporären Dateien'}), 500
|
Reference in New Issue
Block a user