From 73673258199b353f9b3e04da9b37ae95077e2c8b Mon Sep 17 00:00:00 2001 From: Ernest Hysa <59969602+ErnestHysa@users.noreply.github.com> Date: Fri, 5 Jun 2026 14:12:54 +0100 Subject: [PATCH] fix(caldav): include owner in calendar ID hash to prevent PK collision (#2765) _stable_cal_id hashed only the remote URL, producing the same calendar ID for all users syncing the same CalDAV endpoint. The second user would get an IntegrityError on the primary key. Now includes owner in the hash so each user gets a distinct calendar row. --- src/caldav_sync.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/caldav_sync.py b/src/caldav_sync.py index 663c0bd59..f875b7c89 100644 --- a/src/caldav_sync.py +++ b/src/caldav_sync.py @@ -86,10 +86,12 @@ def validate_caldav_url(raw_url: str) -> str: return urlunparse(parsed._replace(fragment="")).rstrip("/") -def _stable_cal_id(remote_url: str) -> str: +def _stable_cal_id(remote_url: str, owner: str = "") -> str: """Deterministic local id for a remote CalDAV calendar — same URL - always maps to the same local row across restarts and re-syncs.""" - h = hashlib.sha256(remote_url.encode("utf-8")).hexdigest()[:24] + always maps to the same local row across restarts and re-syncs. + Owner is included in the hash to prevent PK collisions when multiple + users sync the same CalDAV endpoint.""" + h = hashlib.sha256(f"{owner}:{remote_url}".encode("utf-8")).hexdigest()[:24] return f"caldav-{h}" @@ -170,7 +172,7 @@ def _sync_blocking(owner: str, url: str, username: str, password: str) -> dict: for remote_cal in calendars: try: remote_url = str(remote_cal.url) - cal_id = _stable_cal_id(remote_url) + cal_id = _stable_cal_id(remote_url, owner) display_name = (remote_cal.name or "").strip() or "CalDAV" local_cal = db.query(CalendarCal).filter(