""" Benutzer-Blueprint für das 3D-Druck-Management-System Dieses Modul enthält alle Benutzer-spezifischen Routen und Funktionen, einschließlich Profilverwaltung, Einstellungen und Passwort-Änderung. """ import json from datetime import datetime from flask import Blueprint, render_template, request, jsonify, redirect, url_for, flash, make_response from flask_login import login_required, current_user from werkzeug.security import check_password_hash from models import User, get_db_session from utils.logging_config import get_logger # Blueprint erstellen user_blueprint = Blueprint('user', __name__, url_prefix='/user') # Logger initialisieren user_logger = get_logger("user") @user_blueprint.route("/profile", methods=["GET"]) @login_required def profile(): """Benutzerprofil anzeigen""" return render_template('user/profile.html', user=current_user) @user_blueprint.route("/settings", methods=["GET"]) @login_required def settings(): """Benutzereinstellungen anzeigen""" return render_template('user/settings.html', user=current_user) @user_blueprint.route("/update-profile", methods=["POST"]) @login_required def update_profile(): """Benutzerprofil aktualisieren (Form-basiert)""" try: db_session = get_db_session() user = db_session.query(User).filter(User.id == current_user.id).first() if not user: db_session.close() flash("Benutzer nicht gefunden", "error") return redirect(url_for('user.profile')) # Aktualisierbare Felder aus dem Formular user.name = request.form.get('name', user.name) user.email = request.form.get('email', user.email) user.department = request.form.get('department', user.department) user.position = request.form.get('position', user.position) user.phone = request.form.get('phone', user.phone) user.bio = request.form.get('bio', user.bio) user.updated_at = datetime.now() db_session.commit() user_logger.info(f"Profil aktualisiert für Benutzer {user.username}") flash("Profil erfolgreich aktualisiert", "success") db_session.close() return redirect(url_for('user.profile')) except Exception as e: user_logger.error(f"Fehler beim Aktualisieren des Profils: {str(e)}") flash("Fehler beim Aktualisieren des Profils", "error") return redirect(url_for('user.profile')) @user_blueprint.route("/api/update-settings", methods=["POST"]) @login_required def api_update_settings(): """API-Endpunkt für Einstellungen-Updates""" try: data = request.get_json() db_session = get_db_session() user = db_session.query(User).filter(User.id == current_user.id).first() if not user: db_session.close() return jsonify({"error": "Benutzer nicht gefunden"}), 404 # Einstellungen JSON aktualisieren current_settings = user.settings or {} if isinstance(current_settings, str): try: current_settings = json.loads(current_settings) except json.JSONDecodeError: current_settings = {} # Neue Einstellungen hinzufügen/aktualisieren for key, value in data.items(): current_settings[key] = value user.settings = json.dumps(current_settings) user.updated_at = datetime.now() db_session.commit() user_logger.info(f"Einstellungen aktualisiert für Benutzer {user.username}") db_session.close() return jsonify({ "success": True, "message": "Einstellungen erfolgreich aktualisiert" }) except Exception as e: user_logger.error(f"Fehler beim Aktualisieren der Einstellungen: {str(e)}") return jsonify({"error": "Fehler beim Aktualisieren der Einstellungen"}), 500 @user_blueprint.route("/update-settings", methods=["POST"]) @login_required def update_settings(): """Benutzereinstellungen aktualisieren (Form-basiert)""" try: db_session = get_db_session() user = db_session.query(User).filter(User.id == current_user.id).first() if not user: db_session.close() flash("Benutzer nicht gefunden", "error") return redirect(url_for('user.settings')) # Einstellungen aus dem Formular sammeln settings = {} # Theme-Einstellungen settings['theme'] = request.form.get('theme', 'light') settings['language'] = request.form.get('language', 'de') # Benachrichtigungseinstellungen settings['email_notifications'] = request.form.get('email_notifications') == 'on' settings['push_notifications'] = request.form.get('push_notifications') == 'on' settings['job_completion_notifications'] = request.form.get('job_completion_notifications') == 'on' settings['printer_error_notifications'] = request.form.get('printer_error_notifications') == 'on' # Dashboard-Einstellungen settings['default_dashboard_view'] = request.form.get('default_dashboard_view', 'overview') settings['auto_refresh_interval'] = int(request.form.get('auto_refresh_interval', 30)) # Privacy-Einstellungen settings['show_profile_publicly'] = request.form.get('show_profile_publicly') == 'on' settings['allow_job_sharing'] = request.form.get('allow_job_sharing') == 'on' user.settings = json.dumps(settings) user.updated_at = datetime.now() db_session.commit() user_logger.info(f"Einstellungen aktualisiert für Benutzer {user.username}") flash("Einstellungen erfolgreich aktualisiert", "success") db_session.close() return redirect(url_for('user.settings')) except Exception as e: user_logger.error(f"Fehler beim Aktualisieren der Einstellungen: {str(e)}") flash("Fehler beim Aktualisieren der Einstellungen", "error") return redirect(url_for('user.settings')) @user_blueprint.route("/change-password", methods=["POST"]) @login_required def change_password(): """Passwort ändern""" try: # Daten aus Form oder JSON extrahieren if request.is_json: data = request.get_json() current_password = data.get('current_password') new_password = data.get('new_password') confirm_password = data.get('confirm_password') else: current_password = request.form.get('current_password') new_password = request.form.get('new_password') confirm_password = request.form.get('confirm_password') # Validierung if not all([current_password, new_password, confirm_password]): error_msg = "Alle Passwort-Felder sind erforderlich" if request.is_json: return jsonify({"error": error_msg}), 400 flash(error_msg, "error") return redirect(url_for('user.settings')) if new_password != confirm_password: error_msg = "Neue Passwörter stimmen nicht überein" if request.is_json: return jsonify({"error": error_msg}), 400 flash(error_msg, "error") return redirect(url_for('user.settings')) if len(new_password) < 8: error_msg = "Das neue Passwort muss mindestens 8 Zeichen lang sein" if request.is_json: return jsonify({"error": error_msg}), 400 flash(error_msg, "error") return redirect(url_for('user.settings')) db_session = get_db_session() user = db_session.query(User).filter(User.id == current_user.id).first() if not user: db_session.close() error_msg = "Benutzer nicht gefunden" if request.is_json: return jsonify({"error": error_msg}), 404 flash(error_msg, "error") return redirect(url_for('user.settings')) # Aktuelles Passwort überprüfen if not user.check_password(current_password): db_session.close() error_msg = "Aktuelles Passwort ist falsch" if request.is_json: return jsonify({"error": error_msg}), 401 flash(error_msg, "error") return redirect(url_for('user.settings')) # Neues Passwort setzen user.set_password(new_password) user.updated_at = datetime.now() db_session.commit() user_logger.info(f"Passwort geändert für Benutzer {user.username}") db_session.close() success_msg = "Passwort erfolgreich geändert" if request.is_json: return jsonify({"success": True, "message": success_msg}) flash(success_msg, "success") return redirect(url_for('user.settings')) except Exception as e: user_logger.error(f"Fehler beim Ändern des Passworts: {str(e)}") error_msg = "Fehler beim Ändern des Passworts" if request.is_json: return jsonify({"error": error_msg}), 500 flash(error_msg, "error") return redirect(url_for('user.settings')) @user_blueprint.route("/export", methods=["GET"]) @login_required def export_data(): """Benutzerdaten exportieren (DSGVO-Compliance)""" try: db_session = get_db_session() user = db_session.query(User).filter(User.id == current_user.id).first() if not user: db_session.close() flash("Benutzer nicht gefunden", "error") return redirect(url_for('user.settings')) # Benutzerdaten sammeln user_data = { "personal_information": { "id": user.id, "username": user.username, "email": user.email, "name": user.name, "department": user.department, "position": user.position, "phone": user.phone, "bio": user.bio, "role": user.role, "created_at": user.created_at.isoformat() if user.created_at else None, "last_login": user.last_login.isoformat() if user.last_login else None, "updated_at": user.updated_at.isoformat() if user.updated_at else None, "last_activity": user.last_activity.isoformat() if user.last_activity else None }, "settings": json.loads(user.settings) if user.settings else {}, "jobs": [], "export_date": datetime.now().isoformat(), "export_note": "Dies ist ein Export Ihrer persönlichen Daten gemäß DSGVO Art. 20" } # Benutzer-Jobs sammeln (falls verfügbar) try: from models import Job user_jobs = db_session.query(Job).filter(Job.user_id == user.id).all() for job in user_jobs: user_data["jobs"].append({ "id": job.id, "filename": job.filename, "status": job.status, "created_at": job.created_at.isoformat() if job.created_at else None, "estimated_duration": job.estimated_duration, "material_used": job.material_used, "notes": job.notes }) except Exception as job_error: user_logger.warning(f"Fehler beim Sammeln der Job-Daten: {str(job_error)}") db_session.close() # JSON-Response erstellen response = make_response(jsonify(user_data)) response.headers['Content-Disposition'] = f'attachment; filename=user_data_{user.username}_{datetime.now().strftime("%Y%m%d_%H%M%S")}.json' response.headers['Content-Type'] = 'application/json' user_logger.info(f"Datenexport erstellt für Benutzer {user.username}") return response except Exception as e: user_logger.error(f"Fehler beim Datenexport: {str(e)}") flash("Fehler beim Erstellen des Datenexports", "error") return redirect(url_for('user.settings')) @user_blueprint.route("/profile", methods=["PUT"]) @login_required def update_profile_api(): """API-Endpunkt für Profil-Updates""" try: data = request.get_json() db_session = get_db_session() user = db_session.query(User).filter(User.id == current_user.id).first() if not user: db_session.close() return jsonify({"error": "Benutzer nicht gefunden"}), 404 # Aktualisierbare Felder (ohne sensitive Daten) updatable_fields = ['name', 'email', 'department', 'position', 'phone', 'bio'] for field in updatable_fields: if field in data: setattr(user, field, data[field]) user.updated_at = datetime.now() db_session.commit() user_logger.info(f"Profil über API aktualisiert für Benutzer {user.username}") # Aktuelle Benutzerdaten zurückgeben user_data = { "id": user.id, "username": user.username, "email": user.email, "name": user.name, "department": user.department, "position": user.position, "phone": user.phone, "bio": user.bio, "role": user.role, "updated_at": user.updated_at.isoformat() } db_session.close() return jsonify({ "success": True, "message": "Profil erfolgreich aktualisiert", "user": user_data }) except Exception as e: user_logger.error(f"Fehler beim API-Profil-Update: {str(e)}") return jsonify({"error": "Fehler beim Aktualisieren des Profils"}), 500