Security News
New Python Packaging Proposal Aims to Solve Phantom Dependency Problem with SBOMs
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
github.com/ayidana-aboraah/go-gdoctableapp
This is a Golang library for managing tables on Google Document using Google Docs API.
Google Docs API has been released. When I used this API, I found that it is very difficult for me to manage the tables on Google Document using Google Docs API. Although I checked the official document, unfortunately, I thought that it's very difficult for me. So in order to easily manage the tables on Google Document, I created this library.
I manages the tables on Google Document using several languages. So I created the libraries for 4 languages which are golang, node.js and python. Google Apps Script has Class DocumentApp. So I has never created the GAS library yet.
Method | Explanation |
---|---|
GetTables() | Get all tables from Document. |
GetValues() | Get values from a table from Document. |
SetValuesBy2DArray(values [][]interface{}) | Set values to a table with 2 dimensional array. |
SetValuesByObject(values []ValueObject) | Set values to a table with an object. |
DeleteTable() | Delete a table. |
DeleteRowsAndColumns(d *DeleteRowsColumnsRequest) | Delete rows and columns of a table. |
CreateTable(c *CreateTableRequest) | Create new table including sell values. |
AppendRow(c *AppendRowRequest) | Append row to a table by including values. |
ReplaceTextsToImagesByURL(from, to string) | Replace texts with images from URL. |
ReplaceTextsToImagesByFile(from, to string) | Replace texts with images from files on local PC. |
This library uses google-api-go-client.
The structure of response from this library is as follows.
Result struct {
Tables []Table `json:"tables,omitempty"`
Values [][]string `json:"values,omitempty"`
ResponseFromAPIs []interface{} `json:"responseFromAPIs,omitempty"`
LibraryVersion string `json:"libraryVersion"`
}
GetTables()
is used, you can see the values with Tables
.GetValues()
is used, you can see the values with Values
.ShowAPIResponse
is true
, you can see the responses from APIs which were used for the method. And also, you can know the number of APIs, which were used for the method, by the length of array of ResponseFromAPIs
.About the authorization, please check the section of Authorization. In order to use this library, it is required to confirm that the Quickstart works fine.
Please import this libray as follows.
gdoctableapp "github.com/tanaikech/go-gdoctableapp"
And, please use as follows.
client := ### // Please use your client.
g := gdoctableapp.New()
res, err := g.Docs(documentID).TableIndex(tableIndex).GetValues().Do(client)
In this library, using the scope of https://www.googleapis.com/auth/documents
is recommended. When the method of ReplaceTextsToImagesByFile
is used, also please add https://www.googleapis.com/auth/drive
.
Get all tables from Document. All values, table index and table position are retrieved.
This sample script retrieves all tables from the Google Document of document ID.
documentID := "###"
g := gdoctableapp.New()
res, err := g.Docs(documentID).GetTables().Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res.Tables) // You can see the retrieved values like this.
the structure of res.Tables
is as follows.
Table struct {
Index int64 `json:"index"` // TableIdx
Values [][]string `json:"values"`
TablePosition struct {
StartIndex int64 `json:"startIndex"`
EndIndex int64 `json:"endIndex"`
}
}
When the option of ShowAPIResponse
is used, the responses from Docs API can be retrieved. This option can be used for all methods.
documentID := "###"
g := gdoctableapp.New()
res, err := g.Docs(documentID).GetTables().ShowAPIResponse(true).Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res.Tables) // You can see the retrieved values like this.
fmt.Println(res.ResponseFromAPIs) // You can see the responses from Docs API like this.
Get values from the table. All values are retrieved.
This sample script retrieves the values from 1st table in Google Document. You can see the retrieved values as [][]string
. Because when the values are retrieved by Docs API, all values are automatically converted to the string data.
documentID := "###"
tableIndex := 0
g := gdoctableapp.New()
res, err := g.Docs(documentID).TableIndex(tableIndex).GetValues().Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res.Values) // You can see the retrieved values like this.
documentID
: Document ID.tableIndex
: Table index. If you want to use the 3rd table in Google Document. It's 2. The start number of index is 0.client
: *Client
for using Docs API. Please check the section of Authorization.Set values to the table with 2 dimensional array. When the rows and columns of values which are put are over those of the table, this method can automatically expand the rows and columns.
This sample script puts the values to the first table in Google Document.
documentID := "###"
tableIndex := 0
g := gdoctableapp.New()
valuesBy2DArray := [][]interface{}{{"a1", "b1"}, {"a2", "b2"}, {"a3", "b3", "c3"}}
res, err := g.Docs(documentID).TableIndex(tableIndex).SetValuesBy2DArray(valuesBy2DArray).Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res)
documentID
: Document ID.tableIndex
: Table index. If you want to use the 3rd table in Google Document. It's 2. The start number of index is 0.client
: *Client
for using Docs API. Please check the section of Authorization.valuesBy2DArray
: [][]interface{}
When above script is run, the following result is obtained.
Set values to a table with an object. In this method, you can set the values using the range. When the rows and columns of values which are put are over those of the table, this method can automatically expand the rows and columns.
This script puts the values with the range to the first table in Google Document.
documentID := "###"
tableIndex := 0
g := gdoctableapp.New()
valuesByObject := []gdoctableapp.ValueObject{}
vo1 := &gdoctableapp.ValueObject{}
vo1.Range.StartRowIndex = 0
vo1.Range.StartColumnIndex = 0
vo1.Values = [][]interface{}{{"A1"}, {"A2", "B2", "c2", "d2"}, {"A3"}}
valuesByObject = append(valuesByObject, *vo1)
vo2 := &gdoctableapp.ValueObject{}
vo2.Range.StartRowIndex = 0
vo2.Range.StartColumnIndex = 1
vo2.Values = [][]interface{}{{"B1", "C1"}}
valuesByObject = append(valuesByObject, *vo2)
res, err := g.Docs(documentID).TableIndex(tableIndex).SetValuesByObject(valuesByObject).Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res)
documentID
: Document ID.tableIndex
: Table index. If you want to use the 3rd table in Google Document. It's 2. The start number of index is 0.client
: *Client
for using Docs API. Please check the section of Authorization.Range.StartRowIndex
of valuesByObject
: Row index of values[0][0]
.Range.StartColumnIndex
of valuesByObject
: Column index of values[0][0]
.Values
of valuesByObject
: Values you want to put.For example, when the row, column indexes and values are 1, 2 and "value", respectively, "value" is put to "C3".
When above script is run, the following result is obtained.
This script deletes the first table in Google Document.
documentID := "###"
tableIndex := 0
g := gdoctableapp.New()
res, err := g.Docs(documentID).TableIndex(tableIndex).DeleteTable().Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res)
documentID
: Document ID.tableIndex
: Table index. If you want to use the 3rd table in Google Document. It's 2. The start number of index is 0.client
: *Client
for using Docs API. Please check the section of Authorization.This script deletes rows of indexes of 3, 1 and 2 of the first table in Google Document. And also this script deletes columns of indexes of 2, 1 and 3.
documentID := "###"
tableIndex := 0
g := gdoctableapp.New()
obj := &gdoctableapp.DeleteRowsColumnsRequest{
Rows: []int64{3, 1, 2}, // Start index is 0.
Columns: []int64{2, 1, 3}, // Start index is 0.
}
res, err := g.Docs(documentID).TableIndex(tableIndex).DeleteRowsAndColumns(obj).Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res)
documentID
: Document ID.tableIndex
: Table index. If you want to use the 3rd table in Google Document. It's 2. The start number of index is 0.client
: *Client
for using Docs API. Please check the section of Authorization.Rows
of obj
: Indexes of rows you want to delete.Columns
of obj
: Indexes of columns you want to delete.This script creates new table to the top of Google Document, and the cells of the table have values.
documentID := "###"
g := gdoctableapp.New()
obj := &gdoctableapp.CreateTableRequest{
Rows: 3,
Columns: 5,
Index: 1,
// Append: true, // When this is used instead of "Index", new table is created to the end of Document.
Values: [][]interface{}{{"a1", "b1"}, {"a2", "b2"}, {"a3", "b3", "c3"}},
}
res, err := g.Docs(documentID).CreateTable(obj).Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res)
documentID
: Document ID.client
: *Client
for using Docs API. Please check the section of Authorization.Rows
of obj
: Number of rows of new table.Columns
of obj
: Number of columns of new table.Index
of obj
: Index of Document for putting new table. For example, 1
is the top of Document.Append
of obj
: When Append
is true
instead of Index
, the new table is created to the end of Google Document.Values
of obj
: If you want to put the values when new table is created, please use this.When above script is run, the following result is obtained. In this case, the new table is created to the top of Google Document.
This sample script appends the values to the first table of Google Document.
documentID := "###"
tableIndex := 0
g := gdoctableapp.New()
obj := &gdoctableapp.AppendRowRequest{
Values: [][]interface{}{{"a1", "b1", "c1", 1, "", 2}, {"a2", "b2", "c2", 1, "", 2}},
}
res, err := g.Docs(documentID).TableIndex(tableIndex).AppendRow(obj).Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res)
documentID
: Document ID.tableIndex
: Table index. If you want to use the 3rd table in Google Document. It's 2. The start number of index is 0.client
: *Client
for using Docs API. Please check the section of Authorization.Values
of obj
: Values you want to append to the existing table.When above script is run, the following result is obtained. In this case, the values are put to the last row. And you can see that 3 columns are automatically added when the script is run.
In this sample, the texts {{sample}}
in all tables are replaced with the image retrieved by the URL of https://###/sample.png
.
documentID := "###"
searchText := "{{sample}}"
tableOnly := true
replaceImageURL := "https://###/sample.png"
g := gdoctableapp.New()
res, err := g.Docs(documentID).ReplaceTextsToImagesByURL(searchText, replaceImageURL).TableOnly(tableOnly).Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res)
In this sample, the texts {{sample}}
in all tables are replaced with the image retrieved by the file of ./sample.png
on your local PC.
documentID := "###"
searchText := "{{sample}}"
tableOnly := true // default is false
replaceImageFilePath := "./sample.png"
g := gdoctableapp.New()
res, err := g.Docs(documentID).ReplaceTextsToImagesByFile(searchText, replaceImageFilePath).TableOnly(tableOnly).Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res)
documentID
: Document ID.client
: *Client
for using Docs API. Please check the section of Authorization.searchText
: Search text. This text is replaced with image.tableOnly
: When this is true
, only texts in the table are replaced with image. When this is false
, the texts in the body are replaced.replaceImageURL
: URL of the image.replaceImageFilePath
: File path of the image.If you want to change the width and height of the image, please use the method of SetImageSize(width, height float64)
like below.
res, err := g.Docs(documentID).SetImageSize(100, 100).ReplaceTextsToImagesByFile(searchText, replaceImageFilePath).TableOnly(tableOnly).Do(client)
The flow for replacing the text with the image on the local PC.
About SetImageSize
objectSize: The size that the image should appear as in the document. This property is optional and the final size of the image in the document is determined by the following rules: _ If neither width nor height is specified, then a default size of the image is calculated based on its resolution. _ If one dimension is specified then the other dimension is calculated to preserve the aspect ratio of the image. * If both width and height are specified, the image is scaled to fit within the provided dimensions while maintaining its aspect ratio.
When above script is run, the following result is obtained.
The image of https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png
was used as the sample image.
When tableOnly
is false
, the following result is retrieved.
There are 2 patterns for using this library.
Document of OAuth2 is here.
In this sample script, the authorization process uses the Quickstart for Go. You can see the detail information at there.
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
gdoctableapp "github.com/tanaikech/go-gdoctableapp"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/docs/v1"
)
// Retrieves a token, saves the token, then returns the generated client.
func getClient(config *oauth2.Config) *http.Client {
tokFile := "token.json"
tok, err := tokenFromFile(tokFile)
if err != nil {
tok = getTokenFromWeb(config)
saveToken(tokFile, tok)
}
return config.Client(context.Background(), tok)
}
// Requests 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(oauth2.NoContext, 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)
defer f.Close()
if err != nil {
return nil, err
}
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)
defer f.Close()
if err != nil {
log.Fatalf("Unable to cache OAuth token: %v", err)
}
json.NewEncoder(f).Encode(token)
}
// OAuth2 : Use OAuth2
func OAuth2() *http.Client {
credentialFile := "credentials.json"
b, err := os.ReadFile(credentialFile)
if err != nil {
log.Fatalf("Unable to read client secret file: %v", err)
}
config, err := google.ConfigFromJSON(b, docs.DocumentsScope)
if err != nil {
log.Fatalf("Unable to parse client secret file to config: %v", err)
}
client := getClient(config)
return client
}
func main() {
documentID := "###" // Please set here
tableIndex := 0 // Please set here
client := OAuth2()
g := gdoctableapp.New()
res, err := g.Docs(documentID).TableIndex(tableIndex).GetValues().Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res.Values)
}
Document of Service account is here. When you use Service account, please share Google Document with the email of Service account.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
gdoctableapp "github.com/tanaikech/go-gdoctableapp"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"golang.org/x/oauth2/jwt"
docs "google.golang.org/api/docs/v1"
)
// ServiceAccount : Use Service account
func ServiceAccount(credentialFile string) *http.Client {
b, err := ioutil.ReadFile(credentialFile)
if err != nil {
log.Fatal(err)
}
var c = struct {
Email string `json:"client_email"`
PrivateKey string `json:"private_key"`
}{}
json.Unmarshal(b, &c)
config := &jwt.Config{
Email: c.Email,
PrivateKey: []byte(c.PrivateKey),
Scopes: []string{
docs.DocumentsScope,
},
TokenURL: google.JWTTokenURL,
}
client := config.Client(oauth2.NoContext)
return client
}
func main() {
documentID := "###" // Please set here
tableIndex := 0 // Please set here
client := ServiceAccount("credential.json") // Please set here
g := gdoctableapp.New()
res, err := g.Docs(documentID).TableIndex(tableIndex).GetValues().Do(client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(res.Values)
}
tableCellStyle
cannot be modified by Google Docs API. By this, the formats of cells cannot be modified. About this, I have posted as Feature Request.If you have any questions and commissions for me, feel free to tell me.
v1.0.0 (July 18, 2019)
v1.0.5 (January 21, 2020)
v1.1.0 (January 22, 2020)
v1.1.0 (April 18, 2023)
FAQs
Unknown package
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
Security News
Socket CEO Feross Aboukhadijeh discusses open source security challenges, including zero-day attacks and supply chain risks, on the Cyber Security Council podcast.
Security News
Research
Socket researchers uncover how threat actors weaponize Out-of-Band Application Security Testing (OAST) techniques across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.