from fastapi import Depends, HTTPException, Request from .auth import get_current_user, get_current_user_event_stream from .db import get_portal_item def check(user: dict, *features: str) -> None: access = user.get("features") or {} if user.get("role") == "admin": return if not any(access.get(feature, False) for feature in features): raise HTTPException(status_code=403, detail="This feature is disabled for your account") def require_stats(user: dict = Depends(get_current_user)) -> dict: check(user, "stats") return user def require_invites(user: dict = Depends(get_current_user)) -> dict: check(user, "invites") return user def require_request_access(request: Request, user: dict = Depends(get_current_user)) -> None: path = request.url.path.rstrip("/") if path.endswith("/search") and "/actions/" not in path: # The issue picker uses the same media search; creation is checked separately. check(user, "new_requests", "issues") elif path.endswith(("/create", "/request-options")): check(user, "new_requests") elif path.endswith(("/issue-options", "/replacement-options", "/actions/replace", "/actions/search-missing", "/actions/repair-subtitles")): check(user, "issues") else: check(user, "requests") async def require_portal_access(request: Request, user: dict = Depends(get_current_user)) -> None: if user.get("role") == "admin": return path = request.url.path.rstrip("/") access = user.get("features", {}) if access.get("requests") and access.get("issues") and access.get("new_requests"): return if "/issues" in path: check(user, "issues") elif path.endswith("/requests") or path.endswith("/pipeline"): check(user, "requests") elif "item_id" in request.path_params: try: item = get_portal_item(int(request.path_params["item_id"])) except (ValueError, TypeError): item = None if not item: raise HTTPException(status_code=404, detail="Item not found") check(user, "requests" if item.get("kind") == "request" else "issues") elif path.endswith("/items") and request.method == "POST": payload = await request.json() check(user, "new_requests" if isinstance(payload, dict) and payload.get("kind", "request") == "request" else "issues") elif path.endswith(("/items", "/overview")) and request.query_params.get("kind"): check(user, "requests" if request.query_params["kind"] == "request" else "issues") else: # Unfiltered lists/overview can include both kinds. check(user, "requests") check(user, "issues") def require_request_stream(user: dict = Depends(get_current_user_event_stream)) -> dict: check(user, "requests") return user