timer/.gcal.go

92 lines
1.8 KiB
Go

package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"os"
"path"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/calendar/v3"
)
type GCal struct {
httpc interface {
Do(*http.Request) (*http.Response, error)
}
}
func NewGCal() *GCal {
return &GCal{}
}
func (gcal *GCal) Login(ctx context.Context) error {
token, err := gcal.getToken(ctx)
if err != nil {
return err
}
conf, err := gcal.oauth2Config()
if err != nil {
return err
}
gcal.httpc = conf.Client(ctx, &token)
return nil
}
func (gcal *GCal) getToken(ctx context.Context) (oauth2.Token, error) {
var token oauth2.Token
if b, _ := os.ReadFile(gcal.tokenFile()); len(b) == 0 {
} else if err := json.Unmarshal(b, &token); err != nil {
return token, nil
}
token, err := gcal.newToken(ctx)
if err != nil {
return token, err
}
b, _ := json.Marshal(token)
return token, os.WriteFile(gcal.tokenFile(), b, os.ModePerm)
}
func (gcal *GCal) newToken(ctx context.Context) (oauth2.Token, error) {
conf, err := gcal.oauth2Config()
if err != nil {
return oauth2.Token{}, err
}
u := conf.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
fmt.Printf("visit %s\n", u)
var code string
if _, err := fmt.Scan(&code); err != nil {
return oauth2.Token{}, err
}
token, err := conf.Exchange(ctx, code)
if err != nil {
return oauth2.Token{}, err
}
return *token, nil
}
func (gcal *GCal) tokenFile() string {
return path.Join(os.Getenv("HOME"), "timer.gcal")
}
func (gcal *GCal) oauth2Config() (*oauth2.Config, error) {
b, err := os.ReadFile(path.Join(os.Getenv("HOME"), ".config", "gcloud", "application_default_credentials.json"))
if err != nil {
return nil, err
}
conf, err := google.ConfigFromJSON(b, calendar.CalendarReadonlyScope)
if err != nil {
return nil, err
}
return conf, nil
}