feat(calendar): Kalender an Nutzer und Gruppen freigeben

Nicht als eigene Tabelle, wie im Plan vorgesehen: acl_entries beantwortet
fuer Ordner und Dateien laengst dieselbe Frage -- wer darf was, direkt oder
ueber eine Gruppe. Ein zweites Rechtesystem daneben waere eine zweite
Antwort auf dieselbe Frage, mit eigener Gruppenaufloesung, eigenem
Widerruf, eigenem Pruefpfad; die Luecke dazwischen faellt erst auf, wenn
jemand sieht, was er nicht sehen soll. Migration 25 haengt deshalb nur eine
dritte Ressourcenspalte an.

Der Gewinn: Freigeben an eine **Gruppe** kostete keine Zeile extra.

Drei Entscheidungen, die nicht offensichtlich waren:

* Ein fremder Kalender steht immer unter seiner UUID, nie unter dem
  Pfadsegment des Eigentuemers -- das hat der sich ausgesucht, und zwei
  Leute duerfen denselben Namen waehlen. Sonst laegen im Kalenderbestand
  des Empfaengers zwei Kalender auf derselben Adresse.
* Alle Wege laufen durch RequireCalendar. CalDAV und Weboberflaeche sind
  zwei getrennte Zugaenge zu denselben Daten; ein Recht, das nur einer von
  beiden prueft, ist kein Recht. Im CalDAV-Teil genuegte, resolveCalendar
  umzustellen -- dort kommt jede Operation vorbei.
* Wer ein Recht geliehen hat, darf es nicht weiterverleihen: Umbenennen,
  Loeschen und Freigeben bleiben auch mit Schreibrecht beim Eigentuemer.

Oberflaeche: fremde Kalender tragen Eigentuemer und "(nur lesen)", das
Menue zeigt nur, was auch geht, und ein Termin laesst sich gar nicht erst
in einen Kalender ziehen, den der Server danach ablehnen wuerde.

scripts/kalender-teilen-selbsttest.py, 41 Pruefungen, jede ueber beide
Zugaenge. Er beginnt damit, dass der Empfaenger vorher nichts sieht --
ohne diesen Anfang beweist der Rest nichts.

Dabei hatte der Test selbst eine Falle: Mit festem Testdatum lief die
Terminliste aus ihrem Standardzeitraum, und die Pruefung "beim Eigentuemer
ist nichts angekommen" bestand **leer**.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-09-12 13:46:18 +02:00
1 parent 8fdde182b7
commit 5d90c0a2d2
21 files changed
+1031 -60

No files matched your search

+30 -5
View File
@@ -86,7 +86,7 @@ Die abgeleiteten Spalten sind nur zum Vorsortieren da.
| **1** | CalDAV lesend und schreibend, ein Kalender, Anmeldung über App-Passwörter, Auffindpfade (`/.well-known/caldav`, `current-user-principal`, `calendar-home-set`). Ziel: DAVx5 gleicht ab. | ✅ |
| **2** | Mehrere Kalender, Farbe, Umbenennen, Löschen. Export als `.ics`, Import einer bestehenden Datei. | ✅ |
| **3** | Weboberfläche in Aether: Monat, Woche, Liste; Termin anlegen, ändern, löschen. Der Teil, der Spaß macht – und dessen Fehler man **sieht**. | ✅ |
| **4** | `sync-collection` ✅, Aufgabenansicht, Teilen mit anderen Nutzern, öffentlicher Abo-Link, Kalender in der HoneyOS-Leiste. | läuft |
| **4** | `sync-collection` ✅, Teilen mit anderen Nutzern ✅, Aufgabenansicht (vertagt), öffentlicher Abo-Link, Kalender in der HoneyOS-Leiste. | läuft |
| **5** | Kontakte (CardDAV). Dieselbe Maschinerie, dieselbe Bibliothek – und **einfacher**, weil es dort keine Wiederholungen gibt. | später entscheiden |
Über die Phasen hinaus dazugekommen, weil es sich beim Prüfen als nötig
@@ -162,10 +162,35 @@ Fall, auf den es ankommt: *ohne Änderung kommt nichts zurück*.
1. **Derselbe Kalender auf mehreren Geräten.** Das ist der Sinn der Sache und
ab Phase 1 da.
2. **Ein Kalender, den ein anderer Nutzer sieht** – lesend oder schreibend, wie
das Teilen in Nextcloud. Geht, und es ist keine Protokollarbeit: Wir kennen
unsere Nutzer und unsere Kalender, also ist es eine Tabelle
(`kalender × nutzer × recht`) und eine Bedingung in `ListCalendars`. Der
Client sieht danach schlicht einen Kalender mehr in seiner Liste. **Phase 4.**
das Teilen in Nextcloud. ✅ **12.09.2026.**
Gebaut wurde es **nicht** als eigene Tabelle, wie hier ursprünglich geplant.
`acl_entries` beantwortet für Ordner und Dateien längst genau diese Frage –
wer darf was, direkt oder über eine Gruppe. Ein zweites Rechtesystem daneben
hieße zwei Antworten auf dieselbe Frage, mit eigener Gruppenauflösung,
eigenem Widerruf, eigenem Prüfpfad; die Lücke dazwischen fällt erst auf,
wenn jemand sieht, was er nicht sehen soll. Migration 25 hängt deshalb nur
eine dritte Ressourcenspalte an (`resource_calendar_id`).
Der Gewinn dabei: **Freigeben an eine Gruppe kostete keine Zeile extra.**
Drei Entscheidungen, die nicht offensichtlich waren:
* **Ein fremder Kalender steht immer unter seiner UUID**, nie unter dem
Pfadsegment des Eigentümers. Das Segment hat sich der Eigentümer
ausgesucht („…/arbeit/"), und zwei Leute dürfen denselben Namen wählen –
im Kalenderbestand des Empfängers lägen dann zwei Kalender auf derselben
Adresse (`Access.Ref`).
* **Alle Wege laufen durch `RequireCalendar`.** CalDAV und die
Weboberfläche sind zwei getrennte Zugänge zu denselben Daten; ein Recht,
das nur einer von beiden prüft, ist kein Recht. Im CalDAV-Teil genügte
dafür, `resolveCalendar` umzustellen – dort kommt jede Operation vorbei.
* **Wer ein Recht geliehen hat, darf es nicht weiterverleihen.** Auch mit
Schreibrecht bleiben Umbenennen, Löschen und Freigeben beim Eigentümer.
Geprüft in `scripts/kalender-teilen-selbsttest.py` (41 Prüfungen), und zwar
jede über **beide** Zugänge. Der Test beginnt damit, dass der Empfänger
vorher nichts sieht – ohne diesen Anfang beweist der Rest nichts.
3. **Ein Kalender an der Adresse eines Links**, den jemand ohne Konto
abonnieren kann – nur lesend, wie ein Freigabelink für Dateien. Klein, und
Aether hat die Freigabelinks schon. **Phase 4.**