From e0e02a29d8b7d895150c03a526df9366b9bbe06a Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Wed, 27 Mar 2019 05:04:39 +0100 Subject: [PATCH 01/15] sketch first draft --- data/resource.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/data/resource.go b/data/resource.go index 41f1e55..9048bd4 100644 --- a/data/resource.go +++ b/data/resource.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" "time" + "regexp" "github.com/laurent22/ical-go" @@ -103,8 +104,51 @@ func (r *Resource) EndTimeUTC() time.Time { } func (r *Resource) Recurrences() []ResourceRecurrence { - // TODO: Implement. This server does not support ical recurrences yet. We just return an empty array. - return []ResourceRecurrence{} + vevent := r.icalVEVENT() + rrule := vevent.PropString("RRULE", "") + + if ( rrule != "" ) { + result := []ResourceRecurrence{} + log.Printf("RECURRENCE : %s, Path: %s", rrule, r.Path ) + var rex = regexp.MustCompile("(\\w+)=(\\w+)") + data := rex.FindAllStringSubmatch(rrule, -1) + + res := make(map[string]string) + for _, kv := range data { + k := kv[1] + v := kv[2] + res[k] = v + } + log.Println(res) + + // TODO Parse rrule + // start: + // FREQ + // INTERVAL (SECONDLY, MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY) + + // cond: + // BYSECOND + // BYMINUTE + // BYHOUR + // BYDAY + // BYMONTHDAY + // BYYEARDAY + // BYWEEKNO + // BYMONTH + // BYSETPOS + // WKST + + // end + // COUNT + // UNTIL + + // TODO add rdate + // TODO remove exdate + return result + + } else { + return []ResourceRecurrence{} + } } func (r *Resource) HasProperty(propPath ...string) bool { From d2af016b5b646303e7817c3946eef4d760c22cd8 Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Wed, 27 Mar 2019 07:34:12 +0100 Subject: [PATCH 02/15] create new method --- data/resource.go | 81 +++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/data/resource.go b/data/resource.go index 9048bd4..50defa5 100644 --- a/data/resource.go +++ b/data/resource.go @@ -108,42 +108,11 @@ func (r *Resource) Recurrences() []ResourceRecurrence { rrule := vevent.PropString("RRULE", "") if ( rrule != "" ) { - result := []ResourceRecurrence{} log.Printf("RECURRENCE : %s, Path: %s", rrule, r.Path ) - var rex = regexp.MustCompile("(\\w+)=(\\w+)") - data := rex.FindAllStringSubmatch(rrule, -1) - - res := make(map[string]string) - for _, kv := range data { - k := kv[1] - v := kv[2] - res[k] = v - } - log.Println(res) - - // TODO Parse rrule - // start: - // FREQ - // INTERVAL (SECONDLY, MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY) - - // cond: - // BYSECOND - // BYMINUTE - // BYHOUR - // BYDAY - // BYMONTHDAY - // BYYEARDAY - // BYWEEKNO - // BYMONTH - // BYSETPOS - // WKST - - // end - // COUNT - // UNTIL - - // TODO add rdate - // TODO remove exdate + start := r.StartTimeUTC() + end := r.EndTimeUTC() + duration := end.Sub(start) + result := r.calcRecurrences( start, duration, rrule ) return result } else { @@ -277,6 +246,45 @@ func (r *Resource) icalendar() *ical.Node { return icalNode } +func (r *Resource) calcRecurrences( start time.Time, duraction time.Duration, rrule string) ([]ResourceRecurrence) { + result := []ResourceRecurrence{} + var rex = regexp.MustCompile("(\\w+)=(\\w+)") + data := rex.FindAllStringSubmatch(rrule, -1) + + res := make(map[string]string) + for _, kv := range data { + k := kv[1] + v := kv[2] + res[k] = v + } + log.Println(res) + + // TODO Parse rrule + // start: + // FREQ + // INTERVAL (SECONDLY, MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY) + + // cond: + // BYSECOND + // BYMINUTE + // BYHOUR + // BYDAY + // BYMONTHDAY + // BYYEARDAY + // BYWEEKNO + // BYMONTH + // BYSETPOS + // WKST + + // end + // COUNT + // UNTIL + + // TODO add rdate + // TODO remove exdate + return result; +} + type FileResourceAdapter struct { finfo os.FileInfo resourcePath string @@ -319,3 +327,6 @@ func (adp *FileResourceAdapter) CalculateEtag() string { func (adp *FileResourceAdapter) GetModTime() time.Time { return adp.finfo.ModTime() } + + + From ac2d570053951a88ae4d991b3c61cb76f662f24d Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Wed, 27 Mar 2019 08:23:44 +0100 Subject: [PATCH 03/15] add first test --- data/resource.go | 48 +++++++++++++++++++++++++++++++++++++++---- data/resource_test.go | 19 +++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/data/resource.go b/data/resource.go index 50defa5..cf58128 100644 --- a/data/resource.go +++ b/data/resource.go @@ -246,18 +246,58 @@ func (r *Resource) icalendar() *ical.Node { return icalNode } -func (r *Resource) calcRecurrences( start time.Time, duraction time.Duration, rrule string) ([]ResourceRecurrence) { +func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rrule string) ([]ResourceRecurrence) { result := []ResourceRecurrence{} var rex = regexp.MustCompile("(\\w+)=(\\w+)") data := rex.FindAllStringSubmatch(rrule, -1) - res := make(map[string]string) + params := make(map[string]string) for _, kv := range data { k := kv[1] v := kv[2] - res[k] = v + params[k] = v + } + log.Println(params) + + count := 1000; + if val, ok := params["COUNT"]; ok { + tmp, err := strconv.Atoi(val) + if err == nil { + count = tmp + } + + } + var inc time.Duration + + interval := params["INTERVAL"] + switch interval { + case "SECONDLY": + inc,_ = time.ParseDuration("1s") + case "MINUTELY": + inc,_ = time.ParseDuration("1m") + case "HOURLY": + inc,_ = time.ParseDuration("1h") + case "DAILY": + inc,_ = time.ParseDuration("24h") + case "WEEKLY": + inc,_ = time.ParseDuration("168h") + case "MONTHLY": + inc,_ = time.ParseDuration("744h") + case "YEARLY": + inc,_ = time.ParseDuration("8760h") + default: + return result; + } + + c := 0 + stmp := start + + for c < count { + c += 1 + stmp = stmp.Add(inc) + recurrence := ResourceRecurrence{ stmp, stmp.Add(duration) } + result = append(result, recurrence) } - log.Println(res) // TODO Parse rrule // start: diff --git a/data/resource_test.go b/data/resource_test.go index f13718f..d073877 100644 --- a/data/resource_test.go +++ b/data/resource_test.go @@ -327,6 +327,25 @@ func TestPropertyParams(t *testing.T) { } } +func TestRecurrenceOnce(t *testing.T) { + adp := new(FakeResourceAdapter) + res := NewResource("/foo", adp) + + adp.contentData = ` + BEGIN:VCALENDAR + BEGIN:VEVENT + DTSTART:20160914T170000Z + DTEND:20160914T180000Z + RRULE: INTERVAL=DAILY;COUNT=1 + END:VEVENT + END:VCALENDAR + ` + if len(res.Recurrences()) != 1 { + t.Error("Expected 1 Recurrencies got, ", len(res.Recurrences())) + } +} + + type FakeResourceAdapter struct { collection bool etag string From c29489db5ef0974e8502aca6533f79224af30f60 Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Thu, 28 Mar 2019 04:10:40 +0100 Subject: [PATCH 04/15] add interval and fix frequency --- data/resource.go | 15 +++++++++++---- data/resource_test.go | 28 +++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/data/resource.go b/data/resource.go index cf58128..181e978 100644 --- a/data/resource.go +++ b/data/resource.go @@ -265,12 +265,19 @@ func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rru if err == nil { count = tmp } - } + interval := 1; + if val, ok := params["INTERVAL"]; ok { + tmp, err := strconv.Atoi(val) + if err == nil { + interval = tmp + } + } + var inc time.Duration - interval := params["INTERVAL"] - switch interval { + freq := params["FREQ"] + switch freq { case "SECONDLY": inc,_ = time.ParseDuration("1s") case "MINUTELY": @@ -288,7 +295,7 @@ func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rru default: return result; } - + inc = time.Duration(int64(inc)*int64(interval)) c := 0 stmp := start diff --git a/data/resource_test.go b/data/resource_test.go index d073877..3da91a0 100644 --- a/data/resource_test.go +++ b/data/resource_test.go @@ -336,13 +336,39 @@ func TestRecurrenceOnce(t *testing.T) { BEGIN:VEVENT DTSTART:20160914T170000Z DTEND:20160914T180000Z - RRULE: INTERVAL=DAILY;COUNT=1 + RRULE: FREQ=DAILY;COUNT=1 END:VEVENT END:VCALENDAR ` if len(res.Recurrences()) != 1 { t.Error("Expected 1 Recurrencies got, ", len(res.Recurrences())) } + + if (res.Recurrences()[0].StartTime != time.Date(2016,9,15,17,0,0,0, time.UTC)) { + t.Error("Unexpected Start time, ", res.Recurrences()[0].StartTime); + } +} + +func TestRecurrenceCountInterval(t *testing.T) { + adp := new(FakeResourceAdapter) + res := NewResource("/foo", adp) + + adp.contentData = ` + BEGIN:VCALENDAR + BEGIN:VEVENT + DTSTART:20160914T170000Z + DTEND:20160914T180000Z + RRULE: FREQ=DAILY;COUNT=2;INTERVAL=2 + END:VEVENT + END:VCALENDAR + ` + if len(res.Recurrences()) != 2 { + t.Error("Expected 2 Recurrencies got, ", len(res.Recurrences())) + } + + if (res.Recurrences()[1].StartTime != time.Date(2016,9,18,17,0,0,0, time.UTC)) { + t.Error("Unexpected Start time, ", res.Recurrences()[1].StartTime); + } } From fef2f381e46066da36e8a94aaf21ea2ec55e716b Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Thu, 28 Mar 2019 04:36:22 +0100 Subject: [PATCH 05/15] implement until --- data/resource.go | 13 +++++++++++++ data/resource_test.go | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/data/resource.go b/data/resource.go index 181e978..07fdf6f 100644 --- a/data/resource.go +++ b/data/resource.go @@ -295,13 +295,26 @@ func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rru default: return result; } + inc = time.Duration(int64(inc)*int64(interval)) + until := time.Date(9999,1,1,0,0,0,0,time.UTC) + if tmp,ok := params["UNTIL"]; ok { + if d,ok2 := time.Parse("20060102T150405Z", tmp);ok2==nil { + until = d + } else { + log.Println("ERR ", ok2) + } + } + log.Println("UNTIL ", until) c := 0 stmp := start for c < count { c += 1 stmp = stmp.Add(inc) + if (!stmp.Before(until)) { + break + } recurrence := ResourceRecurrence{ stmp, stmp.Add(duration) } result = append(result, recurrence) } diff --git a/data/resource_test.go b/data/resource_test.go index 3da91a0..de949c3 100644 --- a/data/resource_test.go +++ b/data/resource_test.go @@ -371,6 +371,28 @@ func TestRecurrenceCountInterval(t *testing.T) { } } +func TestRecurrenceUntil(t *testing.T) { + adp := new(FakeResourceAdapter) + res := NewResource("/foo", adp) + + adp.contentData = ` + BEGIN:VCALENDAR + BEGIN:VEVENT + DTSTART:20160914T170000Z + DTEND:20160914T180000Z + RRULE: FREQ=WEEKLY; UNTIL=20160929T000000Z + END:VEVENT + END:VCALENDAR + ` + if len(res.Recurrences()) != 2 { + t.Error("Expected 2 Recurrencies got, ", res.Recurrences()) + } + + if (res.Recurrences()[1].StartTime != time.Date(2016,9,28,17,0,0,0, time.UTC)) { + t.Error("Unexpected Start time, ", res.Recurrences()[1].StartTime); + } +} + type FakeResourceAdapter struct { collection bool From 8b73fa20b57be122bf9cfaf0b2f14ff45367d519 Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Thu, 28 Mar 2019 07:31:44 +0100 Subject: [PATCH 06/15] refactor functions --- data/resource.go | 95 +++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/data/resource.go b/data/resource.go index 07fdf6f..30304bf 100644 --- a/data/resource.go +++ b/data/resource.go @@ -248,35 +248,13 @@ func (r *Resource) icalendar() *ical.Node { func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rrule string) ([]ResourceRecurrence) { result := []ResourceRecurrence{} - var rex = regexp.MustCompile("(\\w+)=(\\w+)") - data := rex.FindAllStringSubmatch(rrule, -1) - - params := make(map[string]string) - for _, kv := range data { - k := kv[1] - v := kv[2] - params[k] = v - } - log.Println(params) - - count := 1000; - if val, ok := params["COUNT"]; ok { - tmp, err := strconv.Atoi(val) - if err == nil { - count = tmp - } - } - interval := 1; - if val, ok := params["INTERVAL"]; ok { - tmp, err := strconv.Atoi(val) - if err == nil { - interval = tmp - } - } + rule := NewRecurrenceRule(rrule) + count := rule.getIntParam("COUNT", 1000) + interval := rule.getIntParam("INTERVAL", 1) var inc time.Duration - freq := params["FREQ"] + freq := rule.getParam("FREQ", "") switch freq { case "SECONDLY": inc,_ = time.ParseDuration("1s") @@ -297,14 +275,7 @@ func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rru } inc = time.Duration(int64(inc)*int64(interval)) - until := time.Date(9999,1,1,0,0,0,0,time.UTC) - if tmp,ok := params["UNTIL"]; ok { - if d,ok2 := time.Parse("20060102T150405Z", tmp);ok2==nil { - until = d - } else { - log.Println("ERR ", ok2) - } - } + until := rule.getTimeParam("UNTIL", time.Date(9999,12,31,23,59,59,00,time.UTC)) log.Println("UNTIL ", until) c := 0 stmp := start @@ -345,6 +316,8 @@ func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rru return result; } + + type FileResourceAdapter struct { finfo os.FileInfo resourcePath string @@ -389,4 +362,58 @@ func (adp *FileResourceAdapter) GetModTime() time.Time { } +type RecurrenceRuleInterface interface { + GetIntParam(name string, defaultValue int) int + GetStringParam(name string, defaultValue string) string + GetTimeParam(name string, defaultValue time.Time) time.Time +} + +type RecurrenceRule struct { + rrule string + params map[string]string +} +func NewRecurrenceRule(rrule string) RecurrenceRule { + var rex = regexp.MustCompile("(\\w+)=(\\w+)") + data := rex.FindAllStringSubmatch(rrule, -1) + + p := make(map[string]string) + for _, kv := range data { + k := kv[1] + v := kv[2] + p[k] = v + } + return RecurrenceRule{ + rrule: rrule, + params: p, + } +} + +func (r *RecurrenceRule) getIntParam(name string, defaultValue int) int { + v := defaultValue + if val, ok := r.params[name]; ok { + tmp, err := strconv.Atoi(val) + if err == nil { + v = tmp + } + } + return v +} + +func (r *RecurrenceRule) getParam(name string, defaultValue string) string { + v := defaultValue + if val, ok := r.params[name]; ok { + v = val + } + return v +} + +func (r *RecurrenceRule) getTimeParam(name string, defaultValue time.Time) time.Time { + v := defaultValue + if tmp,ok := r.params[name]; ok { + if d,ok2 := time.Parse("20060102T150405Z", tmp);ok2==nil { + v = d + } + } + return v +} From 8bdcb319d822c3e19a1ee3a3b808515e319cd5df Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Sun, 31 Mar 2019 06:05:50 +0200 Subject: [PATCH 07/15] fix month and year --- data/resource.go | 97 +++++++++++++++++++++++++++++-------------- data/resource_test.go | 45 ++++++++++++++++++++ 2 files changed, 110 insertions(+), 32 deletions(-) diff --git a/data/resource.go b/data/resource.go index 30304bf..f7c748d 100644 --- a/data/resource.go +++ b/data/resource.go @@ -251,38 +251,15 @@ func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rru rule := NewRecurrenceRule(rrule) count := rule.getIntParam("COUNT", 1000) - interval := rule.getIntParam("INTERVAL", 1) - var inc time.Duration - - freq := rule.getParam("FREQ", "") - switch freq { - case "SECONDLY": - inc,_ = time.ParseDuration("1s") - case "MINUTELY": - inc,_ = time.ParseDuration("1m") - case "HOURLY": - inc,_ = time.ParseDuration("1h") - case "DAILY": - inc,_ = time.ParseDuration("24h") - case "WEEKLY": - inc,_ = time.ParseDuration("168h") - case "MONTHLY": - inc,_ = time.ParseDuration("744h") - case "YEARLY": - inc,_ = time.ParseDuration("8760h") - default: - return result; - } - - inc = time.Duration(int64(inc)*int64(interval)) until := rule.getTimeParam("UNTIL", time.Date(9999,12,31,23,59,59,00,time.UTC)) + log.Println("UNTIL ", until) c := 0 stmp := start for c < count { c += 1 - stmp = stmp.Add(inc) + stmp = rule.GetNext(stmp) if (!stmp.Before(until)) { break } @@ -292,9 +269,9 @@ func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rru // TODO Parse rrule // start: - // FREQ - // INTERVAL (SECONDLY, MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY) - + // FREQ (SECONDLY, MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY) + // INTERVAL (done) + // These can either be filters or set a value directly - if the freq is smaller than the unit it filters otherwise sets to a fixed value // cond: // BYSECOND // BYMINUTE @@ -308,16 +285,14 @@ func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rru // WKST // end - // COUNT - // UNTIL + // COUNT (done) + // UNTIL (done) // TODO add rdate // TODO remove exdate return result; } - - type FileResourceAdapter struct { finfo os.FileInfo resourcePath string @@ -417,3 +392,61 @@ func (r *RecurrenceRule) getTimeParam(name string, defaultValue time.Time) time. } return v } + +func (r *RecurrenceRule) GetNext(start time.Time) time.Time { + interval := r.getIntParam("INTERVAL", 1) + var inc time.Duration + + freq := r.getParam("FREQ", "") + switch freq { + case "SECONDLY": + inc,_ = time.ParseDuration("1s") + inc = time.Duration(int64(inc)*int64(interval)) + return start.Add(inc) + case "MINUTELY": + inc,_ = time.ParseDuration("1m") + inc = time.Duration(int64(inc)*int64(interval)) + return start.Add(inc) + case "HOURLY": + inc,_ = time.ParseDuration("1h") + inc = time.Duration(int64(inc)*int64(interval)) + return start.Add(inc) + case "DAILY": + inc,_ = time.ParseDuration("24h") + inc = time.Duration(int64(inc)*int64(interval)) + return start.Add(inc) + case "WEEKLY": + inc,_ = time.ParseDuration("168h") + inc = time.Duration(int64(inc)*int64(interval)) + return start.Add(inc) + case "MONTHLY": + year:=start.Year() + month:=int(start.Month())-1 + if month + interval >= 12 { + year = year + 1 + } + month = (month + interval) % 12 + day:=start.Day() + hour:=start.Hour() + minute:=start.Minute() + second:=start.Second() + nanosecond:=start.Nanosecond() + return time.Date(year, time.Month(month+1), day, hour, minute, second, nanosecond, time.UTC) + case "YEARLY": + year:=start.Year() + year = year + interval + + month:=start.Month() + day:=start.Day() + hour:=start.Hour() + minute:=start.Minute() + second:=start.Second() + nanosecond:=start.Nanosecond() + return time.Date(year, month, day, hour, minute, second, nanosecond, time.UTC) + default: + inc,_ = time.ParseDuration("24h") + inc = time.Duration(int64(inc)*int64(interval)) + return start.Add(inc) + } + +} diff --git a/data/resource_test.go b/data/resource_test.go index de949c3..dd605ce 100644 --- a/data/resource_test.go +++ b/data/resource_test.go @@ -371,6 +371,51 @@ func TestRecurrenceCountInterval(t *testing.T) { } } +func TestRecurrenceCountYearly(t *testing.T) { + adp := new(FakeResourceAdapter) + res := NewResource("/foo", adp) + + adp.contentData = ` + BEGIN:VCALENDAR + BEGIN:VEVENT + DTSTART:20160914T170000Z + DTEND:20160914T180000Z + RRULE: FREQ=YEARLY;COUNT=2;INTERVAL=2 + END:VEVENT + END:VCALENDAR + ` + if len(res.Recurrences()) != 2 { + t.Error("Expected 2 Recurrencies got, ", len(res.Recurrences())) + } + + if (res.Recurrences()[1].StartTime != time.Date(2020,9,14,17,0,0,0, time.UTC)) { + t.Error("Unexpected Start time, ", res.Recurrences()[1].StartTime); + } +} + + +func TestRecurrenceCountMonthly(t *testing.T) { + adp := new(FakeResourceAdapter) + res := NewResource("/foo", adp) + + adp.contentData = ` + BEGIN:VCALENDAR + BEGIN:VEVENT + DTSTART:20160914T170000Z + DTEND:20160914T180000Z + RRULE: FREQ=MONTHLY;COUNT=2;INTERVAL=2 + END:VEVENT + END:VCALENDAR + ` + if len(res.Recurrences()) != 2 { + t.Error("Expected 2 Recurrencies got, ", len(res.Recurrences())) + } + + if (res.Recurrences()[1].StartTime != time.Date(2017,1,14,17,0,0,0, time.UTC)) { + t.Error("Unexpected Start time, ", res.Recurrences()[1].StartTime); + } +} + func TestRecurrenceUntil(t *testing.T) { adp := new(FakeResourceAdapter) res := NewResource("/foo", adp) From 5070283cae332088f130dd0b1ac915cc8ff92b74 Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Sat, 6 Apr 2019 16:12:20 +0200 Subject: [PATCH 08/15] implement simple set version --- data/resource.go | 88 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 11 deletions(-) diff --git a/data/resource.go b/data/resource.go index f7c748d..4c79a2e 100644 --- a/data/resource.go +++ b/data/resource.go @@ -256,13 +256,16 @@ func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rru log.Println("UNTIL ", until) c := 0 stmp := start - + var skip bool for c < count { c += 1 - stmp = rule.GetNext(stmp) + stmp, skip = rule.GetNext(stmp) if (!stmp.Before(until)) { break } + if (skip) { + continue + } recurrence := ResourceRecurrence{ stmp, stmp.Add(duration) } result = append(result, recurrence) } @@ -375,6 +378,13 @@ func (r *RecurrenceRule) getIntParam(name string, defaultValue int) int { return v } +func( r *RecurrenceRule) hasParam(name string) bool { + if _, ok := r.params[name]; ok { + return true; + } + return false +} + func (r *RecurrenceRule) getParam(name string, defaultValue string) string { v := defaultValue if val, ok := r.params[name]; ok { @@ -393,32 +403,34 @@ func (r *RecurrenceRule) getTimeParam(name string, defaultValue time.Time) time. return v } -func (r *RecurrenceRule) GetNext(start time.Time) time.Time { +func (r *RecurrenceRule) GetNext(start time.Time) (time.Time, bool) { interval := r.getIntParam("INTERVAL", 1) var inc time.Duration freq := r.getParam("FREQ", "") + var res time.Time + switch freq { case "SECONDLY": inc,_ = time.ParseDuration("1s") inc = time.Duration(int64(inc)*int64(interval)) - return start.Add(inc) + res = start.Add(inc) case "MINUTELY": inc,_ = time.ParseDuration("1m") inc = time.Duration(int64(inc)*int64(interval)) - return start.Add(inc) + res = start.Add(inc) case "HOURLY": inc,_ = time.ParseDuration("1h") inc = time.Duration(int64(inc)*int64(interval)) - return start.Add(inc) + res = start.Add(inc) case "DAILY": inc,_ = time.ParseDuration("24h") inc = time.Duration(int64(inc)*int64(interval)) - return start.Add(inc) + res = start.Add(inc) case "WEEKLY": inc,_ = time.ParseDuration("168h") inc = time.Duration(int64(inc)*int64(interval)) - return start.Add(inc) + res = start.Add(inc) case "MONTHLY": year:=start.Year() month:=int(start.Month())-1 @@ -431,7 +443,7 @@ func (r *RecurrenceRule) GetNext(start time.Time) time.Time { minute:=start.Minute() second:=start.Second() nanosecond:=start.Nanosecond() - return time.Date(year, time.Month(month+1), day, hour, minute, second, nanosecond, time.UTC) + res = time.Date(year, time.Month(month+1), day, hour, minute, second, nanosecond, time.UTC) case "YEARLY": year:=start.Year() year = year + interval @@ -442,11 +454,65 @@ func (r *RecurrenceRule) GetNext(start time.Time) time.Time { minute:=start.Minute() second:=start.Second() nanosecond:=start.Nanosecond() - return time.Date(year, month, day, hour, minute, second, nanosecond, time.UTC) + res = time.Date(year, month, day, hour, minute, second, nanosecond, time.UTC) default: inc,_ = time.ParseDuration("24h") inc = time.Duration(int64(inc)*int64(interval)) - return start.Add(inc) + res = start.Add(inc) } + return r.replaceBy(res), r.skipBy(res) +} + +func (r *RecurrenceRule) freqToInt(freq string) int { + switch freq { + case "SECONDLY": + return 0 + case "MINUTELY": + return 1 + case "HOURLY": + return 2 + case "DAILY": + return 3 + case "WEEKLY": + return 4 + case "MONTHLY": + return 5 + case "YEARLY": + return 6 + default: + return 6 + } +} + +func (r *RecurrenceRule) replaceBy(t time.Time) time.Time { + year:=t.Year() + month:=int(t.Month())-1 + fint := r.freqToInt(r.getParam("FREQ", "")) + if (fint > 5 && r.hasParam("BYMONTH")) { + month = r.getIntParam("BYMONTH", 0)-1 + } + day:=t.Day() + if (fint > 4 && r.hasParam("BYMONTHDAY")) { + day = r.getIntParam("BYMONTHDAY", 0) + } + hour:=t.Hour() + if (fint > 3 && r.hasParam("BYHOUR")) { + hour = r.getIntParam("BYHOUR", 0) + } + minute:=t.Minute() + if (fint > 2 && r.hasParam("BYMINUTE")) { + minute = r.getIntParam("BYMINUTE", 0) + } + second:=t.Second() + if (fint > 1 && r.hasParam("BYSECOND")) { + second = r.getIntParam("BYSECOND", 0) + } + nanosecond:=t.Nanosecond() + + t = time.Date(year, time.Month(month+1), day, hour, minute, second, nanosecond, time.UTC) + return t; +} +func (r *RecurrenceRule) skipBy(t time.Time) bool { + return false } From a7fbc1c7f83755d0d0a83c97968a596ae7f7912b Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Wed, 10 Apr 2019 07:20:02 +0200 Subject: [PATCH 09/15] add comments --- data/resource.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/data/resource.go b/data/resource.go index 4c79a2e..baa78b7 100644 --- a/data/resource.go +++ b/data/resource.go @@ -485,16 +485,24 @@ func (r *RecurrenceRule) freqToInt(freq string) int { } func (r *RecurrenceRule) replaceBy(t time.Time) time.Time { + // TODO WKST + // TODO LISTS of by values + // TODO BYEASTER + // TODO BYWEEKDAY + // TODO BYSETPOS year:=t.Year() month:=int(t.Month())-1 fint := r.freqToInt(r.getParam("FREQ", "")) if (fint > 5 && r.hasParam("BYMONTH")) { month = r.getIntParam("BYMONTH", 0)-1 } + // TODO BYYEARDAY day:=t.Day() if (fint > 4 && r.hasParam("BYMONTHDAY")) { day = r.getIntParam("BYMONTHDAY", 0) } + // TODO BYWEEKNO + // TODO BYWEEKDAY hour:=t.Hour() if (fint > 3 && r.hasParam("BYHOUR")) { hour = r.getIntParam("BYHOUR", 0) From e017f9ed54ceea6809540878d8001678982b9431 Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Wed, 10 Apr 2019 07:40:37 +0200 Subject: [PATCH 10/15] add simple weekday implementation --- data/resource.go | 43 ++++++++++++++++++++++++++++++++++++++----- data/resource_test.go | 23 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/data/resource.go b/data/resource.go index baa78b7..a724495 100644 --- a/data/resource.go +++ b/data/resource.go @@ -484,25 +484,37 @@ func (r *RecurrenceRule) freqToInt(freq string) int { } } -func (r *RecurrenceRule) replaceBy(t time.Time) time.Time { +func (r *RecurrenceRule) replaceBy(start time.Time) time.Time { // TODO WKST // TODO LISTS of by values // TODO BYEASTER - // TODO BYWEEKDAY + // TODO BYDAY // TODO BYSETPOS + fint := r.freqToInt(r.getParam("FREQ", "")) + t := start + if (fint > 3 && r.hasParam("BYDAY")) { + w1 := int(t.Weekday()) + w2 := r.parseWeekday(r.getParam("BYDAY", "")) + wdiff := w2-w1 + if wdiff < 0 { + wdiff += 7 + } + inc,_ := time.ParseDuration("24h") + inc = time.Duration(int64(inc)*int64(wdiff)) + t = start.Add(inc) + } + year:=t.Year() month:=int(t.Month())-1 - fint := r.freqToInt(r.getParam("FREQ", "")) if (fint > 5 && r.hasParam("BYMONTH")) { month = r.getIntParam("BYMONTH", 0)-1 } - // TODO BYYEARDAY day:=t.Day() + // TODO BYYEARDAY if (fint > 4 && r.hasParam("BYMONTHDAY")) { day = r.getIntParam("BYMONTHDAY", 0) } // TODO BYWEEKNO - // TODO BYWEEKDAY hour:=t.Hour() if (fint > 3 && r.hasParam("BYHOUR")) { hour = r.getIntParam("BYHOUR", 0) @@ -521,6 +533,27 @@ func (r *RecurrenceRule) replaceBy(t time.Time) time.Time { return t; } +func (r *RecurrenceRule) parseWeekday(day string) int { + switch day { + case "SO": + return 0 + case "MO": + return 1 + case "TU": + return 2 + case "WE": + return 3 + case "TH": + return 4 + case "FR": + return 5 + case "SA": + return 6 + default: + return 1 + } +} + func (r *RecurrenceRule) skipBy(t time.Time) bool { return false } diff --git a/data/resource_test.go b/data/resource_test.go index dd605ce..17fe74a 100644 --- a/data/resource_test.go +++ b/data/resource_test.go @@ -438,6 +438,29 @@ func TestRecurrenceUntil(t *testing.T) { } } +func TestByWeekday(t *testing.T) { + adp := new(FakeResourceAdapter) + res := NewResource("/foo", adp) + + adp.contentData = ` + BEGIN:VCALENDAR + BEGIN:VEVENT + DTSTART:20190101T170000Z + DTEND:20190101T180000Z + RRULE: FREQ=WEEKLY;BYDAY=MO;COUNT=3 + END:VEVENT + END:VCALENDAR + ` + if len(res.Recurrences()) != 3 { + t.Error("Expected 3 Recurrencies got, ", res.Recurrences()) + } + + if (res.Recurrences()[2].StartTime != time.Date(2019,1,28,17,0,0,0, time.UTC)) { + t.Error("Unexpected Start time, ", res.Recurrences()[2].StartTime); + } +} + + type FakeResourceAdapter struct { collection bool From 67b79b949cd489f207e424436a4c62cbfd35849a Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Wed, 10 Apr 2019 08:40:59 +0200 Subject: [PATCH 11/15] implement weekly and monthly by day --- data/resource.go | 53 ++++++++++++++++++++++-- data/resource_test.go | 95 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 3 deletions(-) diff --git a/data/resource.go b/data/resource.go index a724495..036fe01 100644 --- a/data/resource.go +++ b/data/resource.go @@ -253,7 +253,7 @@ func (r *Resource) calcRecurrences( start time.Time, duration time.Duration, rru count := rule.getIntParam("COUNT", 1000) until := rule.getTimeParam("UNTIL", time.Date(9999,12,31,23,59,59,00,time.UTC)) - log.Println("UNTIL ", until) + //log.Println("UNTIL ", until) c := 0 stmp := start var skip bool @@ -352,7 +352,7 @@ type RecurrenceRule struct { } func NewRecurrenceRule(rrule string) RecurrenceRule { - var rex = regexp.MustCompile("(\\w+)=(\\w+)") + var rex = regexp.MustCompile("(\\w+)=([a-zA-Z0-9-]+)") data := rex.FindAllStringSubmatch(rrule, -1) p := make(map[string]string) @@ -361,6 +361,7 @@ func NewRecurrenceRule(rrule string) RecurrenceRule { v := kv[2] p[k] = v } + return RecurrenceRule{ rrule: rrule, params: p, @@ -492,7 +493,7 @@ func (r *RecurrenceRule) replaceBy(start time.Time) time.Time { // TODO BYSETPOS fint := r.freqToInt(r.getParam("FREQ", "")) t := start - if (fint > 3 && r.hasParam("BYDAY")) { + if (fint == 4 && r.hasParam("BYDAY")) { // Weekly w1 := int(t.Weekday()) w2 := r.parseWeekday(r.getParam("BYDAY", "")) wdiff := w2-w1 @@ -514,6 +515,47 @@ func (r *RecurrenceRule) replaceBy(start time.Time) time.Time { if (fint > 4 && r.hasParam("BYMONTHDAY")) { day = r.getIntParam("BYMONTHDAY", 0) } + if (fint == 5 && r.hasParam("BYDAY")) { // Monthly + byday := r.getParam("BYDAY", "") + d:=0 + pos:= r.getIntParam("BYPOS", 1) + if (len(byday) <= 2) { + d = r.parseWeekday(byday) + } else { + d = r.parseWeekday(byday[len(byday)-1:]) + tmp,err:=strconv.Atoi(byday[:len(byday)-2]) + if err == nil { + pos = tmp + } + } + if pos > 0 { + first := time.Date(year, time.Month(month+1), 1, 0, 0, 0, 0, time.UTC) + + w1 := int(first.Weekday()) + wdiff := d - w1; + if wdiff < 0 { + wdiff+=7 + } + day = 1+ wdiff + 7*(pos-1) + } else { + yofs := 0 + if month == 11 { + yofs = 1 // handle december + } + first := time.Date(year+yofs, time.Month(month+2), 1, 0, 0, 0, 0, time.UTC) + + w1 := int(first.Weekday()) + wdiff := d - w1; + if wdiff < 0 { + wdiff+=7 + } + wdiff += pos * 7 + inc,_ := time.ParseDuration("24h") + inc = time.Duration(int64(inc)*int64(wdiff)) + day = first.Add(inc).Day() + } + } + // TODO BYWEEKNO hour:=t.Hour() if (fint > 3 && r.hasParam("BYHOUR")) { @@ -534,6 +576,11 @@ func (r *RecurrenceRule) replaceBy(start time.Time) time.Time { } func (r *RecurrenceRule) parseWeekday(day string) int { + i, err := strconv.Atoi(day) + if err == nil { + return i + } + switch day { case "SO": return 0 diff --git a/data/resource_test.go b/data/resource_test.go index 17fe74a..05ea9b2 100644 --- a/data/resource_test.go +++ b/data/resource_test.go @@ -460,6 +460,101 @@ func TestByWeekday(t *testing.T) { } } +func TestByWeekdayNum(t *testing.T) { + adp := new(FakeResourceAdapter) + res := NewResource("/foo", adp) + + adp.contentData = ` + BEGIN:VCALENDAR + BEGIN:VEVENT + DTSTART:20190101T170000Z + DTEND:20190101T180000Z + RRULE: FREQ=WEEKLY;BYDAY=1;COUNT=3 + END:VEVENT + END:VCALENDAR + ` + if len(res.Recurrences()) != 3 { + t.Error("Expected 3 Recurrencies got, ", res.Recurrences()) + } + + if (res.Recurrences()[2].StartTime != time.Date(2019,1,28,17,0,0,0, time.UTC)) { + t.Error("Unexpected Start time, ", res.Recurrences()[2].StartTime); + } +} + +func TestByWeekdayPos(t *testing.T) { + adp := new(FakeResourceAdapter) + res := NewResource("/foo", adp) + + adp.contentData = ` + BEGIN:VCALENDAR + BEGIN:VEVENT + DTSTART:20190101T170000Z + DTEND:20190101T180000Z + RRULE: FREQ=MONTHLY;BYDAY=2MO;COUNT=3 + END:VEVENT + END:VCALENDAR + ` + + fmt.Println(res.Recurrences()) + if len(res.Recurrences()) != 3 { + t.Error("Expected 3 Recurrencies got, ", res.Recurrences()) + } + + if (res.Recurrences()[2].StartTime != time.Date(2019,4,8,17,0,0,0, time.UTC)) { + t.Error("Unexpected Start time, ", res.Recurrences()[2].StartTime); + } +} + +func TestByWeekdayPosParam(t *testing.T) { + adp := new(FakeResourceAdapter) + res := NewResource("/foo", adp) + + adp.contentData = ` + BEGIN:VCALENDAR + BEGIN:VEVENT + DTSTART:20190101T170000Z + DTEND:20190101T180000Z + RRULE: FREQ=MONTHLY;BYDAY=MO;BYPOS=2;COUNT=3 + END:VEVENT + END:VCALENDAR + ` + + fmt.Println(res.Recurrences()) + if len(res.Recurrences()) != 3 { + t.Error("Expected 3 Recurrencies got, ", res.Recurrences()) + } + + if (res.Recurrences()[2].StartTime != time.Date(2019,4,8,17,0,0,0, time.UTC)) { + t.Error("Unexpected Start time, ", res.Recurrences()[2].StartTime); + } +} + +func TestByWeekdayPosNeg(t *testing.T) { + adp := new(FakeResourceAdapter) + res := NewResource("/foo", adp) + + adp.contentData = ` + BEGIN:VCALENDAR + BEGIN:VEVENT + DTSTART:20190101T170000Z + DTEND:20190101T180000Z + RRULE: FREQ=MONTHLY;BYDAY=-1MO;COUNT=3 + END:VEVENT + END:VCALENDAR + ` + + fmt.Println(res.Recurrences()) + if len(res.Recurrences()) != 3 { + t.Error("Expected 3 Recurrencies got, ", res.Recurrences()) + } + + if (res.Recurrences()[2].StartTime != time.Date(2019,4,29,17,0,0,0, time.UTC)) { + t.Error("Unexpected Start time, ", res.Recurrences()[2].StartTime); + } +} + + type FakeResourceAdapter struct { From 333df1469dcf6bbd8cd5258479e4bb8a55708946 Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Sat, 13 Apr 2019 05:23:04 +0200 Subject: [PATCH 12/15] add skip function --- data/resource.go | 80 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/data/resource.go b/data/resource.go index 036fe01..483f060 100644 --- a/data/resource.go +++ b/data/resource.go @@ -464,33 +464,11 @@ func (r *RecurrenceRule) GetNext(start time.Time) (time.Time, bool) { return r.replaceBy(res), r.skipBy(res) } -func (r *RecurrenceRule) freqToInt(freq string) int { - switch freq { - case "SECONDLY": - return 0 - case "MINUTELY": - return 1 - case "HOURLY": - return 2 - case "DAILY": - return 3 - case "WEEKLY": - return 4 - case "MONTHLY": - return 5 - case "YEARLY": - return 6 - default: - return 6 - } -} - func (r *RecurrenceRule) replaceBy(start time.Time) time.Time { // TODO WKST // TODO LISTS of by values // TODO BYEASTER - // TODO BYDAY - // TODO BYSETPOS + // TODO BYWEEKNO fint := r.freqToInt(r.getParam("FREQ", "")) t := start if (fint == 4 && r.hasParam("BYDAY")) { // Weekly @@ -511,7 +489,16 @@ func (r *RecurrenceRule) replaceBy(start time.Time) time.Time { month = r.getIntParam("BYMONTH", 0)-1 } day:=t.Day() - // TODO BYYEARDAY + if (fint == 6 && r.hasParam("BYYEARDAY")) { + first := time.Date(year, time.Month(1), 1, 0, 0, 0, 0, time.UTC) + inc,_ := time.ParseDuration("24h") + days := r.getIntParam("BYYEARDAY",0) + inc = time.Duration(int64(inc)*int64(days)) + tmp := first.Add(inc) + day = tmp.Day() + month =int(tmp.Month())-1 + } + if (fint > 4 && r.hasParam("BYMONTHDAY")) { day = r.getIntParam("BYMONTHDAY", 0) } @@ -556,7 +543,6 @@ func (r *RecurrenceRule) replaceBy(start time.Time) time.Time { } } - // TODO BYWEEKNO hour:=t.Hour() if (fint > 3 && r.hasParam("BYHOUR")) { hour = r.getIntParam("BYHOUR", 0) @@ -575,6 +561,27 @@ func (r *RecurrenceRule) replaceBy(start time.Time) time.Time { return t; } +func (r *RecurrenceRule) freqToInt(freq string) int { + switch freq { + case "SECONDLY": + return 0 + case "MINUTELY": + return 1 + case "HOURLY": + return 2 + case "DAILY": + return 3 + case "WEEKLY": + return 4 + case "MONTHLY": + return 5 + case "YEARLY": + return 6 + default: + return 6 + } +} + func (r *RecurrenceRule) parseWeekday(day string) int { i, err := strconv.Atoi(day) if err == nil { @@ -602,5 +609,28 @@ func (r *RecurrenceRule) parseWeekday(day string) int { } func (r *RecurrenceRule) skipBy(t time.Time) bool { + fint := r.freqToInt(r.getParam("FREQ", "")) + month:=int(t.Month()) + hour:=t.Hour() + minute:=t.Minute() + second:=t.Second() + + if (fint <= 5 && r.hasParam("BYMONTH")) { + return r.getIntParam("BYMONTH",1) != month; + } + if (fint <= 3 && r.hasParam("BYDAY")) { + d1 := int(t.Weekday()) + d2 := r.parseWeekday( r.getParam("BYDAY","")) + return d1 != d2 + } + if (fint <= 2 && r.hasParam("BYHOUR")) { + return r.getIntParam("BYHOUR",0) != hour + } + if (fint <= 1 && r.hasParam("BYMINUTE")) { + return r.getIntParam("BYMINUTE",0) != minute + } + if (fint == 0 && r.hasParam("BYSECOND")) { + return r.getIntParam("BYSECOND",0) != second + } return false } From 7d0ce875578c1c1a6fbf2ad8f64880d5a0acf68d Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Fri, 11 Oct 2019 21:20:27 +0200 Subject: [PATCH 13/15] fix colors, infcloud support --- data/resource.go | 7 +++++-- handlers/multistatus.go | 7 +++++++ handlers/report.go | 4 ++-- ixml/ixml.go | 6 +++++- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/data/resource.go b/data/resource.go index 483f060..fe172c8 100644 --- a/data/resource.go +++ b/data/resource.go @@ -53,10 +53,13 @@ type Resource struct { func NewResource(resPath string, adp ResourceAdapter) Resource { pClean := lib.ToSlashPath(resPath) pSplit := strings.Split(strings.Trim(pClean, "/"), "/") - + p := pClean + if (adp.IsCollection()) { + p+="/" + } return Resource{ Name: pSplit[len(pSplit)-1], - Path: pClean, + Path: p, pathSplit: pSplit, adapter: adp, } diff --git a/handlers/multistatus.go b/handlers/multistatus.go index 345fb39..6640d88 100644 --- a/handlers/multistatus.go +++ b/handlers/multistatus.go @@ -128,6 +128,13 @@ func (ms *multistatusResp) Propstats(resource *data.Resource, reqprops []xml.Nam } pfound = true } + case ixml.CALENDAR_COLOR_TG: + if resource.IsCollection() { + if (resource.HasProperty("VEVENT","COLOR")) { + pvalue.Contents = append(pvalue.Contents, resource.GetPropertyValue("VEVENT","COLOR")) + pfound = true + } + } } if !pfound { diff --git a/handlers/report.go b/handlers/report.go index 299a4a0..f8f37fd 100644 --- a/handlers/report.go +++ b/handlers/report.go @@ -113,8 +113,8 @@ func (rh reportHandler) fetchResourcesByFilters(origin *data.Resource, filtersXM return reps, err } - for _, resource := range resources { - reps = append(reps, reportRes{resource.Path, &resource, true}) + for in, resource := range resources { + reps = append(reps, reportRes{resource.Path, &resources[in], true}) } } else { // the origin resource is not a collection, so returns just that as the result diff --git a/ixml/ixml.go b/ixml/ixml.go index 99ab5b9..8aad98b 100644 --- a/ixml/ixml.go +++ b/ixml/ixml.go @@ -13,12 +13,14 @@ const ( DAV_NS = "DAV:" CALDAV_NS = "urn:ietf:params:xml:ns:caldav" CALSERV_NS = "http://calendarserver.org/ns/" + APPLE_NS = "http://apple.com/ns/ical/" ) var NS_PREFIXES = map[string]string{ DAV_NS: "D", CALDAV_NS: "C", CALSERV_NS: "CS", + APPLE_NS: "A", } var ( @@ -44,13 +46,15 @@ var ( RESOURCE_TYPE_TG = xml.Name{DAV_NS, "resourcetype"} STATUS_TG = xml.Name{DAV_NS, "status"} SUPPORTED_CALENDAR_COMPONENT_SET_TG = xml.Name{CALDAV_NS, "supported-calendar-component-set"} + CALENDAR_COLOR_TG = xml.Name{APPLE_NS, "calendar-color"} ) func Namespaces() string { bf := new(lib.StringBuffer) bf.Write(`xmlns:%s="%s" `, NS_PREFIXES[DAV_NS], DAV_NS) bf.Write(`xmlns:%s="%s" `, NS_PREFIXES[CALDAV_NS], CALDAV_NS) - bf.Write(`xmlns:%s="%s"`, NS_PREFIXES[CALSERV_NS], CALSERV_NS) + bf.Write(`xmlns:%s="%s" `, NS_PREFIXES[CALSERV_NS], CALSERV_NS) + bf.Write(`xmlns:%s="%s"`, NS_PREFIXES[APPLE_NS], APPLE_NS) return bf.String() } From 8bb8c7e6bffb4a3e100f9fb8f929009108290f31 Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Tue, 29 Oct 2019 06:36:17 +0100 Subject: [PATCH 14/15] change namespace of fork --- config.go | 4 ++-- data/filters.go | 2 +- data/resource.go | 4 ++-- data/storage.go | 4 ++-- files/paths.go | 2 +- glide.yaml | 2 +- global/global.go | 4 ++-- handler.go | 4 ++-- handlers/builder.go | 4 ++-- handlers/multistatus.go | 8 ++++---- handlers/multistatus_test.go | 2 +- handlers/put.go | 2 +- handlers/report.go | 4 ++-- handlers/report_test.go | 4 ++-- handlers/response.go | 2 +- integration_test.go | 4 ++-- ixml/ixml.go | 2 +- test/resources.go | 4 ++-- 18 files changed, 31 insertions(+), 31 deletions(-) diff --git a/config.go b/config.go index 5b9c831..d01a78e 100644 --- a/config.go +++ b/config.go @@ -1,8 +1,8 @@ package caldav import ( - "github.com/samedi/caldav-go/data" - "github.com/samedi/caldav-go/global" + "github.com/ngradwohl/caldav-go/data" + "github.com/ngradwohl/caldav-go/global" ) // SetupStorage sets the storage to be used by the server. The storage is where the resources data will be fetched from. diff --git a/data/filters.go b/data/filters.go index 24349f2..3c7c8d0 100644 --- a/data/filters.go +++ b/data/filters.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/samedi/caldav-go/lib" + "github.com/ngradwohl/caldav-go/lib" ) const ( diff --git a/data/resource.go b/data/resource.go index dab18c3..fbb3b35 100644 --- a/data/resource.go +++ b/data/resource.go @@ -12,8 +12,8 @@ import ( "github.com/laurent22/ical-go" - "github.com/samedi/caldav-go/files" - "github.com/samedi/caldav-go/lib" + "github.com/ngradwohl/caldav-go/files" + "github.com/ngradwohl/caldav-go/lib" ) // ResourceInterface defines the main interface of a CalDAV resource object. This diff --git a/data/storage.go b/data/storage.go index 524fa10..68e1a91 100644 --- a/data/storage.go +++ b/data/storage.go @@ -1,8 +1,8 @@ package data import ( - "github.com/samedi/caldav-go/errs" - "github.com/samedi/caldav-go/files" + "github.com/ngradwohl/caldav-go/errs" + "github.com/ngradwohl/caldav-go/files" "io/ioutil" "log" "os" diff --git a/files/paths.go b/files/paths.go index cfcc4e8..9fb8851 100644 --- a/files/paths.go +++ b/files/paths.go @@ -1,7 +1,7 @@ package files import ( - "github.com/samedi/caldav-go/lib" + "github.com/ngradwohl/caldav-go/lib" "path/filepath" "strings" ) diff --git a/glide.yaml b/glide.yaml index 03463de..c6186b8 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,4 +1,4 @@ -package: github.com/samedi/caldav-go +package: github.com/ngradwohl/caldav-go import: - package: github.com/beevik/etree - package: github.com/laurent22/ical-go diff --git a/global/global.go b/global/global.go index 371c8a6..baab764 100644 --- a/global/global.go +++ b/global/global.go @@ -3,8 +3,8 @@ package global import ( - "github.com/samedi/caldav-go/data" - "github.com/samedi/caldav-go/lib" + "github.com/ngradwohl/caldav-go/data" + "github.com/ngradwohl/caldav-go/lib" ) // Storage represents the global storage used in the CRUD operations of resources. Default storage is the `data.FileStorage`. diff --git a/handler.go b/handler.go index b4bc63e..8dd2777 100644 --- a/handler.go +++ b/handler.go @@ -3,8 +3,8 @@ package caldav import ( "net/http" - "github.com/samedi/caldav-go/data" - "github.com/samedi/caldav-go/handlers" + "github.com/ngradwohl/caldav-go/data" + "github.com/ngradwohl/caldav-go/handlers" ) // RequestHandler handles the given CALDAV request and writes the reponse righ away. This function is to be diff --git a/handlers/builder.go b/handlers/builder.go index e7f638d..628b7bc 100644 --- a/handlers/builder.go +++ b/handlers/builder.go @@ -3,8 +3,8 @@ package handlers import ( "net/http" - "github.com/samedi/caldav-go/data" - "github.com/samedi/caldav-go/global" + "github.com/ngradwohl/caldav-go/data" + "github.com/ngradwohl/caldav-go/global" ) // HandlerInterface represents a CalDAV request handler. It has only one function `Handle`, diff --git a/handlers/multistatus.go b/handlers/multistatus.go index a1f80a4..bf35a3b 100644 --- a/handlers/multistatus.go +++ b/handlers/multistatus.go @@ -3,10 +3,10 @@ package handlers import ( "encoding/xml" "fmt" - "github.com/samedi/caldav-go/data" - "github.com/samedi/caldav-go/global" - "github.com/samedi/caldav-go/ixml" - "github.com/samedi/caldav-go/lib" + "github.com/ngradwohl/caldav-go/data" + "github.com/ngradwohl/caldav-go/global" + "github.com/ngradwohl/caldav-go/ixml" + "github.com/ngradwohl/caldav-go/lib" "net/http" ) diff --git a/handlers/multistatus_test.go b/handlers/multistatus_test.go index dccd6cc..d34f644 100644 --- a/handlers/multistatus_test.go +++ b/handlers/multistatus_test.go @@ -4,7 +4,7 @@ import ( "encoding/xml" "testing" - "github.com/samedi/caldav-go/test" + "github.com/ngradwohl/caldav-go/test" ) // Tests the XML serialization when the option to return a minimal content is set or not. diff --git a/handlers/put.go b/handlers/put.go index 339439c..0e3484d 100644 --- a/handlers/put.go +++ b/handlers/put.go @@ -1,7 +1,7 @@ package handlers import ( - "github.com/samedi/caldav-go/errs" + "github.com/ngradwohl/caldav-go/errs" "net/http" ) diff --git a/handlers/report.go b/handlers/report.go index 5171aa3..4d99e92 100644 --- a/handlers/report.go +++ b/handlers/report.go @@ -6,8 +6,8 @@ import ( "net/http" "strings" - "github.com/samedi/caldav-go/data" - "github.com/samedi/caldav-go/ixml" + "github.com/ngradwohl/caldav-go/data" + "github.com/ngradwohl/caldav-go/ixml" ) type reportHandler struct { diff --git a/handlers/report_test.go b/handlers/report_test.go index b047ec2..a88d375 100644 --- a/handlers/report_test.go +++ b/handlers/report_test.go @@ -5,8 +5,8 @@ import ( "net/http" "testing" - "github.com/samedi/caldav-go/ixml" - "github.com/samedi/caldav-go/test" + "github.com/ngradwohl/caldav-go/ixml" + "github.com/ngradwohl/caldav-go/test" ) // Test 1: when the URL path points to a collection and passing the list of hrefs in the body. diff --git a/handlers/response.go b/handlers/response.go index 3e87a4d..b5255d2 100644 --- a/handlers/response.go +++ b/handlers/response.go @@ -1,7 +1,7 @@ package handlers import ( - "github.com/samedi/caldav-go/errs" + "github.com/ngradwohl/caldav-go/errs" "io" "net/http" ) diff --git a/integration_test.go b/integration_test.go index 4e6fc96..64313a6 100644 --- a/integration_test.go +++ b/integration_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "github.com/samedi/caldav-go/ixml" - "github.com/samedi/caldav-go/test" + "github.com/ngradwohl/caldav-go/ixml" + "github.com/ngradwohl/caldav-go/test" ) // ============= TESTS ====================== diff --git a/ixml/ixml.go b/ixml/ixml.go index 064bee6..76a77af 100644 --- a/ixml/ixml.go +++ b/ixml/ixml.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/samedi/caldav-go/lib" + "github.com/ngradwohl/caldav-go/lib" ) const ( diff --git a/test/resources.go b/test/resources.go index 2935312..efba5a6 100644 --- a/test/resources.go +++ b/test/resources.go @@ -3,8 +3,8 @@ package test import ( "os" - "github.com/samedi/caldav-go/data" - "github.com/samedi/caldav-go/global" + "github.com/ngradwohl/caldav-go/data" + "github.com/ngradwohl/caldav-go/global" ) // Creates a fake storage to be used in unit tests. From e63a6c049d5c678b5396702a2d024f0a716a12e9 Mon Sep 17 00:00:00 2001 From: ngradwohl Date: Tue, 29 Oct 2019 06:43:37 +0100 Subject: [PATCH 15/15] fix tests --- handlers/multistatus_test.go | 6 +++--- handlers/report_test.go | 8 ++++---- integration_test.go | 16 ++++++++-------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/handlers/multistatus_test.go b/handlers/multistatus_test.go index d34f644..f57823d 100644 --- a/handlers/multistatus_test.go +++ b/handlers/multistatus_test.go @@ -29,7 +29,7 @@ func TestToXML(t *testing.T) { ms.Minimal = false expected := ` - + /123 @@ -55,7 +55,7 @@ func TestToXML(t *testing.T) { ms.Minimal = true expected = ` - + /123 @@ -80,7 +80,7 @@ func TestToXML(t *testing.T) { expected = ` - + /123 diff --git a/handlers/report_test.go b/handlers/report_test.go index a88d375..13329fc 100644 --- a/handlers/report_test.go +++ b/handlers/report_test.go @@ -42,7 +42,7 @@ func TestHandle1(t *testing.T) { // the ones that do not belong are ignored. expectedRespBody := fmt.Sprintf(` - + /test-data/report/123-456-789.ics @@ -105,7 +105,7 @@ func TestHandle2(t *testing.T) { // The response should contain only the resource from the URL. The rest are ignored expectedRespBody := fmt.Sprintf(` - + /test-data/report/123-456-789.ics @@ -160,7 +160,7 @@ func TestHandle3(t *testing.T) { expectedRespBody := fmt.Sprintf(` - + /test-data/report/football.ics @@ -218,7 +218,7 @@ func TestHandle4(t *testing.T) { // The response should omit all the nodes with status 404. expectedRespBody := fmt.Sprintf(` - + /test-data/report/123-456-789.ics diff --git a/integration_test.go b/integration_test.go index 64313a6..e03afb7 100644 --- a/integration_test.go +++ b/integration_test.go @@ -186,7 +186,7 @@ func TestPROPFIND(t *testing.T) { ` expectedRespBody := fmt.Sprintf(` - + /test-data/propfind/123-456-789.ics @@ -238,7 +238,7 @@ func TestPROPFIND(t *testing.T) { ` expectedRespBody = fmt.Sprintf(` - + /test-data/propfind/123-456-789.ics @@ -274,7 +274,7 @@ func TestPROPFIND(t *testing.T) { // the response should omit all the nodes with status 404. expectedRespBody = fmt.Sprintf(` - + /test-data/propfind/123-456-789.ics @@ -313,9 +313,9 @@ func TestPROPFIND(t *testing.T) { expectedRespBody = ` - + - /test-data/propfind + /test-data/propfind/ text/calendar @@ -335,9 +335,9 @@ func TestPROPFIND(t *testing.T) { expectedRespBody = ` - + - /test-data/propfind + /test-data/propfind/ text/calendar @@ -383,7 +383,7 @@ func TestREPORT(t *testing.T) { expectedRespBody := fmt.Sprintf(` - + /test-data/report/123-456-789.ics