feat: Serientermin-Bearbeitung: Nur diesen Termin oder Serie

Klick auf einen wiederkehrenden Termin oeffnet zuerst einen Dialog:
"Nur diesen Termin" oder "Ganze Serie".

* Serie: bearbeitet den Master wie bisher
* Nur dieser: fuegt EXDATE fuer das geklickte Datum zum Master
  hinzu und legt einen eigenstaendigen Ersatz-Termin mit den
  bearbeiteten Daten an

Backend:
* CalendarEvent.exdates speichert Ausnahmedaten kommasepariert
* POST /events/<id>/exception fuegt EXDATE hinzu, erstellt
  optional das Replacement-Event mit frischer UID
* _build_vevent schreibt jetzt EXDATE-Zeilen in die ical_data,
  sodass CalDAV-Clients die Ausnahmen auch sehen werden

Frontend:
* FullCalendar rrule-Plugin bekommt die exdate-Liste und blendet
  die uebersprungenen Tage aus
* Drag & Drop verschiebt weiterhin die ganze Serie (Shortcut -
  fuer Einzelverschiebung Termin anklicken und bearbeiten)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker
2026-04-12 12:41:35 +02:00
parent ddd8f57e69
commit c1b05e2525
3 changed files with 165 additions and 7 deletions
+2
View File
@@ -49,6 +49,7 @@ class CalendarEvent(db.Model):
dtend = db.Column(db.DateTime, nullable=True)
all_day = db.Column(db.Boolean, default=False)
recurrence_rule = db.Column(db.Text, nullable=True)
exdates = db.Column(db.Text, nullable=True) # Komma-separiert, ISO-Datum (YYYY-MM-DD)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc),
onupdate=lambda: datetime.now(timezone.utc))
@@ -65,6 +66,7 @@ class CalendarEvent(db.Model):
'dtend': self.dtend.isoformat() if self.dtend else None,
'all_day': self.all_day,
'recurrence_rule': self.recurrence_rule,
'exdates': self.exdates.split(',') if self.exdates else [],
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
}