Public Access
feat: manual match pin/unpin endpoints
This commit is contained in:
@@ -1,16 +1,23 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Response, status
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import or_
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import get_db
|
||||
from app.models import Ingredient
|
||||
from app.schemas.ingredient import IngredientCreate, IngredientRead, IngredientUpdate
|
||||
from app.models import Ingredient, IngredientGroceryMatch, IngredientMatchSource
|
||||
from app.schemas.ingredient import (
|
||||
IngredientCreate,
|
||||
IngredientGroceryMatchRead,
|
||||
IngredientRead,
|
||||
IngredientUpdate,
|
||||
)
|
||||
from app.security import require_admin
|
||||
|
||||
|
||||
@@ -105,3 +112,65 @@ def delete_ingredient(ingredient_id: UUID, db: Session = Depends(get_db)):
|
||||
db.delete(row)
|
||||
db.commit()
|
||||
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
class _PinMatchBody(BaseModel):
|
||||
grocery_item_id: UUID
|
||||
confidence: float = 1.0
|
||||
|
||||
|
||||
@admin_router.post(
|
||||
"/{ingredient_id}/matches",
|
||||
response_model=IngredientGroceryMatchRead,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
)
|
||||
def pin_match(
|
||||
ingredient_id: UUID,
|
||||
payload: _PinMatchBody,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
existing = (
|
||||
db.query(IngredientGroceryMatch)
|
||||
.filter(
|
||||
IngredientGroceryMatch.ingredient_id == ingredient_id,
|
||||
IngredientGroceryMatch.grocery_item_id == payload.grocery_item_id,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if existing:
|
||||
existing.source = IngredientMatchSource.MANUAL
|
||||
existing.confidence = Decimal(str(round(payload.confidence, 3)))
|
||||
db.commit()
|
||||
db.refresh(existing)
|
||||
return existing
|
||||
row = IngredientGroceryMatch(
|
||||
ingredient_id=ingredient_id,
|
||||
grocery_item_id=payload.grocery_item_id,
|
||||
confidence=Decimal(str(round(payload.confidence, 3))),
|
||||
source=IngredientMatchSource.MANUAL,
|
||||
)
|
||||
db.add(row)
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
return row
|
||||
|
||||
|
||||
_match_admin_router = APIRouter(
|
||||
prefix="/api/admin/ingredient-matches",
|
||||
tags=["ingredients-admin"],
|
||||
dependencies=[Depends(require_admin)],
|
||||
)
|
||||
|
||||
|
||||
@_match_admin_router.delete(
|
||||
"/{match_id}",
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
response_class=Response,
|
||||
)
|
||||
def unpin_match(match_id: UUID, db: Session = Depends(get_db)) -> Response:
|
||||
row = db.query(IngredientGroceryMatch).filter(IngredientGroceryMatch.id == match_id).first()
|
||||
if row is None:
|
||||
raise HTTPException(status_code=404, detail="match not found")
|
||||
db.delete(row)
|
||||
db.commit()
|
||||
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@@ -41,5 +41,6 @@ app.include_router(pantry.router, prefix="/api/pantry", tags=["pantry"])
|
||||
app.include_router(admin.router, prefix="/api/admin", tags=["admin"])
|
||||
app.include_router(ingredients_api.public_router)
|
||||
app.include_router(ingredients_api.admin_router)
|
||||
app.include_router(ingredients_api._match_admin_router)
|
||||
app.include_router(recipes_api.public_router)
|
||||
app.include_router(recipes_api.admin_router)
|
||||
|
||||
Reference in New Issue
Block a user