from typing import Generator from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer from jose import JWTError, jwt from pydantic import ValidationError from sqlalchemy.orm import Session from app.core.config import settings from app.crud.user import user as user_crud from app.db.session import SessionLocal from app.models.user import User from app.schemas.token import TokenPayload reusable_oauth2 = OAuth2PasswordBearer(tokenUrl=f"{settings.API_V1_STR}/auth/login") def get_db() -> Generator: """ Dependency function that yields a SQLAlchemy database session. The session is closed after the request is complete. """ try: db = SessionLocal() yield db finally: db.close() def get_current_user( db: Session = Depends(get_db), token: str = Depends(reusable_oauth2) ) -> User: """ Decode JWT token to get user identity and fetch user object from database. Args: db: Database session token: JWT token Returns: User object Raises: HTTPException: If token is invalid or user not found """ try: payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"]) token_data = TokenPayload(**payload) except (JWTError, ValidationError): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) user = user_crud.get(db, id=token_data.sub) if not user: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found" ) return user def get_current_active_user( current_user: User = Depends(get_current_user), ) -> User: """ Check if current user is active. Args: current_user: Current user Returns: User object Raises: HTTPException: If user is inactive """ if not user_crud.is_active(current_user): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Inactive user" ) return current_user def get_current_active_superuser( current_user: User = Depends(get_current_user), ) -> User: """ Check if current user is a superuser. Args: current_user: Current user Returns: User object Raises: HTTPException: If user is not a superuser """ if not user_crud.is_superuser(current_user): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="The user doesn't have enough privileges", ) return current_user