"""RBAC decorators and shared request utilities.""" from functools import wraps from urllib.parse import urlparse from flask import abort, request from flask_login import current_user from app.models.enums import Role def safe_referrer(fallback: str) -> str: """Return request.referrer only when it is same-origin; else fallback.""" ref = request.referrer if ref: parsed = urlparse(ref) if parsed.netloc in ("", request.host): return ref return fallback def role_required(*roles): """Require the current user to hold one of the given roles.""" def decorator(fn): @wraps(fn) def wrapper(*args, **kwargs): if not current_user.is_authenticated: abort(401) if current_user.role not in roles: abort(403) return fn(*args, **kwargs) return wrapper return decorator def admin_required(fn): @wraps(fn) def wrapper(*args, **kwargs): if not current_user.is_authenticated: abort(401) if not current_user.is_admin: abort(403) return fn(*args, **kwargs) return wrapper def moderator_required(fn): @wraps(fn) def wrapper(*args, **kwargs): if not current_user.is_authenticated: abort(401) if not current_user.is_moderator: abort(403) return fn(*args, **kwargs) return wrapper