list_calendars only kept PROPFIND responses whose resourcetype was
<c:calendar>, so external subscriptions (webcal/ICS feeds) — exposed by
Nextcloud as <cs:subscribed> collections — were silently dropped and never
appeared in nc_calendar_list_calendars (issue #830).
- Construct the calendar DAV client with `X-NC-CalDAV-Webcal-Caching: On` so
Nextcloud exposes subscriptions as queryable CachedSubscription calendars,
making their events readable through the existing event/search tools (the
same mechanism Evolution/KDE desktop clients use).
- In list_calendars, override that header to "Off" so subscriptions are
returned as cs:subscribed collections with their cs:source href, then parse
responses whose resourcetype is c:calendar OR cs:subscribed. Subscriptions
are reported with read_only=True and their source feed URL; their color is
read from the Apple iCal namespace as a fallback.
- Send the custom PROPFIND markup via `body=` instead of `props=`: under
caldav 3.x `props=` expects a list of property names and discards a raw XML
string, producing an empty <prop/>. This also restores display_name,
description and color which were previously falling back to defaults.
- Add `read_only` and `source` fields to the Calendar model.
Adds unit tests for subscription parsing, the body/header wiring, and the
webcal-caching header; extends the integration test to assert the new fields.
The CalDAV REPORT in `_search_events_by_date` unconditionally requested
server-side `<C:expand>`. Per RFC 4791 §9.6.5 the server then normalizes
every expanded DTSTART/DTEND to UTC `Z`, which destroyed two pieces of
information on the read path:
- RFC 5545 floating local times came back as fake-UTC (a `+00:00` suffix
that did not match the stored value), so a 2:30 PM floating event was
indistinguishable from a 14:30 UTC event in the MCP response.
- TZID-bound events lost their IANA TZID context — a "10am America/New_York"
event came back as `14:00:00+00:00`, making it impossible for callers to
reconstruct DST-aware recurrence semantics.
Replace `<C:expand>` with client-side recurrence expansion via the
`recurring-ical-events` library (promoted from transitive to direct dep),
so the wire response retains its original DTSTART format. Surface the
TZID parameter as new `start_tz`/`end_tz` fields on `CalendarEventSummary`.
Add an optional `timezone` (IANA name) parameter to `nc_calendar_create_event`
and `nc_calendar_update_event` so callers can pin a TZID for naive input;
the helper attaches `ZoneInfo(...)` and emits a paired `VTIMEZONE`
component. Naive input without `timezone` continues to store as RFC 5545
floating local time (with a warning logged). Offset-aware input continues
to store as UTC `Z`.
Drive-by: switch the update path's DTSTART/DTEND assignment from raw
`datetime` to `vDDDTypes(dt)` wrappers — the previous code produced invalid
iCal like `DTSTART:2026-05-14 10:00:00+00:00` for any TZ-aware update.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restore contact email/birthday/nickname data and per-event calendar
source that were silently dropped during response model wrapping.
Remove dead elif branches in OAuth deck tests, add regression tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>