mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-07-02 01:22:07 -04:00
fix(calendar): keep imported events with non-positive duration visible (#4484)
A single-day all-day event whose source writes DTEND equal to DTSTART (treating DTEND as an inclusive bound rather than the RFC 5545 exclusive one) was stored verbatim as a zero-duration row. list_events selects events overlapping the window with `dtstart < end AND dtend > start`, so that row is filtered out for any window starting at or after its date and the event never appears, even though the import reported success. Events created via the API never hit this because creation always synthesizes a positive duration; only the two import paths can persist a non-positive one. Clamp a non-positive end at import (import_ics and the CalDAV pull) to the same default span used when DTEND is absent: one day for all-day events, one hour otherwise. Also repair the persisted state for users who already imported before this clamp existed. Their stored zero-duration row is invisible, and re-importing the same ICS hit the duplicate branch and skipped without touching it, so the event stayed hidden. The duplicate branch now backfills the clamp onto the matched row before skipping, and the response reports a `repaired` count. (The CalDAV pull already rewrites dtend on re-sync, so it self-heals.)
This commit is contained in:
@@ -274,6 +274,7 @@ def _sync_blocking(owner: str, url: str, username: str, password: str, account_i
|
||||
# the integrations form still works, sync just no-ops with an error.
|
||||
from caldav.lib.error import AuthorizationError, NotFoundError
|
||||
from core.database import CalendarCal, CalendarEvent, SessionLocal
|
||||
from routes.calendar_routes import _ensure_positive_duration
|
||||
|
||||
result = {"calendars": 0, "events": 0, "deleted": 0, "errors": []}
|
||||
|
||||
@@ -390,6 +391,11 @@ def _sync_blocking(owner: str, url: str, username: str, password: str, account_i
|
||||
end_dt = start_dt + timedelta(days=1)
|
||||
else:
|
||||
end_dt = start_dt + timedelta(hours=1)
|
||||
# A synced event with DTEND <= DTSTART (e.g. a single-day
|
||||
# all-day event whose source wrote DTEND equal to DTSTART)
|
||||
# would be stored zero-duration and silently dropped by the
|
||||
# list_events overlap filter. Clamp to a positive span.
|
||||
end_dt = _ensure_positive_duration(start_dt, end_dt, all_day)
|
||||
|
||||
# is_utc reflects whether the source carried a TZ
|
||||
# we converted from. All-day = no TZ semantics.
|
||||
|
||||
Reference in New Issue
Block a user