sync(api): copy latest standalone code and merge alembic migrations

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Barcode Betty
2026-04-03 07:54:31 +00:00
parent 3a2231921a
commit b52fae5894
32 changed files with 717 additions and 498 deletions
+5 -3
View File
@@ -1,5 +1,7 @@
"""Alert routes: list alerts, manage settings."""
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
@@ -13,7 +15,7 @@ router = APIRouter(prefix="/alerts", tags=["alerts"])
@router.get("", response_model=list[AlertResponse])
async def list_alerts(
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = AlertService(db)
@@ -22,7 +24,7 @@ async def list_alerts(
@router.get("/settings", response_model=AlertSettingsResponse)
async def get_alert_settings(
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = AlertService(db)
@@ -32,7 +34,7 @@ async def get_alert_settings(
@router.put("/settings")
async def update_alert_settings(
body: AlertSettingsRequest,
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
raise HTTPException(
+2 -2
View File
@@ -16,7 +16,7 @@ router = APIRouter(prefix="/coupons", tags=["coupons"])
@router.get("", response_model=list[CouponResponse])
async def list_coupons(
store_id: UUID | None = Query(None),
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = CouponService(db)
@@ -25,7 +25,7 @@ async def list_coupons(
@router.get("/relevant", response_model=list[CouponResponse])
async def relevant_coupons(
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = CouponService(db)
+3 -3
View File
@@ -20,7 +20,7 @@ router = APIRouter(prefix="/prices", tags=["prices"])
@router.get("/trends", response_model=list[PriceTrendResponse])
async def price_trends(
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
category: str | None = Query(None),
db: AsyncSession = Depends(get_db),
):
@@ -30,7 +30,7 @@ async def price_trends(
@router.get("/increases", response_model=list[PriceIncreaseResponse])
async def price_increases(
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = PriceService(db)
@@ -40,7 +40,7 @@ async def price_increases(
@router.get("/comparison", response_model=list[PriceComparisonResponse])
async def price_comparison(
product_ids: Annotated[list[UUID], Query()],
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = PriceService(db)
+3 -3
View File
@@ -15,7 +15,7 @@ router = APIRouter(prefix="/products", tags=["products"])
@router.get("", response_model=list[ProductResponse])
async def list_products(
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
q: str | None = Query(None),
category: str | None = Query(None),
page: int = Query(1, ge=1),
@@ -29,7 +29,7 @@ async def list_products(
@router.get("/{product_id}", response_model=ProductDetailResponse)
async def get_product(
product_id: UUID,
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = ProductService(db)
@@ -44,7 +44,7 @@ async def get_product(
@router.get("/{product_id}/prices", response_model=PriceTrendResponse)
async def get_product_prices(
product_id: UUID,
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = ProductService(db)
+3 -3
View File
@@ -15,7 +15,7 @@ router = APIRouter(prefix="/purchases", tags=["purchases"])
@router.get("", response_model=list[PurchaseResponse])
async def list_purchases(
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
store_id: UUID | None = Query(None),
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
@@ -27,7 +27,7 @@ async def list_purchases(
@router.get("/stats", response_model=PurchaseStatsResponse)
async def purchase_stats(
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = PurchaseService(db)
@@ -37,7 +37,7 @@ async def purchase_stats(
@router.get("/{purchase_id}", response_model=PurchaseDetailResponse)
async def get_purchase(
purchase_id: UUID,
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = PurchaseService(db)
+4 -2
View File
@@ -1,5 +1,7 @@
"""Scraping routes: trigger sync, check status (proxy to ReceiptWitness)."""
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, status
from httpx import HTTPStatusError, RequestError
@@ -11,7 +13,7 @@ router = APIRouter(prefix="/scraping", tags=["scraping"])
@router.post("/{store_slug}/sync", response_model=SyncTriggerResponse)
async def trigger_sync(store_slug: str, user_id: str = Depends(get_current_user)):
async def trigger_sync(store_slug: str, user_id: UUID = Depends(get_current_user)):
client = ReceiptWitnessClient()
try:
result = await client.trigger_sync(str(user_id), store_slug)
@@ -29,7 +31,7 @@ async def trigger_sync(store_slug: str, user_id: str = Depends(get_current_user)
@router.get("/status", response_model=list[SyncStatusResponse])
async def sync_status(user_id: str = Depends(get_current_user)):
async def sync_status(user_id: UUID = Depends(get_current_user)):
client = ReceiptWitnessClient()
try:
return await client.get_sync_status(str(user_id))
+4 -2
View File
@@ -1,5 +1,7 @@
"""Shopping routes: optimize list, saved lists."""
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, status
from httpx import HTTPStatusError, RequestError
@@ -11,7 +13,7 @@ router = APIRouter(prefix="/shopping", tags=["shopping"])
@router.post("/optimize", response_model=OptimizeResponse)
async def optimize_shopping(body: OptimizeRequest, user_id: str = Depends(get_current_user)):
async def optimize_shopping(body: OptimizeRequest, user_id: UUID = Depends(get_current_user)):
client = ClipArtistClient()
try:
result = await client.optimize(
@@ -35,7 +37,7 @@ async def optimize_shopping(body: OptimizeRequest, user_id: str = Depends(get_cu
@router.get("/lists", response_model=list[ShoppingListResponse])
async def list_shopping_lists(user_id: str = Depends(get_current_user)):
async def list_shopping_lists(user_id: UUID = Depends(get_current_user)):
client = ClipArtistClient()
try:
return await client.get_shopping_lists(str(user_id))
+5 -3
View File
@@ -1,5 +1,7 @@
"""Store routes: list stores, manage user store connections."""
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
@@ -19,7 +21,7 @@ async def list_stores(db: AsyncSession = Depends(get_db)):
@router.get("/me/stores", response_model=list[StoreAccountResponse])
async def list_user_stores(
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = StoreService(db)
@@ -34,7 +36,7 @@ async def list_user_stores(
async def connect_store(
store_slug: str,
body: ConnectStoreRequest,
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = StoreService(db)
@@ -49,7 +51,7 @@ async def connect_store(
@router.delete("/me/stores/{store_slug}", status_code=status.HTTP_204_NO_CONTENT)
async def disconnect_store(
store_slug: str,
user_id: str = Depends(get_current_user),
user_id: UUID = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
svc = StoreService(db)