caldav: return SupportedComponentSet in PROPFIND

I started using this project to export tasks over CalDav, more
specifically to Reminders on iOS/macOS. I quickly realized that
even if you specify that `SupportedComponentSet` contains `VTODO`, that
isn't reflected properly when doing the `PROPFIND`.

This patch should fix that, while keeping the behaviour of defaulting to
`VEVENT` for propfind. Also added some tests to make sure that I didn't
break anything (Which I hope I didn't 😅).
This commit is contained in:
Dan Berglund 2023-07-03 10:47:34 +02:00 committed by GitHub
parent 150f74a6f0
commit 46dbba12fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 96 additions and 3 deletions

View File

@ -525,10 +525,16 @@ func (b *backend) propFindCalendar(ctx context.Context, propfind *internal.PropF
}, nil }, nil
}, },
supportedCalendarComponentSetName: func(*internal.RawXMLValue) (interface{}, error) { supportedCalendarComponentSetName: func(*internal.RawXMLValue) (interface{}, error) {
components := []comp{}
if cal.SupportedComponentSet != nil {
for _, name := range cal.SupportedComponentSet {
components = append(components, comp{Name: name})
}
} else {
components = append(components, comp{Name: ical.CompEvent})
}
return &supportedCalendarComponentSet{ return &supportedCalendarComponentSet{
Comp: []comp{ Comp: components,
{Name: ical.CompEvent},
},
}, nil }, nil
}, },
} }

87
caldav/server_test.go Normal file
View File

@ -0,0 +1,87 @@
package caldav
import (
"context"
"io"
"io/ioutil"
"net/http/httptest"
"strings"
"testing"
"github.com/emersion/go-ical"
)
var propFindSupportedCalendarComponentRequest = `
<d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:prop>
<c:supported-calendar-component-set />
</d:prop>
</d:propfind>
`
var testPropFindSupportedCalendarComponentCases = map[*Calendar][]string{
&Calendar{Path: "/user/calendars/cal"}: []string{"VEVENT"},
&Calendar{Path: "/user/calendars/cal", SupportedComponentSet: []string{"VTODO"}}: []string{"VTODO"},
&Calendar{Path: "/user/calendars/cal", SupportedComponentSet: []string{"VEVENT", "VTODO"}}: []string{"VEVENT", "VTODO"},
}
func TestPropFindSupportedCalendarComponent(t *testing.T) {
for calendar, expected := range testPropFindSupportedCalendarComponentCases {
req := httptest.NewRequest("PROPFIND", calendar.Path, nil)
req.Body = io.NopCloser(strings.NewReader(propFindSupportedCalendarComponentRequest))
req.Header.Set("Content-Type", "application/xml")
w := httptest.NewRecorder()
handler := Handler{Backend: testBackend{calendar: calendar}}
handler.ServeHTTP(w, req)
res := w.Result()
defer res.Body.Close()
data, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Error(err)
}
resp := string(data)
for _, comp := range expected {
// Would be nicer to do a proper XML-decoding here, but this is probably good enough for now.
if !strings.Contains(resp, comp) {
t.Errorf("Expected component: %v not found in response:\n%v", comp, resp)
}
}
}
}
type testBackend struct {
calendar *Calendar
}
func (t testBackend) Calendar(ctx context.Context) (*Calendar, error) {
return t.calendar, nil
}
func (t testBackend) CalendarHomeSetPath(ctx context.Context) (string, error) {
return "", nil
}
func (t testBackend) CurrentUserPrincipal(ctx context.Context) (string, error) {
return "", nil
}
func (t testBackend) DeleteCalendarObject(ctx context.Context, path string) error {
return nil
}
func (t testBackend) GetCalendarObject(ctx context.Context, path string, req *CalendarCompRequest) (*CalendarObject, error) {
return nil, nil
}
func (t testBackend) PutCalendarObject(ctx context.Context, path string, calendar *ical.Calendar, opts *PutCalendarObjectOptions) (string, error) {
return "", nil
}
func (t testBackend) ListCalendarObjects(ctx context.Context, req *CalendarCompRequest) ([]CalendarObject, error) {
return nil, nil
}
func (t testBackend) QueryCalendarObjects(ctx context.Context, query *CalendarQuery) ([]CalendarObject, error) {
return nil, nil
}