@@ -10,6 +10,7 @@ import (
1010 "io"
1111 "net/http"
1212 "strings"
13+ "sync"
1314 "time"
1415
1516 "github.com/charmbracelet/log"
@@ -24,6 +25,11 @@ type ACalClient struct {
2425 AppPassword string
2526 CalendarID string
2627 httpClient * http.Client
28+
29+ resolveOnce sync.Once
30+ cachedPrincipalID string
31+ cachedCalendarID string
32+ resolutionError error
2733}
2834
2935type CalDAVPropfind struct {
@@ -418,30 +424,51 @@ func (c *ACalClient) convertVEventToEvent(vevent *ical.Component, href string) *
418424 return event
419425}
420426
421- func (c * ACalClient ) CreateEvent (ctx context.Context , event models.Event ) error {
427+ func (c * ACalClient ) createOrUpdateEvent (ctx context.Context , event models.Event , isUpdate bool ) error {
428+ principalID , resolvedCalendarID , err := c .getResolvedCalendarInfo (ctx )
429+ if err != nil {
430+ return fmt .Errorf ("failed to resolve calendar '%s': %w" , c .CalendarID , err )
431+ }
432+
422433 icalData := c .eventToICalendar (event )
423434
424- // Generate unique filename
425- filename := fmt .Sprintf ("%s.ics" , event . Metadata . SyncID )
426- eventPath := fmt .Sprintf ("/%s/calendars/%s/%s/%s " , c . Username , c . Username , c . CalendarID , filename )
435+ uid := strings . ReplaceAll ( event . ICalUID , "@" , "-" )
436+ filename := fmt .Sprintf ("%s.ics" , uid )
437+ eventPath := fmt .Sprintf ("/%s/calendars/%s/%s" , principalID , resolvedCalendarID , filename )
427438
428- _ , err := c .makeRequest (ctx , "PUT" , eventPath , []byte (icalData ), map [string ]string {
439+ // Set headers based on operation type
440+ headers := map [string ]string {
429441 "Content-Type" : "text/calendar; charset=utf-8" ,
430- })
442+ }
443+
444+ // Only add If-None-Match for new resource creation
445+ if ! isUpdate {
446+ headers ["If-None-Match" ] = "*"
447+ }
431448
449+ _ , err = c .makeRequest (ctx , "PUT" , eventPath , []byte (icalData ), headers )
432450 return err
433451}
434452
453+ func (c * ACalClient ) CreateEvent (ctx context.Context , event models.Event ) error {
454+ return c .createOrUpdateEvent (ctx , event , false )
455+ }
456+
435457func (c * ACalClient ) UpdateEvent (ctx context.Context , event models.Event ) error {
436- // For updates, we use the same PUT method with the existing resource path
437- return c .CreateEvent (ctx , event )
458+ return c .createOrUpdateEvent (ctx , event , true )
438459}
439460
440461func (c * ACalClient ) DeleteEvent (ctx context.Context , event models.Event ) error {
441- filename := fmt .Sprintf ("%s.ics" , event .Metadata .SyncID )
442- eventPath := fmt .Sprintf ("/%s/calendars/%s/%s/%s" , c .Username , c .Username , c .CalendarID , filename )
462+ principalID , resolvedCalendarID , err := c .getResolvedCalendarInfo (ctx )
463+ if err != nil {
464+ return fmt .Errorf ("failed to resolve calendar '%s': %w" , c .CalendarID , err )
465+ }
443466
444- _ , err := c .makeRequest (ctx , "DELETE" , eventPath , nil , nil )
467+ uid := strings .ReplaceAll (event .ICalUID , "@" , "-" )
468+ filename := fmt .Sprintf ("%s.ics" , uid )
469+ eventPath := fmt .Sprintf ("/%s/calendars/%s/%s" , principalID , resolvedCalendarID , filename )
470+
471+ _ , err = c .makeRequest (ctx , "DELETE" , eventPath , nil , nil )
445472 return err
446473}
447474
@@ -585,3 +612,18 @@ func (c *ACalClient) GetCalendarHash() string {
585612 id = append (id , sum [:]... )
586613 return base64 .URLEncoding .EncodeToString (id )
587614}
615+
616+ func (c * ACalClient ) getResolvedCalendarInfo (ctx context.Context ) (string , string , error ) {
617+ c .resolveOnce .Do (func () {
618+ c .cachedPrincipalID , c .cachedCalendarID , c .resolutionError = c .ResolveCalendarID (ctx , c .CalendarID )
619+ })
620+
621+ return c .cachedPrincipalID , c .cachedCalendarID , c .resolutionError
622+ }
623+
624+ func (c * ACalClient ) resetCache () {
625+ c .resolveOnce = sync.Once {}
626+ c .cachedPrincipalID = ""
627+ c .cachedCalendarID = ""
628+ c .resolutionError = nil
629+ }
0 commit comments