Feature: Tierarzt-Bewertungen — Sterne-Rating pro Praxis mit Detail-Modal (SW by-v700)
This commit is contained in:
parent
c5030024b0
commit
40de0f38aa
5 changed files with 461 additions and 5 deletions
|
|
@ -27,6 +27,14 @@ class TierarztCreate(BaseModel):
|
|||
osm_id: Optional[str] = None
|
||||
|
||||
|
||||
class BewertungCreate(BaseModel):
|
||||
gesamt: int
|
||||
wartezeit: Optional[int] = None
|
||||
freundlichkeit: Optional[int] = None
|
||||
kompetenz: Optional[int] = None
|
||||
text: Optional[str] = None
|
||||
|
||||
|
||||
class TierarztUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
strasse: Optional[str] = None
|
||||
|
|
@ -220,3 +228,109 @@ async def update_tierarzt(tierarzt_id: int, data: TierarztUpdate,
|
|||
)
|
||||
row = conn.execute("SELECT * FROM tieraerzte WHERE id=?", (tierarzt_id,)).fetchone()
|
||||
return dict(row)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# BEWERTUNGEN
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _refresh_vet_rating(conn, tierarzt_id: int):
|
||||
"""Aktualisiert avg_rating und anz_bewertungen in tieraerzte."""
|
||||
row = conn.execute(
|
||||
"""SELECT COUNT(*) AS n, AVG(CAST(gesamt AS REAL)) AS avg
|
||||
FROM tierarzt_bewertungen WHERE tierarzt_id=?""",
|
||||
(tierarzt_id,)
|
||||
).fetchone()
|
||||
n = row["n"] or 0
|
||||
avg = row["avg"] or 0.0
|
||||
conn.execute(
|
||||
"UPDATE tieraerzte SET avg_rating=?, anz_bewertungen=? WHERE id=?",
|
||||
(round(avg, 1), n, tierarzt_id)
|
||||
)
|
||||
|
||||
|
||||
@router.post("/{tierarzt_id}/bewertung", status_code=201)
|
||||
async def create_bewertung(tierarzt_id: int, data: BewertungCreate,
|
||||
user=Depends(get_current_user)):
|
||||
"""Bewertung abgeben (1×pro User+Tierarzt, UPSERT)."""
|
||||
if not (1 <= data.gesamt <= 5):
|
||||
raise HTTPException(400, "Gesamtbewertung muss zwischen 1 und 5 liegen.")
|
||||
for field in ("wartezeit", "freundlichkeit", "kompetenz"):
|
||||
val = getattr(data, field)
|
||||
if val is not None and not (1 <= val <= 5):
|
||||
raise HTTPException(400, f"{field} muss zwischen 1 und 5 liegen.")
|
||||
|
||||
text = (data.text or "").strip()[:500] or None
|
||||
|
||||
with db() as conn:
|
||||
vet = conn.execute("SELECT id FROM tieraerzte WHERE id=?", (tierarzt_id,)).fetchone()
|
||||
if not vet:
|
||||
raise HTTPException(404, "Tierarzt nicht gefunden.")
|
||||
|
||||
conn.execute(
|
||||
"""INSERT INTO tierarzt_bewertungen
|
||||
(tierarzt_id, user_id, gesamt, wartezeit, freundlichkeit, kompetenz, text)
|
||||
VALUES (?,?,?,?,?,?,?)
|
||||
ON CONFLICT(tierarzt_id, user_id) DO UPDATE SET
|
||||
gesamt=excluded.gesamt,
|
||||
wartezeit=excluded.wartezeit,
|
||||
freundlichkeit=excluded.freundlichkeit,
|
||||
kompetenz=excluded.kompetenz,
|
||||
text=excluded.text,
|
||||
created_at=datetime('now')""",
|
||||
(tierarzt_id, user["id"], data.gesamt, data.wartezeit,
|
||||
data.freundlichkeit, data.kompetenz, text)
|
||||
)
|
||||
_refresh_vet_rating(conn, tierarzt_id)
|
||||
row = conn.execute(
|
||||
"SELECT * FROM tieraerzte WHERE id=?", (tierarzt_id,)
|
||||
).fetchone()
|
||||
return dict(row)
|
||||
|
||||
|
||||
@router.get("/{tierarzt_id}/bewertungen")
|
||||
async def list_bewertungen(tierarzt_id: int):
|
||||
"""Alle Bewertungen für einen Tierarzt (public). Gibt Zusammenfassung + letzte 5 Texte."""
|
||||
with db() as conn:
|
||||
vet = conn.execute(
|
||||
"SELECT id, avg_rating, anz_bewertungen FROM tieraerzte WHERE id=?",
|
||||
(tierarzt_id,)
|
||||
).fetchone()
|
||||
if not vet:
|
||||
raise HTTPException(404, "Tierarzt nicht gefunden.")
|
||||
|
||||
# Stern-Verteilung
|
||||
verteilung = {}
|
||||
for star in range(1, 6):
|
||||
r = conn.execute(
|
||||
"SELECT COUNT(*) AS n FROM tierarzt_bewertungen WHERE tierarzt_id=? AND gesamt=?",
|
||||
(tierarzt_id, star)
|
||||
).fetchone()
|
||||
verteilung[str(star)] = r["n"]
|
||||
|
||||
# Letzte 5 Kommentare
|
||||
kommentare = conn.execute(
|
||||
"""SELECT gesamt, wartezeit, freundlichkeit, kompetenz, text, created_at
|
||||
FROM tierarzt_bewertungen
|
||||
WHERE tierarzt_id=? AND text IS NOT NULL AND text != ''
|
||||
ORDER BY created_at DESC LIMIT 5""",
|
||||
(tierarzt_id,)
|
||||
).fetchall()
|
||||
|
||||
return {
|
||||
"avg_rating": vet["avg_rating"] or 0,
|
||||
"anz_bewertungen": vet["anz_bewertungen"] or 0,
|
||||
"verteilung": verteilung,
|
||||
"kommentare": [dict(k) for k in kommentare],
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{tierarzt_id}/meine-bewertung")
|
||||
async def get_meine_bewertung(tierarzt_id: int, user=Depends(get_current_user)):
|
||||
"""Eigene Bewertung für einen Tierarzt (oder null)."""
|
||||
with db() as conn:
|
||||
row = conn.execute(
|
||||
"SELECT * FROM tierarzt_bewertungen WHERE tierarzt_id=? AND user_id=?",
|
||||
(tierarzt_id, user["id"])
|
||||
).fetchone()
|
||||
return dict(row) if row else None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue