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:
marcandClaude Opus 5 committed 2026-09-05 18:11:25 +02:00
1 parent d7b5c1cd5f
commit 128d54035a
5 files changed
+492 -28

No files matched your search

+26 -18
View File
@@ -41,35 +41,43 @@ anderen.
python3 scripts/caldav-selbsttest.py
39 Prüfungen: Anmeldung (falsches Passwort und **Kontopasswort** werden
45 Prüfungen: Anmeldung (falsches Passwort und **Kontopasswort** werden
abgewiesen – für CalDAV gelten nur App-Passwörter), Auffinden über
`.well-known/caldav` samt der Umleitung, der Clients mit GET folgen,
Kalenderliste mit Anzeigename und Komponenten, PUT/GET/DELETE eines
Termins, `If-Match` (falsches ETag muss 412 geben), `calendar-query` mit
Zeitfenster und `calendar-multiget`, beide Richtungen zwischen Web und
CalDAV (Ganztagstermin als reines Datum mit exklusivem DTEND, Terminfarbe
als CSS3-Name, RRULE, EXDATE), das Umhängen aus Client-Sicht (Datei
verschwindet in der Quelle, taucht im Ziel auf, UID bleibt) und dass ein
fremder Benutzerpfad 404 gibt statt eines leeren 207.
Kalenderliste mit Anzeigename, Komponenten, `getctag` und
`calendar-color`, PUT/GET/DELETE eines Termins, `If-Match` (falsches ETag
muss 412 geben), `calendar-query` mit Zeitfenster und `calendar-multiget`,
beide Richtungen zwischen Web und CalDAV (Ganztagstermin als reines Datum
mit exklusivem DTEND, Terminfarbe als CSS3-Name, RRULE, EXDATE), das
Umhängen aus Client-Sicht (Datei verschwindet in der Quelle, taucht im Ziel
auf, UID bleibt) und dass ein fremder Benutzerpfad 404 gibt statt eines
leeren 207.
Legt sich ein eigenes App-Passwort und zwei eigene Kalender an und räumt
beides am Ende weg; vorhandene Kalender werden nur gelesen.
### Zwei bekannte Lücken, die das Skript als Hinweis meldet
### Zwei Eigenschaften kommen nicht aus der Bibliothek
Beide kommen daher, dass `go-webdav` v0.7.0 nur einen festen Satz
Eigenschaften beantwortet und keinen Haken bietet, um eigene dazuzulegen:
`go-webdav` v0.7.0 beantwortet in PROPFIND einen festen Satz Eigenschaften
und bietet keinen Haken, eigene dazuzulegen. `getctag` (Calendarserver) und
`calendar-color` (Apple) ergänzt Aether deshalb selbst
(`backend/internal/calendar/propfind.go`): Beide werden aus der Anfrage
genommen, bevor go-webdav sie zu sehen bekommt, und der Antwort als eigener
`propstat`-Block wieder angehängt. Ohne das Herausnehmen stünde dieselbe
Eigenschaft zweimal in der Antwort – einmal mit 404, einmal mit 200.
- ⚠️ **`getctag` fehlt** (Antwort 404). Clients können nicht billig fragen
„hat sich etwas geändert?" und listen stattdessen bei jedem Abgleich alle
Termine auf. Der Abgleich bleibt richtig, kostet aber mehr Daten und Akku.
- ⚠️ **`calendar-color` fehlt** (Antwort 404). Der Kalender erscheint im
Client in dessen Vorgabefarbe. **Terminfarben** sind davon nicht
betroffen – die stehen im .ics selbst und kommen an.
Weil das eigener Code ist und nicht Bibliothek, prüft das Skript ihn
besonders: dass beide mit 200 kommen, die Farbe in Apple-Schreibweise
(`#RRGGBBAA`), dass das ctag sich bei jeder Änderung **ändert** (ein
festgefrorenes ctag ist schlimmer als gar keins – der Client fragt einmal
und hält den Kalender danach für unverändert), dass eine Anfrage nach
*nur* diesen Eigenschaften funktioniert (sonst bliebe für go-webdav ein
leeres `<prop>` übrig, das es abweist), und dass ohne Nachfrage auch nichts
davon in der Antwort steht.
Dazu eine Ungenauigkeit ohne Folgen: Ein PUT, das einen vorhandenen Termin
überschreibt, antwortet mit `201 Created` statt `204 No Content`. Das kommt
ebenfalls aus go-webdav; Clients prüfen auf 2xx.
aus go-webdav; Clients prüfen auf 2xx.
## Notfall: Migration hängt fest ("Dirty database version")