from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from datetime import datetime from app.core import get_db, get_password_hash, verify_password, create_access_token, create_refresh_token from app.core.security import decode_token from app.models import User from app.schemas import LoginRequest, Token, TokenRefresh, UserCreate, UserResponse router = APIRouter(prefix="/auth", tags=["Authentication"]) @router.post("/login", response_model=Token) async def login(login_data: LoginRequest, db: Session = Depends(get_db)): """User login""" user = db.query(User).filter( (User.username == login_data.username) | (User.email == login_data.username) ).first() if not user or not verify_password(login_data.password, user.hashed_password): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid username or password" ) if not user.is_active: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="User account is inactive" ) # Update last login user.last_login = datetime.utcnow() db.commit() # Create tokens access_token = create_access_token(data={"sub": str(user.id)}) refresh_token = create_refresh_token(data={"sub": str(user.id)}) return Token(access_token=access_token, refresh_token=refresh_token) @router.post("/refresh", response_model=Token) async def refresh_token(token_data: TokenRefresh, db: Session = Depends(get_db)): """Refresh access token""" payload = decode_token(token_data.refresh_token) if payload.get("type") != "refresh": raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token type" ) user_id = payload.get("sub") user = db.query(User).filter(User.id == user_id).first() if not user or not user.is_active: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found or inactive" ) access_token = create_access_token(data={"sub": str(user.id)}) refresh_token = create_refresh_token(data={"sub": str(user.id)}) return Token(access_token=access_token, refresh_token=refresh_token) @router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED) async def register(user_data: UserCreate, db: Session = Depends(get_db)): """Register a new user (for initial setup only)""" # Check if any users exist existing_users = db.query(User).count() # If users exist, only allow superadmin to create new users if existing_users > 0: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Registration is disabled. Contact admin to create accounts." ) # Check if username or email already exists if db.query(User).filter(User.username == user_data.username).first(): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Username already registered" ) if db.query(User).filter(User.email == user_data.email).first(): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered" ) # Create user (first user becomes superadmin) user = User( email=user_data.email, username=user_data.username, hashed_password=get_password_hash(user_data.password), full_name=user_data.full_name, phone=user_data.phone, role="superadmin" if existing_users == 0 else user_data.role ) db.add(user) db.commit() db.refresh(user) return user