from fastapi import Cookie, Depends, HTTPException, status from jose import JWTError from sqlalchemy.orm import Session from .database import get_db from .models import User, UserRole, UserStatus from .security import decode_access_token def get_current_user( access_token: str | None = Cookie(default=None), db: Session = Depends(get_db), ) -> User: """ Reads the JWT from the HttpOnly `access_token` cookie, validates it, and returns the authenticated User ORM object. Raises 401 on any failure. """ credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated.", ) if access_token is None: raise credentials_exception try: user_id = decode_access_token(access_token) except JWTError: raise credentials_exception user = db.get(User, user_id) if user is None: raise credentials_exception # Guard: approved users only (pending/rejected cannot use the API) if user.status != UserStatus.approved: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Your account is pending admin approval.", ) return user def require_role(*roles: UserRole): """ Returns a FastAPI dependency that asserts the current user has one of the given roles. Usage: Depends(require_role(UserRole.admin, UserRole.teacher)) """ def _check(current_user: User = Depends(get_current_user)) -> User: if current_user.role not in roles: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="You do not have permission to perform this action.", ) return current_user return _check def require_admin(current_user: User = Depends(get_current_user)) -> User: if current_user.role != UserRole.admin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Admin access required.", ) return current_user