from datetime import timedelta from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import OAuth2PasswordRequestForm from sqlalchemy.orm import Session from pydantic import BaseModel, EmailStr from backend.database import get_db, User from backend.auth import ( verify_password, get_password_hash, create_access_token, create_refresh_token, decode_token, get_current_user ) router = APIRouter() class RegisterRequest(BaseModel): email: EmailStr password: str class LoginResponse(BaseModel): access_token: str refresh_token: str token_type: str = "bearer" user: dict class TokenRefreshRequest(BaseModel): refresh_token: str class UserResponse(BaseModel): id: str email: str is_active: bool created_at: str @router.post("/register", response_model=UserResponse) async def register(request: RegisterRequest, db: Session = Depends(get_db)): existing = db.query(User).filter(User.email == request.email).first() if existing: raise HTTPException(status_code=400, detail="Email already registered") user = User( email=request.email, hashed_password=get_password_hash(request.password), is_active=True ) db.add(user) db.commit() db.refresh(user) return UserResponse( id=user.id, email=user.email, is_active=user.is_active, created_at=user.created_at.isoformat() ) @router.post("/login", response_model=LoginResponse) async def login(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)): user = db.query(User).filter(User.email == form_data.username).first() if not user or not verify_password(form_data.password, user.hashed_password): raise HTTPException(status_code=401, detail="Invalid credentials") if not user.is_active: raise HTTPException(status_code=403, detail="User account is disabled") access_token = create_access_token({"sub": user.id}) refresh_token = create_refresh_token({"sub": user.id}) return LoginResponse( access_token=access_token, refresh_token=refresh_token, user={"id": user.id, "email": user.email} ) @router.post("/refresh") async def refresh_token(request: TokenRefreshRequest, db: Session = Depends(get_db)): payload = decode_token(request.refresh_token) if payload.get("type") != "refresh": raise HTTPException(status_code=401, 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=401, detail="User not found") access_token = create_access_token({"sub": user.id}) return {"access_token": access_token, "token_type": "bearer"} @router.get("/me", response_model=UserResponse) async def get_me(current_user: User = Depends(get_current_user)): return UserResponse( id=current_user.id, email=current_user.email, is_active=current_user.is_active, created_at=current_user.created_at.isoformat() ) @router.post("/logout") async def logout(): return {"message": "Successfully logged out"}