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 } ev := class.buildEvent(date) 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 }