from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from app.core.database import get_db from app.core.security import create_access_token, create_token_payload from app.core.redis import get_redis from app.models.user import User from app.schemas.auth import LoginRequest, LoginResponse, UserInfo from app.services.auth_client import ( verify_credentials, AuthAPIError, AuthAPIConnectionError, ) from app.middleware.auth import get_current_user router = APIRouter() @router.post("/login", response_model=LoginResponse) async def login( request: LoginRequest, db: Session = Depends(get_db), redis_client=Depends(get_redis), ): """ Authenticate user via external API and return JWT token. """ try: # Verify credentials with external API auth_result = await verify_credentials(request.email, request.password) except AuthAPIConnectionError: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Authentication service temporarily unavailable", ) except AuthAPIError as e: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials", ) # Find or create user in local database user = db.query(User).filter(User.email == request.email).first() if not user: # Create new user based on auth API response user = User( email=request.email, name=auth_result.get("name", request.email.split("@")[0]), is_active=True, ) db.add(user) db.commit() db.refresh(user) if not user.is_active: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="User account is disabled", ) # Get role name role_name = user.role.name if user.role else None # Create token payload token_data = create_token_payload( user_id=user.id, email=user.email, role=role_name, department_id=user.department_id, is_system_admin=user.is_system_admin, ) # Create access token access_token = create_access_token(token_data) # Store session in Redis redis_client.setex( f"session:{user.id}", 900, # 15 minutes access_token, ) return LoginResponse( access_token=access_token, user=UserInfo( id=user.id, email=user.email, name=user.name, role=role_name, department_id=user.department_id, is_system_admin=user.is_system_admin, ), ) @router.post("/logout") async def logout( current_user: User = Depends(get_current_user), redis_client=Depends(get_redis), ): """ Logout user and invalidate session. """ # Remove session from Redis redis_client.delete(f"session:{current_user.id}") return {"message": "Successfully logged out"} @router.get("/me", response_model=UserInfo) async def get_current_user_info( current_user: User = Depends(get_current_user), ): """ Get current authenticated user information. """ role_name = current_user.role.name if current_user.role else None return UserInfo( id=current_user.id, email=current_user.email, name=current_user.name, role=role_name, department_id=current_user.department_id, is_system_admin=current_user.is_system_admin, )