"""Auth API: register, login, refresh, change-password.""" from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.config import settings from app.database import get_db from app.middleware.auth import require_auth from app.models.user import User from app.schemas.auth import ( ChangePasswordRequest, LoginRequest, RegisterRequest, TokenResponse, ) from app.schemas.user import UserResponse from app.services.auth_service import ( authenticate_user, create_access_token, create_user, decode_access_token, get_user_by_username, hash_password, verify_password, ) router = APIRouter(prefix="/api/v1/auth", tags=["auth"]) @router.post("/register", status_code=201, response_model=UserResponse) async def register(body: RegisterRequest, db: AsyncSession = Depends(get_db)): existing = await get_user_by_username(db, body.username) if existing: raise HTTPException(status_code=409, detail="Username already exists") result = await db.execute(select(User).where(User.email == body.email)) if result.scalar_one_or_none(): raise HTTPException(status_code=409, detail="Email already exists") user = await create_user(db, body.username, body.email, body.password) return user @router.post("/login", response_model=TokenResponse) async def login(body: LoginRequest, db: AsyncSession = Depends(get_db)): user = await authenticate_user(db, body.username, body.password) token = create_access_token(user.id, user.role.value) return TokenResponse( access_token=token, expires_in=settings.jwt_expire_minutes * 60, ) @router.post("/refresh", response_model=TokenResponse) async def refresh(user: User = Depends(require_auth)): token = create_access_token(user.id, user.role.value) return TokenResponse( access_token=token, expires_in=settings.jwt_expire_minutes * 60, ) @router.post("/change-password") async def change_password( body: ChangePasswordRequest, user: User = Depends(require_auth), db: AsyncSession = Depends(get_db), ): if not verify_password(body.old_password, user.hashed_password): raise HTTPException(status_code=400, detail="Old password is incorrect") user.hashed_password = hash_password(body.new_password) await db.commit() return {"detail": "Password changed successfully"}