Google Sheets API: golang BatchUpdateValuesRequest - go

I'm trying to follow the Google Sheets API quickstart here:
https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchUpdate
(scroll down to "Examples" then click "GO")
This is how I tried to update a spreadsheet:
package main
// BEFORE RUNNING:
// ---------------
// 1. If not already done, enable the Google Sheets API
// and check the quota for your project at
// https://console.developers.google.com/apis/api/sheets
// 2. Install and update the Go dependencies by running `go get -u` in the
// project directory.
import (
"errors"
"fmt"
"log"
"net/http"
"golang.org/x/net/context"
"google.golang.org/api/sheets/v4"
)
func main() {
ctx := context.Background()
c, err := getClient(ctx)
if err != nil {
log.Fatal(err)
}
sheetsService, err := sheets.New(c)
if err != nil {
log.Fatal(err)
}
// The ID of the spreadsheet to update.
spreadsheetId := "1diQ943LGMDNkbCRGG4VqgKZdzyanCtT--V8o7r6kCR0"
var jsonPayloadVar []string
monthVar := "Apr"
thisCellVar := "A26"
thisLinkVar := "http://test.url"
jsonRackNumberVar := "\"RACKNUM01\""
jsonPayloadVar = append(jsonPayloadVar, fmt.Sprintf("(\"range\": \"%v!%v\", \"values\": [[\"%v,%v)\"]]),", monthVar, thisCellVar, thisLinkVar, jsonRackNumberVar))
rb := &sheets.BatchUpdateValuesRequest{"ValueInputOption": "USER_ENTERED", "data": jsonPayloadVar}
resp, err := sheetsService.Spreadsheets.Values.BatchUpdate(spreadsheetId, rb).Context(ctx).Do()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", resp)
}
func getClient(ctx context.Context) (*http.Client, error) {
// https://developers.google.com/sheets/quickstart/go#step_3_set_up_the_sample
//
// Authorize using the following scopes:
// sheets.DriveScope
// sheets.DriveFileScope
sheets.SpreadsheetsScope
return nil, errors.New("not implemented")
}
Output:
hello.go:43: invalid field name "ValueInputOption" in struct initializer
hello.go:43: invalid field name "data" in struct initializer
hello.go:58: sheets.SpreadsheetsScope evaluated but not used
There are 2 things that aren't working:
It's not obvious how to enter the fields into variable rb
I need to use sheets.SpreadsheetsScope
Can anyone provide a working example that does a BatchUpdate?
References:
This article shows how to do an update that is not a BatchUpdate: Golang google sheets API V4 - Write/Update example?
Google's API reference - see the ValueInputOption section starting at line 1437: https://github.com/google/google-api-go-client/blob/master/sheets/v4/sheets-gen.go
This article shows how to do a BatchUpdate in Java: Write data to Google Sheet using Google Sheet API V4 - Java Sample Code

