import uuid from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.auth.deps import get_current_user from app.auth.hashing import hash_password, verify_password from app.auth.jwt import create_token from app.database import get_db from app.models.schemas import ( RegisterRequest, LoginRequest, TokenResponse, UserResponse, CollectionCreate, CollectionResponse, ) from app.models.user import User from app.models.collection import Collection router = APIRouter(prefix="/api", tags=["auth"]) @router.post("/register", response_model=TokenResponse, status_code=status.HTTP_201_CREATED) async def register(body: RegisterRequest, db: AsyncSession = Depends(get_db)): result = await db.execute(select(User).where(User.email == body.email)) if result.scalar_one_or_none(): raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Email already registered") api_key = str(uuid.uuid4().hex[:32]) user = User( email=body.email, password_hash=hash_password(body.password), api_key=api_key, plan=body.plan, ) db.add(user) await db.commit() await db.refresh(user) return TokenResponse(access_token=create_token(user.id)) @router.post("/login", response_model=TokenResponse) async def login(body: LoginRequest, db: AsyncSession = Depends(get_db)): result = await db.execute(select(User).where(User.email == body.email)) user = result.scalar_one_or_none() if not user or not verify_password(body.password, user.password_hash): raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials") return TokenResponse(access_token=create_token(user.id)) @router.get("/me", response_model=UserResponse) async def get_me(user: User = Depends(get_current_user)): return user @router.post("/collections", response_model=CollectionResponse, status_code=status.HTTP_201_CREATED) async def create_collection( body: CollectionCreate, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): collection = Collection(user_id=user.id, name=body.name) db.add(collection) await db.commit() await db.refresh(collection) return collection @router.get("/collections", response_model=list[CollectionResponse]) async def list_collections( user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): result = await db.execute( select(Collection).where(Collection.user_id == user.id).order_by(Collection.created_at.desc()) ) return result.scalars().all() @router.get("/collections/{collection_id}", response_model=CollectionResponse) async def get_collection( collection_id: uuid.UUID, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): result = await db.execute( select(Collection).where(Collection.id == collection_id, Collection.user_id == user.id) ) collection = result.scalar_one_or_none() if not collection: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Collection not found") return collection @router.delete("/collections/{collection_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_collection( collection_id: uuid.UUID, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): result = await db.execute( select(Collection).where(Collection.id == collection_id, Collection.user_id == user.id) ) collection = result.scalar_one_or_none() if not collection: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Collection not found") await db.delete(collection) await db.commit()