2017-02-02 17:03:02 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
2017-02-16 15:59:33 +00:00
|
|
|
"errors"
|
2017-02-02 17:03:02 +00:00
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
2017-03-15 19:38:37 +00:00
|
|
|
"sort"
|
2017-02-23 17:20:29 +00:00
|
|
|
"time"
|
2017-02-02 17:03:02 +00:00
|
|
|
|
|
|
|
"golang.org/x/oauth2"
|
|
|
|
"golang.org/x/oauth2/google"
|
2017-02-16 15:59:33 +00:00
|
|
|
|
|
|
|
calendar "google.golang.org/api/calendar/v3"
|
2017-02-02 17:03:02 +00:00
|
|
|
)
|
|
|
|
|
2017-02-16 15:59:33 +00:00
|
|
|
type Account struct {
|
2017-03-16 21:11:39 +00:00
|
|
|
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
|
2017-02-16 15:59:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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())
|
|
|
|
}
|
2017-03-16 21:11:39 +00:00
|
|
|
|
|
|
|
a.Colors, err = calendar.NewColorsService(a.Service).Get().Do()
|
|
|
|
return a, err
|
2017-02-16 15:59:33 +00:00
|
|
|
}
|
|
|
|
|
2017-03-15 19:38:37 +00:00
|
|
|
// Get Todays Events gets events for today from all calendars
|
2017-02-16 15:59:33 +00:00
|
|
|
func (a *Account) GetTodaysEvents() []Event {
|
2017-03-15 19:38:37 +00:00
|
|
|
if time.Now().Before(a.EventListUseBy) {
|
|
|
|
return a.EventList
|
|
|
|
}
|
2017-02-16 15:59:33 +00:00
|
|
|
var ret []Event
|
2017-03-15 19:38:37 +00:00
|
|
|
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)
|
2017-02-16 15:59:33 +00:00
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2017-03-16 21:11:39 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-03-23 12:44:45 +00:00
|
|
|
sort.Sort(ByStartTime(ret))
|
2017-03-16 21:11:39 +00:00
|
|
|
for i := range ret {
|
|
|
|
ret[i].InstanceId = startIdx
|
|
|
|
startIdx++
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2017-02-16 15:59:33 +00:00
|
|
|
func (a *Account) GetDefaultCalendar() *Calendar {
|
2017-02-23 17:20:29 +00:00
|
|
|
c, _ := a.Service.CalendarList.Get("primary").Do()
|
2017-02-16 15:59:33 +00:00
|
|
|
return GoogleCalendarToLocal(c)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Account) GetCalendarList() []Calendar {
|
2017-02-23 17:20:29 +00:00
|
|
|
if time.Now().Before(a.CalListUseBy) {
|
|
|
|
return a.CalendarList
|
|
|
|
}
|
2017-02-16 15:59:33 +00:00
|
|
|
var ret []Calendar
|
2017-02-23 17:20:29 +00:00
|
|
|
calList, err := a.Service.CalendarList.List().Do()
|
2017-02-16 15:59:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
for _, c := range calList.Items {
|
|
|
|
ret = append(ret, *GoogleCalendarToLocal(c))
|
|
|
|
}
|
2017-02-23 17:20:29 +00:00
|
|
|
a.CalendarList = ret
|
2017-03-15 19:38:37 +00:00
|
|
|
a.CalListUseBy = time.Now().Add(time.Hour * 24 * 7)
|
2017-02-16 15:59:33 +00:00
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2017-03-16 21:11:39 +00:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
2017-02-02 17:03:02 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2017-02-16 15:59:33 +00:00
|
|
|
if c.tkn, err = c.cfg.Exchange(oauth2.NoContext, code); err == nil {
|
|
|
|
c.TokenToRaw()
|
|
|
|
}
|
2017-02-02 17:03:02 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *CalClient) TokenToRaw() {
|
|
|
|
var tmpToken bytes.Buffer
|
|
|
|
t := c.tkn
|
|
|
|
json.NewEncoder(&tmpToken).Encode(t)
|
|
|
|
c.rawToken = tmpToken.Bytes()
|
|
|
|
}
|
2017-02-16 15:59:33 +00:00
|
|
|
|
|
|
|
func (c *CalClient) GetRawToken() []byte {
|
|
|
|
return c.rawToken
|
|
|
|
}
|