This commit is contained in:
Nicola Malizia
2025-10-10 21:05:58 +02:00
parent a0a5bab4f1
commit 8ed8fcde6c
8 changed files with 239 additions and 111 deletions

View File

@@ -1,4 +1,5 @@
import os
import sqlalchemy as sa
from sqlalchemy.orm import Session, joinedload
from . import models, schemas
@@ -6,11 +7,25 @@ def get_celebrity(db: Session, celebrity_id: int):
# Usiamo joinedload per caricare in anticipo le relazioni e evitare query N+1
return db.query(models.Celebrity).options(
joinedload(models.Celebrity.profile_image),
joinedload(models.Celebrity.images)
joinedload(models.Celebrity.images),
joinedload(models.Celebrity.aliases) # Carica anche gli alias
).filter(models.Celebrity.id == celebrity_id).first()
def get_celebrities(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.Celebrity).offset(skip).limit(limit).all()
def get_celebrities(db: Session, skip: int = 0, limit: int = 100, search: str = None):
query = db.query(models.Celebrity).options(
joinedload(models.Celebrity.profile_image)
)
if search:
search_term = f"%{search}%"
# Esegue un join con la tabella degli alias e filtra per nome o per alias
query = query.outerjoin(models.Celebrity.aliases).filter(
sa.or_(
models.Celebrity.name.ilike(search_term),
models.CelebrityAlias.alias_name.ilike(search_term)
)
).distinct() # distinct() evita duplicati se una celebrità ha più alias che matchano
return query.offset(skip).limit(limit).all()
def create_celebrity(db: Session, celebrity: schemas.CelebrityCreate):
db_celebrity = models.Celebrity(**celebrity.model_dump())
@@ -41,6 +56,23 @@ def delete_celebrity(db: Session, celebrity_id: int):
db.commit()
return db_celebrity
# --- Funzioni CRUD per gli Alias ---
def create_celebrity_alias(db: Session, celebrity_id: int, alias: schemas.CelebrityAliasCreate):
db_alias = models.CelebrityAlias(celebrity_id=celebrity_id, alias_name=alias.alias_name)
db.add(db_alias)
db.commit()
db.refresh(db_alias)
return db_alias
def delete_celebrity_alias(db: Session, alias_id: int):
db_alias = db.query(models.CelebrityAlias).filter(models.CelebrityAlias.id == alias_id).first()
if not db_alias:
return None
db.delete(db_alias)
db.commit()
return db_alias
# --- Funzioni CRUD per le Immagini ---
def get_image(db: Session, image_id: int):

View File

@@ -1,8 +1,9 @@
from fastapi import APIRouter, Depends, HTTPException, File, UploadFile
from fastapi import APIRouter, Depends, HTTPException, File, UploadFile, Response
from sqlalchemy.orm import Session
from typing import List
from typing import List, Optional
import uuid
import shutil
import httpx
from .. import crud, models, schemas
from ..database import get_db
@@ -15,12 +16,12 @@ router = APIRouter(
@router.post("/", response_model=schemas.Celebrity, status_code=201)
def create_celebrity(celebrity: schemas.CelebrityCreate, db: Session = Depends(get_db)):
# Qui potresti aggiungere un check per vedere se una celebrità con lo stesso nome esiste già
# Qui potresti aggiungere un check per vedere se una celebrità con lo stesso nome esiste già
return crud.create_celebrity(db=db, celebrity=celebrity)
@router.get("/", response_model=List[schemas.Celebrity])
def read_celebrities(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
celebrities = crud.get_celebrities(db, skip=skip, limit=limit)
def read_celebrities(skip: int = 0, limit: int = 100, search: Optional[str] = None, db: Session = Depends(get_db)):
celebrities = crud.get_celebrities(db, skip=skip, limit=limit, search=search)
return celebrities
@router.get("/{celebrity_id}", response_model=schemas.Celebrity)
@@ -44,7 +45,23 @@ def delete_celebrity(celebrity_id: int, db: Session = Depends(get_db)):
raise HTTPException(status_code=404, detail="Celebrity not found")
return db_celebrity
# --- NUOVI ENDPOINT PER LE IMMAGINI ---
# --- NUOVI ENDPOINT PER GLI ALIAS ---
@router.post("/{celebrity_id}/aliases", response_model=schemas.CelebrityAlias, status_code=201)
def add_alias_to_celebrity(celebrity_id: int, alias: schemas.CelebrityAliasCreate, db: Session = Depends(get_db)):
db_celebrity = crud.get_celebrity(db, celebrity_id=celebrity_id)
if db_celebrity is None:
raise HTTPException(status_code=404, detail="Celebrity not found")
return crud.create_celebrity_alias(db=db, celebrity_id=celebrity_id, alias=alias)
@router.delete("/aliases/{alias_id}", status_code=204)
def delete_alias(alias_id: int, db: Session = Depends(get_db)):
db_alias = crud.delete_celebrity_alias(db, alias_id=alias_id)
if db_alias is None:
raise HTTPException(status_code=404, detail="Alias not found")
return Response(status_code=204)
# --- ENDPOINT PER LE IMMAGINI ---
@router.post("/{celebrity_id}/images", response_model=List[schemas.Image], status_code=201)
def upload_celebrity_images(celebrity_id: int, files: List[UploadFile] = File(...), db: Session = Depends(get_db)):
@@ -69,9 +86,6 @@ def upload_celebrity_images(celebrity_id: int, files: List[UploadFile] = File(..
created_images.append(db_image)
except Exception as e:
# Se un file fallisce, potremmo voler continuare con gli altri,
# ma per ora lanciamo un'eccezione per l'intero batch.
# In un'app di produzione, si potrebbe restituire una risposta parziale.
print(f"Failed to upload file {file.filename}: {e}")
raise HTTPException(status_code=500, detail=f"Could not upload file: {file.filename}")
@@ -89,7 +103,6 @@ async def add_image_from_url(celebrity_id: int, request: schemas.ImageUrlRequest
url = str(request.url)
try:
async with httpx.AsyncClient() as client:
# Eseguiamo prima una richiesta HEAD per controllare il tipo e la dimensione
head_response = await client.head(url, follow_redirects=True, timeout=10)
head_response.raise_for_status()
@@ -97,16 +110,13 @@ async def add_image_from_url(celebrity_id: int, request: schemas.ImageUrlRequest
if not content_type or not content_type.startswith('image/'):
raise HTTPException(status_code=400, detail="URL does not point to a valid image.")
# Limite di dimensione (es. 10MB)
content_length = int(head_response.headers.get('content-length', 0))
if content_length > 10 * 1024 * 1024:
raise HTTPException(status_code=400, detail="Image size exceeds 10MB limit.")
# Scarica l'immagine
get_response = await client.get(url, follow_redirects=True, timeout=30)
get_response.raise_for_status()
# Determina l'estensione del file
file_extension = content_type.split('/')[-1]
if file_extension == 'jpeg': file_extension = 'jpg'
@@ -130,8 +140,6 @@ def set_celebrity_profile_image(celebrity_id: int, request: schemas.SetProfileIm
raise HTTPException(status_code=404, detail="Celebrity or Image not found, or image does not belong to celebrity.")
return updated_celebrity
# NOTA: Un approccio pi├╣ RESTful sarebbe /api/images/{image_id} in un router dedicato.
# Per semplicità, lo inseriamo qui.
@router.delete("/images/{image_id}", response_model=schemas.Image)
def delete_image(image_id: int, db: Session = Depends(get_db)):
db_image = crud.delete_image(db, image_id=image_id)