feat(calendar): getctag und calendar-color fuer CalDAV-Clients
Beide Eigenschaften fragt jeder verbreitete Client ab, und beide kennt
go-webdav v0.7.0 nicht:
getctag die billige Frage "hat sich in diesem Kalender etwas
geaendert?". Ohne sie laedt ein Client bei jedem
Abgleich die Liste aller Termine herunter, um sie zu
vergleichen -- richtig, aber teuer an Daten und Akku.
calendar-color die Farbe des Kalenders. Ohne sie zeigt das Telefon
ihn in seiner eigenen Vorgabefarbe, und die Farbgebung
dort hat mit der in der Cloud nichts mehr zu tun.
Die Bibliothek beantwortet einen festen Satz Eigenschaften und bietet
keinen Haken, eigene dazuzulegen (server.go, propFindCalendar). Deshalb
faengt der Handler PROPFIND jetzt ab: Er nimmt die beiden aus der
Anfrage heraus, bevor go-webdav sie zu sehen bekommt, und haengt sie der
Antwort als eigenen propstat-Block wieder an.
Das Herausnehmen ist der Punkt, an dem es sonst schiefgeht: Ohne das
meldet go-webdav sie als "nicht gefunden", und dieselbe Eigenschaft
stuende zweimal in derselben Antwort -- einmal mit 404, einmal mit 200.
Was ein Client daraus macht, ist Gluecksache.
Zwei Fallen dabei, beide abgedeckt: Fragt ein Client *nur* nach diesen
Eigenschaften, bliebe ein leeres <prop> uebrig, das go-webdav abweist --
dann schiebt Aether resourcetype als Platzhalter unter. Und die Farbe
geht als #RRGGBBAA hinaus, mit Alpha-Anteil, weil manche Clients sie
sonst gar nicht anzeigen.
Der Neuaufbau des Anfragerumpfs ist verlustfrei, weil in einem PROPFIND
ausschliesslich leere Elemente stehen: Name und Namensraum sind alles,
was eine Eigenschaft dort ausmacht.
Unit-Tests fuer die XML-Arbeit (propfind_test.go), CalDAV-Selbsttest von
39 auf 45 Pruefungen: beide Eigenschaften mit 200, Apple-Schreibweise,
ctag aendert sich bei Aenderungen (ein festgefrorenes ctag ist schlimmer
als gar keins), Anfrage nur nach ihnen, Farben in der Kalenderliste, und
ohne Nachfrage kommt auch nichts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d7b5c1cd5f
commit
128d54035a
5 files changed
+492
-28
No files matched your search
@@ -185,15 +185,49 @@ try:
|
||||
return int(m.group(1)) if m else 0
|
||||
return 0
|
||||
|
||||
check("ctag oder calendar-color werden überhaupt gemeldet",
|
||||
prop_status(x, "getctag") or prop_status(x, "calendar-color"), x[:200])
|
||||
if prop_status(x, "getctag") != 200:
|
||||
hinweis("getctag fehlt (404) – Clients können nicht billig fragen "
|
||||
"\u201ehat sich etwas ge\u00e4ndert?\u201c und listen stattdessen jedes "
|
||||
"Mal alle Termine auf. Abgleich bleibt richtig, kostet aber mehr.")
|
||||
if prop_status(x, "calendar-color") != 200:
|
||||
hinweis("calendar-color fehlt (404) – die Farbe des Kalenders erscheint im "
|
||||
"Client in dessen Vorgabefarbe. Terminfarben sind davon nicht betroffen.")
|
||||
def wert(xml_text, prop):
|
||||
m = re.search(rf"<{prop}[^>]*>([^<]*)</{prop}>", xml_text)
|
||||
return m.group(1) if m else None
|
||||
|
||||
# Diese beiden kennt go-webdav nicht; Aether ergänzt sie selbst
|
||||
# (backend/internal/calendar/propfind.go). Genau deshalb gehören sie
|
||||
# geprüft: Sie hängen an eigenem Code, nicht an der Bibliothek.
|
||||
check("getctag wird geliefert (200)", prop_status(x, "getctag") == 200,
|
||||
prop_status(x, "getctag"))
|
||||
check("calendar-color wird geliefert (200)", prop_status(x, "calendar-color") == 200,
|
||||
prop_status(x, "calendar-color"))
|
||||
check("Farbe in Apple-Schreibweise #RRGGBBAA",
|
||||
wert(x, "calendar-color") == "#A142F4FF", wert(x, "calendar-color"))
|
||||
|
||||
# Ein ctag, das sich nicht ändert, ist schlimmer als gar keins: Der
|
||||
# Client fragt einmal und hält den Kalender danach für unverändert.
|
||||
vor = wert(x, "getctag")
|
||||
st_, tmp = api("POST", f"/api/v1/calendars/{CAL}/events",
|
||||
{"summary": "ctag-Probe", "start": "2026-12-01T09:00:00Z",
|
||||
"end": "2026-12-01T10:00:00Z", "all_day": False}, CSRF)
|
||||
_, _, x2 = propfind(CAL_PFAD, "<cs:getctag/>")
|
||||
check("ctag ändert sich, wenn sich etwas ändert", wert(x2, "getctag") != vor,
|
||||
f"{vor} -> {wert(x2, 'getctag')}")
|
||||
api("DELETE", f"/api/v1/calendars/{CAL}/events/{tmp['uid']}", None, CSRF)
|
||||
|
||||
# Fragt ein Client *nur* danach, bliebe für go-webdav ein leeres <prop>
|
||||
# übrig – das weist es ab. Aether schiebt dann einen Platzhalter unter.
|
||||
_, _, x3 = propfind(CAL_PFAD, "<cs:getctag/>")
|
||||
check("Anfrage nur nach getctag funktioniert", prop_status(x3, "getctag") == 200,
|
||||
x3[:200])
|
||||
|
||||
# In der Übersicht (Depth 1 auf das Home-Set) muss jeder Kalender seine
|
||||
# eigene Farbe tragen – dort holt sich ein Client sie beim Einrichten.
|
||||
_, _, x4 = propfind(HOME, "<d:displayname/><i:calendar-color/>", depth="1")
|
||||
farben = re.findall(r"<calendar-color[^>]*>([^<]*)</calendar-color>", x4)
|
||||
check("Kalenderliste trägt die Farben", "#A142F4FF" in farben and "#34A853FF" in farben,
|
||||
farben)
|
||||
|
||||
# Und eine Anfrage, in der nichts davon vorkommt, darf auch nichts davon
|
||||
# zurückbekommen – sonst antwortete der Server auf ungestellte Fragen.
|
||||
_, _, x5 = propfind(CAL_PFAD, "<d:displayname/>")
|
||||
check("ohne Nachfrage keine Zusatz-Eigenschaften",
|
||||
"getctag" not in x5 and "calendar-color" not in x5, x5[:200])
|
||||
|
||||
# ── Termine schreiben und lesen wie ein Client ──────────────────────
|
||||
print("\n── Termin anlegen, ändern, löschen (PUT/GET/DELETE) ──")
|
||||
|
||||
Reference in new issue
Block a user