- backend/schemas/swipe.py: SwipeItem, SwipeItemCreate, SwipeItemUpdate, SwipeListResponse - backend/services/swipe_service.py: SwipeService con load/save/add/update/delete/mark_used su swipe_file.json - backend/routers/swipe.py: 5 endpoint REST (GET/POST/PUT/DELETE/mark-used), lazy init pattern - backend/main.py: registra swipe.router prima del SPA catch-all mount
142 lines
4.3 KiB
Python
142 lines
4.3 KiB
Python
"""Router per la gestione dello Swipe File.
|
|
|
|
Endpoint:
|
|
- GET /api/swipe — lista tutte le idee (ordine: piu' recenti prima)
|
|
- POST /api/swipe — aggiunge una nuova idea
|
|
- PUT /api/swipe/{item_id} — modifica una voce esistente
|
|
- DELETE /api/swipe/{item_id} — elimina una voce
|
|
- POST /api/swipe/{item_id}/mark-used — segna la voce come usata in un calendario
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from fastapi import APIRouter, HTTPException
|
|
|
|
from backend.config import DATA_PATH
|
|
from backend.schemas.swipe import (
|
|
SwipeItem,
|
|
SwipeItemCreate,
|
|
SwipeItemUpdate,
|
|
SwipeListResponse,
|
|
)
|
|
from backend.services.swipe_service import SwipeService
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/api/swipe", tags=["swipe"])
|
|
|
|
# SwipeService creato lazily perche' DATA_PATH viene creato nel lifespan di FastAPI
|
|
_swipe_service: SwipeService | None = None
|
|
|
|
|
|
def _get_swipe_service() -> SwipeService:
|
|
"""Ritorna l'istanza SwipeService, creandola al primo accesso.
|
|
|
|
La creazione e' lazy perche' la directory DATA_PATH viene creata
|
|
durante il lifespan di FastAPI (main.py), non al momento dell'import.
|
|
"""
|
|
global _swipe_service
|
|
if _swipe_service is None:
|
|
# Assicura che la directory esista (normalmente gia' creata dal lifespan)
|
|
DATA_PATH.mkdir(parents=True, exist_ok=True)
|
|
_swipe_service = SwipeService(DATA_PATH)
|
|
return _swipe_service
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Endpoint
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@router.get("/", response_model=SwipeListResponse)
|
|
async def list_swipe_items() -> SwipeListResponse:
|
|
"""Lista tutte le idee salvate nello Swipe File.
|
|
|
|
Returns:
|
|
SwipeListResponse con items ordinati per data creazione (piu' recenti prima).
|
|
"""
|
|
items = _get_swipe_service().list_items()
|
|
return SwipeListResponse(items=items, total=len(items))
|
|
|
|
|
|
@router.post("/", response_model=SwipeItem, status_code=201)
|
|
async def add_swipe_item(body: SwipeItemCreate) -> SwipeItem:
|
|
"""Aggiunge una nuova idea allo Swipe File.
|
|
|
|
Args:
|
|
body: SwipeItemCreate con topic (obbligatorio), nicchia e note (opzionali).
|
|
|
|
Returns:
|
|
SwipeItem creato con id e timestamp generati automaticamente.
|
|
"""
|
|
item = _get_swipe_service().add_item(body)
|
|
logger.info("SwipeItem aggiunto | id=%s | topic=%s", item.id, item.topic[:50])
|
|
return item
|
|
|
|
|
|
@router.put("/{item_id}", response_model=SwipeItem)
|
|
async def update_swipe_item(item_id: str, body: SwipeItemUpdate) -> SwipeItem:
|
|
"""Modifica una voce esistente dello Swipe File.
|
|
|
|
Args:
|
|
item_id: ID della voce da modificare.
|
|
body: SwipeItemUpdate con i campi da aggiornare (tutti opzionali).
|
|
|
|
Returns:
|
|
SwipeItem aggiornato.
|
|
|
|
Raises:
|
|
HTTPException 404: Se la voce non esiste.
|
|
"""
|
|
try:
|
|
item = _get_swipe_service().update_item(item_id, body)
|
|
logger.info("SwipeItem aggiornato | id=%s", item_id)
|
|
return item
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
|
|
|
|
|
@router.delete("/{item_id}")
|
|
async def delete_swipe_item(item_id: str) -> dict:
|
|
"""Elimina una voce dallo Swipe File.
|
|
|
|
Args:
|
|
item_id: ID della voce da eliminare.
|
|
|
|
Returns:
|
|
{"deleted": True} se l'operazione e' riuscita.
|
|
|
|
Raises:
|
|
HTTPException 404: Se la voce non esiste.
|
|
"""
|
|
try:
|
|
_get_swipe_service().delete_item(item_id)
|
|
logger.info("SwipeItem eliminato | id=%s", item_id)
|
|
return {"deleted": True}
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
|
|
|
|
|
@router.post("/{item_id}/mark-used", response_model=SwipeItem)
|
|
async def mark_swipe_item_used(item_id: str) -> SwipeItem:
|
|
"""Segna una voce come utilizzata in un calendario generato.
|
|
|
|
Args:
|
|
item_id: ID della voce da segnare come usata.
|
|
|
|
Returns:
|
|
SwipeItem aggiornato con used=True.
|
|
|
|
Raises:
|
|
HTTPException 404: Se la voce non esiste.
|
|
"""
|
|
try:
|
|
item = _get_swipe_service().mark_used(item_id)
|
|
logger.info("SwipeItem segnato come usato | id=%s", item_id)
|
|
return item
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|