personal-lifecycle-tracker / backend / app / routers / auth.py
auth.py
Raw
from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, status

from app.auth import (
    create_access_token,
    get_current_user,
    hash_password,
    verify_password,
)
from app.models import (
    AuthResponse,
    LoginRequest,
    MessageResponse,
    SignupRequest,
    User,
)
from app.store import DatabaseStore, get_store
from app.telemetry import record_user_login, record_user_signup

router = APIRouter()


@router.post("/signup", response_model=AuthResponse, status_code=status.HTTP_201_CREATED)
async def signup(
    payload: SignupRequest,
    store: DatabaseStore = Depends(get_store),
) -> AuthResponse:
    existing = store.get_user_by_email(payload.email)
    if existing:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Email already exists",
        )

    hashed_pw = hash_password(payload.password)
    user_db = store.create_user(
        email=payload.email,
        name=payload.name,
        hashed_password=hashed_pw,
    )
    user = User(
        id=user_db.id,
        email=user_db.email,
        name=user_db.name,
        createdAt=user_db.createdAt,
    )
    token = create_access_token({"sub": user.id, "email": user.email})
    record_user_signup()
    return AuthResponse(user=user, token=token)


@router.post("/login", response_model=AuthResponse, status_code=status.HTTP_200_OK)
async def login(
    payload: LoginRequest,
    store: DatabaseStore = Depends(get_store),
) -> AuthResponse:
    user_db = store.get_user_by_email(payload.email)
    if not user_db or not verify_password(payload.password, user_db.hashed_password):
        record_user_login(success=False)
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid email or password",
        )

    user = User(
        id=user_db.id,
        email=user_db.email,
        name=user_db.name,
        createdAt=user_db.createdAt,
    )
    token = create_access_token({"sub": user.id, "email": user.email})
    record_user_login(success=True)
    return AuthResponse(user=user, token=token)


@router.get("/me", response_model=User, status_code=status.HTTP_200_OK)
async def get_me(
    current_user: User = Depends(get_current_user),
) -> User:
    return current_user


@router.post("/logout", response_model=MessageResponse, status_code=status.HTTP_200_OK)
async def logout() -> MessageResponse:
    return MessageResponse(message="Logged out successfully")