forked from TeamShellSMM/ShellBot3000
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGS.js
More file actions
244 lines (215 loc) · 6.46 KB
/
GS.js
File metadata and controls
244 lines (215 loc) · 6.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
'use strict'
const request = require('request-promise')
const { google } = require("googleapis");
const querystring = require("querystring");
var GS=function(config){
let jwtClient = new google.auth.JWT(
config.client_email,
null,
config.private_key,
["https://spreadsheets.google.com/feeds"]
);
let google_auth=null
async function get_token(){
if (!(google_auth && google_auth.expiry_date > +new Date())){
google_auth=await jwtClient.authorize()
}
return google_auth
}
this.lastUpdated=null
this.timestampVarName="Timestamp"
this.timestamp=function(){
return Math.floor(Date.now() / 1000) //seconds epoch
}
let json_header={}
let SheetCache={} //not sure if I need a mutex here or not
let ArrayCache={}
this.getHeaders=function(){
return json_header
}
this.getArrayFormat=function(sheets){
var SheetCache={}
sheets.forEach((sheet)=>{
var range=sheet.split('!')
var sheet_name=range[0].replace(/'/g,'')
SheetCache[sheet_name]=this.getArray(sheet)
})
return SheetCache
}
this.getArray=function(range){
range=range.replace(/\\/g,'').split('!')
var sheet_name=range[0].replace(/'/g,'')
var sheet=JSON.parse(ArrayCache[sheet_name])
if(sheet && range[1]&&range[1].length==1){
var rangeLength=range[1].charCodeAt(0)-64
for(var i=0;i<sheet.length;i++){
sheet[i]=sheet[i].slice(0,rangeLength)
}
}
return sheet
}
this.loadSheets=async function(ranges){ //input is sheets to be loaded. load to cache to be stored
try {
let authClient=await get_token()
ranges=ranges?ranges.join("&ranges="):""
let url = "https://sheets.googleapis.com/v4/spreadsheets/"+config.spreadsheetId+"/values:batchGet?ranges="+ranges
const response=await request( {
url: url,
method: 'GET',
headers:{
Authorization: 'Bearer ' + authClient.access_token
},
gzip: true
})
var returnData={}
let data=JSON.parse(response)
this.lastUpdated=this.timestamp()
if(data.valueRanges){
for(var i=0;i<data.valueRanges.length;i++){
var range=data.valueRanges[i].range.split("!")
range=range[0].replace(/'/g,'')
ArrayCache[range]=JSON.stringify(data.valueRanges[i].values)
var header=data.valueRanges[i].values.shift()
json_header[range]=header;
returnData[range]=[]
for(var j=0;j<data.valueRanges[i].values.length;j++){
var row={}
for(var k=0;k<header.length;k++){
row[header[k]]=data.valueRanges[i].values[j][k]
}
row["GS_sheet_name"]=range
row["GS_row_id"]=(j+1); //for r1c1. header is r1
returnData[range].push(row)
}
SheetCache[range]=returnData[range]
}
}
return returnData
} catch (error){
console.error(error)
}
}
//need to load
this.select=function(sheet,filter){
return this.query(sheet,{
filter:filter
})
}
this.query=function (sheet,parameters){ //may break if column named updated or row
try{
var querySheet = SheetCache[sheet]
if(!querySheet) throw "No cached sheet found"
var headers=json_header[sheet];
var header_to_id={}
for(var i=0;i<headers.length;i++){
header_to_id[headers[i]]=i;
}
if(parameters && parameters.filter){
var filter=function(row){
var matched=true;
for(var f in parameters.filter){
if(row[f]!=parameters.filter[f]) matched=false;
}
return matched;
}
} else {
var filter=function(){return true;}
}
var ret=[]
for (var row = 0; row < querySheet.length; row++){
if(filter(querySheet[row])){
var obj=querySheet[row]
var updated={}
if(parameters && parameters.update){
var data=[]
for(var u in parameters.update){
if(obj[u]!=parameters.update[u]){
data.push({
range: r1c1(sheet,querySheet[row]["GS_row_id"],header_to_id[u]),
values: [[parameters.update[u]]]
})
updated[u]=true;
} else {
updated[u]=false;
}
}
if(data){
obj.update_ranges=data
}
}
obj.updated=updated
ret.push(obj)
}
}
return (ret.length>1) ? ret : ret[0]
} catch (error){
console.error(error)
}
}
function r1c1(sheet,r,c){ //A1 = R1C1
return "'"+sheet+"'!r"+(r+1)+"c"+(c+1);
}
this.insert =async function(sheet,pData){
try {
var header=json_header[sheet];
if(!sheet) throw "No sheet selected";
if(!header) throw "Sheet has not been loaded or doesn't exist";
if(!pData) throw "Passed data must not be null";
let url = "https://sheets.googleapis.com/v4/spreadsheets/"+config.spreadsheetId+"/values/"+encodeURI("'"+sheet+"'")+":append?insertDataOption=INSERT_ROWS&valueInputOption=USER_ENTERED"
var new_row=[],hasData=false;
for(var i=0;i<header.length;i++){
var cur_col=pData[header[i]]
if(cur_col===undefined || cur_col===null){
cur_col=''
}
if(!cur_col && header[i]==this.timestampVarName){
cur_col=this.timestamp();
}
if(cur_col) hasData=true;
new_row.push(cur_col);
}
if(!hasData) throw "There was no valid data given for this sheet";
var data={
"values":[new_row]
}
let authClient=await get_token()
const response=await request( {
url: url,
method: 'POST',
headers:{
Authorization: 'Bearer ' + authClient.access_token
},
gzip: true,
body: JSON.stringify(data)
});
return response
} catch(error){
console.error(error)
}
}
//store batchUpdates in a cache then run batchUpdate to save changes?
this.batchUpdate=async function(ranges){ //for ease of use format will be strictly r1c1
try {
let url="https://sheets.googleapis.com/v4/spreadsheets/"+config.spreadsheetId+"/values:batchUpdate"
var data={
"valueInputOption": "USER_ENTERED",
"data": ranges,
"includeValuesInResponse": false
}
let authClient=await get_token()
const response=await request( {
url: url,
method: 'POST',
headers:{
Authorization: 'Bearer ' + authClient.access_token
},
gzip: true,
body: JSON.stringify(data)
})
return response
} catch(error){
console.error(error)
}
}
}
module.exports=GS