from contextlib import asynccontextmanager from fastapi import FastAPI, Depends, HTTPException, status from fastapi.middleware.cors import CORSMiddleware from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from database import engine, get_db, Base from models import Counter, User from auth import ( UserCreate, UserLogin, UserResponse, TokenResponse, get_password_hash, get_user_by_email, authenticate_user, create_access_token, get_current_user, ) @asynccontextmanager async def lifespan(app: FastAPI): async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) yield app = FastAPI(lifespan=lifespan) app.add_middleware( CORSMiddleware, allow_origins=["http://localhost:3000"], allow_methods=["*"], allow_headers=["*"], allow_credentials=True, ) # Auth endpoints @app.post("/api/auth/register", response_model=TokenResponse) async def register(user_data: UserCreate, db: AsyncSession = Depends(get_db)): existing_user = await get_user_by_email(db, user_data.email) if existing_user: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered", ) user = User( email=user_data.email, hashed_password=get_password_hash(user_data.password), ) db.add(user) await db.commit() await db.refresh(user) access_token = create_access_token(data={"sub": str(user.id)}) return TokenResponse( access_token=access_token, token_type="bearer", user=UserResponse(id=user.id, email=user.email), ) @app.post("/api/auth/login", response_model=TokenResponse) async def login(user_data: UserLogin, db: AsyncSession = Depends(get_db)): user = await authenticate_user(db, user_data.email, user_data.password) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect email or password", ) access_token = create_access_token(data={"sub": str(user.id)}) return TokenResponse( access_token=access_token, token_type="bearer", user=UserResponse(id=user.id, email=user.email), ) @app.get("/api/auth/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) # Counter endpoints async def get_or_create_counter(db: AsyncSession) -> Counter: result = await db.execute(select(Counter).where(Counter.id == 1)) counter = result.scalar_one_or_none() if not counter: counter = Counter(id=1, value=0) db.add(counter) await db.commit() await db.refresh(counter) return counter @app.get("/api/counter") async def get_counter( db: AsyncSession = Depends(get_db), _current_user: User = Depends(get_current_user), ): counter = await get_or_create_counter(db) return {"value": counter.value} @app.post("/api/counter/increment") async def increment_counter( db: AsyncSession = Depends(get_db), _current_user: User = Depends(get_current_user), ): counter = await get_or_create_counter(db) counter.value += 1 await db.commit() return {"value": counter.value}