from flask import Blueprint, request, jsonify from mysql.connector import connect from werkzeug.security import generate_password_hash from auth.token import verify_token from util.db_config import load_config from util.logger import logger admin_bp = Blueprint("admin", __name__) def _require_admin(): user = verify_token() if not user: return None, (jsonify({"message": "Nicht autorisiert"}), 401) if user.get("role") != "admin": logger.warning("🚫 Adminbereich verweigert (kein Admin)") return None, (jsonify({"message": "Adminrechte erforderlich"}), 403) return user, None @admin_bp.route("/api/admin/users", methods=["GET"]) def list_users(): _, err = _require_admin() if err: return err try: cfg = load_config() conn = connect(**cfg) cur = conn.cursor(dictionary=True) cur.execute("SELECT id, username, role FROM users ORDER BY username ASC") users = cur.fetchall() cur.close() conn.close() return jsonify(users) except Exception as e: logger.error(f"[Admin list_users] {e}") return jsonify({"message": "Serverfehler"}), 500 @admin_bp.route("/api/admin/users", methods=["POST"]) def create_user(): admin, err = _require_admin() if err: return err data = request.get_json() or {} username = data.get("username", "").strip() password = data.get("password", "") role = data.get("role", "user") if not username or not password: return jsonify({"message": "Username und Passwort erforderlich"}), 400 try: cfg = load_config() conn = connect(**cfg) cur = conn.cursor(dictionary=True) cur.execute("SELECT id FROM users WHERE username=%s", (username,)) if cur.fetchone(): cur.close() conn.close() return jsonify({"message": "Nutzer existiert bereits"}), 409 cur.execute( "INSERT INTO users (username, password, role) VALUES (%s, %s, %s)", (username, generate_password_hash(password), role) ) conn.commit() new_id = cur.lastrowid cur.close() conn.close() logger.info(f"✅ User erstellt: {username} durch {admin['username']}") return jsonify({"id": new_id, "username": username, "role": role}), 201 except Exception as e: logger.error(f"[Admin create_user] {e}") return jsonify({"message": "Serverfehler"}), 500 @admin_bp.route("/api/admin/users/", methods=["PUT"]) def update_user(user_id): admin, err = _require_admin() if err: return err data = request.get_json() or {} role = data.get("role") password = data.get("password") if role is None and password is None: return jsonify({"message": "Nichts zu aktualisieren"}), 400 try: cfg = load_config() conn = connect(**cfg) cur = conn.cursor() if role: cur.execute("UPDATE users SET role=%s WHERE id=%s", (role, user_id)) if password: cur.execute( "UPDATE users SET password=%s WHERE id=%s", (generate_password_hash(password), user_id) ) conn.commit() cur.close() conn.close() logger.info(f"✏️ User aktualisiert (id={user_id}) durch {admin['username']}") return jsonify({"message": "Aktualisiert"}), 200 except Exception as e: logger.error(f"[Admin update_user] {e}") return jsonify({"message": "Serverfehler"}), 500 @admin_bp.route("/api/admin/users/", methods=["DELETE"]) def delete_user(user_id): admin, err = _require_admin() if err: return err try: cfg = load_config() conn = connect(**cfg) cur = conn.cursor() # Schutz: Admin darf sich nicht selbst löschen cur.execute("SELECT username FROM users WHERE id=%s", (user_id,)) row = cur.fetchone() if not row: cur.close() conn.close() return jsonify({"message": "Nicht gefunden"}), 404 username = row[0] if username == admin["username"]: cur.close() conn.close() return jsonify({"message": "Du kannst dich nicht selbst löschen"}), 400 cur.execute("DELETE FROM users WHERE id=%s", (user_id,)) conn.commit() cur.close() conn.close() logger.info(f"🗑️ User gelöscht (id={user_id}) durch {admin['username']}") return jsonify({"message": "Gelöscht"}), 200 except Exception as e: logger.error(f"[Admin delete_user] {e}") return jsonify({"message": "Serverfehler"}), 500