A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1// SiYuan - Refactor your thinking
2// Copyright (c) 2020-present, b3log.org
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Affero General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17package model
18
19import (
20 "bytes"
21 "context"
22 "errors"
23 "github.com/siyuan-note/siyuan/kernel/util"
24 "os"
25 "path"
26 "strings"
27 "sync"
28
29 "github.com/88250/gulu"
30 "github.com/emersion/go-ical"
31 "github.com/emersion/go-webdav/caldav"
32 "github.com/siyuan-note/logging"
33)
34
35const (
36 // REF: https://developers.google.com/calendar/caldav/v2/guide
37 CalDavPrefixPath = "/caldav"
38 CalDavPrincipalsPath = CalDavPrefixPath + "/principals" // 0 resourceTypeRoot
39 CalDavUserPrincipalPath = CalDavPrincipalsPath + "/main" // 1 resourceTypeUserPrincipal
40 CalDavHomeSetPath = CalDavUserPrincipalPath + "/calendars" // 2 resourceTypeCalendarHomeSet
41 CalDavDefaultCalendarPath = CalDavHomeSetPath + "/default" // 3 resourceTypeCalendar
42
43 CalDavDefaultCalendarName = "default"
44
45 CalDavCalendarsMetaDataFilePath = CalDavHomeSetPath + "/calendars.json"
46
47 ICalendarFileExt = "." + ical.Extension // .ics
48)
49
50type CalDavPathDepth int
51
52const (
53 calDavPathDepth_Root CalDavPathDepth = 1 + iota // /caldav
54 calDavPathDepth_Principals // /caldav/principals
55 calDavPathDepth_UserPrincipal // /caldav/principals/main
56 calDavPathDepth_HomeSet // /caldav/principals/main/calendars
57 calDavPathDepth_Calendar // /caldav/principals/main/calendars/default
58 calDavPathDepth_Object // /caldav/principals/main/calendars/default/id.ics
59)
60
61var (
62 calendarMaxResourceSize int64 = 0
63 calendarSupportedComponentSet = []string{"VEVENT", "VTODO"}
64
65 defaultCalendar = caldav.Calendar{
66 Path: CalDavDefaultCalendarPath,
67 Name: CalDavDefaultCalendarName,
68 Description: "Default calendar",
69 MaxResourceSize: calendarMaxResourceSize,
70 SupportedComponentSet: calendarSupportedComponentSet,
71 }
72 calendars = Calendars{
73 loaded: false,
74 changed: false,
75 lock: sync.Mutex{},
76 calendars: sync.Map{},
77 calendarsMetaData: []*caldav.Calendar{},
78 }
79
80 ErrorCalDavPathInvalid = errors.New("CalDAV: path is invalid")
81
82 ErrorCalDavCalendarNotFound = errors.New("CalDAV: calendar not found")
83 ErrorCalDavCalendarPathInvalid = errors.New("CalDAV: calendar path is invalid")
84
85 ErrorCalDavCalendarObjectNotFound = errors.New("CalDAV: calendar object not found")
86 ErrorCalDavCalendarObjectPathInvalid = errors.New("CalDAV: calendar object path is invalid")
87)
88
89// CalendarsMetaDataFilePath returns the absolute path of the calendars' meta data file
90func CalendarsMetaDataFilePath() string {
91 return DavPath2DirectoryPath(CalDavCalendarsMetaDataFilePath)
92}
93
94func GetCalDavPathDepth(urlPath string) CalDavPathDepth {
95 urlPath = PathCleanWithSlash(urlPath)
96 return CalDavPathDepth(len(strings.Split(urlPath, "/")) - 1)
97}
98
99// GetCardDavPathDepth parses
100func ParseCalendarObjectPath(objectPath string) (calendarPath string, objectID string, err error) {
101 calendarPath, objectFileName := path.Split(objectPath)
102 calendarPath = PathCleanWithSlash(calendarPath)
103 objectID = path.Base(objectFileName)
104 objectFileExt := util.Ext(objectFileName)
105
106 if GetCalDavPathDepth(calendarPath) != calDavPathDepth_Calendar {
107 err = ErrorCalDavCalendarPathInvalid
108 return
109 }
110
111 if objectFileExt != ICalendarFileExt {
112 err = ErrorCalDavCalendarObjectPathInvalid
113 return
114 }
115
116 return
117}
118
119// LoadCalendarObject loads a iCalendar file (*.ics)
120func LoadCalendarObject(filePath string) (calendar *ical.Calendar, err error) {
121 data, err := os.ReadFile(filePath)
122 if err != nil {
123 logging.LogErrorf("read iCalendar file [%s] failed: %s", filePath, err)
124 return
125 }
126
127 decoder := ical.NewDecoder(bytes.NewReader(data))
128 calendar, err = decoder.Decode()
129 return
130}
131
132type Calendars struct {
133 loaded bool
134 changed bool
135 lock sync.Mutex // load & save
136 calendars sync.Map // Path -> *Calendar
137 calendarsMetaData []*caldav.Calendar
138}
139
140func (c *Calendars) load() error {
141 c.calendars.Clear()
142
143 // load calendars meta data file
144 calendarsMetaDataFilePath := CalendarsMetaDataFilePath()
145 metaData, err := os.ReadFile(calendarsMetaDataFilePath)
146 if os.IsNotExist(err) {
147 // create & save default calendar
148 c.calendarsMetaData = []*caldav.Calendar{&defaultCalendar}
149 if err := c.saveCalendarsMetaData(); err != nil {
150 return err
151 }
152 } else {
153 // load meta data file
154 c.calendarsMetaData = []*caldav.Calendar{}
155 if err = gulu.JSON.UnmarshalJSON(metaData, &c.calendarsMetaData); err != nil {
156 logging.LogErrorf("unmarshal address books meta data failed: %s", err)
157 return err
158 }
159 }
160
161 // load iCalendar files (*.ics)
162 wg := &sync.WaitGroup{}
163 wg.Add(len(c.calendarsMetaData))
164 for _, calendarMetaData := range c.calendarsMetaData {
165 calendar := &Calendar{
166 Changed: false,
167 DirectoryPath: DavPath2DirectoryPath(calendarMetaData.Path),
168 MetaData: calendarMetaData,
169 Objects: sync.Map{},
170 }
171 c.calendars.Store(calendarMetaData.Path, calendar)
172 go func() {
173 defer wg.Done()
174 calendar.load()
175 }()
176 }
177 wg.Wait()
178
179 c.loaded = true
180 c.changed = false
181 return nil
182}
183
184// save all calendars
185func (c *Calendars) save(force bool) error {
186 if force || c.changed {
187 // save calendars meta data
188 if err := c.saveCalendarsMetaData(); err != nil {
189 return err
190 }
191
192 // save all calendar object to *.ics files
193 wg := &sync.WaitGroup{}
194 c.calendars.Range(func(path any, calendar any) bool {
195 wg.Add(1)
196 go func() {
197 defer wg.Done()
198 // path_ := path.(string)
199 calendar := calendar.(*Calendar)
200 calendar.save(force)
201 }()
202 return true
203 })
204 wg.Wait()
205 c.changed = false
206 }
207 return nil
208}
209
210// save all calendars meta data
211func (c *Calendars) saveCalendarsMetaData() error {
212 return SaveMetaData(c.calendarsMetaData, CalendarsMetaDataFilePath())
213}
214
215func (c *Calendars) Load() error {
216 c.lock.Lock()
217 defer c.lock.Unlock()
218
219 if !c.loaded {
220 return c.load()
221 }
222 return nil
223}
224
225func (c *Calendars) GetObject(objectPath string) (calendar *Calendar, calendarObject *CalendarObject, err error) {
226 calendarPath, objectID, err := ParseCalendarObjectPath(objectPath)
227 if err != nil {
228 logging.LogErrorf("parse calendar object path [%s] failed: %s", objectPath, err)
229 return
230 }
231
232 if value, ok := c.calendars.Load(calendarPath); ok {
233 calendar = value.(*Calendar)
234 } else {
235 err = ErrorCalDavCalendarNotFound
236 return
237 }
238
239 if value, ok := calendar.Objects.Load(objectID); ok {
240 calendarObject = value.(*CalendarObject)
241 } else {
242 err = ErrorCalDavCalendarObjectNotFound
243 return
244 }
245
246 return
247}
248
249func (c *Calendars) DeleteObject(objectPath string) (calendar *Calendar, calendarObject *CalendarObject, err error) {
250 calendarPath, objectID, err := ParseCalendarObjectPath(objectPath)
251 if err != nil {
252 logging.LogErrorf("parse calendar object path [%s] failed: %s", objectPath, err)
253 return
254 }
255
256 if value, ok := c.calendars.Load(calendarPath); ok {
257 calendar = value.(*Calendar)
258 } else {
259 err = ErrorCalDavCalendarNotFound
260 return
261 }
262
263 if value, loaded := calendar.Objects.LoadAndDelete(objectID); loaded {
264 calendarObject = value.(*CalendarObject)
265 } else {
266 err = ErrorCalDavCalendarObjectNotFound
267 return
268 }
269
270 if err = os.Remove(calendarObject.FilePath); err != nil {
271 logging.LogErrorf("remove file [%s] failed: %s", calendarObject.FilePath, err)
272 return
273 }
274
275 return
276}
277
278func (c *Calendars) CreateCalendar(calendarMetaData *caldav.Calendar) (err error) {
279 c.lock.Lock()
280 defer c.lock.Unlock()
281
282 var calendar *Calendar
283
284 // update map
285 if value, ok := c.calendars.Load(calendarMetaData.Path); ok {
286 // update map item
287 calendar = value.(*Calendar)
288 calendar.MetaData = calendarMetaData
289 } else {
290 // insert map item
291 calendar = &Calendar{
292 Changed: false,
293 DirectoryPath: DavPath2DirectoryPath(calendarMetaData.Path),
294 MetaData: calendarMetaData,
295 Objects: sync.Map{},
296 }
297 c.calendars.Store(calendarMetaData.Path, calendar)
298 }
299
300 var index = -1
301 for i, item := range c.calendarsMetaData {
302 if item.Path == calendarMetaData.Path {
303 index = i
304 break
305 }
306 }
307
308 if index >= 0 {
309 // update list
310 c.calendarsMetaData[index] = calendarMetaData
311 } else {
312 // insert list
313 c.calendarsMetaData = append(c.calendarsMetaData, calendarMetaData)
314 }
315
316 // create calendar directory
317 if err = os.MkdirAll(calendar.DirectoryPath, 0755); err != nil {
318 logging.LogErrorf("create directory [%s] failed: %s", calendar.DirectoryPath, err)
319 return
320 }
321
322 // save meta data
323 if err = c.saveCalendarsMetaData(); err != nil {
324 return
325 }
326
327 return
328}
329
330func (c *Calendars) ListCalendars() (calendars []caldav.Calendar, err error) {
331 c.lock.Lock()
332 defer c.lock.Unlock()
333
334 for _, calendar := range c.calendarsMetaData {
335 calendars = append(calendars, *calendar)
336 }
337 return
338}
339
340func (c *Calendars) GetCalendar(calendarPath string) (calendar *caldav.Calendar, err error) {
341 c.lock.Lock()
342 defer c.lock.Unlock()
343
344 if value, ok := calendars.calendars.Load(calendarPath); ok {
345 calendar = value.(*Calendar).MetaData
346 return
347 }
348
349 err = ErrorCalDavCalendarNotFound
350 return
351}
352
353func (c *Calendars) DeleteCalendar(calendarPath string) (err error) {
354 c.lock.Lock()
355 defer c.lock.Unlock()
356
357 var calendar *Calendar
358
359 // delete map item
360 if value, loaded := c.calendars.LoadAndDelete(calendarPath); loaded {
361 calendar = value.(*Calendar)
362 }
363
364 // delete list item
365 for i, item := range c.calendarsMetaData {
366 if item.Path == calendarPath {
367 c.calendarsMetaData = append(c.calendarsMetaData[:i], c.calendarsMetaData[i+1:]...)
368 break
369 }
370 }
371
372 // remove address book directory
373 if err = os.RemoveAll(calendar.DirectoryPath); err != nil {
374 logging.LogErrorf("remove directory [%s] failed: %s", calendar.DirectoryPath, err)
375 return
376 }
377
378 // save meta data
379 if err = c.saveCalendarsMetaData(); err != nil {
380 return
381 }
382
383 return nil
384}
385
386func (c *Calendars) PutCalendarObject(objectPath string, calendarData *ical.Calendar, opts *caldav.PutCalendarObjectOptions) (calendarObject *caldav.CalendarObject, err error) {
387 c.lock.Lock()
388 defer c.lock.Unlock()
389
390 calendarPath, objectID, err := ParseCalendarObjectPath(objectPath)
391 if err != nil {
392 logging.LogErrorf("parse calendar object path [%s] failed: %s", objectPath, err)
393 return
394 }
395
396 var calendar *Calendar
397 if value, ok := c.calendars.Load(calendarPath); ok {
398 calendar = value.(*Calendar)
399 } else {
400 err = ErrorCalDavCalendarNotFound
401 return
402 }
403
404 // TODO: 处理 opts.IfNoneMatch (If-None-Match) 与 opts.IfMatch (If-Match)
405
406 var object *CalendarObject
407 if value, ok := calendar.Objects.Load(objectID); ok {
408 object = value.(*CalendarObject)
409 object.Data.Data = calendarData
410 object.Changed = true
411 } else {
412 object = &CalendarObject{
413 Changed: true,
414 FilePath: DavPath2DirectoryPath(objectPath),
415 CalendarPath: calendarPath,
416 Data: &caldav.CalendarObject{
417 Data: calendarData,
418 },
419 }
420 }
421
422 err = object.save(true)
423 if err != nil {
424 return
425 }
426
427 err = object.update()
428 if err != nil {
429 return
430 }
431
432 calendar.Objects.Store(objectID, object)
433 calendarObject = object.Data
434 return
435}
436
437func (c *Calendars) ListCalendarObjects(calendarPath string, req *caldav.CalendarCompRequest) (calendarObjects []caldav.CalendarObject, err error) {
438 c.lock.Lock()
439 defer c.lock.Unlock()
440
441 var calendar *Calendar
442 if value, ok := c.calendars.Load(calendarPath); ok {
443 calendar = value.(*Calendar)
444 } else {
445 err = ErrorCalDavCalendarNotFound
446 return
447 }
448
449 calendar.Objects.Range(func(id any, object any) bool {
450 // TODO: filter calendar objects' props and comps
451 calendarObjects = append(calendarObjects, *object.(*CalendarObject).Data)
452 return true
453 })
454
455 return
456}
457
458func (c *Calendars) GetCalendarObject(objectPath string, req *caldav.CalendarCompRequest) (calendarObject *caldav.CalendarObject, err error) {
459 c.lock.Lock()
460 defer c.lock.Unlock()
461
462 _, object, err := c.GetObject(objectPath)
463 if err != nil {
464 return
465 }
466
467 calendarObject = object.Data
468 // TODO: filter calendar object's props and comps
469 return
470}
471
472func (c *Calendars) QueryCalendarObjects(calendarPath string, query *caldav.CalendarQuery) (calendarObjects []caldav.CalendarObject, err error) {
473 c.lock.Lock()
474 defer c.lock.Unlock()
475
476 calendarObjects, err = c.ListCalendarObjects(calendarPath, &query.CompRequest)
477 if err != nil {
478 return
479 }
480
481 calendarObjects, err = caldav.Filter(query, calendarObjects)
482 if err != nil {
483 return
484 }
485
486 return
487}
488
489func (c *Calendars) DeleteCalendarObject(objectPath string) (err error) {
490 c.lock.Lock()
491 defer c.lock.Unlock()
492
493 _, _, err = c.DeleteObject(objectPath)
494 if err != nil {
495 return
496 }
497
498 return
499}
500
501type Calendar struct {
502 Changed bool
503 DirectoryPath string
504 MetaData *caldav.Calendar
505 Objects sync.Map // id -> *CalendarObject
506}
507
508func (c *Calendar) load() error {
509 if err := os.MkdirAll(c.DirectoryPath, 0755); err != nil {
510 logging.LogErrorf("create directory [%s] failed: %s", c.DirectoryPath, err)
511 return err
512 }
513
514 entries, err := os.ReadDir(c.DirectoryPath)
515 if err != nil {
516 logging.LogErrorf("read dir [%s] failed: %s", c.DirectoryPath, err)
517 return err
518 }
519
520 wg := &sync.WaitGroup{}
521 for _, entry := range entries {
522 if !entry.IsDir() {
523 filename := entry.Name()
524 ext := util.Ext(filename)
525 if ext == ICalendarFileExt {
526 wg.Add(1)
527 go func() {
528 defer wg.Done()
529
530 // create & load calendar object
531 calendarObjectFilePath := path.Join(c.DirectoryPath, filename)
532 calendarObject := &CalendarObject{
533 Changed: false,
534 FilePath: calendarObjectFilePath,
535 CalendarPath: c.MetaData.Path,
536 }
537 err = calendarObject.load()
538 if err != nil {
539 return
540 }
541
542 id := path.Base(filename)
543 c.Objects.Store(id, calendarObject)
544 }()
545 }
546 }
547 }
548 wg.Wait()
549 return nil
550}
551
552// save an calendar to multiple *.ics files
553func (c *Calendar) save(force bool) error {
554 if force || c.Changed {
555 // create directory
556 if err := os.MkdirAll(c.DirectoryPath, 0755); err != nil {
557 logging.LogErrorf("create directory [%s] failed: %s", c.DirectoryPath, err)
558 return err
559 }
560
561 wg := &sync.WaitGroup{}
562 c.Objects.Range(func(id any, object any) bool {
563 wg.Add(1)
564 go func() {
565 defer wg.Done()
566 // id_ := id.(string)
567 object_ := object.(*CalendarObject)
568 object_.save(force)
569 object_.update()
570 }()
571 return true
572 })
573 wg.Wait()
574 c.Changed = false
575 }
576
577 return nil
578}
579
580type CalendarObject struct {
581 Changed bool
582 FilePath string
583 CalendarPath string
584 Data *caldav.CalendarObject
585}
586
587func (o *CalendarObject) load() error {
588 // load iCalendar file
589 calendarObjectData, err := LoadCalendarObject(o.FilePath)
590 if err != nil {
591 return err
592 }
593
594 // create address object
595 o.Data = &caldav.CalendarObject{
596 Data: calendarObjectData,
597 }
598
599 // update file info
600 err = o.update()
601 if err != nil {
602 return err
603 }
604
605 o.Changed = false
606 return nil
607}
608
609// save an object to *.ics file
610func (o *CalendarObject) save(force bool) error {
611 if force || o.Changed {
612 var objectData bytes.Buffer
613
614 // encode data
615 encoder := ical.NewEncoder(&objectData)
616 if err := encoder.Encode(o.Data.Data); err != nil {
617 logging.LogErrorf("encode iCalendar [%s] failed: %s", o.Data.Path, err)
618 return err
619 }
620
621 // create directory
622 dirPath := path.Dir(o.FilePath)
623 if err := os.MkdirAll(dirPath, 0755); err != nil {
624 logging.LogErrorf("create directory [%s] failed: %s", dirPath, err)
625 return err
626 }
627
628 // write file
629 if err := os.WriteFile(o.FilePath, objectData.Bytes(), 0755); err != nil {
630 logging.LogErrorf("write file [%s] failed: %s", o.FilePath, err)
631 return err
632 }
633
634 o.Changed = false
635 }
636 return nil
637}
638
639// update file info
640func (o *CalendarObject) update() error {
641 addressFileInfo, err := os.Stat(o.FilePath)
642 if err != nil {
643 logging.LogErrorf("get file [%s] info failed: %s", o.FilePath, err)
644 return err
645 }
646
647 o.Data.Path = PathJoinWithSlash(o.CalendarPath, addressFileInfo.Name())
648 o.Data.ModTime = addressFileInfo.ModTime()
649 o.Data.ContentLength = addressFileInfo.Size()
650 o.Data.ETag = FileETag(addressFileInfo)
651
652 return nil
653}
654
655type CalDavBackend struct{}
656
657func (b *CalDavBackend) CurrentUserPrincipal(ctx context.Context) (string, error) {
658 // logging.LogDebugf("CalDAV CurrentUserPrincipal")
659 return CalDavUserPrincipalPath, nil
660}
661
662func (b *CalDavBackend) CalendarHomeSetPath(ctx context.Context) (string, error) {
663 // logging.LogDebugf("CalDAV CalendarHomeSetPath")
664 return CalDavHomeSetPath, nil
665}
666
667func (b *CalDavBackend) CreateCalendar(ctx context.Context, calendar *caldav.Calendar) (err error) {
668 // logging.LogDebugf("CalDAV CreateCalendar -> calendar: %#v", calendar)
669 calendar.Path = PathCleanWithSlash(calendar.Path)
670
671 if err = calendars.Load(); err != nil {
672 return
673 }
674
675 err = calendars.CreateCalendar(calendar)
676 // logging.LogDebugf("CalDAV CreateCalendar <- err: %s", err)
677 return
678}
679
680func (b *CalDavBackend) ListCalendars(ctx context.Context) (calendars_ []caldav.Calendar, err error) {
681 // logging.LogDebugf("CalDAV ListCalendars")
682 if err = calendars.Load(); err != nil {
683 return
684 }
685
686 calendars_, err = calendars.ListCalendars()
687 // logging.LogDebugf("CalDAV ListCalendars <- calendars: %#v, err: %s", calendars_, err)
688 return
689}
690
691func (b *CalDavBackend) GetCalendar(ctx context.Context, calendarPath string) (calendar *caldav.Calendar, err error) {
692 // logging.LogDebugf("CalDAV GetCalendar -> calendarPath: %s", calendarPath)
693 calendarPath = PathCleanWithSlash(calendarPath)
694
695 if err = calendars.Load(); err != nil {
696 return
697 }
698
699 calendar, err = calendars.GetCalendar(calendarPath)
700 // logging.LogDebugf("CalDAV GetCalendar <- calendar: %#v, err: %s", calendar, err)
701 return
702}
703
704func (b *CalDavBackend) DeleteCalendar(ctx context.Context, calendarPath string) (err error) {
705 // logging.LogDebugf("CalDAV DeleteCalendar -> calendarPath: %s", calendarPath)
706 calendarPath = PathCleanWithSlash(calendarPath)
707
708 if err = calendars.Load(); err != nil {
709 return
710 }
711
712 err = calendars.DeleteCalendar(calendarPath)
713 // logging.LogDebugf("CalDAV DeleteCalendar <- err: %s", err)
714 return
715}
716
717func (b *CalDavBackend) PutCalendarObject(ctx context.Context, objectPath string, calendar *ical.Calendar, opts *caldav.PutCalendarObjectOptions) (calendarObject *caldav.CalendarObject, err error) {
718 // logging.LogDebugf("CalDAV PutCalendarObject -> objectPath: %s, opts: %#v", objectPath, opts)
719 objectPath = PathCleanWithSlash(objectPath)
720
721 if err = calendars.Load(); err != nil {
722 return
723 }
724
725 calendarObject, err = calendars.PutCalendarObject(objectPath, calendar, opts)
726 // logging.LogDebugf("CalDAV PutCalendarObject <- calendarObject: %#v, err: %s", calendarObject, err)
727 return
728}
729
730func (b *CalDavBackend) ListCalendarObjects(ctx context.Context, calendarPath string, req *caldav.CalendarCompRequest) (calendarObjects []caldav.CalendarObject, err error) {
731 // logging.LogDebugf("CalDAV ListCalendarObjects -> calendarPath: %s, req: %#v", calendarPath, req)
732 calendarPath = PathCleanWithSlash(calendarPath)
733
734 if err = calendars.Load(); err != nil {
735 return
736 }
737
738 calendarObjects, err = calendars.ListCalendarObjects(calendarPath, req)
739 // logging.LogDebugf("CalDAV ListCalendarObjects <- calendarObjects: %#v, err: %s", calendarObjects, err)
740 return
741}
742
743func (b *CalDavBackend) GetCalendarObject(ctx context.Context, objectPath string, req *caldav.CalendarCompRequest) (calendarObject *caldav.CalendarObject, err error) {
744 // logging.LogDebugf("CalDAV GetCalendarObject -> objectPath: %s, req: %#v", objectPath, req)
745 objectPath = PathCleanWithSlash(objectPath)
746
747 if err = calendars.Load(); err != nil {
748 return
749 }
750
751 calendarObject, err = calendars.GetCalendarObject(objectPath, req)
752 // logging.LogDebugf("CalDAV GetCalendarObject <- calendarObject: %#v, err: %s", calendarObject, err)
753 return
754}
755
756func (b *CalDavBackend) QueryCalendarObjects(ctx context.Context, calendarPath string, query *caldav.CalendarQuery) (calendarObjects []caldav.CalendarObject, err error) {
757 // logging.LogDebugf("CalDAV QueryCalendarObjects -> calendarPath: %s, query: %#v", calendarPath, query)
758 calendarPath = PathCleanWithSlash(calendarPath)
759
760 if err = calendars.Load(); err != nil {
761 return
762 }
763
764 calendarObjects, err = calendars.QueryCalendarObjects(calendarPath, query)
765 // logging.LogDebugf("CalDAV QueryCalendarObjects <- calendarObjects: %#v, err: %s", calendarObjects, err)
766 return
767}
768
769func (b *CalDavBackend) DeleteCalendarObject(ctx context.Context, objectPath string) (err error) {
770 // logging.LogDebugf("CalDAV DeleteCalendarObject -> objectPath: %s", objectPath)
771 objectPath = PathCleanWithSlash(objectPath)
772
773 if err = calendars.Load(); err != nil {
774 return
775 }
776
777 err = calendars.DeleteCalendarObject(objectPath)
778 // logging.LogDebugf("CalDAV DeleteCalendarObject <- err: %s", err)
779 return
780}