from __future__ import annotations import functools from quart import session, redirect, url_for, abort from fablednetmon.models.users import UserRole _ROLE_ORDER = [UserRole.viewer, UserRole.operator, UserRole.admin] def require_role(minimum_role: UserRole): """Decorator: requires authenticated user with at least minimum_role.""" def decorator(f): @functools.wraps(f) async def wrapper(*args, **kwargs): user_id = session.get("user_id") if not user_id: return redirect(url_for("auth.login")) user_role = UserRole(session.get("user_role", "viewer")) if _ROLE_ORDER.index(user_role) < _ROLE_ORDER.index(minimum_role): abort(403) return await f(*args, **kwargs) return wrapper return decorator def login_user(user) -> None: """Write user identity into the session.""" session["user_id"] = user.id session["user_role"] = user.role.value session["username"] = user.username def logout_user() -> None: session.clear() def current_user_id() -> str | None: return session.get("user_id")