feat: iCloud-Kontaktgruppen synchronisieren und API-Endpunkte hinzufügen

Erkennt iCloud-Gruppen (vCards mit X-ADDRESSBOOKSERVER-KIND:group) beim
CardDAV-Sync und speichert sie separat in den neuen Tabellen groups und
group_members statt als Kontakte in die contacts-Tabelle.

Änderungen:
- sql/schema.sql: Neue Tabellen groups + group_members (FK CASCADE)
- src/vcard_parser.py: is_group_vcard() + parse_group() Funktionen
- src/db.py: DB-Funktionen für Gruppen (upsert, delete, replace, get)
- src/sync.py: _classify_vcards() trennt Gruppen von Kontakten
- src/api/schemas.py: Pydantic-Modelle für Gruppen-Responses
- src/api/main.py: 3 neue Endpunkte (/api/groups, /{id}, /{id}/members)
- src/api/templates/contact.html: Gruppen-Section im Kontakt-Detail
- README.md + SPEC.md: Dokumentation aktualisiert
This commit is contained in:
2026-08-07 15:18:44 +02:00
parent 38b03a2c8a
commit 94a279f207
9 changed files with 369 additions and 38 deletions
+23 -2
View File
@@ -148,6 +148,24 @@ python3 mailer.py
aus MariaDB entfernt, ohne Archiv.
- Nur iCloud als Quelle, Google/Microsoft sind nicht Teil dieses Repos.
## Kontaktruppen
iCloud-Länder speichern Gruppen als eigene vCards mit
`X-ADDRESSBOOKSERVER-KIND:group`. Diese werden beim Sync automatisch
erkannt und separat in den Tabellen `groups` und `group_members`
gespeichert (nicht als Kontakte).
Gruppen sind über die API abrufbar:
- `GET /api/groups` — Alle Gruppen mit Member-Anzahl
- `GET /api/groups/{id}` — Gruppe mit aufgelösten Members
- `GET /api/groups/{id}/members` — Nur Members einer Gruppe
- `GET /api/contacts/{id}` — Enthält `groups`-Feld mit Gruppennamen
Wird ein Kontakt gelöscht, wird die Mitgliedschaft in Gruppen
automatisch entfernt (`ON DELETE CASCADE`). Die Gruppe selbst bleibt
erhalten.
## 11. Web-Ansicht und API (interner Zugriff über Authelia)
Läuft als zweiter Service aus demselben Image, aber mit anderem
@@ -206,13 +224,16 @@ Zugriff ohne den Reverse-Proxy ist damit nicht möglich.
|---------|------|--------------|
| `GET` | `/` | Dashboard mit Kontaktdaten-Übersicht, letzten Sync-Status und Geburtstagen der nächsten 7 Tage (HTML) |
| `GET` | `/search` | Web-UI -- Suchfunktion, zeigt Kontakte des eingeloggten Users |
| `GET` | `/contacts/{id}` | Web-UI -- Detailseite eines einzelnen Kontakts |
| `GET` | `/contacts/{id}` | Web-UI -- Detailseite eines einzelnen Kontakts (inkl. Gruppen) |
| `GET` | `/api/health` | Health Check (`{"status": "ok"}`), kein Login nötig |
| `GET` | `/api/contacts` | Kontaktsuche mit Pagination (`?q=...&limit=...&offset=...`) |
| `GET` | `/api/contacts/{id}` | Einzelnen Kontakt per ID abrufen |
| `GET` | `/api/contacts/{id}` | Einzelnen Kontakt per ID abrufen (inkl. `groups`-Feld) |
| `GET` | `/api/contacts/count` | Anzahl der Kontakte des eingeloggten Users |
| `GET` | `/api/contacts/birthdays/today` | Heutige Geburtstage |
| `GET` | `/api/contacts/birthdays/upcoming` | Geburtstage der nächsten N Tage (`?days=7`, Default 7) |
| `GET` | `/api/groups` | Gruppenliste mit Member-Anzahl |
| `GET` | `/api/groups/{id}` | Einzelne Gruppe mit aufgelösten Members |
| `GET` | `/api/groups/{id}/members` | Members einer Gruppe (Kontaktdaten) |
| `GET` | `/api/sync-runs` | Letzte 50 Sync-Runs (Status, Zeitstempel, Fehler) |
Alle Endpunkte (außer `/api/health`) erfordern eine Authentifizierung