Sprint 15: Suche, Ausweis, Teilen, Widget

- Volltext-Suche im Tagebuch (LIKE über Titel/Text/Tags, Debounce 350ms)
- Digitaler Heimtierausweis als druckbare HTML-Seite (/ausweis/{dog_id})
  Enthält Impfungen, Medikamente, Allergien, Tierärzte, Chip-Nr.
- Hund teilen: Einladungslink-System (dog_shares-Tabelle, /teilen/{token})
  Geteilte Hunde erscheinen in der Hundeliste, Tagebuch/Gesundheit lesbar
- Widget-Seite /#widget: zufälliges Tagebuchbild + nächste Erinnerung
  Als PWA-Shortcut im Manifest verankert
- SW-Cache by-v144, APP_VER 117
This commit is contained in:
rene 2026-04-17 15:51:09 +02:00
parent d5f09cd16b
commit 34f29f9d0a
16 changed files with 917 additions and 35 deletions

View file

@ -33,9 +33,17 @@ class DiaryUpdate(BaseModel):
def _own_dog(dog_id: int, user_id: int, conn):
"""Eigener Hund ODER geteilter Hund (angenommene Einladung)."""
dog = conn.execute(
"SELECT id FROM dogs WHERE id=? AND user_id=?", (dog_id, user_id)
).fetchone()
if not dog:
dog = conn.execute(
"""SELECT d.id FROM dogs d
JOIN dog_shares ds ON ds.dog_id = d.id
WHERE d.id=? AND ds.shared_with_id=? AND ds.accepted_at IS NOT NULL""",
(dog_id, user_id)
).fetchone()
if not dog:
raise HTTPException(404, "Hund nicht gefunden.")
return dog
@ -82,18 +90,30 @@ def _entry_dict(row, dog_ids_map: dict) -> dict:
@router.get("/{dog_id}/diary")
async def list_diary(dog_id: int, limit: int = 20, offset: int = 0,
q: Optional[str] = None,
user=Depends(get_current_user)):
with db() as conn:
_own_dog(dog_id, user["id"], conn)
# Einträge des primären Hundes SOWIE Einträge wo der Hund als weiterer zugeordnet ist
rows = conn.execute(
"""SELECT DISTINCT d.* FROM diary d
LEFT JOIN diary_dogs dd ON dd.diary_id = d.id
WHERE d.dog_id = ? OR dd.dog_id = ?
ORDER BY d.datum DESC, d.created_at DESC
LIMIT ? OFFSET ?""",
(dog_id, dog_id, limit, offset)
).fetchall()
if q:
pattern = f"%{q}%"
rows = conn.execute(
"""SELECT DISTINCT d.* FROM diary d
LEFT JOIN diary_dogs dd ON dd.diary_id = d.id
WHERE (d.dog_id = ? OR dd.dog_id = ?)
AND (d.titel LIKE ? OR d.text LIKE ? OR d.tags LIKE ?)
ORDER BY d.datum DESC, d.created_at DESC
LIMIT ? OFFSET ?""",
(dog_id, dog_id, pattern, pattern, pattern, limit, offset)
).fetchall()
else:
rows = conn.execute(
"""SELECT DISTINCT d.* FROM diary d
LEFT JOIN diary_dogs dd ON dd.diary_id = d.id
WHERE d.dog_id = ? OR dd.dog_id = ?
ORDER BY d.datum DESC, d.created_at DESC
LIMIT ? OFFSET ?""",
(dog_id, dog_id, limit, offset)
).fetchall()
ids = [r["id"] for r in rows]
dogs_map = _fetch_dog_ids(conn, ids)