@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
|
@@ -3,12 +3,14 @@ import { Auth } from '../../support/auth.js'
|
|
|
3
3
|
import { syncLog } from '../../support/workersync/synclogger.js'
|
|
4
4
|
|
|
5
5
|
let __client = null;
|
|
6
|
+
let __authClient = null;
|
|
6
7
|
syncLog('...importing Calendar API');
|
|
7
8
|
export const getCalendarApiClient = () => {
|
|
8
|
-
const auth = Auth.getAuthClient()
|
|
9
|
-
if (!__client) {
|
|
9
|
+
const auth = Auth.getAuthClient();
|
|
10
|
+
if (!__client || auth !== __authClient) {
|
|
10
11
|
syncLog('Creating new Calendar API client');
|
|
11
12
|
__client = google.calendar({ version: 'v3', auth });
|
|
13
|
+
__authClient = auth;
|
|
12
14
|
}
|
|
13
15
|
return __client;
|
|
14
16
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { google } from "googleapis";
|
|
2
2
|
import { Auth } from '../../support/auth.js'
|
|
3
|
-
import { syncLog} from '../../support/workersync/synclogger.js'
|
|
3
|
+
import { syncLog } from '../../support/workersync/synclogger.js'
|
|
4
4
|
|
|
5
5
|
let __client = null;
|
|
6
|
+
let __authClient = null;
|
|
6
7
|
|
|
7
8
|
export const getDocsApiClient = () => {
|
|
8
9
|
const auth = Auth.getAuthClient()
|
|
9
|
-
if (!__client) {
|
|
10
|
+
if (!__client || auth !== __authClient) {
|
|
10
11
|
syncLog('Creating new Docs API client');
|
|
11
12
|
__client = google.docs({ version: 'v1', auth });
|
|
13
|
+
__authClient = auth;
|
|
12
14
|
}
|
|
13
15
|
return __client;
|
|
14
16
|
}
|
|
15
|
-
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { google } from "googleapis";
|
|
2
2
|
import { Auth } from '../../support/auth.js'
|
|
3
|
-
import { syncLog} from '../../support/workersync/synclogger.js'
|
|
4
|
-
|
|
3
|
+
import { syncLog } from '../../support/workersync/synclogger.js'
|
|
5
4
|
let __client = null;
|
|
6
|
-
|
|
5
|
+
let __authClient = null;
|
|
6
|
+
|
|
7
7
|
export const getDriveApiClient = () => {
|
|
8
|
-
const auth = Auth.
|
|
9
|
-
|
|
8
|
+
const auth = Auth.getAuth(); // Now returns the patched AuthClient instance
|
|
9
|
+
|
|
10
|
+
if (!__client || auth !== __authClient) {
|
|
10
11
|
syncLog('Creating new Drive API client');
|
|
12
|
+
// The Drive SDK sees a standard AuthClient and uses its (hijacked) getAccessToken
|
|
11
13
|
__client = google.drive({ version: 'v3', auth });
|
|
14
|
+
__authClient = auth;
|
|
12
15
|
}
|
|
13
16
|
return __client;
|
|
14
17
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { google } from "googleapis";
|
|
2
2
|
import { Auth } from '../../support/auth.js'
|
|
3
|
-
import { syncLog} from '../../support/workersync/synclogger.js'
|
|
3
|
+
import { syncLog } from '../../support/workersync/synclogger.js'
|
|
4
4
|
|
|
5
5
|
let __client = null;
|
|
6
|
+
let __authClient = null;
|
|
6
7
|
|
|
7
8
|
export const getFormsApiClient = () => {
|
|
8
9
|
const auth = Auth.getAuthClient()
|
|
9
|
-
if (!__client) {
|
|
10
|
+
if (!__client || auth !== __authClient) {
|
|
10
11
|
syncLog('Creating new Forms API client');
|
|
11
12
|
__client = google.forms({ version: 'v1', auth });
|
|
13
|
+
__authClient = auth;
|
|
12
14
|
}
|
|
13
15
|
return __client;
|
|
14
16
|
}
|
|
15
|
-
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { google } from "googleapis";
|
|
2
2
|
import { Auth } from '../../support/auth.js'
|
|
3
|
-
import { syncLog} from '../../support/workersync/synclogger.js'
|
|
3
|
+
import { syncLog } from '../../support/workersync/synclogger.js'
|
|
4
4
|
|
|
5
5
|
let __client = null;
|
|
6
|
+
let __authClient = null;
|
|
6
7
|
|
|
7
8
|
export const getGmailApiClient = () => {
|
|
8
9
|
const auth = Auth.getAuthClient()
|
|
9
|
-
if (!__client) {
|
|
10
|
+
if (!__client || auth !== __authClient) {
|
|
10
11
|
syncLog('Creating new Gmail API client');
|
|
11
12
|
__client = google.gmail({ version: 'v1', auth });
|
|
13
|
+
__authClient = auth;
|
|
12
14
|
}
|
|
13
15
|
return __client;
|
|
14
16
|
}
|
|
15
|
-
|
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
import { google } from "googleapis";
|
|
2
2
|
import { Auth } from '../../support/auth.js'
|
|
3
|
-
import { syncLog} from '../../support/workersync/synclogger.js'
|
|
4
|
-
|
|
3
|
+
import { syncLog } from '../../support/workersync/synclogger.js'
|
|
4
|
+
|
|
5
5
|
let __client = null;
|
|
6
|
+
let __authClient = null;
|
|
6
7
|
syncLog('...importing Sheets API');
|
|
7
8
|
export const getSheetsApiClient = () => {
|
|
8
9
|
const auth = Auth.getAuthClient()
|
|
9
|
-
|
|
10
|
-
if (__client && currentAuth !== auth) {
|
|
11
|
-
syncLog('Auth has changed - creating new Sheets API client');
|
|
12
|
-
__client = null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
currentAuth = auth;
|
|
16
|
-
if (!__client) {
|
|
10
|
+
if (!__client || auth !== __authClient) {
|
|
17
11
|
syncLog('Creating new Sheets API client');
|
|
18
12
|
__client = google.sheets({ version: 'v4', auth });
|
|
13
|
+
__authClient = auth;
|
|
19
14
|
}
|
|
20
15
|
return __client;
|
|
21
16
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
|
|
2
1
|
import { google } from "googleapis";
|
|
3
2
|
import { Auth } from '../../support/auth.js'
|
|
4
|
-
import { syncLog} from '../../support/workersync/synclogger.js'
|
|
3
|
+
import { syncLog } from '../../support/workersync/synclogger.js'
|
|
5
4
|
|
|
6
5
|
let __client = null;
|
|
6
|
+
let __authClient = null;
|
|
7
7
|
syncLog('...importing Slides API');
|
|
8
8
|
export const getSlidesApiClient = () => {
|
|
9
9
|
const auth = Auth.getAuthClient()
|
|
10
|
-
if (!__client) {
|
|
10
|
+
if (!__client || auth !== __authClient) {
|
|
11
11
|
syncLog('Creating new Slides API client');
|
|
12
12
|
__client = google.slides({ version: 'v1', auth });
|
|
13
|
+
__authClient = auth;
|
|
13
14
|
}
|
|
14
15
|
return __client;
|
|
15
16
|
}
|
|
@@ -3,6 +3,8 @@ import { newFakeDriveFile } from './fakedrivefile.js'
|
|
|
3
3
|
import { newFakeFolderApp } from './fakefolderapp.js'
|
|
4
4
|
import { notYetImplemented, isFolder } from '../../support/helpers.js'
|
|
5
5
|
import { Proxies } from '../../support/proxies.js'
|
|
6
|
+
import { Utils } from '../../support/utils.js'
|
|
7
|
+
const { is } = Utils
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -42,11 +44,17 @@ export class FakeDriveApp {
|
|
|
42
44
|
* @returns {newFakeDriveFile|null}
|
|
43
45
|
*/
|
|
44
46
|
getFileById(id) {
|
|
47
|
+
if (!is.nonEmptyString(id)) {
|
|
48
|
+
throw new Error(`API call to DriveApp.getFileById failed with error: Invalid argument: id`)
|
|
49
|
+
}
|
|
45
50
|
const file = Drive.Files.get(id, {}, { allow404: true })
|
|
46
51
|
return file ? newFakeDriveFile(file) : null
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
getFolderById(id) {
|
|
55
|
+
if (!is.nonEmptyString(id)) {
|
|
56
|
+
throw new Error(`API call to DriveApp.getFolderById failed with error: Invalid argument: id`)
|
|
57
|
+
}
|
|
50
58
|
const file = Drive.Files.get(id, {}, { allow404: true })
|
|
51
59
|
return file ? newFakeDriveFolder(file) : null
|
|
52
60
|
}
|
|
@@ -86,9 +94,9 @@ export class FakeDriveApp {
|
|
|
86
94
|
}
|
|
87
95
|
|
|
88
96
|
searchFiles(params) {
|
|
89
|
-
return this.folderApp.searchFiles({
|
|
97
|
+
return this.folderApp.searchFiles({ params })
|
|
90
98
|
}
|
|
91
|
-
|
|
99
|
+
|
|
92
100
|
searchFolders(params) {
|
|
93
101
|
return this.folderApp.searchFolders({ params })
|
|
94
102
|
}
|
|
@@ -174,12 +174,15 @@ const writeToCloudOrConsole = (message, loggerInstance) => {
|
|
|
174
174
|
loggerInstance.__cloudLogLink = base + encodedQueryParam + `?project=${projectId}`;
|
|
175
175
|
|
|
176
176
|
const apiBase = 'https://logging.googleapis.com/v2/entries:write'
|
|
177
|
+
// Log the actual entry with its logName
|
|
178
|
+
metadata.logName = `projects/${projectId}/logs/${logName.replace('/', '%2F')}`
|
|
179
|
+
|
|
177
180
|
const payload = JSON.stringify({
|
|
178
181
|
entries: [
|
|
179
182
|
metadata
|
|
180
183
|
]
|
|
181
184
|
})
|
|
182
|
-
const token = ScriptApp.
|
|
185
|
+
const token = ScriptApp.__getSourceOAuthToken()
|
|
183
186
|
const headers = {
|
|
184
187
|
Authorization: `Bearer ${token}`,
|
|
185
188
|
'content-type': "application/json",
|
|
@@ -189,9 +192,9 @@ const writeToCloudOrConsole = (message, loggerInstance) => {
|
|
|
189
192
|
headers,
|
|
190
193
|
})
|
|
191
194
|
if (response.getResponseCode() !== 200) {
|
|
192
|
-
console.error
|
|
195
|
+
console.error('logging failure', response.getContentText())
|
|
193
196
|
}
|
|
194
|
-
|
|
197
|
+
|
|
195
198
|
}
|
|
196
199
|
|
|
197
200
|
};
|
|
@@ -8,19 +8,22 @@ import { Syncit } from '../../support/syncit.js'
|
|
|
8
8
|
import { Auth } from '../../support/auth.js'
|
|
9
9
|
import { Proxies } from '../../support/proxies.js'
|
|
10
10
|
import { newFakeBehavior } from './behavior.js'
|
|
11
|
-
import { newCacheDropin
|
|
12
|
-
import {slogger } from "../../support/slogger.js";
|
|
11
|
+
import { newCacheDropin } from '@mcpher/gas-flex-cache'
|
|
12
|
+
import { slogger } from "../../support/slogger.js";
|
|
13
13
|
/**
|
|
14
14
|
* fake ScriptApp.getOAuthToken
|
|
15
15
|
* @return {string} token
|
|
16
16
|
*/
|
|
17
17
|
const getOAuthToken = () => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
return Syncit.fxGetAccessToken(Auth)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* gets the token of the person running the script
|
|
23
|
+
* @return {string} token
|
|
24
|
+
*/
|
|
25
|
+
const getSourceOAuthToken = () => {
|
|
26
|
+
return Syncit.fxGetSourceAccessTokenInfo(Auth).token
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
|
|
@@ -66,7 +69,7 @@ const checkScopesMatch = (required) => {
|
|
|
66
69
|
const scopes = Auth.getTokenScopes()
|
|
67
70
|
|
|
68
71
|
// now we're syncronous all the way
|
|
69
|
-
const tokened = new Set(scopes.split(" "))
|
|
72
|
+
const tokened = new Set((typeof scopes === 'string' ? scopes : "").split(" "))
|
|
70
73
|
|
|
71
74
|
// see which ones are missing
|
|
72
75
|
const missing = required.filter(s => {
|
|
@@ -115,6 +118,7 @@ if (typeof globalThis[name] === typeof undefined) {
|
|
|
115
118
|
|
|
116
119
|
_app = {
|
|
117
120
|
getOAuthToken,
|
|
121
|
+
__getSourceOAuthToken: getSourceOAuthToken,
|
|
118
122
|
requireAllScopes,
|
|
119
123
|
requireScopes,
|
|
120
124
|
getScriptId: Auth.getScriptId,
|
|
@@ -122,14 +126,15 @@ if (typeof globalThis[name] === typeof undefined) {
|
|
|
122
126
|
return Auth.getProjectId()
|
|
123
127
|
},
|
|
124
128
|
get __userId() {
|
|
125
|
-
|
|
129
|
+
// this is actually the active user/ not the effective user
|
|
130
|
+
return Auth.getActiveUser().id
|
|
126
131
|
},
|
|
127
132
|
AuthMode: {
|
|
128
133
|
FULL: 'FULL'
|
|
129
134
|
},
|
|
130
135
|
__behavior: newFakeBehavior(),
|
|
131
136
|
__newCacheDropin: newCacheDropin,
|
|
132
|
-
|
|
137
|
+
__proxies: Proxies
|
|
133
138
|
}
|
|
134
139
|
|
|
135
140
|
|
|
@@ -254,6 +254,10 @@ class FakeBehavior {
|
|
|
254
254
|
this.__createdIds = new Set();
|
|
255
255
|
this.__createdGmailIds = new Set();
|
|
256
256
|
this.__createdCalendarIds = new Set();
|
|
257
|
+
// Specifically for sandbox mode - files created when sandbox mode is on
|
|
258
|
+
this.__allowedIds = new Set();
|
|
259
|
+
this.__allowedGmailIds = new Set();
|
|
260
|
+
this.__allowedCalendarIds = new Set();
|
|
257
261
|
// in sandbox mode we only allow access to files created in this instance
|
|
258
262
|
// this is to emulate the behavior of a drive.file scope
|
|
259
263
|
this.__sandboxMode = false;
|
|
@@ -341,39 +345,69 @@ class FakeBehavior {
|
|
|
341
345
|
get sandBoxMode() {
|
|
342
346
|
return this.__sandboxMode;
|
|
343
347
|
}
|
|
344
|
-
|
|
348
|
+
resetDrive() {
|
|
349
|
+
this.__createdIds.clear();
|
|
350
|
+
this.__allowedIds.clear();
|
|
351
|
+
return this;
|
|
352
|
+
}
|
|
353
|
+
resetGmail() {
|
|
354
|
+
this.__createdGmailIds.clear();
|
|
355
|
+
this.__allowedGmailIds.clear();
|
|
356
|
+
return this;
|
|
357
|
+
}
|
|
358
|
+
resetCalendar() {
|
|
359
|
+
this.__createdCalendarIds.clear();
|
|
360
|
+
this.__allowedCalendarIds.clear();
|
|
361
|
+
return this;
|
|
362
|
+
}
|
|
363
|
+
reset() {
|
|
364
|
+
this.resetDrive();
|
|
365
|
+
this.resetGmail();
|
|
366
|
+
this.resetCalendar();
|
|
367
|
+
return this;
|
|
368
|
+
}
|
|
369
|
+
addFile(id, force = false) {
|
|
345
370
|
if (!is.nonEmptyString(id)) {
|
|
346
371
|
throw new Error(`Invalid sandbox id parameter (${id}) - must be a non-empty string`);
|
|
347
372
|
}
|
|
348
|
-
if (
|
|
349
|
-
slogger.log(`...adding file ${id} to sandbox allowed list`);
|
|
373
|
+
if (this.sandboxMode || force) {
|
|
350
374
|
this.__createdIds.add(id);
|
|
375
|
+
if (!this.__allowedIds.has(id)) {
|
|
376
|
+
slogger.log(`...adding file ${id} to sandbox allowed list`);
|
|
377
|
+
this.__allowedIds.add(id);
|
|
378
|
+
}
|
|
351
379
|
}
|
|
352
380
|
return id
|
|
353
381
|
}
|
|
354
|
-
addGmailId(id) {
|
|
382
|
+
addGmailId(id, force = false) {
|
|
355
383
|
if (!is.nonEmptyString(id)) {
|
|
356
384
|
throw new Error(`Invalid sandbox id parameter (${id}) - must be a non-empty string`);
|
|
357
385
|
}
|
|
358
|
-
if (
|
|
359
|
-
slogger.log(`...adding gmail id ${id} to sandbox allowed list`);
|
|
386
|
+
if (this.sandboxMode || force) {
|
|
360
387
|
this.__createdGmailIds.add(id);
|
|
388
|
+
if (!this.__allowedGmailIds.has(id)) {
|
|
389
|
+
slogger.log(`...adding gmail id ${id} to sandbox allowed list`);
|
|
390
|
+
this.__allowedGmailIds.add(id);
|
|
391
|
+
}
|
|
361
392
|
}
|
|
362
393
|
return id
|
|
363
394
|
}
|
|
364
|
-
addCalendarId(id) {
|
|
395
|
+
addCalendarId(id, force = false) {
|
|
365
396
|
if (!is.nonEmptyString(id)) {
|
|
366
397
|
throw new Error(`Invalid sandbox id parameter (${id}) - must be a non-empty string`);
|
|
367
398
|
}
|
|
368
|
-
if (
|
|
369
|
-
slogger.log(`...adding calendar id ${id} to sandbox allowed list`);
|
|
399
|
+
if (this.sandboxMode || force) {
|
|
370
400
|
this.__createdCalendarIds.add(id);
|
|
401
|
+
if (!this.__allowedCalendarIds.has(id)) {
|
|
402
|
+
slogger.log(`...adding calendar id ${id} to sandbox allowed list`);
|
|
403
|
+
this.__allowedCalendarIds.add(id);
|
|
404
|
+
}
|
|
371
405
|
}
|
|
372
406
|
return id
|
|
373
407
|
}
|
|
374
408
|
isAccessible(id, serviceName, accessType = 'read') {
|
|
375
|
-
if (
|
|
376
|
-
throw new Error(`
|
|
409
|
+
if (!is.nonEmptyString(id)) {
|
|
410
|
+
throw new Error(`API call to ${serviceName} failed with error: Invalid argument: id`);
|
|
377
411
|
}
|
|
378
412
|
|
|
379
413
|
// Advanced services should inherit sandbox rules from their App counterparts.
|
|
@@ -458,114 +492,105 @@ class FakeBehavior {
|
|
|
458
492
|
}
|
|
459
493
|
trash() {
|
|
460
494
|
let trashed = [];
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
let d = null
|
|
479
|
-
try {
|
|
480
|
-
d = DriveApp.getFileById(id)
|
|
481
|
-
} catch (e) {
|
|
482
|
-
d = DriveApp.getFolderById(id)
|
|
483
|
-
}
|
|
484
|
-
if (d) {
|
|
485
|
-
d.setTrashed(true);
|
|
486
|
-
slogger.log(`...trashed file ${d.getName()} (${id})`);
|
|
487
|
-
acc.push(id);
|
|
488
|
-
}
|
|
489
|
-
return acc;
|
|
490
|
-
}, []);
|
|
491
|
-
this.__createdIds.clear();
|
|
492
|
-
} else {
|
|
493
|
-
slogger.log('...skipping cleaning up sandbox files (Drive)');
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// Clean up Gmail artifacts
|
|
497
|
-
let trashedGmail = [];
|
|
498
|
-
const gmailSettings = this.sandboxService.GmailApp;
|
|
499
|
-
const gmailCleanup = gmailSettings && gmailSettings.cleanup; // This will return true/false (inherits or specific)
|
|
500
|
-
|
|
501
|
-
if (gmailCleanup) {
|
|
502
|
-
trashedGmail = Array.from(this.__createdGmailIds).reduce((acc, id) => {
|
|
503
|
-
// Try to determine type or just try deleting as label, then message/thread?
|
|
504
|
-
// IDs for labels vs threads/messages might overlap or be distinct formats.
|
|
505
|
-
// Label IDs are usually strings like 'Label_123'. Thread IDs are hex strings.
|
|
506
|
-
// We can try fetching as label first.
|
|
507
|
-
try {
|
|
508
|
-
// Try as label
|
|
509
|
-
Gmail.Users.Labels.remove('me', id);
|
|
510
|
-
slogger.log(`...deleted gmail label ${id}`);
|
|
511
|
-
acc.push(id);
|
|
495
|
+
const wasSandbox = this.sandboxMode;
|
|
496
|
+
this.sandboxMode = false;
|
|
497
|
+
try {
|
|
498
|
+
// Drive cleanup
|
|
499
|
+
if (this.__cleanup) {
|
|
500
|
+
trashed = Array.from(this.__createdIds).reduce((acc, id) => {
|
|
501
|
+
let d = null
|
|
502
|
+
try {
|
|
503
|
+
d = DriveApp.getFileById(id)
|
|
504
|
+
} catch (e) {
|
|
505
|
+
d = DriveApp.getFolderById(id)
|
|
506
|
+
}
|
|
507
|
+
if (d) {
|
|
508
|
+
d.setTrashed(true);
|
|
509
|
+
slogger.log(`...trashed file ${d.getName()} (${id})`);
|
|
510
|
+
acc.push(id);
|
|
511
|
+
}
|
|
512
512
|
return acc;
|
|
513
|
-
}
|
|
513
|
+
}, []);
|
|
514
|
+
this.__createdIds.clear();
|
|
515
|
+
this.__allowedIds.clear();
|
|
516
|
+
} else {
|
|
517
|
+
slogger.log('...skipping cleaning up sandbox files (Drive)');
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Clean up Gmail artifacts
|
|
521
|
+
let trashedGmail = [];
|
|
522
|
+
const gmailSettings = this.sandboxService.GmailApp;
|
|
523
|
+
const gmailCleanup = gmailSettings && gmailSettings.cleanup; // This will return true/false (inherits or specific)
|
|
524
|
+
|
|
525
|
+
if (gmailCleanup) {
|
|
526
|
+
trashedGmail = Array.from(this.__createdGmailIds).reduce((acc, id) => {
|
|
527
|
+
try {
|
|
528
|
+
// Try as label
|
|
529
|
+
Gmail.Users.Labels.remove('me', id);
|
|
530
|
+
slogger.log(`...deleted gmail label ${id}`);
|
|
531
|
+
acc.push(id);
|
|
532
|
+
return acc;
|
|
533
|
+
} catch (e) { /* not a label or failed */ }
|
|
534
|
+
|
|
535
|
+
try {
|
|
536
|
+
// Try as thread - move to trash
|
|
537
|
+
Gmail.Users.Threads.trash('me', id);
|
|
538
|
+
slogger.log(`...trashed gmail thread ${id}`);
|
|
539
|
+
acc.push(id);
|
|
540
|
+
return acc;
|
|
541
|
+
} catch (e) { /* not a thread */ }
|
|
542
|
+
|
|
543
|
+
try {
|
|
544
|
+
Gmail.Users.Messages.trash('me', id);
|
|
545
|
+
slogger.log(`...trashed gmail message ${id}`);
|
|
546
|
+
acc.push(id);
|
|
547
|
+
return acc;
|
|
548
|
+
} catch (e) { /* not a message */ }
|
|
514
549
|
|
|
515
|
-
try {
|
|
516
|
-
// Try as thread - move to trash
|
|
517
|
-
Gmail.Users.Threads.trash('me', id);
|
|
518
|
-
slogger.log(`...trashed gmail thread ${id}`);
|
|
519
|
-
acc.push(id);
|
|
520
550
|
return acc;
|
|
521
|
-
}
|
|
551
|
+
}, []);
|
|
552
|
+
this.__createdGmailIds.clear();
|
|
553
|
+
this.__allowedGmailIds.clear();
|
|
554
|
+
} else {
|
|
555
|
+
slogger.log('...skipping cleaning up sandbox files (Gmail)');
|
|
556
|
+
}
|
|
522
557
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
558
|
+
// Clean up Calendar artifacts
|
|
559
|
+
let trashedCalendars = [];
|
|
560
|
+
const calendarSettings = this.sandboxService.CalendarApp;
|
|
561
|
+
const calendarCleanup = calendarSettings && calendarSettings.cleanup;
|
|
562
|
+
|
|
563
|
+
if (calendarCleanup) {
|
|
564
|
+
trashedCalendars = Array.from(this.__createdCalendarIds).reduce((acc, id) => {
|
|
565
|
+
try {
|
|
566
|
+
// Delete calendar
|
|
567
|
+
Calendar.Calendars.delete(id, { noLog404: true });
|
|
568
|
+
slogger.log(`...deleted calendar ${id}`);
|
|
569
|
+
acc.push(id);
|
|
570
|
+
} catch (e) {
|
|
571
|
+
slogger.log(`...failed to delete calendar ${id}: ${e.message}`);
|
|
572
|
+
}
|
|
527
573
|
return acc;
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
slogger.log('...skipping cleaning up sandbox files (Gmail)');
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
// Clean up Calendar artifacts
|
|
538
|
-
let trashedCalendars = [];
|
|
539
|
-
const calendarSettings = this.sandboxService.CalendarApp;
|
|
540
|
-
const calendarCleanup = calendarSettings && calendarSettings.cleanup;
|
|
541
|
-
|
|
542
|
-
if (calendarCleanup) {
|
|
543
|
-
trashedCalendars = Array.from(this.__createdCalendarIds).reduce((acc, id) => {
|
|
544
|
-
try {
|
|
545
|
-
// Delete calendar
|
|
546
|
-
Calendar.Calendars.delete(id, { noLog404: true });
|
|
547
|
-
slogger.log(`...deleted calendar ${id}`);
|
|
548
|
-
acc.push(id);
|
|
549
|
-
} catch (e) {
|
|
550
|
-
slogger.log(`...failed to delete calendar ${id}: ${e.message}`);
|
|
551
|
-
}
|
|
552
|
-
return acc;
|
|
553
|
-
}, []);
|
|
554
|
-
this.__createdCalendarIds.clear();
|
|
555
|
-
} else {
|
|
556
|
-
slogger.log('...skipping cleaning up sandbox calendars');
|
|
557
|
-
}
|
|
574
|
+
}, []);
|
|
575
|
+
this.__createdCalendarIds.clear();
|
|
576
|
+
this.__allowedCalendarIds.clear();
|
|
577
|
+
} else {
|
|
578
|
+
slogger.log('...skipping cleaning up sandbox calendars');
|
|
579
|
+
}
|
|
558
580
|
|
|
559
|
-
|
|
581
|
+
slogger.log(`...trashed ${trashed.length} sandboxed files, ${trashedGmail.length} gmail items, and ${trashedCalendars.length} calendars`);
|
|
582
|
+
} finally {
|
|
583
|
+
this.sandboxMode = wasSandbox;
|
|
584
|
+
}
|
|
560
585
|
return trashed;
|
|
561
586
|
}
|
|
562
587
|
isKnown(id) {
|
|
563
|
-
return this.
|
|
588
|
+
return this.__allowedIds.has(id);
|
|
564
589
|
}
|
|
565
590
|
isKnownGmail(id) {
|
|
566
|
-
return this.
|
|
591
|
+
return this.__allowedGmailIds.has(id);
|
|
567
592
|
}
|
|
568
593
|
isKnownCalendar(id) {
|
|
569
|
-
return this.
|
|
594
|
+
return this.__allowedCalendarIds.has(id);
|
|
570
595
|
}
|
|
571
596
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { newFakeUser} from '../common/fakeuser.js'
|
|
2
|
-
import { Auth } from '../../support/auth.js'
|
|
1
|
+
import { newFakeUser } from '../common/fakeuser.js'
|
|
3
2
|
import { Proxies } from '../../support/proxies.js'
|
|
4
|
-
|
|
3
|
+
import { Syncit } from '../../support/syncit.js'
|
|
4
|
+
import { Auth } from '../../support/auth.js'
|
|
5
5
|
class FakeSession {
|
|
6
|
-
constructor
|
|
7
|
-
|
|
6
|
+
constructor() {
|
|
7
|
+
// Active user is the impersonated user (the one we're acting as)
|
|
8
|
+
this._activeUser = newFakeUser(Syncit.fxGetAccessTokenInfo().tokenInfo)
|
|
9
|
+
// Effective user is also the impersonated user in this context
|
|
10
|
+
this._effectiveUser = newFakeUser(Syncit.fxGetAccessTokenInfo().tokenInfo)
|
|
8
11
|
}
|
|
9
12
|
getActiveUser() {
|
|
10
13
|
return this._activeUser
|
|
@@ -14,15 +17,27 @@ class FakeSession {
|
|
|
14
17
|
* @returns {string}
|
|
15
18
|
*/
|
|
16
19
|
getEffectiveUser() {
|
|
17
|
-
return this.
|
|
20
|
+
return this._effectiveUser
|
|
18
21
|
}
|
|
19
22
|
/**
|
|
20
23
|
* @returns {string}
|
|
21
24
|
*/
|
|
22
25
|
getActiveUserLocale() {
|
|
23
|
-
const lang =
|
|
26
|
+
const lang =
|
|
27
|
+
process.env.LANG ||
|
|
28
|
+
process.env.LANGUAGE ||
|
|
29
|
+
process.env.LC_ALL ||
|
|
30
|
+
process.env.LC_MESSAGES ||
|
|
31
|
+
(function () {
|
|
32
|
+
try {
|
|
33
|
+
return Intl.DateTimeFormat().resolvedOptions().locale
|
|
34
|
+
} catch (e) {
|
|
35
|
+
return 'en'
|
|
36
|
+
}
|
|
37
|
+
})() ||
|
|
38
|
+
'en'
|
|
24
39
|
// it'll be a format like en_US.UTF-8 so we need to drop the encoding to be like apps script
|
|
25
|
-
return lang.
|
|
40
|
+
return lang.split(/[._-]/)[0]
|
|
26
41
|
}
|
|
27
42
|
/**
|
|
28
43
|
* this'll come from the manifest on Node (on Apps Script it'll be where the user is running from)
|
|
@@ -42,4 +57,4 @@ class FakeSession {
|
|
|
42
57
|
}
|
|
43
58
|
}
|
|
44
59
|
|
|
45
|
-
export const newFakeSession = (...args) => Proxies.guard
|
|
60
|
+
export const newFakeSession = (...args) => Proxies.guard(new FakeSession(...args))
|