from datetime import timedelta from typing import Any from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import OAuth2PasswordRequestForm from sqlalchemy.ext.asyncio import AsyncSession from app.core.config import settings from app.core.database import get_db from app.core.security import create_access_token from app.crud import user as crud_user from app.schemas.user import Token, User, UserCreate, UserLogin router = APIRouter() @router.post("/auth/register", response_model=User, status_code=status.HTTP_201_CREATED) async def register(user_in: UserCreate, db: AsyncSession = Depends(get_db)) -> Any: """ Register a new user. """ # Check if user with this email already exists user = await crud_user.get_by_email(db, email=user_in.email) if user: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered", ) # Create new user user = await crud_user.create(db, obj_in=user_in) return user @router.post("/auth/login", response_model=Token) async def login( form_data: OAuth2PasswordRequestForm = Depends(), db: AsyncSession = Depends(get_db) ) -> Any: """ OAuth2 compatible token login, get an access token for future requests. """ user = await crud_user.authenticate( db, email=form_data.username, password=form_data.password ) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect email or password", headers={"WWW-Authenticate": "Bearer"}, ) if not user.is_active: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Inactive user" ) # Update last login timestamp await crud_user.update_last_login(db, user=user) # Create access token access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) return { "access_token": create_access_token( user.id, expires_delta=access_token_expires ), "token_type": "bearer", } @router.post("/auth/login/json", response_model=Token) async def login_json(login_data: UserLogin, db: AsyncSession = Depends(get_db)) -> Any: """ JSON compatible login, get an access token for future requests. """ user = await crud_user.authenticate( db, email=login_data.email, password=login_data.password ) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect email or password", headers={"WWW-Authenticate": "Bearer"}, ) if not user.is_active: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Inactive user" ) # Update last login timestamp await crud_user.update_last_login(db, user=user) # Create access token access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) return { "access_token": create_access_token( user.id, expires_delta=access_token_expires ), "token_type": "bearer", }