You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

260 lines
9.2 KiB

from fastapi import APIRouter, Depends, HTTPException, Query, status
from typing import List, Optional, Dict, Any
import json
from datetime import datetime
from core.database import get_database, DatabaseManager
from models.pietanze import PietanzaCreate, PietanzaUpdate, PietanzaResponse
from models.common import ErrorResponse
from core.auth import get_current_user, get_current_admin_user
from core.exceptions import PietanzaNotFoundError, DatabaseError
router = APIRouter(prefix="/pietanze", tags=["Pietanze"])
@router.get("/", response_model=List[PietanzaResponse])
async def list_pietanze(
skip: int = Query(0, ge=0, description="Numero di elementi da saltare per la paginazione"),
limit: int = Query(20, ge=1, le=1000, description="Numero di elementi da restituire"),
search: Optional[str] = Query(None, description="Ricerca in nome e descrizione"),
allergeni: Optional[str] = Query(None, description="Filtra per allergeni (separati da virgola)"),
db: DatabaseManager = Depends(get_database)
):
"""Ottieni lista delle pietanze disponibili con filtri opzionali"""
try:
# Costruisci query con filtri
where_conditions = []
params = []
param_count = 0
if search:
param_count += 1
where_conditions.append(f"(nome ILIKE ${param_count} OR descrizione ILIKE ${param_count})")
params.append(f"%{search}%")
if allergeni:
allergen_list = [a.strip() for a in allergeni.split(",")]
param_count += 1
where_conditions.append(f"allergeni ?| ${param_count}")
params.append(allergen_list)
where_clause = ""
if where_conditions:
where_clause = "WHERE " + " AND ".join(where_conditions)
# Conta il totale degli elementi
count_query = f"SELECT COUNT(*) FROM pietanze {where_clause}"
count_result = await db.execute_one(count_query, *params)
total = count_result[0] if count_result else 0
# Ottieni elementi con paginazione
param_count += 1
limit_param = param_count
param_count += 1
offset_param = param_count
query = f"""
SELECT id, nome, descrizione, allergeni, created_at, updated_at
FROM pietanze
{where_clause}
ORDER BY nome
LIMIT ${limit_param} OFFSET ${offset_param}
"""
params.extend([limit, skip])
rows = await db.execute_query(query, *params)
pietanze = []
for row in rows:
pietanze.append(PietanzaResponse(
id=row['id'],
nome=row['nome'],
descrizione=row['descrizione'],
allergeni=row['allergeni'] or [],
created_at=row['created_at'],
updated_at=row['updated_at']
))
return pietanze
except Exception as e:
raise DatabaseError(f"Errore nel recupero delle pietanze: {str(e)}")
@router.get("/{pietanza_id}", response_model=PietanzaResponse)
async def get_pietanza(
pietanza_id: int,
db: DatabaseManager = Depends(get_database)
):
"""Ottieni pietanza specifica per ID"""
try:
query = """
SELECT id, nome, descrizione, allergeni, created_at, updated_at
FROM pietanze
WHERE id = $1
"""
row = await db.execute_one(query, pietanza_id)
if not row:
raise PietanzaNotFoundError(pietanza_id)
return PietanzaResponse(
id=row['id'],
nome=row['nome'],
descrizione=row['descrizione'],
allergeni=row['allergeni'] or [],
created_at=row['created_at'],
updated_at=row['updated_at']
)
except PietanzaNotFoundError:
raise
except Exception as e:
raise DatabaseError(f"Errore nel recupero della pietanza: {str(e)}")
@router.post("/", response_model=PietanzaResponse, status_code=status.HTTP_201_CREATED)
async def create_pietanza(
pietanza: PietanzaCreate,
#current_user: Dict[str, Any] = Depends(get_current_admin_user),
db: DatabaseManager = Depends(get_database)
):
"""Crea nuova pietanza (solo amministratori)"""
try:
query = """
INSERT INTO pietanze (nome, descrizione, allergeni, created_at, updated_at)
VALUES ($1, $2, $3, $4, $4)
RETURNING id, nome, descrizione, allergeni, created_at, updated_at
"""
now = datetime.utcnow()
allergeni_json = json.dumps(pietanza.allergeni) if pietanza.allergeni else None
row = await db.execute_one(
query,
pietanza.nome,
pietanza.descrizione,
allergeni_json,
now
)
if not row:
raise DatabaseError("Errore nella creazione della pietanza")
return PietanzaResponse(
id=row['id'],
nome=row['nome'],
descrizione=row['descrizione'],
allergeni=row['allergeni'] or [],
created_at=row['created_at'],
updated_at=row['updated_at']
)
except Exception as e:
raise DatabaseError(f"Errore nella creazione della pietanza: {str(e)}")
@router.put("/{pietanza_id}", response_model=PietanzaResponse)
async def update_pietanza(
pietanza_id: int,
pietanza_update: PietanzaUpdate,
current_user: Dict[str, Any] = Depends(get_current_admin_user),
db: DatabaseManager = Depends(get_database)
):
"""Aggiorna pietanza esistente (solo amministratori)"""
try:
# Verifica se la pietanza esiste
existing = await db.execute_one("SELECT id FROM pietanze WHERE id = $1", pietanza_id)
if not existing:
raise PietanzaNotFoundError(pietanza_id)
# Costruisci query di aggiornamento dinamicamente
update_fields = []
params = []
param_count = 0
if pietanza_update.nome is not None:
param_count += 1
update_fields.append(f"nome = ${param_count}")
params.append(pietanza_update.nome)
if pietanza_update.descrizione is not None:
param_count += 1
update_fields.append(f"descrizione = ${param_count}")
params.append(pietanza_update.descrizione)
if pietanza_update.allergeni is not None:
param_count += 1
update_fields.append(f"allergeni = ${param_count}")
params.append(json.dumps(pietanza_update.allergeni))
if not update_fields:
# Nessun campo da aggiornare, restituisci pietanza corrente
return await get_pietanza(pietanza_id, db)
# Aggiungi updated_at e pietanza_id
param_count += 1
update_fields.append(f"updated_at = ${param_count}")
params.append(datetime.utcnow())
param_count += 1
params.append(pietanza_id)
query = f"""
UPDATE pietanze
SET {', '.join(update_fields)}
WHERE id = ${param_count}
RETURNING id, nome, descrizione, allergeni, created_at, updated_at
"""
row = await db.execute_one(query, *params)
return PietanzaResponse(
id=row['id'],
nome=row['nome'],
descrizione=row['descrizione'],
allergeni=row['allergeni'] or [],
created_at=row['created_at'],
updated_at=row['updated_at']
)
except PietanzaNotFoundError:
raise
except Exception as e:
raise DatabaseError(f"Errore nell'aggiornamento della pietanza: {str(e)}")
@router.delete("/{pietanza_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_pietanza(
pietanza_id: int,
current_user: Dict[str, Any] = Depends(get_current_admin_user),
db: DatabaseManager = Depends(get_database)
):
"""Elimina pietanza (solo amministratori)"""
try:
# Verifica se la pietanza è associata a qualche pasto usando operatori JSONB
# Controlla se l'ID della pietanza (come stringa) appare come chiave in qualsiasi portata
pasto_check = await db.execute_one("""
SELECT COUNT(*)
FROM pasti
WHERE EXISTS (
SELECT 1
FROM jsonb_each(portate) AS p
WHERE jsonb_typeof(p.value) = 'object'
AND p.value ? $1
)
""", str(pietanza_id))
if pasto_check and pasto_check[0] > 0:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Impossibile eliminare la pietanza: è ancora associata a uno o più pasti"
)
# Elimina la pietanza e verifica se esisteva
result = await db.execute_one("DELETE FROM pietanze WHERE id = $1 RETURNING id", pietanza_id)
if not result:
raise PietanzaNotFoundError(pietanza_id)
except PietanzaNotFoundError:
raise
except HTTPException:
raise
except Exception as e:
raise DatabaseError(f"Errore nell'eliminazione della pietanza: {str(e)}")