"""Admin blueprint - user management.""" from flask import Blueprint, flash, jsonify, redirect, render_template, request, session, url_for from flask_babel import gettext as _ from blueprints.auth import login_required from services.api_client import api_client admin_bp = Blueprint("admin", __name__, url_prefix="/admin") def admin_required(f): """Decorator to require admin privileges.""" from functools import wraps @wraps(f) def decorated(*args, **kwargs): user = session.get("user", {}) if not user.get("is_admin"): flash(_("Accesso non autorizzato"), "error") return redirect(url_for("measure.select_recipe")) return f(*args, **kwargs) return decorated # ============================================================================ # PAGINE (GET) # ============================================================================ @admin_bp.route("/users") @login_required @admin_required def user_list(): """User management page.""" resp = api_client.get("/api/users") if isinstance(resp, dict) and resp.get("error"): flash(_("Errore nel caricamento degli utenti: %(error)s", error=resp.get("detail", "")), "error") users = [] elif isinstance(resp, list): users = resp else: users = [] return render_template("admin/users.html", users=users) @admin_bp.route("/stations") @login_required @admin_required def station_list(): """Station management page.""" resp = api_client.get("/api/stations") if isinstance(resp, dict) and resp.get("error"): flash(_("Errore nel caricamento delle stazioni: %(error)s", error=resp.get("detail", "")), "error") stations = [] elif isinstance(resp, list): stations = resp else: stations = [] recipes_resp = api_client.get("/api/recipes") if isinstance(recipes_resp, list): all_recipes = recipes_resp elif isinstance(recipes_resp, dict) and isinstance(recipes_resp.get("items"), list): all_recipes = recipes_resp["items"] else: all_recipes = [] return render_template("admin/stations.html", stations=stations, all_recipes=all_recipes) # ============================================================================ # API PROXY AJAX (JSON) # ============================================================================ @admin_bp.route("/api/users", methods=["POST"]) @login_required @admin_required def api_create_user(): """Proxy: Create new user.""" data = request.get_json(silent=True) or {} resp = api_client.post("/api/users", data=data) if isinstance(resp, dict) and resp.get("error"): return jsonify(resp), resp.get("status_code", 500) return jsonify(resp), 201 @admin_bp.route("/api/users/", methods=["PUT"]) @login_required @admin_required def api_update_user(user_id: int): """Proxy: Update user.""" data = request.get_json(silent=True) or {} resp = api_client.put(f"/api/users/{user_id}", data=data) if isinstance(resp, dict) and resp.get("error"): return jsonify(resp), resp.get("status_code", 500) return jsonify(resp), 200 @admin_bp.route("/api/users//password", methods=["PUT"]) @login_required @admin_required def api_change_password(user_id: int): """Proxy: Change user password.""" data = request.get_json(silent=True) or {} resp = api_client.put(f"/api/users/{user_id}/password", data=data) if isinstance(resp, dict) and resp.get("error"): return jsonify(resp), resp.get("status_code", 500) return jsonify(resp), 200 @admin_bp.route("/api/users//toggle-active", methods=["POST"]) @login_required @admin_required def api_toggle_active(user_id: int): """Proxy: Toggle user active status.""" data = request.get_json(silent=True) or {} active = data.get("active", True) resp = api_client.put(f"/api/users/{user_id}", data={"active": active}) if isinstance(resp, dict) and resp.get("error"): return jsonify(resp), resp.get("status_code", 500) return jsonify(resp), 200 # --- Stations --- @admin_bp.route("/api/stations", methods=["POST"]) @login_required @admin_required def api_create_station(): """Proxy: Create a new station.""" data = request.get_json(silent=True) or {} resp = api_client.post("/api/stations", data=data) if isinstance(resp, dict) and resp.get("error"): return jsonify(resp), resp.get("status_code", 500) return jsonify(resp), 201 @admin_bp.route("/api/stations/", methods=["PUT"]) @login_required @admin_required def api_update_station(station_id: int): """Proxy: Update a station.""" data = request.get_json(silent=True) or {} resp = api_client.put(f"/api/stations/{station_id}", data=data) if isinstance(resp, dict) and resp.get("error"): return jsonify(resp), resp.get("status_code", 500) return jsonify(resp), 200 @admin_bp.route("/api/stations/", methods=["DELETE"]) @login_required @admin_required def api_delete_station(station_id: int): """Proxy: Delete a station.""" resp = api_client.delete(f"/api/stations/{station_id}") if isinstance(resp, dict) and resp.get("error"): return jsonify(resp), resp.get("status_code", 500) return jsonify({"deleted": True}), 200 @admin_bp.route("/api/stations//recipes", methods=["GET"]) @login_required @admin_required def api_list_station_recipes(station_id: int): """Proxy: List recipes assigned to a station.""" resp = api_client.get(f"/api/stations/{station_id}/recipes") if isinstance(resp, dict) and resp.get("error"): return jsonify(resp), resp.get("status_code", 500) return jsonify(resp), 200 @admin_bp.route("/api/stations//recipes", methods=["POST"]) @login_required @admin_required def api_assign_recipe(station_id: int): """Proxy: Assign a recipe to a station.""" data = request.get_json(silent=True) or {} resp = api_client.post(f"/api/stations/{station_id}/recipes", data=data) if isinstance(resp, dict) and resp.get("error"): return jsonify(resp), resp.get("status_code", 500) return jsonify(resp), 201 @admin_bp.route("/api/stations//recipes/", methods=["DELETE"]) @login_required @admin_required def api_unassign_recipe(station_id: int, recipe_id: int): """Proxy: Remove a recipe assignment from a station.""" resp = api_client.delete(f"/api/stations/{station_id}/recipes/{recipe_id}") if isinstance(resp, dict) and resp.get("error"): return jsonify(resp), resp.get("status_code", 500) return jsonify({"deleted": True}), 200