feat: implement caldav search

This commit is contained in:
2022-04-18 12:47:47 +02:00
parent f9e8f4b9c1
commit d7191461eb
57 changed files with 3893 additions and 20 deletions

View File

@ -0,0 +1,51 @@
package entities
import (
"encoding/xml"
"github.com/dolanor/caldav-go/caldav/values"
"github.com/dolanor/caldav-go/icalendar"
"github.com/dolanor/caldav-go/icalendar/components"
"github.com/dolanor/caldav-go/utils"
"strings"
)
// a CalDAV calendar data object
type CalendarData struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav calendar-data"`
Component *Component `xml:",omitempty"`
RecurrenceSetLimit *RecurrenceSetLimit `xml:",omitempty"`
ExpandRecurrenceSet *ExpandRecurrenceSet `xml:",omitempty"`
Content string `xml:",chardata"`
}
func (c *CalendarData) CalendarComponent() (*components.Calendar, error) {
cal := new(components.Calendar)
if content := strings.TrimSpace(c.Content); content == "" {
return nil, utils.NewError(c.CalendarComponent, "no calendar data to decode", c, nil)
} else if err := icalendar.Unmarshal(content, cal); err != nil {
return nil, utils.NewError(c.CalendarComponent, "decoding calendar data failed", c, err)
} else {
return cal, nil
}
}
// an iCalendar specifier for returned calendar data
type Component struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav comp"`
Properties []*PropertyName `xml:",omitempty"`
Components []*Component `xml:",omitempty"`
}
// used to restrict recurring event data to a particular time range
type RecurrenceSetLimit struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav limit-recurrence-set"`
StartTime *values.DateTime `xml:"start,attr"`
EndTime *values.DateTime `xml:"end,attr"`
}
// used to expand recurring events into individual calendar event data
type ExpandRecurrenceSet struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav expand"`
StartTime *values.DateTime `xml:"start,attr"`
EndTime *values.DateTime `xml:"end,attr"`
}

View File

@ -0,0 +1,59 @@
package entities
import (
"encoding/xml"
"github.com/dolanor/caldav-go/caldav/values"
"github.com/dolanor/caldav-go/utils"
"github.com/dolanor/caldav-go/webdav/entities"
"time"
)
// a CalDAV calendar query object
type CalendarQuery struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav calendar-query"`
Prop *Prop `xml:",omitempty"`
AllProp *entities.AllProp `xml:",omitempty"`
Filter *Filter `xml:",omitempty"`
}
// creates a new CalDAV query for iCalendar events from a particular time range
func NewEventRangeQuery(start, end time.Time) (*CalendarQuery, error) {
var err error
var dtstart, dtend *values.DateTime
if dtstart, err = values.NewDateTime("start", start); err != nil {
return nil, utils.NewError(NewEventRangeQuery, "unable to encode start time", start, err)
} else if dtend, err = values.NewDateTime("end", end); err != nil {
return nil, utils.NewError(NewEventRangeQuery, "unable to encode end time", end, err)
}
// construct the query object
query := new(CalendarQuery)
// request all calendar data
query.Prop = new(Prop)
query.Prop.CalendarData = new(CalendarData)
// expand recurring events
query.Prop.CalendarData.ExpandRecurrenceSet = new(ExpandRecurrenceSet)
query.Prop.CalendarData.ExpandRecurrenceSet.StartTime = dtstart
query.Prop.CalendarData.ExpandRecurrenceSet.EndTime = dtend
// filter down calendar data to only iCalendar data
query.Filter = new(Filter)
query.Filter.ComponentFilter = new(ComponentFilter)
query.Filter.ComponentFilter.Name = values.CalendarComponentName
// filter down iCalendar data to only events
query.Filter.ComponentFilter.ComponentFilter = new(ComponentFilter)
query.Filter.ComponentFilter.ComponentFilter.Name = values.EventComponentName
// filter down the events to only those that fall within the time range
query.Filter.ComponentFilter.ComponentFilter.TimeRange = new(TimeRange)
query.Filter.ComponentFilter.ComponentFilter.TimeRange.StartTime = dtstart
query.Filter.ComponentFilter.ComponentFilter.TimeRange.EndTime = dtend
// return the event query
return query, nil
}

View File

@ -0,0 +1,62 @@
package entities
import (
"encoding/xml"
"github.com/dolanor/caldav-go/caldav/values"
"github.com/dolanor/caldav-go/icalendar/properties"
)
// a CalDAV query filter entity
type Filter struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav filter"`
ComponentFilter *ComponentFilter `xml:",omitempty"`
}
// used to filter down calendar components, such as VCALENDAR > VEVENT
type ComponentFilter struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav comp-filter"`
Name values.ComponentName `xml:"name,attr"`
ComponentFilter *ComponentFilter `xml:",omitempty"`
TimeRange *TimeRange `xml:",omitempty"`
PropertyFilter *PropertyFilter `xml:",omitempty"`
ParameterFilter *ParameterFilter `xml:",omitempty"`
}
// used to restrict component filters to a particular time range
type TimeRange struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav time-range"`
StartTime *values.DateTime `xml:"start,attr"`
EndTime *values.DateTime `xml:"end,attr"`
}
// used to restrict component filters to a property value
type PropertyFilter struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav prop-filter"`
Name properties.PropertyName `xml:"name,attr"`
TextMatch *TextMatch `xml:",omitempty"`
ParameterFilter *ParameterFilter `xml:",omitempty"`
}
// used to restrict component filters to a parameter value
type ParameterFilter struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav param-filter"`
Name properties.ParameterName `xml:"name,attr"`
TextMatch *TextMatch `xml:",omitempty"`
}
// used to match properties by text value
type TextMatch struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav text-match"`
Collation values.TextCollation `xml:"collation,attr,omitempty"`
NegateCondition values.HumanBoolean `xml:"attr,negate-condition,omitempty"`
Content string `xml:",innerxml"`
}
// creates a new CalDAV property value matcher
func NewPropertyMatcher(name properties.PropertyName, content string) *PropertyFilter {
pf := new(PropertyFilter)
pf.Name = name
pf.TextMatch = new(TextMatch)
pf.TextMatch.Content = content
return pf
}

View File

@ -0,0 +1,23 @@
package entities
import "encoding/xml"
// metadata about a property
type PropStat struct {
XMLName xml.Name `xml:"propstat"`
Status string `xml:"status"`
Prop *Prop `xml:",omitempty"`
}
// a multistatus response entity
type Response struct {
XMLName xml.Name `xml:"response"`
Href string `xml:"href"`
PropStats []*PropStat `xml:"propstat,omitempty"`
}
// a request to find properties on an an entity or collection
type Multistatus struct {
XMLName xml.Name `xml:"DAV: multistatus"`
Responses []*Response `xml:"response,omitempty"`
}

View File

@ -0,0 +1,23 @@
package entities
import (
"encoding/xml"
"github.com/dolanor/caldav-go/webdav/entities"
)
// a CalDAV Property resource
type Prop struct {
XMLName xml.Name `xml:"DAV: prop"`
GetContentType string `xml:"getcontenttype,omitempty"`
DisplayName string `xml:"displayname,omitempty"`
CalendarData *CalendarData `xml:",omitempty"`
ResourceType *entities.ResourceType `xml:",omitempty"`
CTag string `xml:"http://calendarserver.org/ns/ getctag,omitempty"`
ETag string `xml:"http://calendarserver.org/ns/ getetag,omitempty"`
}
// used to restrict properties returned in calendar data
type PropertyName struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav prop"`
Name string `xml:"name,attr"`
}