mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-16 17:55:26 -04:00
fix(caldav): don't prune locally-created events on sync (#2706)
The CalDAV pull prunes events in the synced calendar+window whose UID the server didn't just return, to propagate upstream deletions. But CalendarEvent had no field distinguishing a server-pulled row from a locally-created one, so the prune also deleted events that were never on the server: events created by the agent / email triage (which never write back to the server) and UI events whose best-effort write-back failed. Result: silent, unrecoverable loss of the user's appointments (hard db.delete, no soft-delete). Add an 'origin' column to calendar_events (lightweight idempotent migration, mirroring _migrate_add_calendar_is_utc), set origin='caldav' on rows the sync inserts/updates, and gate the prune on origin == 'caldav'. Locally-created events carry origin NULL and are never pruned. On the first sync after the migration nothing is pruned (all rows NULL until re-marked), erring toward keeping data. Fixes #2704
This commit is contained in:
@@ -265,6 +265,7 @@ def _sync_blocking(owner: str, url: str, username: str, password: str) -> dict:
|
||||
existing.all_day = all_day
|
||||
existing.is_utc = row_is_utc
|
||||
existing.rrule = rrule
|
||||
existing.origin = "caldav"
|
||||
else:
|
||||
new_ev = CalendarEvent(
|
||||
uid=uid_val,
|
||||
@@ -277,6 +278,7 @@ def _sync_blocking(owner: str, url: str, username: str, password: str) -> dict:
|
||||
all_day=all_day,
|
||||
is_utc=row_is_utc,
|
||||
rrule=rrule,
|
||||
origin="caldav",
|
||||
)
|
||||
db.add(new_ev)
|
||||
pending[uid_val] = new_ev
|
||||
@@ -286,8 +288,13 @@ def _sync_blocking(owner: str, url: str, username: str, password: str) -> dict:
|
||||
# Prune locally-cached CalDAV events that vanished
|
||||
# upstream (only within our sync window — events outside
|
||||
# the window aren't in `objs`, so we'd false-delete them).
|
||||
# Only rows we previously pulled from the server (origin=="caldav")
|
||||
# are prunable; locally-created events (agent / email triage / a
|
||||
# UI event whose write-back failed) carry origin NULL and must
|
||||
# never be deleted just because the server didn't return them.
|
||||
stale = db.query(CalendarEvent).filter(
|
||||
CalendarEvent.calendar_id == local_cal.id,
|
||||
CalendarEvent.origin == "caldav",
|
||||
CalendarEvent.dtstart >= start,
|
||||
CalendarEvent.dtstart <= end,
|
||||
~CalendarEvent.uid.in_(seen_uids) if seen_uids else CalendarEvent.uid.isnot(None),
|
||||
|
||||
Reference in New Issue
Block a user