Add CalDAV time-range filtering with server-side query support - #1
Closed
thoscut wants to merge 1 commit into
Closed
Add CalDAV time-range filtering with server-side query support#1thoscut wants to merge 1 commit into
thoscut wants to merge 1 commit into
Conversation
…-query The range parameter of CalDavClient::list_events was bound as _range and never used: the client always fetched every resource in the calendar, so the start/end parameters of the list_events tool had no effect on any server, contradicting the docs. list_events now issues a CalDAV calendar-query REPORT (RFC 4791) with a time-range filter nested inside comp-filter VCALENDAR > VEVENT — the only placement Nextcloud and other servers honor — and then fetches only the matching resources via calendar-multiget. Range bounds are parsed from ISO 8601 (offset, naive, or date-only) and serialized as UTC with a trailing Z (e.g. 20260101T000000Z) as the spec requires; naive inputs are treated as UTC. When range is None, behavior is unchanged. Date/time handling uses the time crate through a new re-export from moltis-agents (which already depends on it), so no new direct dependency or lockfile change is needed. The mock client applies equivalent client-side overlap filtering (new time_filter module) so tests exercise the range semantics: events fully outside the range are dropped, boundary-overlapping events are kept, all-day events span a full day, and events without DTEND are treated as instantaneous. A unit test also asserts the generated REPORT XML nests time-range under VCALENDAR > VEVENT with UTC Z timestamps. Claude-Session: https://claude.ai/code/session_012UDpqLhTib2oMkPj2roqaB
Owner
Author
|
Superseded by the upstream PR: moltis-org#1147 (same branch, Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements server-side time-range filtering for CalDAV event queries. The
rangeparameter ofCalDavClient::list_eventswas previously bound as_rangeand ignored — thestart/endparameters of thelist_eventstool had no effect on any server, contradicting the docs.list_eventsnow converts ISO 8601 date/time strings to iCalendar UTC basic format and issues an RFC 4791calendar-queryREPORT with atime-rangeelement to fetch only events intersecting the requested window.Key Changes
time_filtermodule (crates/caldav/src/time_filter.rs):to_ical_utc(): Converts ISO 8601 strings (offset, naive, or date-only) to iCalendar UTC basic format (YYYYMMDDTHHMMSSZ)event_overlaps()/filter_events(): Client-side overlap filtering used by the mock client so tests exercise the range semanticsLibDavCalDavClient::list_events(crates/caldav/src/client.rs):TimeRange, performs a server-sidecalendar-queryREPORT with thetime-rangefilter nested insidecomp-filter VCALENDAR > VEVENT(the only placement Nextcloud and other servers honor), then fetches only matching resources viacalendar-multigetbuild_time_range_query()helper constructs the properly-nested RFC 4791 queryrange = Nonebehavior unchanged (all events returned); public trait signature unchangedMockCalDavClient::list_events(crates/caldav/src/tool.rs): applies the same range filtering; new test suite for boundary overlaps, all-day events, missing DTEND, andNonerangecrates/agents/src/lib.rs: re-exports thetimecrate somoltis-caldavuses consistent date/time types without a new direct dependency (noCargo.toml/Cargo.lockchange)docs/src/caldav.md): documents that filtering runs server-side when bothstartandendare providedImplementation Details
range.startor start afterrange.endtime-rangeunderVCALENDAR > VEVENTand uses UTCZtimestampsValidation
Completed
cargo test -p moltis-caldav— 48/48 passedcargo test -p moltis-agents— 418/418 passedcargo clippy -p moltis-caldav -p moltis-agents --all-features --all-targets— no warningscargo fmt --all -- --check— cleancargo fetch --locked— lockfile in syncjust build-release— Linux amd64 release build succeeded (target/release/moltis, ELF x86-64)Remaining
just lint— full-workspace clippy with--all-features(requires CUDA toolchain; not available in the dev container, covered by CI)just test— full-workspace nextest with--all-features(same CUDA constraint)Manual QA
moltis.toml([caldav]withenabled = trueand an account withurl/username/password).caldavtool withoperation = list_events, acalendarhref, andstart/end(ISO 8601, e.g.2026-07-01T00:00:00→2026-07-31T23:59:59).start/end— all events must be returned (unchanged behavior).<C:time-range start="...Z" end="...Z"/>insidecomp-filter name="VEVENT"withincomp-filter name="VCALENDAR".https://claude.ai/code/session_012UDpqLhTib2oMkPj2roqaB