Tagebuch: manuelle Positionierung reichert POIs + Wetter an (v1305)
Bisher holte nur der Create-/Foto-EXIF-Pfad Wetter+POIs. Wer einem Eintrag nachträglich (Edit) einen Standort gab, bekam nichts. Jetzt: GPS neu/geändert im Update-Handler -> POIs immer + Wetter fürs Eintragsdatum. - weather.get_weather_for_date(): heute -> aktuelles Wetter; Vergangenheit -> stündliche Historie (Open-Meteo Forecast <=90 Tage, sonst Archive-API), Stunde aus created_at. Gleiche Dict-Struktur wie get_weather_for_location. - diary.update_diary(): erfasst alten GPS-Stand, reichert nach DB-Commit an (async), schreibt nur erfolgreich geholte Felder (kein Datenverlust bei API-Fehler), identische Koordinaten -> kein erneuter Abruf. - Tests: tests/test_diary_location_enrich.py (Anreicherung, kein GPS=kein Abruf, Resave ohne Re-Fetch).
This commit is contained in:
parent
e2219fb8ba
commit
140140f690
8 changed files with 244 additions and 17 deletions
|
|
@ -591,6 +591,13 @@ async def update_diary(dog_id: int, entry_id: int, data: DiaryUpdate,
|
|||
if not exists:
|
||||
raise HTTPException(404, "Eintrag nicht gefunden.")
|
||||
|
||||
# GPS-Stand VOR dem Update merken (für Anreicherungs-Entscheidung unten)
|
||||
old = conn.execute(
|
||||
"SELECT gps_lat, gps_lon FROM diary WHERE id=?", (entry_id,)
|
||||
).fetchone()
|
||||
old_lat = old["gps_lat"] if old else None
|
||||
old_lon = old["gps_lon"] if old else None
|
||||
|
||||
# Felder updaten — location_name/gps_* dürfen explizit auf None gesetzt werden
|
||||
raw = data.model_dump(exclude={"dog_ids"})
|
||||
NULLABLE = {"location_name", "gps_lat", "gps_lon"}
|
||||
|
|
@ -617,6 +624,49 @@ async def update_diary(dog_id: int, entry_id: int, data: DiaryUpdate,
|
|||
dogs_map = _fetch_dog_ids(conn, [entry_id])
|
||||
media_map = _fetch_media_items(conn, [entry_id])
|
||||
|
||||
# Nachträgliche Positionierung: wurde GPS neu gesetzt oder geändert, POIs
|
||||
# (immer) + Wetter fürs Eintragsdatum (historisch korrekt) nachladen —
|
||||
# analog zum Create-Pfad, aber NACH dem DB-Commit (async HTTP).
|
||||
new_lat, new_lon = row["gps_lat"], row["gps_lon"]
|
||||
coords_changed = (
|
||||
old_lat is None or old_lon is None
|
||||
or round(old_lat, 5) != round(new_lat, 5)
|
||||
or round(old_lon, 5) != round(new_lon, 5)
|
||||
) if (new_lat is not None and new_lon is not None) else False
|
||||
|
||||
if coords_changed:
|
||||
weather_json = None
|
||||
poi_json = None
|
||||
# Stunde fürs historische Wetter aus created_at, falls selber Tag wie datum.
|
||||
hour = None
|
||||
ca = row["created_at"]
|
||||
if ca and len(ca) >= 13 and ca[:10] == (row["datum"] or "")[:10]:
|
||||
try: hour = int(ca[11:13])
|
||||
except (ValueError, TypeError): hour = None
|
||||
try:
|
||||
wd = await weather_mod.get_weather_for_date(new_lat, new_lon, row["datum"], hour)
|
||||
weather_json = json.dumps(wd)
|
||||
except Exception as exc:
|
||||
logger.warning("Wetter-Anreicherung beim Diary-Update fehlgeschlagen: %s", exc)
|
||||
try:
|
||||
pois = await _fetch_pois_for_coords(new_lat, new_lon, limit=5)
|
||||
if pois:
|
||||
poi_json = json.dumps(pois)
|
||||
except Exception as exc:
|
||||
logger.warning("POI-Anreicherung beim Diary-Update fehlgeschlagen: %s", exc)
|
||||
|
||||
# Nur erfolgreich geholte Felder schreiben — ein API-Fehler überschreibt
|
||||
# vorhandene Daten nicht (kein Datenverlust).
|
||||
sets, vals = [], []
|
||||
if weather_json is not None:
|
||||
sets.append("weather_json=?"); vals.append(weather_json)
|
||||
if poi_json is not None:
|
||||
sets.append("poi_json=?"); vals.append(poi_json)
|
||||
if sets:
|
||||
with db() as conn:
|
||||
conn.execute(f"UPDATE diary SET {', '.join(sets)} WHERE id=?", vals + [entry_id])
|
||||
row = conn.execute("SELECT * FROM diary WHERE id=?", (entry_id,)).fetchone()
|
||||
|
||||
return _entry_dict(row, dogs_map, media_map)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue