"""BAN YARO — Bewertungssystem (Ratings)""" from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel from typing import Optional from database import db from auth import get_current_user router = APIRouter() VALID_TYPES = {'walk', 'sitting', 'place', 'route'} # Tabelle → bewertung + anz_bewertungen aktualisieren TABLE_MAP = { 'walk': 'walks', 'sitting': 'sitters', 'place': 'places', 'route': 'routes', } # ------------------------------------------------------------------ # Schemas # ------------------------------------------------------------------ class RatingCreate(BaseModel): target_type: str target_id: int stars: int kommentar: Optional[str] = None # ------------------------------------------------------------------ # POST /api/ratings — Bewertung abgeben oder aktualisieren # ------------------------------------------------------------------ @router.post("", status_code=200) async def upsert_rating(data: RatingCreate, user=Depends(get_current_user)): if data.target_type not in VALID_TYPES: raise HTTPException(400, f"Ungültiger Typ. Erlaubt: {', '.join(VALID_TYPES)}") if not (1 <= data.stars <= 5): raise HTTPException(400, "Sterne müssen zwischen 1 und 5 liegen.") if data.kommentar and len(data.kommentar) > 200: raise HTTPException(400, "Kommentar darf maximal 200 Zeichen lang sein.") table = TABLE_MAP[data.target_type] kommentar = data.kommentar.strip() if data.kommentar else None with db() as conn: # Prüfen ob Zielobjekt existiert row = conn.execute(f"SELECT id FROM {table} WHERE id=?", (data.target_id,)).fetchone() if not row: raise HTTPException(404, "Objekt nicht gefunden.") # Upsert conn.execute(""" INSERT INTO ratings (user_id, target_type, target_id, stars, kommentar) VALUES (?, ?, ?, ?, ?) ON CONFLICT(user_id, target_type, target_id) DO UPDATE SET stars=excluded.stars, kommentar=excluded.kommentar, created_at=datetime('now') """, (user['id'], data.target_type, data.target_id, data.stars, kommentar)) # Durchschnitt berechnen und Zieltabelle aktualisieren agg = conn.execute(""" SELECT AVG(CAST(stars AS REAL)) AS avg_stars, COUNT(*) AS cnt FROM ratings WHERE target_type=? AND target_id=? """, (data.target_type, data.target_id)).fetchone() conn.execute( f"UPDATE {table} SET bewertung=?, anz_bewertungen=? WHERE id=?", (round(agg['avg_stars'], 2), agg['cnt'], data.target_id) ) return {"bewertung": round(agg['avg_stars'], 2), "anz_bewertungen": agg['cnt']} # ------------------------------------------------------------------ # GET /api/ratings/{type}/{id} — Bewertungen für ein Objekt laden # WICHTIG: Feste Route vor {param} in main.py registrieren # ------------------------------------------------------------------ @router.get("/{target_type}/{target_id}") async def get_ratings(target_type: str, target_id: int): if target_type not in VALID_TYPES: raise HTTPException(400, f"Ungültiger Typ. Erlaubt: {', '.join(VALID_TYPES)}") with db() as conn: rows = conn.execute(""" SELECT r.id, r.stars, r.kommentar, r.created_at, u.name AS user_name FROM ratings r JOIN users u ON u.id = r.user_id WHERE r.target_type=? AND r.target_id=? ORDER BY r.created_at DESC """, (target_type, target_id)).fetchall() agg = conn.execute(""" SELECT AVG(CAST(stars AS REAL)) AS avg_stars, COUNT(*) AS cnt FROM ratings WHERE target_type=? AND target_id=? """, (target_type, target_id)).fetchone() return { "bewertung": round(agg['avg_stars'], 2) if agg['avg_stars'] else 0, "anz_bewertungen": agg['cnt'], "ratings": [dict(r) for r in rows], } # ------------------------------------------------------------------ # GET /api/ratings/me/{type}/{id} — Eigene Bewertung für ein Objekt # WICHTIG: Diese Route muss VOR /{target_type}/{target_id} stehen! # ------------------------------------------------------------------ @router.get("/me/{target_type}/{target_id}") async def get_my_rating(target_type: str, target_id: int, user=Depends(get_current_user)): if target_type not in VALID_TYPES: raise HTTPException(400, f"Ungültiger Typ. Erlaubt: {', '.join(VALID_TYPES)}") with db() as conn: row = conn.execute(""" SELECT stars, kommentar FROM ratings WHERE user_id=? AND target_type=? AND target_id=? """, (user['id'], target_type, target_id)).fetchone() if not row: return {"stars": None, "kommentar": None} return dict(row)