1
0
mirror of https://github.com/taigrr/wtf synced 2025-01-18 04:03:14 -08:00

Merge branch 'andrewzolotukhin-master'

This commit is contained in:
Chris Cummer 2018-06-08 15:58:00 -07:00
commit dae2de7ab4
5 changed files with 221 additions and 0 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@
# Misc
.DS_Store
gcal/client_secret.json
gspreadsheets/client_secret.json
#intellij idea
.idea/

View File

@ -79,6 +79,25 @@ wtf:
refreshInterval: 300
secretFile: "~/.wtf/gcal/client_secret.json"
withLocation: true
gspreadsheets:
enabled: true
secretFile: "~/.wtf/gspreadsheets/client_secret.json"
refreshInterval: "300"
sheetId: "id_of_google_spreadsheet"
colors:
values: "green"
cells:
names:
- "Cell 1 name"
- "Cell 2 name"
addresses:
- "A1"
- "A2"
position:
top: 0
left: 0
width: 1
height: 1
git:
commitCount: 5
enabled: true

145
gspreadsheets/client.go Normal file
View File

@ -0,0 +1,145 @@
/*
* This butt-ugly code is direct from Google itself
* https://developers.google.com/sheets/api/quickstart/go
*/
package gspreadsheets
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"os/user"
"path/filepath"
"strings"
"github.com/senorprogrammer/wtf/wtf"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
sheets "google.golang.org/api/sheets/v4"
)
/* -------------------- Exported Functions -------------------- */
func Fetch() ([]*sheets.ValueRange, error) {
ctx := context.Background()
secretPath, _ := wtf.ExpandHomeDir(Config.UString("wtf.mods.gspreadsheets.secretFile"))
b, err := ioutil.ReadFile(secretPath)
if err != nil {
log.Fatalf("Unable to read secretPath. %v", err)
return nil, err
}
config, err := google.ConfigFromJSON(b, "https://www.googleapis.com/auth/spreadsheets.readonly")
if err != nil {
log.Fatalf("Unable to get config from JSON. %v", err)
return nil, err
}
client := getClient(ctx, config)
srv, err := sheets.New(client)
if err != nil {
log.Fatalf("Unable to get create server. %v", err)
return nil, err
}
cells := wtf.ToStrs(Config.UList("wtf.mods.gspreadsheets.cells.addresses"))
documentId := Config.UString("wtf.mods.gspreadsheets.sheetId")
addresses := strings.Join(cells[:], ";")
responses := make([]*sheets.ValueRange, len(cells))
for i := 0; i < len(cells); i++ {
resp, err := srv.Spreadsheets.Values.Get(documentId, cells[i]).Do()
if err != nil {
log.Fatalf("Error fetching cells %s", addresses)
return nil, err
}
responses[i] = resp
}
return responses, err
}
/* -------------------- Unexported Functions -------------------- */
// getClient uses a Context and Config to retrieve a Token
// then generate a Client. It returns the generated Client.
func getClient(ctx context.Context, config *oauth2.Config) *http.Client {
cacheFile, err := tokenCacheFile()
if err != nil {
log.Fatalf("Unable to get path to cached credential file. %v", err)
}
tok, err := tokenFromFile(cacheFile)
if err != nil {
tok = getTokenFromWeb(config)
saveToken(cacheFile, tok)
}
return config.Client(ctx, tok)
}
// getTokenFromWeb uses Config to request a Token.
// It returns the retrieved Token.
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
authURL := config.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)
}
tok, err := config.Exchange(oauth2.NoContext, code)
if err != nil {
log.Fatalf("Unable to retrieve token from web %v", err)
}
return tok
}
// tokenCacheFile generates credential file path/filename.
// It returns the generated credential path/filename.
func tokenCacheFile() (string, error) {
usr, err := user.Current()
if err != nil {
return "", err
}
tokenCacheDir := filepath.Join(usr.HomeDir, ".credentials")
os.MkdirAll(tokenCacheDir, 0700)
return filepath.Join(tokenCacheDir,
url.QueryEscape("spreadsheets-go-quickstart.json")), err
}
// tokenFromFile retrieves a Token from a given file path.
// It returns the retrieved Token and any read error encountered.
func tokenFromFile(file string) (*oauth2.Token, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
t := &oauth2.Token{}
err = json.NewDecoder(f).Decode(t)
defer f.Close()
return t, err
}
// saveToken uses a file path to create a file and store the
// token in it.
func saveToken(file string, token *oauth2.Token) {
fmt.Printf("Saving credential file to: %s\n", file)
f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
log.Fatalf("Unable to cache oauth token: %v", err)
}
defer f.Close()
json.NewEncoder(f).Encode(token)
}

52
gspreadsheets/widget.go Normal file
View File

@ -0,0 +1,52 @@
package gspreadsheets
import (
"fmt"
"github.com/olebedev/config"
"github.com/senorprogrammer/wtf/wtf"
sheets "google.golang.org/api/sheets/v4"
)
// Config is a pointer to the global config object
var Config *config.Config
type Widget struct {
wtf.TextWidget
}
func NewWidget() *Widget {
widget := Widget{
TextWidget: wtf.NewTextWidget(" Google Spreadsheets ", "gspreadsheets", false),
}
return &widget
}
/* -------------------- Exported Functions -------------------- */
func (widget *Widget) Refresh() {
cells, _ := Fetch()
widget.UpdateRefreshedAt()
widget.View.SetText(fmt.Sprintf("%s", widget.contentFrom(cells)))
}
/* -------------------- Unexported Functions -------------------- */
func (widget *Widget) contentFrom(valueRanges []*sheets.ValueRange) string {
if valueRanges == nil {
return "error 1"
}
valuesColor := Config.UString("wtf.mods.gspreadsheets.colors.values", "green")
res := ""
cells := wtf.ToStrs(Config.UList("wtf.mods.gspreadsheets.cells.names"))
for i := 0; i < len(valueRanges); i++ {
res = res + fmt.Sprintf("%s\t[%s]%s\n", cells[i], valuesColor, valueRanges[i].Values[0][0])
}
return res
}

4
wtf.go
View File

@ -19,6 +19,7 @@ import (
"github.com/senorprogrammer/wtf/gcal"
"github.com/senorprogrammer/wtf/git"
"github.com/senorprogrammer/wtf/github"
"github.com/senorprogrammer/wtf/gspreadsheets"
"github.com/senorprogrammer/wtf/help"
"github.com/senorprogrammer/wtf/ipinfo"
"github.com/senorprogrammer/wtf/jira"
@ -185,6 +186,8 @@ func addWidget(app *tview.Application, pages *tview.Pages, widgetName string) {
Widgets = append(Widgets, git.NewWidget(app, pages))
case "github":
Widgets = append(Widgets, github.NewWidget(app, pages))
case "gspreadsheets":
Widgets = append(Widgets, gspreadsheets.NewWidget())
case "ipinfo":
Widgets = append(Widgets, ipinfo.NewWidget())
case "jira":
@ -226,6 +229,7 @@ func makeWidgets(app *tview.Application, pages *tview.Pages) {
gcal.Config = Config
git.Config = Config
github.Config = Config
gspreadsheets.Config = Config
ipinfo.Config = Config
jira.Config = Config
newrelic.Config = Config