How about the following sample script? This is a simple sample script for updating sheet on Spreadsheet. So if you want to do various update, please modify it. The detail of parameters for spreadsheets.values.batchUpdate is here.
Flow :
At first, in ordet to use the link in your question, please use Go Quickstart. In my sample script, the script was made using the Quickstart.
The flow to use this sample script is as follows.
For Go Quickstart, please do Step 1 and Step 2.
Please put client_secret.json to the same directory with my sample script.
Copy and paste my sample script, and create it as new script file.
Run the script.
When Go to the following link in your browser then type the authorization code: is shown on your terminal, please copy the URL and paste to your browser. And then, please authorize and get code.
Put the code to the terminal.
When Done. is displayed, it means that the update of spreadsheet is done.
Request body :
For Spreadsheets.Values.BatchUpdate, BatchUpdateValuesRequest is required as one of parameters. In this case, the range, values and so on that you want to update are included in BatchUpdateValuesRequest. The detail information of this BatchUpdateValuesRequest can be seen at godoc. When it sees BatchUpdateValuesRequest, Data []*ValueRange can be seen. Here, please be carefull that Data is []*ValueRange. Also ValueRange can be seen at godoc. You can see MajorDimension, Range and Values in ValueRange.
When above infomation is reflected to the script, the script can be modified as follows.
Sample script :
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/sheets/v4"
)
// 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 := "./go-quickstart.json"
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
}
// 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
}
func saveToken(file string, token *oauth2.Token) {
fmt.Printf("Saving credential file to: %s\n", file)
f, err := os.Create(file)
if err != nil {
log.Fatalf("Unable to cache oauth token: %v", err)
}
defer f.Close()
json.NewEncoder(f).Encode(token)
}
type body struct {
Data struct {
Range string `json:"range"`
Values [][]string `json:"values"`
} `json:"data"`
ValueInputOption string `json:"valueInputOption"`
}
func main() {
ctx := context.Background()
b, err := ioutil.ReadFile("client_secret.json")
if err != nil {
log.Fatalf("Unable to read client secret file: %v", err)
}
config, 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(ctx, config)
sheetsService, err := sheets.New(client)
if err != nil {
log.Fatalf("Unable to retrieve Sheets Client %v", err)
}
spreadsheetId := "### spreadsheet ID ###"
rangeData := "sheet1!A1:B3"
values := [][]interface{}{{"sample_A1", "sample_B1"}, {"sample_A2", "sample_B2"}, {"sample_A3", "sample_A3"}}
rb := &sheets.BatchUpdateValuesRequest{
ValueInputOption: "USER_ENTERED",
}
rb.Data = append(rb.Data, &sheets.ValueRange{
Range: rangeData,
Values: values,
})
_, err = sheetsService.Spreadsheets.Values.BatchUpdate(spreadsheetId, rb).Context(ctx).Do()
if err != nil {
log.Fatal(err)
}
fmt.Println("Done.")
}
Result :
References :
The detail infomation of spreadsheets.values.batchUpdate is here.
The detail infomation of Go Quickstart is here.
The detail infomation of BatchUpdateValuesRequest is here.
The detail infomation of ValueRange is here.
If I misunderstand your question, I'm sorry.

Related

How to validate JWE token in Golang

