# src/api/routes/auth.py from fastapi import APIRouter, HTTPException, status, Depends, Request from sqlmodel.ext.asyncio.session import AsyncSession from ...models import UserCreate, UserLogin, Token, UserResponse from ...core.dependencies import create_access_token from ...services.user_service import UserService from ...db.database import get_session import logging logger = logging.getLogger(__name__) router = APIRouter(prefix="/auth", tags=["Authentication"]) @router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED) async def register(user_data: UserCreate, session: AsyncSession = Depends(get_session)): """ Register a new user. Args: user_data: User registration data (email, name, password) Returns: UserResponse with created user data Raises: HTTPException 400: If email already exists HTTPException 500: If database operation fails """ try: # Attempt to create user user = await UserService.create_user(user_data, session) if user is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered" ) logger.info(f"New user registered: {user.email}") return user except HTTPException: raise except Exception as e: logger.error(f"Registration error: {e}", exc_info=True) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to register user" ) @router.post("/login", response_model=Token) async def login(credentials: UserLogin, request: Request, session: AsyncSession = Depends(get_session)): """ Login and get access token. Args: credentials: User login credentials (email, password) request: FastAPI request object (for IP and user agent) Returns: Token with JWT access token Raises: HTTPException 401: If credentials are invalid HTTPException 500: If database operation fails """ try: # Verify credentials user = await UserService.verify_credentials( credentials.email, credentials.password, session, ) if user is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid email or password" ) # Log the login session ip_address = request.client.host if request.client else None user_agent = request.headers.get("user-agent") session_id = await UserService.log_login( user_id=user['id'], session=session, ip_address=ip_address, user_agent=user_agent, ) # Create JWT token with session ID token = create_access_token( user_id=user['id'], email=user['email'] ) logger.info(f"User logged in: {user['email']}, session: {session_id}") return Token(access_token=token) except HTTPException: raise except Exception as e: logger.error(f"Login error: {e}", exc_info=True) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to login" )