fix: Import-500 bei doppelten UIDs, Picker-UI & Settings-URL-State

- Import: Dedupe doppelter UIDs innerhalb der Datei (Nextcloud exportiert
  wiederkehrende Termine als mehrere VEVENTs gleicher UID) -> kein
  UNIQUE-constraint-500 mehr; Commit abgesichert. Test ergaenzt (15 gruen).
- Picker (Gruppen-Sichtbarkeit + Mitglieder): als <div>-Zeilen statt <label>,
  damit die globale ".form-group label"-Uppercase/Grau-Regel das Layout nicht
  mehr zerschiesst. Saubere .pick-row-Optik (Checkbox/Radio links, Name links).
- Einstellungen haben jetzt eigenen URL-State (#...&settings=1): Reload/Cache-
  leeren bleibt in den Einstellungen statt zur Kalenderansicht zu springen.
- Version v27.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-05-31 17:15:17 +02:00
parent 8abeefcb5a
commit c7185a128e
5 changed files with 133 additions and 25 deletions

View File

@@ -386,8 +386,17 @@ def _import_ics_into(cal: models.LocalCalendar, raw: bytes, db: Session) -> dict
parsed = ical_io.parse_ics(raw)
imported = 0
skipped = 0
errors = list(parsed["errors"])
# local_events.uid is globally unique. Dedupe against the DB AND within this
# file — e.g. Nextcloud exports recurring events as several VEVENTs sharing a
# UID (RECURRENCE-ID overrides), which would otherwise violate the constraint.
seen_uids: set[str] = set()
for item in parsed["events"]:
uid = item.get("uid") or str(uuid.uuid4())
if uid in seen_uids:
skipped += 1
continue
seen_uids.add(uid)
existing = db.query(models.LocalEvent).filter(models.LocalEvent.uid == uid).first()
if existing:
skipped += 1
@@ -407,8 +416,12 @@ def _import_ics_into(cal: models.LocalCalendar, raw: bytes, db: Session) -> dict
)
db.add(ev)
imported += 1
db.commit()
return {"imported": imported, "skipped": skipped, "errors": parsed["errors"]}
try:
db.commit()
except Exception as exc:
db.rollback()
raise ValueError(f"Import fehlgeschlagen: {exc}")
return {"imported": imported, "skipped": skipped, "errors": errors}
@router.post("/calendars/{calendar_id}/import")