"""Authentication blueprint - login, logout, profile.""" from functools import wraps from flask import Blueprint, abort, flash, redirect, render_template, request, session, url_for from flask_babel import gettext as _ from services.api_client import api_client auth_bp = Blueprint("auth", __name__, url_prefix="/auth") def login_required(f): """Decorator to require login for protected routes.""" @wraps(f) def decorated(*args, **kwargs): if not session.get("api_key"): flash(_("Effettua il login per continuare"), "warning") return redirect(url_for("auth.login")) return f(*args, **kwargs) return decorated def role_required(*roles): """Decorator to require one of the specified roles. Usage: @role_required("MeasurementTec", "Metrologist") def my_view(): ... """ def decorator(f): @wraps(f) def decorated(*args, **kwargs): user = session.get("user", {}) user_roles = user.get("roles", []) if not any(r in user_roles for r in roles): abort(403) return f(*args, **kwargs) return decorated return decorator @auth_bp.route("/login", methods=["GET", "POST"]) def login(): """Login page and form handler.""" # Se giĆ  loggato, redirect a home if session.get("api_key"): try: return redirect(url_for("measure.select_recipe")) except Exception: return redirect(url_for("auth.profile")) if request.method == "POST": username = request.form.get("username", "").strip() password = request.form.get("password", "") if not username or not password: flash(_("Inserisci username e password"), "error") return render_template("auth/login.html") try: response = api_client.post("/api/auth/login", data={"username": username, "password": password}) if response.get("error"): flash(response.get("detail", _("Credenziali non valide")), "error") return render_template("auth/login.html") # Salva in sessione session["api_key"] = response["api_key"] session["user"] = response["user"] session["user_id"] = response["user"]["id"] # Applica preferenze utente user = response["user"] if user.get("language_pref"): session["language"] = user["language_pref"] if user.get("theme_pref"): session["theme"] = user["theme_pref"] # Carica logo aziendale dalle impostazioni di sistema settings_resp = api_client.get("/api/settings") if not settings_resp.get("error"): logo_path = settings_resp.get("company_logo_path") if logo_path: session["company_logo"] = logo_path flash(_("Benvenuto, %(name)s!", name=user.get("display_name", username)), "success") # Redirect dopo login try: return redirect(url_for("measure.select_recipe")) except Exception: return redirect(url_for("auth.profile")) except Exception as e: flash(_("Errore di connessione al server: %(error)s", error=str(e)), "error") return render_template("auth/login.html") return render_template("auth/login.html") @auth_bp.route("/logout", methods=["GET", "POST"]) def logout(): """Clear session and redirect to login.""" # Invalida il token sul server if session.get("api_key"): try: api_client.post("/api/auth/logout") except Exception: pass # Ignora errori durante logout session.clear() flash(_("Logout effettuato"), "info") return redirect(url_for("auth.login")) @auth_bp.route("/profile", methods=["GET", "POST"]) @login_required def profile(): """User profile page - change display name, language, theme.""" if request.method == "POST": display_name = request.form.get("display_name", "").strip() language_pref = request.form.get("language_pref", "").strip() theme_pref = request.form.get("theme_pref", "").strip() try: data = {} if display_name: data["display_name"] = display_name if language_pref: data["language_pref"] = language_pref if theme_pref: data["theme_pref"] = theme_pref response = api_client.put("/api/auth/me", data=data) if response.get("error"): flash(response.get("detail", _("Errore durante l'aggiornamento del profilo")), "error") else: # Aggiorna sessione session["user"] = response if language_pref: session["language"] = language_pref if theme_pref: session["theme"] = theme_pref flash(_("Profilo aggiornato con successo"), "success") return redirect(url_for("auth.profile")) except Exception as e: flash(_("Errore di connessione al server: %(error)s", error=str(e)), "error") # GET - carica dati profilo user_data = api_client.get("/api/auth/me") if user_data.get("error"): flash(_("Errore nel caricamento del profilo: %(error)s", error=user_data.get("detail", "")), "error") user_data = session.get("user", {}) else: session["user"] = user_data return render_template("auth/profile.html", user=user_data)