I've got 2 questions but first I want to provide some context:
On our webapp, we are using NextAuth to generate jwt tokens which then we attach to requests against our Golang server (for fetching resources).
The generated tokens seem to be JWE tokens generated via A256GCM. In our golang server we want to validate the token and extract a few custom claims of it. That said, we're struggling to find a way to do the decryption. We're using go-jose as follows:
rawToken := `eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..aiIqD7-cU8Hu92F8.Kx2k99cyLYJR1P0xK_1wUsVO521T7kYSKx-OEutVJcpzbX27hZH0kh2MlBLxQHdmc8q4uXglhjl4JE3nTp_c6nOjga-faHyxYqKrZGJFLlu9MC4JVUWyonX6doFq0gl3UX9ABtP2t35Qly-w1qKH8BdG9x4iB1YM-yvs1w-HpBbMFQR7U7X4oHWIh_YJQlWADesYq6da7A97GSSXs2Go6yb7SH5WWd7iQzDu-UO6eg._PqujCUyMUqOkID80vJiDw`
key := []byte("thisisaverylongtextusedforhashing")
enc, err := jwt.ParseEncrypted(rawToken)
if err != nil {
panic(err)
}
out := jwt.Claims{}
if err := enc.Claims(key, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
We are getting:
panic: square/go-jose: error in cryptographic primitive
PS: secret I pass to nextAuth used for the JWE generation: thisisaverylongtextusedforhashing
Raw JWE token that NextAuth outputs and which I want to validate in my golang server: eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..aiIqD7-cU8Hu92F8.Kx2k99cyLYJR1P0xK_1wUsVO521T7kYSKx-OEutVJcpzbX27hZH0kh2MlBLxQHdmc8q4uXglhjl4JE3nTp_c6nOjga-faHyxYqKrZGJFLlu9MC4JVUWyonX6doFq0gl3UX9ABtP2t35Qly-w1qKH8BdG9x4iB1YM-yvs1w-HpBbMFQR7U7X4oHWIh_YJQlWADesYq6da7A97GSSXs2Go6yb7SH5WWd7iQzDu-UO6eg._PqujCUyMUqOkID80vJiDw.
Given your input, I put together a response that could help you with your issue. First, I used version 2 of the package gopkg.in/go-jose/go-jose.v2 because (from what I saw) the algorithm A256GCM is not fully compatible in the newest version of the package that should be version 3. Below you can find the relevant code:
package main
import (
"crypto/rand"
"crypto/rsa"
"fmt"
"io"
"os"
"time"
"github.com/golang-jwt/jwt"
jose_jwt "gopkg.in/go-jose/go-jose.v2"
)
type CustomClaims struct {
Username string `json:"username"`
Password string `json:"password"`
jwt.StandardClaims
}
func main() {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
// generate token
token, err := generateToken()
if err != nil {
panic(err)
}
publicKey := &privateKey.PublicKey
encrypter, err := jose_jwt.NewEncrypter(jose_jwt.A256GCM, jose_jwt.Recipient{
Algorithm: jose_jwt.RSA_OAEP_256,
Key: publicKey,
}, nil)
if err != nil {
panic(err)
}
plainText := []byte(token)
object, err := encrypter.Encrypt(plainText)
if err != nil {
panic(err)
}
serialized := object.FullSerialize()
object, err = jose_jwt.ParseEncrypted(serialized)
if err != nil {
panic(err)
}
decrypted, err := object.Decrypt(privateKey)
if err != nil {
panic(err)
}
fmt.Println(string(decrypted))
// parse token
claims, err := ValidateToken(string(decrypted))
if err != nil {
panic(err)
}
fmt.Println(len(claims))
}
Here, we first generate a private key to encrypt the token and then decrypt it through its public key. I omitted the code used to generate and validate a JWT token for brevity. To test out the solution I added two custom claims to the generated token (username and password that are defined in the CustomClaims struct). Then, when we parse the token, we'll be able to retrieve their values.
Let me know if this helps you!

When I try to get the user data with Go and firebase adminSDK, I can only get the memory address

I'm currently using the Firebase adminSDK to get the user data from the firebase authentication.
The following code seems it can access firebase, but the data to be retrieved is a memory address.
I want to get the value.
I tried to find out about this issue, but I couldn't find any clues.
I am happy with any solution or hint.
package main
import (
firebase "firebase.google.com/go"
"fmt"
"golang.org/x/net/context"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
"log"
)
func main() {
ctx := context.Background()
opt := option.WithCredentialsFile("/10_pro4_go/workspace/fb.json")
app, err := firebase.NewApp(ctx, nil, opt)
if err != nil {
log.Fatalln("error initializing app:", err)
}
client, err := app.Auth(ctx)
if err != nil{
log.Fatalln(err)
}
//getting all user data
iter := client.Users(ctx, "")
fmt.Println(*iter)
for {
user, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("error listing users: %s\n", err)
}
userdata := *user
log.Printf("read user user: %v\n", userdata)
}
}
Results:
2021/01/15 23:08:33 read user user: {0xc00024a000 }
2021/01/15 23:08:33 read user user: {0xc00024a050 }
2021/01/15 23:08:33 read user user: {0xc00024a0f0 }
Accodring to the documentation of firebase auth package client.Users returns an Iterator that iterates through ExportedUserRecord objects
https://pkg.go.dev/firebase.google.com/go/v4#v4.6.0/auth#ExportedUserRecord
That ExportedUserRecord have an embedded pointer to UserRecord which is probably what ur searching for:
https://pkg.go.dev/firebase.google.com/go/v4#v4.6.0/auth#UserRecord
So i would suggest printing that UserRecord Data, or even UserInfo array inside of it if that is what you goal is:
user.UserRecrod.ProviderUserInfo

Google Drive API v3 create and upload file

