From fbf10197d72a1de77ad4ac01d0329bd7a1865d3f Mon Sep 17 00:00:00 2001 From: Stefan Hacker Date: Sun, 12 Apr 2026 14:31:53 +0200 Subject: [PATCH] fix: CalDAV calendar-query liefert nur angefragte Props Bisher wurde immer die komplette calendar-data mitgeschickt, auch wenn der Client nur getetag wollte. DAVx5 macht einen zweistufigen Sync: erst calendar-query nach ETags, dann multiget fuer die neuen/geaenderten Events. Server-seitig zu viel zu liefern bricht diesen Ablauf - Client denkt er hat alles und ueberspringt die zweite Stufe, aber die Events landen nicht in der Android-Kalender- DB. Jetzt: calendar-query schaut nach ob in den angefragten Props steht und liefert entsprechend. calendar-multiget liefert weiterhin immer die vollen Daten. Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/app/dav/caldav.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/backend/app/dav/caldav.py b/backend/app/dav/caldav.py index 7ba0de9..e79d185 100644 --- a/backend/app/dav/caldav.py +++ b/backend/app/dav/caldav.py @@ -333,6 +333,11 @@ def report(subpath): multistatus = ET.Element(_qn('d', 'multistatus')) tag = root.tag + # Prüfen ob der Client calendar-data angefragt hat. Falls nicht, + # liefern wir es auch nicht mit - strikter nach RFC und DAVx5 + # entscheidet dann sauber "ich brauche Phase 2: multiget". + wants_data = root.find(f".//{_qn('c', 'calendar-data')}") is not None + if tag == _qn('c', 'calendar-multiget'): hrefs = [h.text for h in root.findall(_qn('d', 'href')) if h.text] for href in hrefs: @@ -343,8 +348,6 @@ def report(subpath): return _xml_response(multistatus) if tag == _qn('c', 'calendar-query'): - # Parse optional time-range. start ohne end = "ab jetzt offen"; - # end ohne start = "bis X"; beide None = kein Filter. start, end = _extract_time_range(root) q = CalendarEvent.query.filter_by(calendar_id=cal.id) if end is not None: @@ -355,7 +358,7 @@ def report(subpath): | (CalendarEvent.recurrence_rule.isnot(None)) ) for ev in q.all(): - multistatus.append(_event_response(user, cal, ev, include_data=True)) + multistatus.append(_event_response(user, cal, ev, include_data=wants_data)) return _xml_response(multistatus) # Unknown report - return empty multistatus so clients don't break