From 303aef52f30dba507b68d42cc606e2ded8cfb8b2 Mon Sep 17 00:00:00 2001 From: Conrad Hoffmann Date: Thu, 31 Mar 2022 11:28:26 +0200 Subject: [PATCH] caldav: implement `handleMultiget()` The implementation has feature parity with the CardDAV one. --- caldav/server.go | 80 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/caldav/server.go b/caldav/server.go index 5243040..8658f9b 100644 --- a/caldav/server.go +++ b/caldav/server.go @@ -85,7 +85,7 @@ func (h *Handler) handleReport(w http.ResponseWriter, r *http.Request) error { if report.Query != nil { return h.handleQuery(r, w, report.Query) } else if report.Multiget != nil { - return h.handleMultiget(w, report.Multiget) + return h.handleMultiget(r.Context(), w, report.Multiget) } return internal.HTTPErrorf(http.StatusBadRequest, "caldav: expected calendar-query or calendar-multiget element in REPORT request") } @@ -158,6 +158,44 @@ func decodeCompFilter(el *compFilter) (*CompFilter, error) { return cf, nil } +func decodeComp(comp *comp) (*CalendarCompRequest, error) { + if comp == nil { + return nil, internal.HTTPErrorf(http.StatusBadRequest, "caldav: unexpected empty calendar-data in request") + } + if comp.Allprop != nil && len(comp.Prop) > 0 { + return nil, internal.HTTPErrorf(http.StatusBadRequest, "caldav: only one of allprop or prop can be specified in calendar-data") + } + if comp.Allcomp != nil && len(comp.Comp) > 0 { + return nil, internal.HTTPErrorf(http.StatusBadRequest, "caldav: only one of allcomp or comp can be specified in calendar-data") + } + + req := &CalendarCompRequest{ + AllProps: comp.Allprop != nil, + AllComps: comp.Allcomp != nil, + } + for _, p := range comp.Prop { + req.Props = append(req.Props, p.Name) + } + for _, c := range comp.Comp { + comp, err := decodeComp(&c) + if err != nil { + return nil, err + } + req.Comps = append(req.Comps, *comp) + } + return req, nil +} + +func decodeCalendarDataReq(calendarData *calendarDataReq) (*CalendarCompRequest, error) { + if calendarData.Comp == nil { + return &CalendarCompRequest{ + AllProps: true, + AllComps: true, + }, nil + } + return decodeComp(calendarData.Comp) +} + func (h *Handler) handleQuery(r *http.Request, w http.ResponseWriter, query *calendarQuery) error { var q CalendarQuery // TODO: calendar-data in query.Prop @@ -192,8 +230,44 @@ func (h *Handler) handleQuery(r *http.Request, w http.ResponseWriter, query *cal return internal.ServeMultistatus(w, ms) } -func (h *Handler) handleMultiget(w http.ResponseWriter, multiget *calendarMultiget) error { - panic("TODO") +func (h *Handler) handleMultiget(ctx context.Context, w http.ResponseWriter, multiget *calendarMultiget) error { + var dataReq CalendarCompRequest + if multiget.Prop != nil { + var calendarData calendarDataReq + if err := multiget.Prop.Decode(&calendarData); err != nil && !internal.IsNotFound(err) { + return err + } + decoded, err := decodeCalendarDataReq(&calendarData) + if err != nil { + return err + } + dataReq = *decoded + } + + var resps []internal.Response + for _, href := range multiget.Hrefs { + co, err := h.Backend.GetCalendarObject(ctx, href.Path, &dataReq) + if err != nil { + resp := internal.NewErrorResponse(href.Path, err) + resps = append(resps, *resp) + continue + } + + b := backend{h.Backend} + propfind := internal.Propfind{ + Prop: multiget.Prop, + AllProp: multiget.AllProp, + PropName: multiget.PropName, + } + resp, err := b.propfindCalendarObject(ctx, &propfind, co) + if err != nil { + return err + } + resps = append(resps, *resp) + } + + ms := internal.NewMultistatus(resps...) + return internal.ServeMultistatus(w, ms) } type backend struct {