I have a python script that creates a Google Drive file via API and uploads it. I am trying to rewrite the script in Go but the API documentation does not provide a Go quickstart. Here is the python script:
#!/bin/python
from __future__ import print_function
import httplib2
import os
from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
from apiclient.http import MediaFileUpload
try:
import argparse
parser = argparse.ArgumentParser(description='Ebay Google Drive Uploader')
parser.add_argument('-r', metavar="rack",
help="-r <rack>")
except ImportError:
parser = None
try:
args = parser.parse_args()
except:
print (parser.error)
#print ("parser = ", parser)
if not args.r:
print ("Please specify rack (-r rack)")
exit
else:
#print ("Processing ", args.r)
sheet_name = args.r + ".csv"
sheet_filename = '/tmp/' + args.r + '.csv'
# If modifying these scopes, delete your previously saved credentials
# at ~/.credentials/drive-python-quickstart.json
SCOPES = 'https://www.googleapis.com/auth/drive'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Ebay Google Drive Uploader - albraden#ebay.com'
def get_credentials():
"""Gets valid user credentials from storage.
Returns:
Credentials, the obtained credential.
"""
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir,
'drive-python-quickstart.json')
store = Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
print ("before flow\n")
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
print ("flow = ", flow)
flow.user_agent = APPLICATION_NAME
if parser:
credentials = tools.run_flow(flow, store, parser)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
return credentials
def main():
"""Creates a spreadsheet using the Google Drive API
"""
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('drive', 'v3', http=http)
file_metadata = {
'name' : sheet_name,
'mimeType' : 'application/vnd.google-apps.spreadsheet'
}
media = MediaFileUpload(sheet_filename,
mimetype='text/csv')
results = service.files().create(body=file_metadata,
media_body=media,
fields='id').execute()
sheet_id = results["id"]
print (sheet_id)
#sheet_url = results["webViewLink"]
#print ('sheet_url = ', sheet_url)
def callback(request_id, response, exception):
if exception:
# Handle error
print (exception)
#else:
#print ("Permission Id: %s" % response.get('id'))
batch = service.new_batch_http_request(callback=callback)
domain_permission = {
'type': 'domain',
'role': 'writer',
'domain': 'ebay.com',
'allowFileDiscovery': True
}
batch.add(service.permissions().create(
fileId=sheet_id,
body=domain_permission,
fields='id',
))
batch.execute()
if __name__ == '__main__':
main()
The problem is that I can't figure out how to specify the media type. In Python I used MediaFileUpload but it looks like Golang requires a different method. Here's what I have in Go:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"os/user"
"path/filepath"
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/drive/v3"
)
// 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("drive-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)
}
func main() {
ctx := context.Background()
b, err := ioutil.ReadFile("/usr/local/lib/client_secret.json")
if err != nil {
log.Fatalf("Unable to read client secret file: %v", err)
}
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/drive-go-quickstart.json
config, err := google.ConfigFromJSON(b, drive.DriveFileScope)
if err != nil {
log.Fatalf("Unable to parse client secret file to config: %v", err)
}
client := getClient(ctx, config)
srv, err := drive.New(client)
if err != nil {
log.Fatalf("Unable to retrieve drive Client %v", err)
}
file_metadata := make(map[string]string)
sheet_name := "SLC:SLC02:02-314:06:04.csv"
sheet_filename := "/tmp/SLC:SLC02:02-314:06:04.csv"
file_metadata["name"] = sheet_name
file_metadata["mimeType"] = "application/vnd.google-apps.spreadsheet"
media = MediaFileUpload(sheet_filename, mimetype="text/csv")
r, err := srv.Files.Create(body=file_metadata,
media_body=media,
fields='id')
if err != nil {
log.Fatalf("Unable to create file: %v", err)
}
}
Can someone provide a working example that creates and uploads a document to Google Drive?
Reference links are here: https://paste.fedoraproject.org/paste/JmElgduugSKLVSAYm1htGw
How about this sample script? This sample was modified main() of your script. When you use this sample, please replace your main() to mine. In your Python script, it converts from CSV to Spreadsheet and modify the permissions. So also it gave the same flow to this sample.
Important points :
Give mimeType of file that it wants to upload to options of Media(r io.Reader, options ...googleapi.MediaOption).
In order to give options, use googleapi.ContentType().
Give mimeType of file that it wants to convert, when it uploads it to Google Drive, to file of Create(file *File).
In order to give file, use &drive.File{}.
For installing permissions, use &drive.Permission{}. Each parameter is the same to them for Python.
Sample script :
func main1() {
ctx := context.Background()
b, err := ioutil.ReadFile("/usr/local/lib/client_secret.json")
if err != nil {
log.Fatalf("Unable to read client secret file: %v", err)
}
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/drive-go-quickstart.json
config, err := google.ConfigFromJSON(b, drive.DriveFileScope)
if err != nil {
log.Fatalf("Unable to parse client secret file to config: %v", err)
}
client := getClient(ctx, config)
srv, err := drive.New(client)
if err != nil {
log.Fatalf("Unable to retrieve drive Client %v", err)
}
// I modified below.
sheet_name := "SLC:SLC02:02-314:06:04.csv" // File you want to upload on Google Drive
sheet_filename := "/tmp/SLC:SLC02:02-314:06:04.csv" // File you want to upload on your PC
baseMimeType := "text/csv" // mimeType of file you want to upload
convertedMimeType := "application/vnd.google-apps.spreadsheet" // mimeType of file you want to convert on Google Drive
file, err := os.Open(sheet_filename)
if err != nil {
log.Fatalf("Error: %v", err)
}
defer file.Close()
f := &drive.File{
Name: sheet_name,
MimeType: convertedMimeType,
}
res, err := srv.Files.Create(f).Media(file, googleapi.ContentType(baseMimeType)).Do()
if err != nil {
log.Fatalf("Error: %v", err)
}
fmt.Printf("%s, %s, %s\n", res.Name, res.Id, res.MimeType)
permissiondata := &drive.Permission{
Type: "domain",
Role: "writer",
Domain: "ebay.com",
AllowFileDiscovery: true,
}
pres, err := srv.Permissions.Create(res.Id, permissiondata).Do()
if err != nil {
log.Fatalf("Error: %v", err)
}
fmt.Printf("%s, %s\n", pres.Type, pres.Role)
}
Result :
SLC:SLC02:02-314:06:04.csv, ### file ID on Google Drive ###, application/vnd.google-apps.spreadsheet
domain, writer
References :
Also I got the infomation for this sample from godoc and GitHub of google-api-go-client.
Files.Create : godoc and GitHub
Permissions.Create : godoc and GitHub
Edit :
This uses Quickstart. In order to use this sample script, please do the Step 1 and Step 2.
Or your library may be required to update.
At this sample script, it works file using google-api-go-client/drive/v3/ of Sep 13, 2017.

