From 580dafe12344efc6bbb7ed279bc1ee3a165d1e68 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 2 Apr 2018 12:56:55 +0200 Subject: [PATCH] Added wholeDay updating --- src/calanonsync/calanonsync.go | 2 +- src/calanonsync/caldav.go | 38 +++++++++++++++++++++++++++++++--- src/calanonsync/caldav_test.go | 24 +++++++++++++++++++-- 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/calanonsync/calanonsync.go b/src/calanonsync/calanonsync.go index c03073d..3f21ba3 100644 --- a/src/calanonsync/calanonsync.go +++ b/src/calanonsync/calanonsync.go @@ -52,7 +52,7 @@ func main() { !ewsItem.End.Equal(calDavItem.End()) { // So times have changed. Update. - calDavItem.Update(ewsItem.Start, ewsItem.End) + calDavItem.Update(ewsItem.Start, ewsItem.End, ewsItem.IsAllDayEvent) err := c.UploadItem(calDavItem) if err == nil { diff --git a/src/calanonsync/caldav.go b/src/calanonsync/caldav.go index 43554a3..2040e02 100644 --- a/src/calanonsync/caldav.go +++ b/src/calanonsync/caldav.go @@ -78,7 +78,39 @@ var fieldMatch = regexp.MustCompile(`^(\w+)[;:]`) // Update the ical structure with a new start/end time (and the // timestamp of the last modification). -func (ical *ICal) Update(newStart, newEnd time.Time) { +// If wholeDay is requested, the start and end times are tried +// first. If they are precisely 0:00 to 0:00, fine. Otherwise +// they are converted to local timezone and tried again. If that +// also fails the event is NOT considered whole day! +func (ical *ICal) Update(newStart, newEnd time.Time, wholeDay bool) { + if wholeDay && (newStart.Hour() != 0 || newStart.Minute() != 0 || + newEnd.Hour() != 0 || newEnd.Hour() != 0) { + + newStart = newStart.In(time.Local) + newEnd = newEnd.In(time.Local) + + if newStart.Hour() != 0 || newStart.Minute() != 0 || + newEnd.Hour() != 0 || newEnd.Hour() != 0 { + + log.Printf("Cannot update event %s as whole day.\n", ical.UID()) + wholeDay = false + } + } + + if wholeDay { + // For wholeDay events, the endDate is the beginning of the next day. For + // the formatting to work, we need to move that back into the previous day. + newEnd = newEnd.Add(-1 * time.Second) + } + + formatTime := func(t time.Time) string { + if wholeDay { + return ";VALUE=DATE:" + t.Format(ICAL_DATE) + } else { + return ":" + t.UTC().Format(ICAL_TIME) + "Z" + } + } + for i, line := range ical.eventData { match := fieldMatch.FindStringSubmatch(line) if match == nil { @@ -90,9 +122,9 @@ func (ical *ICal) Update(newStart, newEnd time.Time) { switch match[1] { case "DTSTART": - ical.eventData[i] = "DTSTART:" + newStart.UTC().Format(ICAL_TIME) + "Z" + ical.eventData[i] = match[1] + formatTime(newStart) case "DTEND": - ical.eventData[i] = "DTEND:" + newEnd.UTC().Format(ICAL_TIME) + "Z" + ical.eventData[i] = match[1] + formatTime(newEnd) case "DTSTAMP", "LAST-MODIFIED": ical.eventData[i] = match[1] + ":" + now.Format(ICAL_TIME) + "Z" } diff --git a/src/calanonsync/caldav_test.go b/src/calanonsync/caldav_test.go index 3ea4be8..fb4fc45 100644 --- a/src/calanonsync/caldav_test.go +++ b/src/calanonsync/caldav_test.go @@ -79,7 +79,7 @@ func TestICal_Update(t *testing.T) { t.Run("Values updated", func(t *testing.T) { ical, _ := ParseICal(strings.NewReader(icsSimple)) - ical.Update(newStart, newEnd) + ical.Update(newStart, newEnd, false) if ical.Start() != newStart { t.Error("Start not updated correctly") @@ -92,6 +92,7 @@ func TestICal_Update(t *testing.T) { t.Error("Timestamp doesn't seem to be updated") } }) + t.Run("Other values untouched", func(t *testing.T) { // Use a ICal structure with dummy/unknown fields but also without // DTSTAMP or LAST-MODIFIED, so we can do a string comparison against @@ -112,7 +113,7 @@ END:VEVENT EVEN;MORE:STUFF END:VCALENDAR`)) - ical.Update(newStart, newEnd) + ical.Update(newStart, newEnd, false) if ical.String() != `BEGIN:VCALENDAR PRODID:-//some//thing//EN @@ -133,6 +134,25 @@ END:VCALENDAR` { t.Error("The resulting ICS seems wrong.") } }) + + t.Run("Values wholeDay", func(t *testing.T) { + newStart := time.Date(2019, 1, 2, 0, 0, 0, 0, time.Local) + newEnd := time.Date(2019, 1, 3, 0, 0, 0, 0, time.Local) + + ical, _ := ParseICal(strings.NewReader(icsSimple)) + ical.Update(newStart, newEnd, true) + + if ical.Start() != newStart { + t.Error("Start not updated correctly") + } + if ical.End() != newEnd { + t.Error("End not updated correctly") + } + + if ical.getTimeField("DTSTAMP").Sub(time.Now()) > 5*time.Second { + t.Error("Timestamp doesn't seem to be updated") + } + }) } const icsWithTZ = `BEGIN:VCALENDAR