from typing import Annotated from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer from sqlmodel import Session, select from app.core.security import decode_access_token from app.db import SessionDep from app.models.mail_template import MailTemplate from app.models.order import Order from app.models.participant import Participant from app.models.purchase_round import PurchaseRound from app.models.route import Route from app.models.user import User from app.models.wine_offering import WineOffering oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/login") def get_current_user(session: SessionDep, token: Annotated[str, Depends(oauth2_scheme)]) -> User: credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) payload = decode_access_token(token) if payload is None or payload.get("sub") is None: raise credentials_exception user = session.get(User, int(payload["sub"])) if user is None or not user.is_active: raise credentials_exception return user CurrentUser = Annotated[User, Depends(get_current_user)] def require_elevated_superuser(current_user: User, token: str) -> None: if not current_user.is_superadmin: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Not enough privileges") payload = decode_access_token(token) if not payload or not payload.get("elevated"): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="This action requires an elevated session — call POST /auth/elevate first", ) def get_current_active_superuser( current_user: CurrentUser, token: Annotated[str, Depends(oauth2_scheme)], ) -> User: require_elevated_superuser(current_user, token) return current_user CurrentSuperuser = Annotated[User, Depends(get_current_active_superuser)] def get_route_in_organization(session: Session, route_id: int, organization_id: int) -> Route: route = session.get(Route, route_id) if route is None or route.organization_id != organization_id: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Route not found") return route def get_participant_in_organization(session: Session, participant_id: int, organization_id: int) -> Participant: participant = session.exec( select(Participant) .join(Route) .where(Participant.id == participant_id, Route.organization_id == organization_id) ).first() if participant is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Participant not found") return participant def get_round_in_organization(session: Session, round_id: int, organization_id: int) -> PurchaseRound: purchase_round = session.exec( select(PurchaseRound) .join(Route) .where(PurchaseRound.id == round_id, Route.organization_id == organization_id) ).first() if purchase_round is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Purchase round not found") return purchase_round def get_order_in_organization(session: Session, order_id: int, organization_id: int) -> Order: order = session.exec( select(Order) .join(PurchaseRound) .join(Route) .where(Order.id == order_id, Route.organization_id == organization_id) ).first() if order is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") return order def get_wine_offering_in_organization(session: Session, wine_offering_id: int, organization_id: int) -> WineOffering: wine_offering = session.exec( select(WineOffering) .join(PurchaseRound) .join(Route) .where(WineOffering.id == wine_offering_id, Route.organization_id == organization_id) ).first() if wine_offering is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Wine offering not found") return wine_offering def get_mail_template_in_organization(session: Session, template_id: int, organization_id: int) -> MailTemplate: mail_template = session.exec( select(MailTemplate) .join(Route) .where(MailTemplate.id == template_id, Route.organization_id == organization_id) ).first() if mail_template is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Mail template not found") return mail_template