diff --git a/.gitignore b/.gitignore index 24f8091..3ecd013 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ credentials.json create-expense token.json +tokenRefresh diff --git a/tokenRefresh.go b/tokenRefresh.go new file mode 100644 index 0000000..cf1c155 --- /dev/null +++ b/tokenRefresh.go @@ -0,0 +1,121 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + + "golang.org/x/oauth2" + "golang.org/x/oauth2/google" + "google.golang.org/api/option" + "google.golang.org/api/sheets/v4" +) + +type Config struct { + SpreadsheetID string `json:"spreadsheetID,omitempty"` + Range string `json:"range,omitempty"` +} + +// Retrieve a token, saves the token, then returns the generated client. +func getClient(config *oauth2.Config) *http.Client { + // The file token.json stores the user's access and refresh tokens, and is + // created automatically when the authorization flow completes for the first + // time. + tokFile := "token.json" + tok, err := tokenFromFile(tokFile) + if err != nil { + tok = getTokenFromWeb(config) + saveToken(tokFile, tok) + } + return config.Client(context.Background(), tok) +} + +// Request a token from the web, then 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 authCode string + if _, err := fmt.Scan(&authCode); err != nil { + log.Fatalf("Unable to read authorization code: %v", err) + } + + tok, err := config.Exchange(context.TODO(), authCode) + if err != nil { + log.Fatalf("Unable to retrieve token from web: %v", err) + } + return tok +} + +// Retrieves a token from a local file. +func tokenFromFile(file string) (*oauth2.Token, error) { + f, err := os.Open(file) + if err != nil { + return nil, err + } + defer f.Close() + tok := &oauth2.Token{} + err = json.NewDecoder(f).Decode(tok) + return tok, err +} + +// Saves a token to a file path. +func saveToken(path string, token *oauth2.Token) { + fmt.Printf("Saving credential file to: %s\n", path) + f, err := os.OpenFile(path, 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) +} + +func main() { + // Get config + var config Config + jsonFile, err := os.Open("config.json") + if err != nil { + panic("config file read: " + err.Error()) + } + byteValue, _ := ioutil.ReadAll(jsonFile) + jsonFile.Close() + err = json.Unmarshal(byteValue, &config) + if err != nil { + panic("config json unmarshal" + err.Error()) + } + // Create sheets client + ctx := context.Background() + b, err := ioutil.ReadFile("credentials.json") + if err != nil { + log.Fatalf("Unable to read client secret file: %v", err) + } + conf, err := google.ConfigFromJSON(b, "https://www.googleapis.com/auth/spreadsheets") + if err != nil { + log.Fatalf("Unable to parse client secret file to config: %v", err) + } + client := getClient(conf) + srv, err := sheets.NewService(ctx, option.WithHTTPClient(client)) + if err != nil { + log.Fatalf("Unable to retrieve Sheets client: %v", err) + } + + resp, err := srv.Spreadsheets.Values.Get(config.SpreadsheetID, config.Range).Do() + if err != nil { + log.Fatalf("Unable to retrieve data from sheet: %v", err) + } + + if len(resp.Values) == 0 { + fmt.Println("No data found.") + } else { + for _, row := range resp.Values { + // Print columns A and E, which correspond to indices 0 and 4. + fmt.Printf("%s, %s, %s, %s, %s\n", row[0], row[1], row[2], row[3], row[4]) + } + } + +}