package main import ( "bytes" "context" "encoding/json" "errors" "fmt" "log" "net/http" "sort" "time" "golang.org/x/oauth2" "golang.org/x/oauth2/google" calendar "google.golang.org/api/calendar/v3" ) type Account struct { CC *CalClient Service *calendar.Service CalendarList []Calendar CalListUseBy time.Time EventList []Event // Today's Events EventListUseBy time.Time ActiveCalendars []string QuickAddCal string Colors *calendar.Colors } func GetAccount(secret, token []byte) (*Account, error) { var err error a := new(Account) // Create the CalClient a.CC = CreateClient(secret, token) a.CC.TokenToRaw() // Create the Calendar Service a.Service, err = calendar.New(a.CC.client) if err != nil { return nil, errors.New("Unable to retrieve calendar Client: " + err.Error()) } a.Colors, err = calendar.NewColorsService(a.Service).Get().Do() return a, err } // Get Todays Events gets events for today from all calendars func (a *Account) GetTodaysEvents() []Event { if time.Now().Before(a.EventListUseBy) { return a.EventList } var ret []Event list := a.GetCalendarList() for i := range list { if list[i].Deleted { continue } ret = append(ret, list[i].GetTodaysEvents()...) } sort.Sort(ByStartTime(ret)) a.EventList = ret a.EventListUseBy = time.Now().Add(time.Hour * 6) return ret } func (a *Account) GetTodaysActiveEvents() []Event { allEvents := a.GetTodaysEvents() var ret []Event var startIdx int for i := range allEvents { for _, calId := range a.ActiveCalendars { if allEvents[i].CalendarId == calId { if time.Until(allEvents[i].GetStartTime()) <= 0 { startIdx-- } ret = append(ret, allEvents[i]) break } } } sort.Sort(ByStartTime(ret)) for i := range ret { ret[i].InstanceId = startIdx startIdx++ } return ret } func (a *Account) GetDefaultCalendar() *Calendar { c, _ := a.Service.CalendarList.Get("primary").Do() return GoogleCalendarToLocal(c) } func (a *Account) GetCalendarList() []Calendar { if time.Now().Before(a.CalListUseBy) { return a.CalendarList } var ret []Calendar calList, err := a.Service.CalendarList.List().Do() if err != nil { return ret } for _, c := range calList.Items { ret = append(ret, *GoogleCalendarToLocal(c)) } a.CalendarList = ret a.CalListUseBy = time.Now().Add(time.Hour * 24 * 7) return ret } func (a *Account) GetCalendarById(id string) (*Calendar, error) { calList := a.GetCalendarList() for _, c := range calList { if c.Id == id { return &c, nil } } return nil, errors.New("Couldn't find calendar") } func (a *Account) GetCalendarColor(id string) (*calendar.ColorDefinition, error) { var cal *Calendar var err error if cal, err = a.GetCalendarById(id); err != nil { return nil, err } if c, ok := a.Colors.Calendar[cal.ColorId]; ok { return &c, nil } return nil, errors.New("Error Finding Calendar Color") } type CalClient struct { rawClientSecret []byte rawToken []byte ctx context.Context cfg *oauth2.Config tkn *oauth2.Token client *http.Client } func CreateClient(secret, tkn []byte) *CalClient { var err error c := CalClient{ rawClientSecret: []byte(secret), rawToken: []byte(tkn), } c.ctx = context.Background() c.cfg, err = google.ConfigFromJSON(c.rawClientSecret, calendar.CalendarScope) if err != nil { log.Fatalf("unable to parse client secret file to config: %v", err) } // Try to create the client with the passed token c.client, err = c.GetClient() if err != nil { log.Fatalf("unable to create client: %v", err) } return &c } func (c *CalClient) GetClient() (*http.Client, error) { err := c.tokenFromRaw() if err != nil { err = c.tokenFromWeb() if err != nil { return nil, err } } return c.cfg.Client(c.ctx, c.tkn), nil } func (c *CalClient) tokenFromRaw() error { c.tkn = &oauth2.Token{} tmpToken := bytes.NewBuffer(c.rawToken) err := json.NewDecoder(tmpToken).Decode(c.tkn) return err } func (c *CalClient) tokenFromWeb() error { var err error authURL := c.cfg.AuthCodeURL("state-token", oauth2.AccessTypeOffline) fmt.Printf("Go to the following link in your browser then type the authorization code:\n%v\n", authURL) var code string if _, err := fmt.Scan(&code); err != nil { log.Fatalf("Unable to read authorization code %v", err) } if c.tkn, err = c.cfg.Exchange(oauth2.NoContext, code); err == nil { c.TokenToRaw() } return err } func (c *CalClient) TokenToRaw() { var tmpToken bytes.Buffer t := c.tkn json.NewEncoder(&tmpToken).Encode(t) c.rawToken = tmpToken.Bytes() } func (c *CalClient) GetRawToken() []byte { return c.rawToken }