diff --git a/go.mod b/go.mod index 29490f9..10c2d00 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,8 @@ go 1.19 require ( github.com/apognu/gocal v0.9.0 - github.com/stretchr/testify v1.8.0 + github.com/go-co-op/gocron v1.18.0 + github.com/stretchr/testify v1.8.1 go.uber.org/zap v1.23.0 ) @@ -14,9 +15,11 @@ require ( github.com/kr/pretty v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.8.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.7.0 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 388b1de..e6b6089 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-co-op/gocron v1.18.0 h1:SxTyJ5xnSN4byCq7b10LmmszFdxQlSQJod8s3gbnXxA= +github.com/go-co-op/gocron v1.18.0/go.mod h1:sD/a0Aadtw5CpflUJ/lpP9Vfdk979Wl1Sg33HPHg0FY= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= @@ -22,17 +24,21 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -41,6 +47,8 @@ go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/icsparser/daily.go b/icsparser/daily.go new file mode 100644 index 0000000..7bbcd84 --- /dev/null +++ b/icsparser/daily.go @@ -0,0 +1,74 @@ +package icsparser + +import ( + "fmt" + "time" + "errors" + + "github.com/nce/ics2mattermost/logger" +) + +type DailyIngest struct { + EventsToday []Event + TravellingPersons string + AbsentPersons string +} + +func (c *Calendar) PrepareDailyIngest() (map[string]string, error) { + + logger.Info(fmt.Sprintf("amount of meetings: %d", len(c.Events))) + + ingest := DailyIngest{ + EventsToday: []Event{}, + TravellingPersons: "*no one*", + AbsentPersons: "*no one*", + } + + for _, event := range c.Events { + travelers, err := event.GetPersonsByCategory("travel") + + if err == nil { + ingest.TravellingPersons = travelers + } + + absents, err := event.GetPersonsByCategory("leaves") + if err == nil { + ingest.AbsentPersons = absents + } + } + + var err error + + //ingest.Daily, err = c.GetEventByName("DAILY (ALL)") + if len(c.Events) == 0 { + + logger.Error(err.Error()) + return nil, errors.New("no events today") + + } else { + + loc := time.Local + var formattedEvents string + + for _, e := range c.Events { + formattedEvents = formattedEvents + ":calendar: " + e.Start.In(loc).Format("15:04") + " - " + + e.End.In(loc).Format("15:04 MST") + " :fire: [" + e.Summary + "](" + e.Location + ")\n" + } + + dailyMessage := map[string]string{ + "name": "Foobar", + "text": "#### Welcome to today's daily ingest\n" + + formattedEvents + + ":airplane: " + ingest.TravellingPersons + "\n" + + ":palm_tree: " + ingest.AbsentPersons, + } + +// logger.Info( +// fmt.Sprintf("Sent out daily digest with %d persons travelling " + +// "and %d persons absent", strings.Count(ingest.TravellingPersons, ","), +// strings.Count(ingest.AbsentPersons, ","))) + + return dailyMessage, nil + + } +} diff --git a/icsparser/parser.go b/icsparser/parser.go index 323c027..0d4863d 100644 --- a/icsparser/parser.go +++ b/icsparser/parser.go @@ -1,17 +1,18 @@ package icsparser import ( - "bytes" - "io" - "strings" + "bytes" + "io" + "strings" "errors" - "github.com/apognu/gocal" - "github.com/nce/ics2mattermost/logger" + "github.com/apognu/gocal" + "github.com/nce/ics2mattermost/logger" - "fmt" - "net/http" - "time" + "fmt" + "net/http" + "time" + "sort" ) type ics struct { @@ -57,6 +58,16 @@ func (i *ics) queryCalendar() *gocal.Gocal { return c } +func beginOfDay() time.Time { + t := time.Now() + return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) +} + +func endOfDay() time.Time { + t := time.Now().Add(1 * 24 * time.Hour) + return t.Truncate(24 * time.Hour) +} + func Setup(icsUrl string, authEmail string, authToken string) *Calendar { var confluence = ics{ @@ -73,7 +84,7 @@ func (c *Calendar) GetTodaysEvents() { //loc, _ := time.LoadLocation("Europe/Berlin") // truncate a day at 23:59 to filter only TODAYS events - start, end := time.Now(), time.Now().Add(1*24*time.Hour).Truncate(24*time.Hour) + start, end := beginOfDay(), endOfDay() c.cal.Start, c.cal.End = &start, &end err := c.cal.Parse() @@ -86,6 +97,11 @@ func (c *Calendar) GetTodaysEvents() { for _, e := range c.cal.Events { c.Events = append(c.Events, Event{e}) } + + // crazy sorting of the events by start time + sort.Slice(c.Events, func(i, j int) bool { + return c.Events[i].Start.Before(*c.Events[j].Start) + }) } func (c *Calendar) GetEventByName(eventName string) (Event, error) { @@ -96,7 +112,9 @@ func (c *Calendar) GetEventByName(eventName string) (Event, error) { } } - return Event{gocal.Event{Summary: "No event found"}}, errors.New("no event found") + return Event{ + gocal.Event{Summary: "No event found"}}, + errors.New("no event found") } func (e *Event) GetPersonsByCategory(calendarCategory string) (string, error) { @@ -120,3 +138,4 @@ func (e *Event) GetPersonsByCategory(calendarCategory string) (string, error) { return strings.Join(attendees, ", "), nil } + diff --git a/icsparser/parser_test.go b/icsparser/parser_test.go index a6a10a1..eeccfa0 100644 --- a/icsparser/parser_test.go +++ b/icsparser/parser_test.go @@ -94,7 +94,7 @@ func TestGetPersonsByCategory(t *testing.T) { assert.Equal(t, "", test) assert.NotNil(t, err) - // one attendee on different cateogry + // one attendee on different category e.Categories = []string{"leaves"} e.Attendees = []gocal.Attendee{{Cn: "Bar Foo"}} test, err = e.GetPersonsByCategory("leaves") diff --git a/main.go b/main.go index 3db2b80..4a1b3bc 100644 --- a/main.go +++ b/main.go @@ -3,22 +3,18 @@ package main import ( "fmt" "os" + "time" "github.com/nce/ics2mattermost/icsparser" "github.com/nce/ics2mattermost/logger" "github.com/nce/ics2mattermost/mattermost" + "github.com/go-co-op/gocron" + "strings" - "time" _ "embed" ) -type DailyIngest struct { - Daily icsparser.Event - TravellingPersons string - AbsentPersons string -} - //go:generate sh setVersion.sh //go:embed version var Version string @@ -36,7 +32,6 @@ func main() { logger.Info(fmt.Sprintf("Application version %s", Version)) - var err error var icsUrl, icsUser, icsToken, mattermostUrl string icsUrl = checkIfEmpty("ICS_URL") @@ -44,62 +39,28 @@ func main() { icsToken = checkIfEmpty("ICS_TOKEN") mattermostUrl = checkIfEmpty("MATTERMOST_URL") - cal := icsparser.Setup( - icsUrl, - icsUser, - icsToken) - webhook := mattermost.Setup(mattermostUrl) - cal.GetTodaysEvents() + s := gocron.NewScheduler(time.Local) - logger.Info(fmt.Sprintf("Meetings: %d", len(cal.Events))) - for _, foo := range cal.Events { - logger.Info(foo.Summary) - } + s.Every("1h").Do(func() { - ingest := DailyIngest{ - Daily: icsparser.Event{}, - TravellingPersons: "*no one*", - AbsentPersons: "*no one*", - } + cal := icsparser.Setup( + icsUrl, + icsUser, + icsToken) - for _, event := range cal.Events { - travelers, err := event.GetPersonsByCategory("travel") + cal.GetTodaysEvents() + dailyMessage, err := cal.PrepareDailyIngest() if err == nil { - ingest.TravellingPersons = travelers + webhook.Send(dailyMessage) + } else { + logger.Error( + fmt.Sprintf("could not prepare daily: %s", err.Error())) } - absents, err := event.GetPersonsByCategory("leaves") - if err == nil { - ingest.AbsentPersons = absents - } - } - - ingest.Daily, err = cal.GetEventByName("DAILY (ALL)") - if err != nil { - logger.Error(err.Error()) - } else { - - loc, _ := time.LoadLocation("Europe/Berlin") - dailyMessage := map[string]string{ - "name": "Foobar", - "text": "#### Welcome to today's daily ingest\n " + - ":calendar: " + ingest.Daily.Summary + " -- " + ingest.Daily.Start.In(loc).Format("15:04 MST") + - " - " + ingest.Daily.End.In(loc).Format("15:04 MST") + "\n" + - ":link: *Daily* ➞ [Microsoft Teams](" + ingest.Daily.Location + ") \n" + - ":airplane: " + ingest.TravellingPersons + "\n" + - ":palm_tree: " + ingest.AbsentPersons, - } - - logger.Info( - fmt.Sprintf("Sent out daily digest with %d persons travelling " + - "and %d persons absent", strings.Count(ingest.TravellingPersons, ","), - strings.Count(ingest.AbsentPersons, ","))) - - webhook.Send(dailyMessage) - - } + }) + s.StartBlocking() } diff --git a/mattermost/icon.png b/mattermost/icon.png deleted file mode 100644 index 9efe31f..0000000 Binary files a/mattermost/icon.png and /dev/null differ