"""Dependency injection utilities.""" from typing import Annotated from uuid import UUID from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import Session from app.auth.jwt import decode_access_token from app.database.models.user import User from app.database.session import get_db # For backwards compatibility with synchronous code from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from app.core.config import settings # Sync engine for synchronous endpoints _sync_engine = create_engine( str(settings.DATABASE_URL), pool_size=settings.DATABASE_POOL_SIZE, max_overflow=settings.DATABASE_MAX_OVERFLOW, pool_pre_ping=True, ) _SyncSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=_sync_engine) def get_db_sync(): """Synchronous database session dependency.""" db = _SyncSessionLocal() try: yield db finally: db.close() # Database session dependency (async) DatabaseSession = Annotated[AsyncSession, Depends(get_db)] # Security scheme for JWT Bearer token security = HTTPBearer() def get_current_user( credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db_sync) ) -> User: """ Get current authenticated user from JWT token (synchronous version). Args: credentials: HTTP Authorization Bearer token db: Database session Returns: Current authenticated user Raises: HTTPException: If token is invalid or user not found """ # Decode token token = credentials.credentials payload = decode_access_token(token) if payload is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid authentication credentials", headers={"WWW-Authenticate": "Bearer"}, ) # Extract user ID from token user_id_str: str = payload.get("sub") if user_id_str is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token payload", headers={"WWW-Authenticate": "Bearer"}, ) try: user_id = UUID(user_id_str) except ValueError: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid user ID in token", headers={"WWW-Authenticate": "Bearer"}, ) from None # Get user from database (sync) user = db.query(User).filter(User.id == user_id).first() if user is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found", headers={"WWW-Authenticate": "Bearer"}, ) if not user.is_active: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="User account is deactivated") return user async def get_current_user_async( credentials: HTTPAuthorizationCredentials = Depends(security), db: AsyncSession = Depends(get_db) ) -> User: """ Get current authenticated user from JWT token (asynchronous version). Args: credentials: HTTP Authorization Bearer token db: Async database session Returns: Current authenticated user Raises: HTTPException: If token is invalid or user not found """ # Decode token token = credentials.credentials payload = decode_access_token(token) if payload is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid authentication credentials", headers={"WWW-Authenticate": "Bearer"}, ) # Extract user ID from token user_id_str: str = payload.get("sub") if user_id_str is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token payload", headers={"WWW-Authenticate": "Bearer"}, ) try: user_id = UUID(user_id_str) except ValueError: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid user ID in token", headers={"WWW-Authenticate": "Bearer"}, ) from None # Get user from database (async) result = await db.execute(select(User).where(User.id == user_id)) user = result.scalar_one_or_none() if user is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found", headers={"WWW-Authenticate": "Bearer"}, ) if not user.is_active: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="User account is deactivated") return user