@mcpher/gas-fakes 1.2.32 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gcloudignore +24 -0
- package/README.md +5 -5
- package/appsscript.json +101 -0
- package/exgcp.sh +4 -4
- package/package.json +5 -6
- package/src/cli/app.js +9 -1
- package/src/cli/lib-manager.js +0 -1
- package/src/cli/setup.js +330 -228
- package/src/services/advcalendar/clapis.js +4 -2
- package/src/services/advdocs/docapis.js +4 -3
- package/src/services/advdrive/drapis.js +8 -5
- package/src/services/advforms/formsapis.js +4 -3
- package/src/services/advgmail/gmailapis.js +4 -3
- package/src/services/advsheets/shapis.js +5 -10
- package/src/services/advslides/slapis.js +4 -3
- package/src/services/driveapp/fakedriveapp.js +10 -2
- package/src/services/logger/fakelogger.js +6 -3
- package/src/services/scriptapp/app.js +16 -11
- package/src/services/scriptapp/behavior.js +132 -107
- package/src/services/session/fakesession.js +24 -9
- package/src/services/slidesapp/fakepresentation.js +19 -8
- package/src/services/slidesapp/fakeslide.js +45 -20
- package/src/services/spreadsheetapp/fakesheet.js +9 -7
- package/src/services/stores/fakestores.js +20 -18
- package/src/services/stores/gasflex.js +13 -14
- package/src/services/urlfetchapp/app.js +3 -3
- package/src/support/auth.js +227 -55
- package/src/support/slogger.js +42 -0
- package/src/support/sxauth.js +42 -39
- package/src/support/sxcalendar.js +9 -43
- package/src/support/sxdocs.js +6 -42
- package/src/support/sxdrive.js +19 -76
- package/src/support/sxfetch.js +36 -30
- package/src/support/sxforms.js +9 -40
- package/src/support/sxgmail.js +9 -37
- package/src/support/sxretry.js +79 -0
- package/src/support/sxsheets.js +6 -37
- package/src/support/sxslides.js +5 -36
- package/src/support/sxtoken.js +15 -0
- package/src/support/syncit.js +27 -10
- package/src/support/workersync/sxfunctions.js +2 -0
- package/src/support/workersync/synclogger.js +22 -5
- package/src/support/workersync/worker.js +8 -11
- package/README.RU.md +0 -373
- package/env.setup.template +0 -16
- package/run.js +0 -35
- package/setup.js +0 -689
- package/src/Code.js +0 -3
- package/src/appsscript.json +0 -5
|
@@ -17,10 +17,10 @@ export class FakePresentation {
|
|
|
17
17
|
constructor(resource) {
|
|
18
18
|
this.__id = resource.presentationId;
|
|
19
19
|
}
|
|
20
|
-
get __file
|
|
20
|
+
get __file() {
|
|
21
21
|
return DriveApp.getFileById(this.__id);
|
|
22
22
|
}
|
|
23
|
-
get __resource
|
|
23
|
+
get __resource() {
|
|
24
24
|
return Slides.Presentations.get(this.__id);
|
|
25
25
|
}
|
|
26
26
|
saveAndClose() {
|
|
@@ -73,14 +73,20 @@ export class FakePresentation {
|
|
|
73
73
|
* @returns {FakeSlide} The new slide.
|
|
74
74
|
*/
|
|
75
75
|
appendSlide(layout) {
|
|
76
|
+
const objectId = `slide_${Math.random().toString(36).substring(2, 11)}`;
|
|
76
77
|
const requests = [{
|
|
77
78
|
createSlide: {
|
|
79
|
+
objectId,
|
|
78
80
|
slideLayoutReference: layout ? { predefinedLayout: layout } : { predefinedLayout: 'BLANK' }
|
|
79
81
|
}
|
|
80
82
|
}];
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
try {
|
|
84
|
+
Slides.Presentations.batchUpdate(requests, this.getId());
|
|
85
|
+
} catch (err) {
|
|
86
|
+
// If it already exists, it means a previous attempt succeeded but timed out
|
|
87
|
+
if (!err?.message?.includes('already exists')) throw err;
|
|
88
|
+
}
|
|
89
|
+
return this.getSlideById(objectId);
|
|
84
90
|
}
|
|
85
91
|
|
|
86
92
|
/**
|
|
@@ -90,15 +96,20 @@ export class FakePresentation {
|
|
|
90
96
|
* @returns {FakeSlide} The new slide.
|
|
91
97
|
*/
|
|
92
98
|
insertSlide(index, layout) {
|
|
99
|
+
const objectId = `slide_${Math.random().toString(36).substring(2, 11)}`;
|
|
93
100
|
const requests = [{
|
|
94
101
|
createSlide: {
|
|
102
|
+
objectId,
|
|
95
103
|
insertionIndex: index,
|
|
96
104
|
slideLayoutReference: layout ? { predefinedLayout: layout } : { predefinedLayout: 'BLANK' }
|
|
97
105
|
}
|
|
98
106
|
}];
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
107
|
+
try {
|
|
108
|
+
Slides.Presentations.batchUpdate(requests, this.getId());
|
|
109
|
+
} catch (err) {
|
|
110
|
+
if (!err?.message?.includes('already exists')) throw err;
|
|
111
|
+
}
|
|
112
|
+
return this.getSlideById(objectId);
|
|
102
113
|
}
|
|
103
114
|
|
|
104
115
|
toString() {
|
|
@@ -91,11 +91,16 @@ export class FakeSlide {
|
|
|
91
91
|
*/
|
|
92
92
|
remove() {
|
|
93
93
|
const presentationId = this.__presentation.getId();
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
try {
|
|
95
|
+
Slides.Presentations.batchUpdate([{
|
|
96
|
+
deleteObject: {
|
|
97
|
+
objectId: this.getObjectId()
|
|
98
|
+
}
|
|
99
|
+
}], presentationId);
|
|
100
|
+
} catch (err) {
|
|
101
|
+
// If not found, it's already deleted (perhaps on a previous timeouted attempt)
|
|
102
|
+
if (!err?.message?.includes('not found')) throw err;
|
|
103
|
+
}
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
/**
|
|
@@ -111,8 +116,10 @@ export class FakeSlide {
|
|
|
111
116
|
// Default size and position if not provided
|
|
112
117
|
// shapeType should be string e.g. TEXT_BOX
|
|
113
118
|
const presentationId = this.__presentation.getId();
|
|
114
|
-
const
|
|
119
|
+
const objectId = `shape_${Math.random().toString(36).substring(2, 11)}`;
|
|
120
|
+
const requests = [{
|
|
115
121
|
createShape: {
|
|
122
|
+
objectId,
|
|
116
123
|
shapeType: shapeType,
|
|
117
124
|
elementProperties: {
|
|
118
125
|
pageObjectId: this.getObjectId(),
|
|
@@ -129,10 +136,13 @@ export class FakeSlide {
|
|
|
129
136
|
}
|
|
130
137
|
}
|
|
131
138
|
}
|
|
132
|
-
}]
|
|
139
|
+
}];
|
|
133
140
|
|
|
134
|
-
|
|
135
|
-
|
|
141
|
+
try {
|
|
142
|
+
Slides.Presentations.batchUpdate(requests, presentationId);
|
|
143
|
+
} catch (err) {
|
|
144
|
+
if (!err?.message?.includes('already exists')) throw err;
|
|
145
|
+
}
|
|
136
146
|
|
|
137
147
|
// We assume the shape is added to the slide and we can retrieve it
|
|
138
148
|
// Wait, we need to return a FakeShape.
|
|
@@ -152,7 +162,7 @@ export class FakeSlide {
|
|
|
152
162
|
// So subsequent access should be fresh.
|
|
153
163
|
|
|
154
164
|
const elements = this.getPageElements();
|
|
155
|
-
const newElement = elements.find(e => e.getObjectId() ===
|
|
165
|
+
const newElement = elements.find(e => e.getObjectId() === objectId);
|
|
156
166
|
if (!newElement) throw new Error('New shape not found');
|
|
157
167
|
return newElement.asShape();
|
|
158
168
|
}
|
|
@@ -168,8 +178,10 @@ export class FakeSlide {
|
|
|
168
178
|
*/
|
|
169
179
|
insertLine(lineCategory, left = 0, top = 0, width = 100, height = 100) {
|
|
170
180
|
const presentationId = this.__presentation.getId();
|
|
171
|
-
const
|
|
181
|
+
const objectId = `line_${Math.random().toString(36).substring(2, 11)}`;
|
|
182
|
+
const requests = [{
|
|
172
183
|
createLine: {
|
|
184
|
+
objectId,
|
|
173
185
|
lineCategory: lineCategory,
|
|
174
186
|
elementProperties: {
|
|
175
187
|
pageObjectId: this.getObjectId(),
|
|
@@ -186,28 +198,41 @@ export class FakeSlide {
|
|
|
186
198
|
}
|
|
187
199
|
}
|
|
188
200
|
}
|
|
189
|
-
}]
|
|
201
|
+
}];
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
Slides.Presentations.batchUpdate(requests, presentationId);
|
|
205
|
+
} catch (err) {
|
|
206
|
+
if (!err?.message?.includes('already exists')) throw err;
|
|
207
|
+
}
|
|
190
208
|
|
|
191
|
-
const newObjectId = result.replies[0].createLine.objectId;
|
|
192
209
|
const elements = this.getPageElements();
|
|
193
|
-
const newElement = elements.find(e => e.getObjectId() ===
|
|
210
|
+
const newElement = elements.find(e => e.getObjectId() === objectId);
|
|
194
211
|
if (!newElement) throw new Error('New line not found');
|
|
195
212
|
return newElement.asLine();
|
|
196
213
|
}
|
|
197
214
|
|
|
198
215
|
duplicate() {
|
|
199
216
|
const presentationId = this.__presentation.getId();
|
|
200
|
-
const
|
|
217
|
+
const objectId = `slide_${Math.random().toString(36).substring(2, 11)}`;
|
|
218
|
+
const requests = [{
|
|
201
219
|
duplicateObject: {
|
|
202
|
-
objectId: this.getObjectId()
|
|
220
|
+
objectId: this.getObjectId(),
|
|
221
|
+
objectIds: {
|
|
222
|
+
[this.getObjectId()]: objectId
|
|
223
|
+
}
|
|
203
224
|
}
|
|
204
|
-
}]
|
|
225
|
+
}];
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
Slides.Presentations.batchUpdate(requests, presentationId);
|
|
229
|
+
} catch (err) {
|
|
230
|
+
if (!err?.message?.includes('already exists')) throw err;
|
|
231
|
+
}
|
|
205
232
|
|
|
206
|
-
// The result contains the new object ID
|
|
207
|
-
const newObjectId = result.replies[0].duplicateObject.objectId;
|
|
208
233
|
// We need to get the updated presentation to find the new slide resource
|
|
209
234
|
const updatedPresentation = Slides.Presentations.get(presentationId);
|
|
210
|
-
const newSlideResource = updatedPresentation.slides.find(s => s.objectId ===
|
|
235
|
+
const newSlideResource = updatedPresentation.slides.find(s => s.objectId === objectId);
|
|
211
236
|
return newFakeSlide(newSlideResource, this.__presentation);
|
|
212
237
|
}
|
|
213
238
|
|
|
@@ -16,7 +16,7 @@ import { newFakeProtection } from "./fakeprotection.js";
|
|
|
16
16
|
import { newFakeOverGridImage } from "./fakeovergridimage.js";
|
|
17
17
|
|
|
18
18
|
import { XMLParser } from "fast-xml-parser";
|
|
19
|
-
import {slogger } from "../../support/slogger.js";
|
|
19
|
+
import { slogger } from "../../support/slogger.js";
|
|
20
20
|
const { is, isEnum } = Utils;
|
|
21
21
|
|
|
22
22
|
export const newFakeSheet = (properties, parent) => {
|
|
@@ -1075,12 +1075,14 @@ export class FakeSheet {
|
|
|
1075
1075
|
const unzipped = Utilities.unzip(blob);
|
|
1076
1076
|
const xmlObj = unzipped.reduce((o, b) => {
|
|
1077
1077
|
const filename = b.getName();
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1078
|
+
if (filename.endsWith('.xml') || filename.endsWith('.rels')) {
|
|
1079
|
+
const parser = new XMLParser({ ignoreAttributes: false });
|
|
1080
|
+
try {
|
|
1081
|
+
const p = parser.parse(b.getDataAsString());
|
|
1082
|
+
o[filename] = p;
|
|
1083
|
+
} catch (err) {
|
|
1084
|
+
slogger.error(`Error parsing ${filename}: ${err.message}`);
|
|
1085
|
+
}
|
|
1084
1086
|
}
|
|
1085
1087
|
return o;
|
|
1086
1088
|
}, {});
|
|
@@ -6,7 +6,7 @@ import { storeModels } from './gasflex.js'
|
|
|
6
6
|
import { newCacheDropin } from '@mcpher/gas-flex-cache'
|
|
7
7
|
import { notYetImplemented } from '../../support/helpers.js'
|
|
8
8
|
const { is } = Utils
|
|
9
|
-
import {slogger } from "../../support/slogger.js";
|
|
9
|
+
import { slogger } from "../../support/slogger.js";
|
|
10
10
|
/**
|
|
11
11
|
* what these props mean
|
|
12
12
|
* store_type = currently upstash or file - it defines the back end and maps to env variable
|
|
@@ -87,7 +87,7 @@ const validateProp = (prop, vob, name = '') => {
|
|
|
87
87
|
// this checks to see if we want to override a service with gas-flex-cache
|
|
88
88
|
const whichCache = () => {
|
|
89
89
|
// this will return the actual value of the enum, not the property name
|
|
90
|
-
const type = validateProp
|
|
90
|
+
const type = validateProp(process.env.STORE_TYPE || "file", StoreType, 'store_type')
|
|
91
91
|
if (type === StoreType.UPSTASH) {
|
|
92
92
|
const url = process.env.UPSTASH_REDIS_REST_URL
|
|
93
93
|
const token = process.env.UPSTASH_REDIS_REST_TOKEN
|
|
@@ -136,7 +136,7 @@ class FakePropertiesService {
|
|
|
136
136
|
* @returns {FakeProperties}
|
|
137
137
|
*/
|
|
138
138
|
getScriptProperties() {
|
|
139
|
-
|
|
139
|
+
return selectCache(StoreDomain.SCRIPT, this.kind)
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -145,7 +145,7 @@ class FakePropertiesService {
|
|
|
145
145
|
*/
|
|
146
146
|
class FakeCacheService {
|
|
147
147
|
constructor(type) {
|
|
148
|
-
this.kind =
|
|
148
|
+
this.kind = ServiceKind.CACHE
|
|
149
149
|
this.type = type
|
|
150
150
|
}
|
|
151
151
|
|
|
@@ -164,7 +164,7 @@ class FakeCacheService {
|
|
|
164
164
|
* @returns {FakeCache}
|
|
165
165
|
*/
|
|
166
166
|
getUserCache() {
|
|
167
|
-
return selectCache(StoreDomain.USER, this.kind,DEFAULT_CACHE_EXPIRY)
|
|
167
|
+
return selectCache(StoreDomain.USER, this.kind, DEFAULT_CACHE_EXPIRY)
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
/**
|
|
@@ -172,7 +172,7 @@ class FakeCacheService {
|
|
|
172
172
|
* @returns {FakeCache}
|
|
173
173
|
*/
|
|
174
174
|
getScriptCache() {
|
|
175
|
-
|
|
175
|
+
return selectCache(StoreDomain.SCRIPT, this.kind, DEFAULT_CACHE_EXPIRY)
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
@@ -182,28 +182,30 @@ class FakeCacheService {
|
|
|
182
182
|
* @returns {FakePropertiesService | FakeCacheService}
|
|
183
183
|
*/
|
|
184
184
|
export const newFakeService = (kind) => {
|
|
185
|
-
kind = validateProp
|
|
186
|
-
const w = whichCache
|
|
187
|
-
slogger.log
|
|
185
|
+
kind = validateProp(kind, ServiceKind, 'service_kind')
|
|
186
|
+
const w = whichCache()
|
|
187
|
+
slogger.log(`...${kind} store service is using store type ${w.type} as backend`)
|
|
188
188
|
return Proxies.guard(kind === ServiceKind.CACHE ? new FakeCacheService(w.type) : new FakePropertiesService(w.type))
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
const selectCache = (domain, kind, defaultExpirationSeconds) => {
|
|
192
192
|
// actually we might be overriding the type of service
|
|
193
|
-
domain = validateProp
|
|
193
|
+
domain = validateProp(domain, StoreDomain, 'store_domain')
|
|
194
194
|
const which = whichCache()
|
|
195
195
|
if (which.type === "UPSTASH") {
|
|
196
196
|
const model = storeModels[domain]
|
|
197
197
|
if (!model) {
|
|
198
|
-
throw new Error(`invalid store type model for ${cacheType}`)
|
|
198
|
+
throw new Error(`invalid store type model for ${cacheType}`)
|
|
199
199
|
}
|
|
200
|
-
return newCacheDropin
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
200
|
+
return newCacheDropin({
|
|
201
|
+
creds: {
|
|
202
|
+
...model,
|
|
203
|
+
...which,
|
|
204
|
+
type: "upstash",
|
|
205
|
+
kind: kind.toLowerCase(),
|
|
206
|
+
defaultExpirationSeconds
|
|
207
|
+
}
|
|
208
|
+
})
|
|
207
209
|
} else if (which.type === StoreType.FILE) {
|
|
208
210
|
const store = kind === ServiceKind.CACHE ? FakeCache : FakeProperties
|
|
209
211
|
return Proxies.guard(new store(domain))
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
import {Auth} from '../../support/auth.js'
|
|
2
|
-
import { getUserIdFromToken} from '@mcpher/gas-flex-cache'
|
|
1
|
+
import { Auth } from '../../support/auth.js'
|
|
2
|
+
import { getUserIdFromToken } from '@mcpher/gas-flex-cache'
|
|
3
3
|
|
|
4
4
|
// these are the default models to match live apps script
|
|
5
5
|
export const storeModels = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
SCRIPT: {
|
|
7
|
+
scriptId: ScriptApp.getScriptId()
|
|
8
|
+
},
|
|
9
|
+
USER: {
|
|
10
|
+
scriptId: ScriptApp.getScriptId(),
|
|
11
|
+
userId: getUserIdFromToken(ScriptApp.getOAuthToken())
|
|
12
|
+
},
|
|
13
|
+
DOCUMENT: {
|
|
14
|
+
scriptId: ScriptApp.getScriptId(),
|
|
15
|
+
documentId: Auth.getDocumentId()
|
|
16
|
+
}
|
|
17
17
|
}
|
|
18
|
-
|
|
@@ -86,8 +86,8 @@ const fetch = (url, options = {}) => {
|
|
|
86
86
|
'rawBody'
|
|
87
87
|
]
|
|
88
88
|
|
|
89
|
-
const
|
|
90
|
-
return responsify(
|
|
89
|
+
const { data } = Syncit.fxFetch(url, options, responseFields)
|
|
90
|
+
return responsify(data)
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
// this has been syncified
|
|
@@ -102,7 +102,7 @@ const fetchAll = (requests) => {
|
|
|
102
102
|
]
|
|
103
103
|
|
|
104
104
|
const responses = Syncit.fxFetchAll(requests, responseFields)
|
|
105
|
-
return responses.map(
|
|
105
|
+
return responses.map(({ data }) => responsify(data))
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
|