Golang google sheets API V4 - Write/Update example?

Trying to write a simple three column table ([][]string) with Go, but can't.
The quick start guide is very nice, I now can read sheets, but there no any example of how to write data to a sheet, maybe it is trivial, but not for me it seems.
The Golang library for my brains is just too complicated to figure out.
And there not a single example I could google...
This C# example very looks close, but I am not sure I clearly understand C#
Well after some tryouts, there is an answer. Everything is same as in https://developers.google.com/sheets/quickstart/go Just changes in the main function
func write() {
ctx := context.Background()
b, err := ioutil.ReadFile("./Google_Sheets_API_Quickstart/client_secret.json")
if err != nil {
log.Fatalf("Unable to read client secret file: %v", err)
}
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/sheets.googleapis.com-go-quickstart.json
config, 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(ctx, config)
srv, err := sheets.New(client)
if err != nil {
log.Fatalf("Unable to retrieve Sheets Client %v", err)
}
spreadsheetId := "YOUR SPREADSHEET ID"
writeRange := "A1"
var vr sheets.ValueRange
myval := []interface{}{"One", "Two", "Three"}
vr.Values = append(vr.Values, myval)
_, err = srv.Spreadsheets.Values.Update(spreadsheetId, writeRange, &vr).ValueInputOption("RAW").Do()
if err != nil {
log.Fatalf("Unable to retrieve data from sheet. %v", err)
}
}
Well if you are looking for Service Account based authentication, then the following worked for me.
Download the client secret file for service account from https://console.developers.google.com
import (
"fmt"
"golang.org/x/net/context"
"google.golang.org/api/option"
"google.golang.org/api/sheets/v4"
"log"
)
const (
client_secret_path = "./credentials/client_secret.json"
)
func NewSpreadsheetService() (*SpreadsheetService, error) {
// Service account based oauth2 two legged integration
ctx := context.Background()
srv, err := sheets.NewService(ctx, option.WithCredentialsFile(client_secret_path), option.WithScopes(sheets.SpreadsheetsScope))
if err != nil {
log.Fatalf("Unable to retrieve Sheets Client %v", err)
}
c := &SpreadsheetService{
service: srv,
}
return c, nil
}
func (s *SpreadsheetService) WriteToSpreadsheet(object *SpreadsheetPushRequest) error {
var vr sheets.ValueRange
vr.Values = append(vr.Values, object.Values)
res, err := s.service.Spreadsheets.Values.Append(object.SpreadsheetId, object.Range, &vr).ValueInputOption("RAW").Do()
fmt.Println("spreadsheet push ", res)
if err != nil {
fmt.Println("Unable to update data to sheet ", err)
}
return err
}
type SpreadsheetPushRequest struct {
SpreadsheetId string `json:"spreadsheet_id"`
Range string `json:"range"`
Values []interface{} `json:"values"`
}
change the scope in the quickstart example from spreadsheets.readonly to spreadsheets for r/w access
here is the write snippet:
writeRange := "A1" // or "sheet1:A1" if you have a different sheet
values := []interface{}{"It worked!"}
var vr sheets.ValueRange
vr.Values = append(vr.Values,values
_, err = srv.Spreadsheets.Values.Update(spreadsheetId,writeRange,&vr).ValueInputOption("RAW").Do()
and that should work:

Firebase: Failed to validate MAC

I am using fireauth and firego from zabawaba99. I am getting an error (please see below) when pushing data to my firebase database. I have been following his examples but I cannot get it to work. Someone got a idea why this is happening?
Error:
2016/06/03 14:30:13 {
"error" : "Failed to validate MAC."
}
Code:
gen := fireauth.New("<API-KEY/SECRET>")
data := fireauth.Data{"uid": "1"}
token, err := gen.CreateToken(data, nil)
if err != nil {
log.Fatal(err)
}
fb := firego.New("https://myapp.firebaseio.com" , nil)
log.Println(token)
fb.Auth(token)
for i := 0; i<len(items); i++ {
item := items[i]
pushedItem, err := fb.Child("items").Push(items)
if err != nil {
log.Fatal(err) // error is happening here
}
var itemTest string
if err := pushedItem.Value(&itemTest); err != nil {
log.Fatal(err)
}
fmt.Printf("%s: %s\n", pusedItem, itemTest)
}
Unfortunately there isn't Go-specific documentation, but I believe, based on the new docs, that the old REST way to authenticate doesn't work any longer.
Having said that, I have been able to get your code to work reading a bunch of docs, lots of trial & error, and by using OAuth authentication by means of JWT.
Firstly, follow this guide: https://firebase.google.com/docs/server/setup but just the "Add Firebase to your App" section.
Issue a go get -u golang.org/x/oauth2 and go get -u golang.org/x/oauth2/google (or use your favorite vendoring way).
Change your code as such:
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/zabawaba99/firego"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)
func main() {
jsonKey, err := ioutil.ReadFile("./key.json") // or path to whatever name you downloaded the JWT to
if err != nil {
log.Fatal(err)
}
conf, err := google.JWTConfigFromJSON(jsonKey, "https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/firebase.database")
if err != nil {
log.Fatal(err)
}
client := conf.Client(oauth2.NoContext)
fb := firego.New("https://myapp.firebaseio.com" , client)
for i := 0; i<len(items); i++ {
item := items[i]
pushedItem, err := fb.Child("items").Push(items)
if err != nil {
log.Fatal(err) // error is happening here
}
var itemTest string
if err := pushedItem.Value(&itemTest); err != nil {
log.Fatal(err)
}
fmt.Printf("%s: %s\n", pusedItem, itemTest)
}
}
The above worked for me!
Edit: Adding reference to StackOverflow answers that helped me:
Using Custom Tokens to make REST requests to FB DB as an admin
Is it still possible to do server side verification of tokens in Firebase 3?

Resources