| 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"} |