2020-09-14 23:01:25 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"log"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"golang.org/x/oauth2/google"
|
|
|
|
|
"google.golang.org/api/calendar/v3"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var _globalCalService *calendar.Service
|
|
|
|
|
|
|
|
|
|
func getCalService() *calendar.Service {
|
|
|
|
|
if _globalCalService != nil {
|
|
|
|
|
return _globalCalService
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b, err := ioutil.ReadFile("credentials.json")
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If modifying these scopes, delete your previously saved token.json.
|
|
|
|
|
config, err := google.ConfigFromJSON(b, calendar.CalendarScope)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
client, err := getClient(config)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_globalCalService, err := calendar.New(client)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _globalCalService
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getCalendarId(calName string) (string, error) {
|
|
|
|
|
client := getCalService()
|
|
|
|
|
|
|
|
|
|
calendars, err := client.CalendarList.List().Do()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, item := range calendars.Items {
|
|
|
|
|
if item.Summary == calName {
|
|
|
|
|
return item.Id, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "", fmt.Errorf("calendar '%s' not found", calName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func updateCalendar(calName string, classes []Class, days int) error {
|
|
|
|
|
loc, err := time.LoadLocation("US/Pacific")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
now := time.Now().In(loc)
|
|
|
|
|
|
|
|
|
|
calId, err := getCalendarId(calName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := 0; i < days; i++ {
|
|
|
|
|
date := now.Add(time.Duration(i * 24) * time.Hour)
|
|
|
|
|
err = updateDay(calId, date, classes)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func updateDay(calId string, date time.Time, classes []Class) error {
|
|
|
|
|
eventMap, err := getDayEvents(calId, date)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, class := range classes {
|
|
|
|
|
if !class.happensOnDay(date) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !class.tagsMatch(date) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 23:25:08 +00:00
|
|
|
ev, err := class.buildEvent(date)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-09-14 23:01:25 +00:00
|
|
|
|
|
|
|
|
old := eventMap[ev.Summary]
|
|
|
|
|
|
|
|
|
|
if old == nil {
|
|
|
|
|
log.Printf("add: [%s] %s", ev.Start.DateTime, ev.Summary)
|
|
|
|
|
_, err := getCalService().Events.Insert(calId, ev).Do()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if !eventsEqual(old, ev) {
|
|
|
|
|
log.Printf("upd: [%s] %s", ev.Start.DateTime, ev.Summary)
|
|
|
|
|
_, err := getCalService().Events.Update(calId, old.Id, ev).Do()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getDayEvents(calendarId string, t time.Time) (map[string]*calendar.Event, error) {
|
|
|
|
|
start := time.Date(
|
|
|
|
|
t.Year(),
|
|
|
|
|
t.Month(),
|
|
|
|
|
t.Day(),
|
|
|
|
|
0, 0, 0, 0,
|
|
|
|
|
t.Location())
|
|
|
|
|
|
|
|
|
|
// This may be wrong for DST changes, but it's the middle of the night and probably doesn't matter
|
|
|
|
|
end := start.Add(24 * time.Hour)
|
|
|
|
|
|
|
|
|
|
events, err := getCalService().Events.List(calendarId).
|
|
|
|
|
ShowDeleted(false).
|
|
|
|
|
SingleEvents(true).
|
|
|
|
|
TimeMin(start.Format(time.RFC3339)).
|
|
|
|
|
TimeMax(end.Format(time.RFC3339)).
|
|
|
|
|
MaxResults(250).
|
|
|
|
|
Do()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eventMap := map[string]*calendar.Event{}
|
|
|
|
|
|
|
|
|
|
for _, item := range events.Items {
|
|
|
|
|
eventMap[item.Summary] = item
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return eventMap, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func eventsEqual(a *calendar.Event, b *calendar.Event) bool {
|
|
|
|
|
if a.Summary != b.Summary {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if a.Description != b.Description {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if a.Start.DateTime[:19] != b.Start.DateTime[:19] {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if a.End.DateTime[:19] != b.End.DateTime[:19] {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(a.Attendees) != len(b.Attendees) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emails := map[string]bool{}
|
|
|
|
|
for _, attendee := range a.Attendees {
|
|
|
|
|
emails[attendee.Email] = true
|
|
|
|
|
}
|
|
|
|
|
for _, attendee := range b.Attendees {
|
|
|
|
|
if !emails[attendee.Email] {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|