"""Shop endpoints: the waitlist for the Ultimate Quantum Box hardware.""" import re from fastapi import APIRouter, Depends, HTTPException, Request, status from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.db import get_db from app.models.waitlist_entry import WaitlistEntry from app.rate_limit import RateLimiter router = APIRouter(prefix="/api/shop", tags=["shop"]) waitlist_limiter = RateLimiter(max_requests=5, window_seconds=3600) _EMAIL_RE = re.compile(r"^[^@\s]{1,64}@[^@\s]{1,255}\.[^@\s]{2,}$") @router.post("/waitlist", status_code=status.HTTP_201_CREATED) async def join_waitlist( payload: dict, request: Request, db: AsyncSession = Depends(get_db) ): email = str(payload.get("email", "")).strip().lower() interest = payload.get("interest") if not _EMAIL_RE.match(email): raise HTTPException( status.HTTP_422_UNPROCESSABLE_ENTITY, "that address does not reach us" ) client_ip = request.client.host if request.client else "unknown" if not waitlist_limiter.allow(client_ip): raise HTTPException( status.HTTP_429_TOO_MANY_REQUESTS, "the veil is crowded — try again later", ) existing = await db.scalar( select(WaitlistEntry).where(WaitlistEntry.email == email) ) if existing is not None: # Idempotent: re-registering the same address is a no-op. return {"status": "already_listed", "email": email} entry = WaitlistEntry( email=email, interest=str(interest)[:64] if interest else None ) db.add(entry) await db.commit() return {"status": "listed", "email": email}