caldav: fix match on open time ranges

Matches on open time ranges (i.e. no end date) were not properly
handled, as `end` is simply the zero time, which confuses the
`.Before()` and `.After()` logic employed here.

This commit fixes that by adding the appropriate `.IsZero()` checks and
also adds a test case.

The current behavior unfortunately broke compatibility with DAVx5, which
by default queries only events less than 90 days ago (by using an open
time range).
This commit is contained in:
Conrad Hoffmann 2024-02-01 14:05:49 +01:00 committed by Simon Ser
parent ced348a58f
commit 5b5b542f2f
2 changed files with 21 additions and 7 deletions

View File

@ -138,7 +138,6 @@ func matchCompTimeRange(start, end time.Time, comp *ical.Component) (bool, error
return len(rset.Between(start, end, true)) > 0, nil return len(rset.Between(start, end, true)) > 0, nil
} }
// TODO handle "infinity" values in query
// TODO handle more than just events // TODO handle more than just events
if comp.Name != ical.CompEvent { if comp.Name != ical.CompEvent {
return false, nil return false, nil
@ -155,15 +154,15 @@ func matchCompTimeRange(start, end time.Time, comp *ical.Component) (bool, error
} }
// Event starts in time range // Event starts in time range
if eventStart.After(start) && eventStart.Before(end) { if eventStart.After(start) && (end.IsZero() || eventStart.Before(end)) {
return true, nil return true, nil
} }
// Event ends in time range // Event ends in time range
if eventEnd.After(start) && eventEnd.Before(end) { if eventEnd.After(start) && (end.IsZero() || eventEnd.Before(end)) {
return true, nil return true, nil
} }
// Event covers entire time range plus some // Event covers entire time range plus some
if eventStart.Before(start) && eventEnd.After(end) { if eventStart.Before(start) && (!end.IsZero() && eventEnd.After(end)) {
return true, nil return true, nil
} }
return false, nil return false, nil
@ -172,13 +171,11 @@ func matchCompTimeRange(start, end time.Time, comp *ical.Component) (bool, error
func matchPropTimeRange(start, end time.Time, field *ical.Prop) (bool, error) { func matchPropTimeRange(start, end time.Time, field *ical.Prop) (bool, error) {
// See https://datatracker.ietf.org/doc/html/rfc4791#section-9.9 // See https://datatracker.ietf.org/doc/html/rfc4791#section-9.9
// TODO handle "infinity" values in query
ptime, err := field.DateTime(start.Location()) ptime, err := field.DateTime(start.Location())
if err != nil { if err != nil {
return false, err return false, err
} }
if ptime.After(start) && ptime.Before(end) { if ptime.After(start) && (end.IsZero() || ptime.Before(end)) {
return true, nil return true, nil
} }
return false, nil return false, nil

View File

@ -209,6 +209,23 @@ END:VCALENDAR`)
addrs: []CalendarObject{event1, event2, event3, todo1}, addrs: []CalendarObject{event1, event2, event3, todo1},
want: []CalendarObject{event2, event3}, want: []CalendarObject{event2, event3},
}, },
{
// https://datatracker.ietf.org/doc/html/rfc4791#section-7.8.1
name: "events in open time range (no end date)",
query: &CalendarQuery{
CompFilter: CompFilter{
Name: "VCALENDAR",
Comps: []CompFilter{
CompFilter{
Name: "VEVENT",
Start: toDate(t, "20060104T000000Z"),
},
},
},
},
addrs: []CalendarObject{event1, event2, event3, todo1},
want: []CalendarObject{event2, event3},
},
{ {
// https://datatracker.ietf.org/doc/html/rfc4791#section-7.8.6 // https://datatracker.ietf.org/doc/html/rfc4791#section-7.8.6
name: "events by UID", name: "events by UID",