iOS-Voll-App M0: Media-Registry (iCloud-Hybrid) — Originale in Nutzer-CloudKit, Server nur Previews: POST/PATCH/GET /api/media (register/confirm/mine/original-Fallback), Phantom-URL+iCloud-404 in serve_media, Registry-Cleanup in Delete-Pfaden, media_items mit storage+ck_record_name; Datenschutz v5 (CloudKit); Fixes: daily_photo_cache in zentrale Migration (Löschen warf auf frischer DB 500), Preview/Thumb-Leichen beim Medium-Löschen; 9 neue Tests, Suite 73 grün
This commit is contained in:
parent
40d117874b
commit
bf5df11f78
7 changed files with 565 additions and 3 deletions
|
|
@ -122,9 +122,14 @@ def _fetch_media_items(conn, entry_ids: list[int]) -> dict:
|
|||
if not entry_ids:
|
||||
return {}
|
||||
ph = ",".join("?" * len(entry_ids))
|
||||
# LEFT JOIN media_registry: iCloud-Hybrid-Medien tragen storage='icloud' +
|
||||
# ck_record_name — die iOS-App holt das Original dann aus CloudKit statt
|
||||
# von der (Phantom-)URL. Server-Medien: storage NULL/'server'.
|
||||
rows = conn.execute(
|
||||
f"SELECT id, diary_id, url, media_type, sort_order, is_cover FROM diary_media "
|
||||
f"WHERE diary_id IN ({ph}) ORDER BY diary_id, sort_order",
|
||||
f"SELECT dm.id, dm.diary_id, dm.url, dm.media_type, dm.sort_order, dm.is_cover, "
|
||||
f" mr.storage AS storage, mr.ck_record_name AS ck_record_name "
|
||||
f"FROM diary_media dm LEFT JOIN media_registry mr ON mr.url = dm.url "
|
||||
f"WHERE dm.diary_id IN ({ph}) ORDER BY dm.diary_id, dm.sort_order",
|
||||
entry_ids
|
||||
).fetchall()
|
||||
result = {}
|
||||
|
|
@ -135,6 +140,8 @@ def _fetch_media_items(conn, entry_ids: list[int]) -> dict:
|
|||
"preview_url": preview_url_from(url),
|
||||
"media_type": r["media_type"], "sort_order": r["sort_order"],
|
||||
"is_cover": r["is_cover"],
|
||||
"storage": r["storage"] or "server",
|
||||
"ck_record_name": r["ck_record_name"],
|
||||
})
|
||||
return result
|
||||
|
||||
|
|
@ -634,6 +641,9 @@ async def delete_diary(dog_id: int, entry_id: int, user=Depends(get_current_user
|
|||
).fetchall()]
|
||||
for u in media_urls:
|
||||
conn.execute("DELETE FROM daily_photo_cache WHERE photo_url=?", (u,))
|
||||
# iCloud-Hybrid: Registry-Row mitlöschen — der nächste App-Sync
|
||||
# (GET /api/media/mine) räumt dann den verwaisten CKRecord ab.
|
||||
conn.execute("DELETE FROM media_registry WHERE url=?", (u,))
|
||||
conn.execute(
|
||||
"DELETE FROM diary WHERE id=? AND dog_id=?", (entry_id, dog_id)
|
||||
)
|
||||
|
|
@ -792,9 +802,16 @@ async def delete_media_item(dog_id: int, entry_id: int, media_id: int,
|
|||
if file_path:
|
||||
try: os.remove(file_path)
|
||||
except OSError: pass
|
||||
# Preview/Thumb mit-entfernen — bei iCloud-Medien die einzige
|
||||
# Server-Datei, bei Server-Medien lagen sie bisher als Leichen herum.
|
||||
base = os.path.splitext(file_path)[0]
|
||||
for leftover in (base + "_preview.webp", base + "_thumb.jpg"):
|
||||
try: os.remove(leftover)
|
||||
except OSError: pass
|
||||
# daily_photo_cache mit-bereinigen falls das Bild als Tagesfoto
|
||||
# gewählt war (sonst lädt der Client 404).
|
||||
conn.execute("DELETE FROM daily_photo_cache WHERE photo_url=?", (row["url"],))
|
||||
conn.execute("DELETE FROM media_registry WHERE url=?", (row["url"],))
|
||||
conn.execute("DELETE FROM diary_media WHERE id=?", (media_id,))
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue