@mcpher/gas-fakes 1.2.26 → 1.2.28
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/package.json +1 -1
- package/src/cli/setup.js +35 -6
- package/src/cli/utils.js +8 -7
- package/src/index.js +1 -0
- package/src/services/advcalendar/clapis.js +14 -0
- package/src/services/advcalendar/fakeadvcalendarcalendarlist.js +30 -0
- package/src/services/advcalendar/fakeadvcalendarcalendars.js +25 -0
- package/src/services/advcalendar/fakeadvcalendarevents.js +51 -1
- package/src/services/calendarapp/app.js +11 -0
- package/src/services/calendarapp/fakecalendar.js +328 -0
- package/src/services/calendarapp/fakecalendarapp.js +147 -0
- package/src/services/calendarapp/fakecalendarevent.js +44 -0
- package/src/services/calendarapp/fakecalendareventseries.js +36 -0
- package/src/services/calendarapp/fakeeventrecurrence.js +19 -0
- package/src/services/enums/calendarenums.js +85 -0
- package/src/services/enums/slidesenums.js +1 -1
- package/src/services/formapp/fakechoiceitem.js +1 -1
- package/src/services/formapp/fakeform.js +4 -3
- package/src/services/formapp/fakeformitem.js +1 -2
- package/src/services/formapp/fakeformresponse.js +3 -2
- package/src/services/formapp/fakelistitem.js +3 -2
- package/src/services/scriptapp/behavior.js +56 -1
- package/src/services/slidesapp/fakeaffinetransform.js +55 -0
- package/src/services/slidesapp/fakeaffinetransformbuilder.js +64 -0
- package/src/services/slidesapp/fakeautofit.js +49 -0
- package/src/services/slidesapp/fakeautotext.js +29 -0
- package/src/services/slidesapp/fakeconnectionsite.js +24 -0
- package/src/services/slidesapp/fakelayout.js +38 -0
- package/src/services/slidesapp/fakeline.js +195 -0
- package/src/services/slidesapp/fakelinefill.js +58 -0
- package/src/services/slidesapp/fakelink.js +31 -0
- package/src/services/slidesapp/fakemaster.js +28 -0
- package/src/services/slidesapp/fakenotespage.js +19 -0
- package/src/services/slidesapp/fakepagebackground.js +17 -0
- package/src/services/slidesapp/fakepageelement.js +395 -0
- package/src/services/slidesapp/fakeparagraph.js +46 -0
- package/src/services/slidesapp/fakepoint.js +24 -0
- package/src/services/slidesapp/fakepresentation.js +61 -3
- package/src/services/slidesapp/fakeshape.js +49 -0
- package/src/services/slidesapp/fakeslide.js +232 -0
- package/src/services/slidesapp/fakeslidesapp.js +5 -0
- package/src/services/slidesapp/faketextrange.js +253 -0
- package/src/services/slidesapp/pageelementfactory.js +19 -0
- package/src/services/stores/gasflex.js +1 -1
- package/src/services/urlfetchapp/app.js +17 -1
- package/src/support/sxcalendar.js +61 -0
- package/src/support/sxfetch.js +39 -13
- package/src/support/sxforms.js +3 -1
- package/src/support/syncit.js +16 -2
- package/src/support/utils.js +2 -0
- package/src/support/workersync/sxfunctions.js +1 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Proxies } from '../../support/proxies.js';
|
|
2
|
+
import * as CalendarEnums from '../enums/calendarenums.js';
|
|
3
|
+
import { newFakeCalendar } from './fakecalendar.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a new FakeCalendarApp instance.
|
|
7
|
+
* @returns {FakeCalendarApp} The new instance.
|
|
8
|
+
*/
|
|
9
|
+
export const newFakeCalendarApp = () => {
|
|
10
|
+
return Proxies.guard(new FakeCalendarApp());
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Placeholder for CalendarApp service.
|
|
15
|
+
* @see https://developers.google.com/apps-script/reference/calendar/calendar-app
|
|
16
|
+
*/
|
|
17
|
+
export class FakeCalendarApp {
|
|
18
|
+
constructor() {
|
|
19
|
+
// Attach enums
|
|
20
|
+
Object.assign(this, CalendarEnums);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
createCalendar(name, options = {}) {
|
|
24
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'createCalendar');
|
|
25
|
+
this.__checkUsage('write');
|
|
26
|
+
const resource = Calendar.Calendars.insert({ summary: name, ...options });
|
|
27
|
+
if (ScriptApp.__behavior.sandboxMode && resource.id) {
|
|
28
|
+
ScriptApp.__behavior.addCalendarId(resource.id);
|
|
29
|
+
}
|
|
30
|
+
return newFakeCalendar(resource.id, resource);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getCalendarById(id) {
|
|
34
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getCalendarById');
|
|
35
|
+
this.__checkUsage('read');
|
|
36
|
+
this.__checkCalendarAccess(id);
|
|
37
|
+
const resource = Calendar.Calendars.get(id);
|
|
38
|
+
return newFakeCalendar(id, resource);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getDefaultCalendar() {
|
|
42
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getDefaultCalendar');
|
|
43
|
+
return this.getCalendarById('primary');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getCalendarsByName(name) {
|
|
47
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getCalendarsByName');
|
|
48
|
+
this.__checkUsage('read');
|
|
49
|
+
const list = Calendar.CalendarList.list();
|
|
50
|
+
return (list.items || [])
|
|
51
|
+
.filter(item => this.__isCalendarAccessible(item.id))
|
|
52
|
+
.filter(item => item.summary === name)
|
|
53
|
+
.map(item => newFakeCalendar(item.id, item));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getAllCalendars() {
|
|
57
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getAllCalendars');
|
|
58
|
+
this.__checkUsage('read');
|
|
59
|
+
const list = Calendar.CalendarList.list();
|
|
60
|
+
return (list.items || [])
|
|
61
|
+
.filter(item => this.__isCalendarAccessible(item.id))
|
|
62
|
+
.map(item => newFakeCalendar(item.id, item));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getAllOwnedCalendars() {
|
|
66
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getAllOwnedCalendars');
|
|
67
|
+
this.__checkUsage('read');
|
|
68
|
+
const list = Calendar.CalendarList.list();
|
|
69
|
+
return (list.items || [])
|
|
70
|
+
.filter(item => this.__isCalendarAccessible(item.id))
|
|
71
|
+
.filter(item => item.accessRole === 'owner')
|
|
72
|
+
.map(item => newFakeCalendar(item.id, item));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
__isCalendarAccessible(calendarId) {
|
|
76
|
+
try {
|
|
77
|
+
this.__checkCalendarAccess(calendarId);
|
|
78
|
+
return true;
|
|
79
|
+
} catch (e) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
__checkCalendarAccess(calendarId) {
|
|
85
|
+
const behavior = ScriptApp.__behavior;
|
|
86
|
+
if (!behavior.sandboxMode) return true;
|
|
87
|
+
|
|
88
|
+
// 1. Session check - calendars created in this session are always accessible
|
|
89
|
+
if (behavior.isKnownCalendar(calendarId)) return true;
|
|
90
|
+
|
|
91
|
+
// 2. Primary calendar is always accessible
|
|
92
|
+
if (calendarId === 'primary') return true;
|
|
93
|
+
|
|
94
|
+
// 3. Whitelist check
|
|
95
|
+
const settings = behavior.sandboxService.CalendarApp;
|
|
96
|
+
const whitelist = settings && settings.calendarWhitelist;
|
|
97
|
+
|
|
98
|
+
if (!whitelist) {
|
|
99
|
+
throw new Error(`Access to calendar ${calendarId} is denied. No calendar whitelist configured.`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Get calendar details to check name
|
|
103
|
+
const calendar = Calendar.Calendars.get(calendarId);
|
|
104
|
+
const calendarName = calendar.summary;
|
|
105
|
+
|
|
106
|
+
// Check if calendar name is in whitelist with read permission
|
|
107
|
+
const entry = whitelist.find(item => item.name === calendarName);
|
|
108
|
+
if (entry && entry.read) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
throw new Error(`Access to calendar "${calendarName}" (${calendarId}) is denied by sandbox rules`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
__checkUsage(type) {
|
|
116
|
+
const serviceName = 'CalendarApp';
|
|
117
|
+
const behavior = ScriptApp.__behavior;
|
|
118
|
+
if (behavior.sandboxMode) {
|
|
119
|
+
const settings = behavior.sandboxService[serviceName];
|
|
120
|
+
let limit = settings && settings.usageLimit;
|
|
121
|
+
if (limit) {
|
|
122
|
+
if (typeof limit === 'number') {
|
|
123
|
+
const total = (settings.usageCount.read || 0) + (settings.usageCount.write || 0) + (settings.usageCount.trash || 0);
|
|
124
|
+
if (total >= limit) {
|
|
125
|
+
throw new Error(`Calendar total usage limit of ${limit} exceeded`);
|
|
126
|
+
}
|
|
127
|
+
settings.incrementUsage(type);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let specificLimit = limit[type];
|
|
132
|
+
if (specificLimit !== undefined) {
|
|
133
|
+
const current = settings.usageCount[type] || 0;
|
|
134
|
+
if (current >= specificLimit) {
|
|
135
|
+
throw new Error(`Calendar ${type} usage limit of ${specificLimit} exceeded`);
|
|
136
|
+
}
|
|
137
|
+
settings.incrementUsage(type);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Common pattern in gas-fakes for internal use
|
|
144
|
+
__addAllowed(id) {
|
|
145
|
+
// Shared logic with other services to track created resources
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Proxies } from '../../support/proxies.js';
|
|
2
|
+
|
|
3
|
+
export const newFakeCalendarEvent = (...args) => {
|
|
4
|
+
return Proxies.guard(new FakeCalendarEvent(...args));
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents a calendar event.
|
|
9
|
+
* @see https://developers.google.com/apps-script/reference/calendar/calendar-event
|
|
10
|
+
*/
|
|
11
|
+
export class FakeCalendarEvent {
|
|
12
|
+
/**
|
|
13
|
+
* @param {string} calendarId The calendar ID.
|
|
14
|
+
* @param {object} resource The underlying Event resource (Advanced).
|
|
15
|
+
*/
|
|
16
|
+
constructor(calendarId, resource) {
|
|
17
|
+
this.__calendarId = calendarId;
|
|
18
|
+
this.__id = resource.id;
|
|
19
|
+
this.__iCalUID = resource.iCalUID;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get __resource() {
|
|
23
|
+
// Try to get by ID
|
|
24
|
+
try {
|
|
25
|
+
return Calendar.Events.get(this.__calendarId, this.__id);
|
|
26
|
+
} catch (e) {
|
|
27
|
+
// Fallback: search by iCalUID if main ID fails (though usually id is reliable for get)
|
|
28
|
+
// or if the event was deleted?
|
|
29
|
+
throw new Error(`Event with ID ${this.__id} not found in calendar ${this.__calendarId}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getId() {
|
|
34
|
+
return this.__resource.iCalUID || this.__resource.id;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getTitle() {
|
|
38
|
+
return this.__resource.summary || '';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
toString() {
|
|
42
|
+
return 'CalendarEvent';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Proxies } from '../../support/proxies.js';
|
|
2
|
+
|
|
3
|
+
export const newFakeCalendarEventSeries = (...args) => {
|
|
4
|
+
return Proxies.guard(new FakeCalendarEventSeries(...args));
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents a series of events (a recurring event).
|
|
9
|
+
* @see https://developers.google.com/apps-script/reference/calendar/calendar-event-series
|
|
10
|
+
*/
|
|
11
|
+
export class FakeCalendarEventSeries {
|
|
12
|
+
/**
|
|
13
|
+
* @param {string} calendarId The calendar ID.
|
|
14
|
+
* @param {object} resource The underlying Event resource (Advanced).
|
|
15
|
+
*/
|
|
16
|
+
constructor(calendarId, resource) {
|
|
17
|
+
this.__calendarId = calendarId;
|
|
18
|
+
this.__id = resource.id;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get __resource() {
|
|
22
|
+
try {
|
|
23
|
+
return Calendar.Events.get(this.__calendarId, this.__id);
|
|
24
|
+
} catch (e) {
|
|
25
|
+
throw new Error(`Event Series with ID ${this.__id} not found in calendar ${this.__calendarId}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getId() {
|
|
30
|
+
return this.__resource.iCalUID || this.__resource.id;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
toString() {
|
|
34
|
+
return 'CalendarEventSeries';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Proxies } from '../../support/proxies.js';
|
|
2
|
+
|
|
3
|
+
export const newFakeEventRecurrence = (...args) => {
|
|
4
|
+
return Proxies.guard(new FakeEventRecurrence(...args));
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents the recurrence settings for an event series.
|
|
9
|
+
* @see https://developers.google.com/apps-script/reference/calendar/event-recurrence
|
|
10
|
+
*/
|
|
11
|
+
export class FakeEventRecurrence {
|
|
12
|
+
constructor() {
|
|
13
|
+
// TODO: Implement recurrence rules storage
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
toString() {
|
|
17
|
+
return 'EventRecurrence';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { newFakeGasenum} from "@mcpher/fake-gasenum";
|
|
2
|
+
export const Color = newFakeGasenum([
|
|
3
|
+
"BLUE",
|
|
4
|
+
"BROWN",
|
|
5
|
+
"CHARCOAL",
|
|
6
|
+
"CHESTNUT",
|
|
7
|
+
"GRAY",
|
|
8
|
+
"GREEN",
|
|
9
|
+
"INDIGO",
|
|
10
|
+
"LIME",
|
|
11
|
+
"MUSTARD",
|
|
12
|
+
"OLIVE",
|
|
13
|
+
"ORANGE",
|
|
14
|
+
"PINK",
|
|
15
|
+
"PLUM",
|
|
16
|
+
"PURPLE",
|
|
17
|
+
"RED",
|
|
18
|
+
"RED_ORANGE",
|
|
19
|
+
"SEA_BLUE",
|
|
20
|
+
"SLATE",
|
|
21
|
+
"TEAL",
|
|
22
|
+
"TURQOISE",
|
|
23
|
+
"YELLOW"
|
|
24
|
+
])
|
|
25
|
+
export const EventColor = newFakeGasenum([
|
|
26
|
+
"BLUE",
|
|
27
|
+
"CYAN",
|
|
28
|
+
"GRAY",
|
|
29
|
+
"GREEN",
|
|
30
|
+
"MAUVE",
|
|
31
|
+
"ORANGE",
|
|
32
|
+
"PALE_BLUE",
|
|
33
|
+
"PALE_GREEN",
|
|
34
|
+
"PALE_RED",
|
|
35
|
+
"RED",
|
|
36
|
+
"YELLOW"
|
|
37
|
+
])
|
|
38
|
+
export const EventTransparency = newFakeGasenum([
|
|
39
|
+
"OPAQUE",
|
|
40
|
+
"TRANSPARENT"
|
|
41
|
+
])
|
|
42
|
+
export const EventType = newFakeGasenum([
|
|
43
|
+
"DEFAULT",
|
|
44
|
+
"BIRTHDAY",
|
|
45
|
+
"FOCUS_TIME",
|
|
46
|
+
"FROM_GMAIL",
|
|
47
|
+
"OUT_OF_OFFICE",
|
|
48
|
+
"WORKING_LOCATION"
|
|
49
|
+
])
|
|
50
|
+
export const GuestStatus = newFakeGasenum([
|
|
51
|
+
"INVITED",
|
|
52
|
+
"MAYBE",
|
|
53
|
+
"NO",
|
|
54
|
+
"OWNER",
|
|
55
|
+
"YES"
|
|
56
|
+
])
|
|
57
|
+
export const Month = newFakeGasenum([
|
|
58
|
+
"JANUARY",
|
|
59
|
+
"FEBRUARY",
|
|
60
|
+
"MARCH",
|
|
61
|
+
"APRIL",
|
|
62
|
+
"MAY",
|
|
63
|
+
"JUNE",
|
|
64
|
+
"JULY",
|
|
65
|
+
"AUGUST",
|
|
66
|
+
"SEPTEMBER",
|
|
67
|
+
"OCTOBER",
|
|
68
|
+
"NOVEMBER",
|
|
69
|
+
"DECEMBER"
|
|
70
|
+
])
|
|
71
|
+
export const Visibility = newFakeGasenum([
|
|
72
|
+
"CONFIDENTIAL",
|
|
73
|
+
"DEFAULT",
|
|
74
|
+
"PRIVATE",
|
|
75
|
+
"PUBLIC"
|
|
76
|
+
])
|
|
77
|
+
export const Weekday = newFakeGasenum([
|
|
78
|
+
"SUNDAY",
|
|
79
|
+
"MONDAY",
|
|
80
|
+
"TUESDAY",
|
|
81
|
+
"WEDNESDAY",
|
|
82
|
+
"THURSDAY",
|
|
83
|
+
"FRIDAY",
|
|
84
|
+
"SATURDAY"
|
|
85
|
+
])
|
|
@@ -45,7 +45,7 @@ export class FakeChoiceItem extends newFakeFormItem().constructor {
|
|
|
45
45
|
|
|
46
46
|
const updateRequest = Forms.newRequest().setUpdateItem({
|
|
47
47
|
item: {
|
|
48
|
-
itemId: this.
|
|
48
|
+
itemId: this.__itemId,
|
|
49
49
|
questionItem: {
|
|
50
50
|
question: {
|
|
51
51
|
choiceQuestion: choiceQuestion,
|
|
@@ -13,7 +13,7 @@ import { newFakeListItem } from './fakelistitem.js';
|
|
|
13
13
|
import { newFakePageBreakItem } from './fakepagebreakitem.js';
|
|
14
14
|
import { newFakeTextItem } from './faketextitem.js';
|
|
15
15
|
import { signatureArgs } from '../../support/helpers.js';
|
|
16
|
-
import {Utils} from '../../support/utils.js';
|
|
16
|
+
import { Utils } from '../../support/utils.js';
|
|
17
17
|
const { is } = Utils
|
|
18
18
|
export const newFakeForm = (...args) => {
|
|
19
19
|
return Proxies.guard(new FakeForm(...args));
|
|
@@ -53,7 +53,7 @@ export class FakeForm {
|
|
|
53
53
|
return this;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
saveAndClose() {
|
|
58
58
|
// this is a no-op in fake environment since it is stateless
|
|
59
59
|
}
|
|
@@ -298,6 +298,7 @@ export class FakeForm {
|
|
|
298
298
|
if (!this.__resource.items) {
|
|
299
299
|
return null;
|
|
300
300
|
}
|
|
301
|
+
const hexId = Utils.toHex(id);
|
|
301
302
|
const isKnownItem = (id, item) => {
|
|
302
303
|
if (item.itemId === id) return true;
|
|
303
304
|
if (item.questionItem?.question?.questionId === id) return true;
|
|
@@ -307,7 +308,7 @@ export class FakeForm {
|
|
|
307
308
|
return found
|
|
308
309
|
}
|
|
309
310
|
|
|
310
|
-
const itemResource = this.__resource.items.find((item) => isKnownItem(
|
|
311
|
+
const itemResource = this.__resource.items.find((item) => isKnownItem(hexId, item));
|
|
311
312
|
|
|
312
313
|
if (!itemResource) {
|
|
313
314
|
return null;
|
|
@@ -114,8 +114,7 @@ export class FakeFormItem {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
getId() {
|
|
117
|
-
|
|
118
|
-
return parseInt(this.__itemId, 16); // Convert to decimal
|
|
117
|
+
return Utils.fromHex(this.__itemId);
|
|
119
118
|
}
|
|
120
119
|
|
|
121
120
|
getIndex() {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Proxies } from '../../support/proxies.js';
|
|
2
2
|
import { newFakeItemResponse } from './fakeitemresponse.js';
|
|
3
|
+
import { Utils } from '../../support/utils.js';
|
|
3
4
|
|
|
4
5
|
export const newFakeFormResponse = (...args) => {
|
|
5
6
|
return Proxies.guard(new FakeFormResponse(...args));
|
|
@@ -33,7 +34,7 @@ export class FakeFormResponse {
|
|
|
33
34
|
* @returns {number} the unique hex ID converted to a decimal number
|
|
34
35
|
*/
|
|
35
36
|
getId() {
|
|
36
|
-
return
|
|
37
|
+
return Utils.fromHex(this.__resource.responseId);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -59,7 +60,7 @@ export class FakeFormResponse {
|
|
|
59
60
|
const groupedAnswers = new Map();
|
|
60
61
|
|
|
61
62
|
for (const [questionId, answer] of Object.entries(this.__resource.answers)) {
|
|
62
|
-
const item = this.__form.getItemById(questionId);
|
|
63
|
+
const item = this.__form.getItemById(Utils.fromHex(questionId));
|
|
63
64
|
|
|
64
65
|
if (item) {
|
|
65
66
|
const itemId = item.getId(); // Use the unique item ID as the key.
|
|
@@ -3,6 +3,7 @@ import { FakeFormItem } from './fakeformitem.js';
|
|
|
3
3
|
import { newFakeChoice } from './fakechoice.js';
|
|
4
4
|
import { registerFormItem } from './formitemregistry.js';
|
|
5
5
|
import { ItemType } from '../enums/formsenums.js';
|
|
6
|
+
import { Utils } from '../../support/utils.js';
|
|
6
7
|
|
|
7
8
|
export const newFakeListItem = (...args) => {
|
|
8
9
|
return Proxies.guard(new FakeListItem(...args));
|
|
@@ -56,7 +57,7 @@ export class FakeListItem extends FakeFormItem {
|
|
|
56
57
|
// Translate from API format back to Apps Script format.
|
|
57
58
|
if (option.goToSectionId) {
|
|
58
59
|
navType = 'GO_TO_PAGE';
|
|
59
|
-
pageId = option.goToSectionId;
|
|
60
|
+
pageId = Utils.fromHex(option.goToSectionId);
|
|
60
61
|
} else if (option.goToAction) {
|
|
61
62
|
switch (option.goToAction) {
|
|
62
63
|
case 'NEXT_SECTION': navType = 'CONTINUE'; break;
|
|
@@ -85,7 +86,7 @@ export class FakeListItem extends FakeFormItem {
|
|
|
85
86
|
case 'GO_TO_PAGE':
|
|
86
87
|
// For navigating to a specific page, you ONLY set the goToSectionId.
|
|
87
88
|
// The pageId is the itemId of the PageBreakItem.
|
|
88
|
-
option.goToSectionId = choice.__pageId;
|
|
89
|
+
option.goToSectionId = Utils.toHex(choice.__pageId);
|
|
89
90
|
break;
|
|
90
91
|
case 'CONTINUE':
|
|
91
92
|
option.goToAction = 'NEXT_SECTION';
|
|
@@ -17,6 +17,7 @@ const serviceModel = {
|
|
|
17
17
|
methodWhitelist: null,
|
|
18
18
|
emailWhitelist: null,
|
|
19
19
|
labelWhitelist: null,
|
|
20
|
+
calendarWhitelist: null,
|
|
20
21
|
usageLimit: null,
|
|
21
22
|
usageCount: 0
|
|
22
23
|
}
|
|
@@ -169,6 +170,17 @@ class FakeSandboxService {
|
|
|
169
170
|
return this.__state.labelWhitelist
|
|
170
171
|
}
|
|
171
172
|
|
|
173
|
+
set calendarWhitelist(value) {
|
|
174
|
+
if (!is.null(value)) {
|
|
175
|
+
checkArgs(value, "array")
|
|
176
|
+
// We expect objects like { name: 'calendar-name', read?: boolean, write?: boolean, delete?: boolean }
|
|
177
|
+
}
|
|
178
|
+
this.__state.calendarWhitelist = value
|
|
179
|
+
}
|
|
180
|
+
get calendarWhitelist() {
|
|
181
|
+
return this.__state.calendarWhitelist
|
|
182
|
+
}
|
|
183
|
+
|
|
172
184
|
set usageLimit(value) {
|
|
173
185
|
if (!is.null(value)) {
|
|
174
186
|
// expect object with read, write, trash keys optionally
|
|
@@ -211,6 +223,11 @@ class FakeSandboxService {
|
|
|
211
223
|
return this.__state.usageCount[type];
|
|
212
224
|
}
|
|
213
225
|
|
|
226
|
+
resetUsageCount() {
|
|
227
|
+
this.__state.usageCount = { read: 0, write: 0, trash: 0, send: 0 };
|
|
228
|
+
return this;
|
|
229
|
+
}
|
|
230
|
+
|
|
214
231
|
set enabled(value) {
|
|
215
232
|
this.__state.enabled = checkArgs(value)
|
|
216
233
|
}
|
|
@@ -236,6 +253,7 @@ class FakeBehavior {
|
|
|
236
253
|
// key is the file id
|
|
237
254
|
this.__createdIds = new Set();
|
|
238
255
|
this.__createdGmailIds = new Set();
|
|
256
|
+
this.__createdCalendarIds = new Set();
|
|
239
257
|
// in sandbox mode we only allow access to files created in this instance
|
|
240
258
|
// this is to emulate the behavior of a drive.file scope
|
|
241
259
|
this.__sandboxMode = false;
|
|
@@ -347,6 +365,18 @@ class FakeBehavior {
|
|
|
347
365
|
}
|
|
348
366
|
return id
|
|
349
367
|
}
|
|
368
|
+
addCalendarId(id) {
|
|
369
|
+
if (this.sandboxMode) {
|
|
370
|
+
if (!is.nonEmptyString(id)) {
|
|
371
|
+
throw new Error(`Invalid sandbox id parameter (${id}) - must be a non-empty string`);
|
|
372
|
+
}
|
|
373
|
+
if (!this.isKnownCalendar(id)) {
|
|
374
|
+
slogger.log(`...adding calendar id ${id} to sandbox allowed list`);
|
|
375
|
+
this.__createdCalendarIds.add(id);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return id
|
|
379
|
+
}
|
|
350
380
|
isAccessible(id, serviceName, accessType = 'read') {
|
|
351
381
|
if (this.sandboxMode && !is.nonEmptyString(id)) {
|
|
352
382
|
throw new Error(`Invalid sandbox id parameter (${id}) - must be a non-empty string`);
|
|
@@ -510,7 +540,29 @@ class FakeBehavior {
|
|
|
510
540
|
slogger.log('...skipping cleaning up sandbox files (Gmail)');
|
|
511
541
|
}
|
|
512
542
|
|
|
513
|
-
|
|
543
|
+
// Clean up Calendar artifacts
|
|
544
|
+
let trashedCalendars = [];
|
|
545
|
+
const calendarSettings = this.sandboxService.CalendarApp;
|
|
546
|
+
const calendarCleanup = calendarSettings && calendarSettings.cleanup;
|
|
547
|
+
|
|
548
|
+
if (calendarCleanup) {
|
|
549
|
+
trashedCalendars = Array.from(this.__createdCalendarIds).reduce((acc, id) => {
|
|
550
|
+
try {
|
|
551
|
+
// Delete calendar
|
|
552
|
+
Calendar.Calendars.delete(id);
|
|
553
|
+
slogger.log(`...deleted calendar ${id}`);
|
|
554
|
+
acc.push(id);
|
|
555
|
+
} catch (e) {
|
|
556
|
+
slogger.log(`...failed to delete calendar ${id}: ${e.message}`);
|
|
557
|
+
}
|
|
558
|
+
return acc;
|
|
559
|
+
}, []);
|
|
560
|
+
this.__createdCalendarIds.clear();
|
|
561
|
+
} else {
|
|
562
|
+
slogger.log('...skipping cleaning up sandbox calendars');
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
slogger.log(`...trashed ${trashed.length} sandboxed files, ${trashedGmail.length} gmail items, and ${trashedCalendars.length} calendars`);
|
|
514
566
|
return trashed;
|
|
515
567
|
}
|
|
516
568
|
isKnown(id) {
|
|
@@ -519,4 +571,7 @@ class FakeBehavior {
|
|
|
519
571
|
isKnownGmail(id) {
|
|
520
572
|
return this.__createdGmailIds.has(id);
|
|
521
573
|
}
|
|
574
|
+
isKnownCalendar(id) {
|
|
575
|
+
return this.__createdCalendarIds.has(id);
|
|
576
|
+
}
|
|
522
577
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Proxies } from '../../support/proxies.js';
|
|
2
|
+
import { newFakeAffineTransformBuilder } from './fakeaffinetransformbuilder.js';
|
|
3
|
+
|
|
4
|
+
export const newFakeAffineTransform = (...args) => {
|
|
5
|
+
return Proxies.guard(new FakeAffineTransform(...args));
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export class FakeAffineTransform {
|
|
9
|
+
constructor(scaleX, shearY, shearX, scaleY, translateX, translateY) {
|
|
10
|
+
this.__scaleX = scaleX;
|
|
11
|
+
this.__shearY = shearY;
|
|
12
|
+
this.__shearX = shearX;
|
|
13
|
+
this.__scaleY = scaleY;
|
|
14
|
+
this.__translateX = translateX;
|
|
15
|
+
this.__translateY = translateY;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getScaleX() {
|
|
19
|
+
return this.__scaleX;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getScaleY() {
|
|
23
|
+
return this.__scaleY;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getShearX() {
|
|
27
|
+
return this.__shearX;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getShearY() {
|
|
31
|
+
return this.__shearY;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getTranslateX() {
|
|
35
|
+
return this.__translateX;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
getTranslateY() {
|
|
39
|
+
return this.__translateY;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
toBuilder() {
|
|
43
|
+
return newFakeAffineTransformBuilder()
|
|
44
|
+
.setScaleX(this.__scaleX)
|
|
45
|
+
.setShearY(this.__shearY)
|
|
46
|
+
.setShearX(this.__shearX)
|
|
47
|
+
.setScaleY(this.__scaleY)
|
|
48
|
+
.setTranslateX(this.__translateX)
|
|
49
|
+
.setTranslateY(this.__translateY);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
toString() {
|
|
53
|
+
return 'AffineTransform';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Proxies } from '../../support/proxies.js';
|
|
2
|
+
import { newFakeAffineTransform } from './fakeaffinetransform.js';
|
|
3
|
+
|
|
4
|
+
export const newFakeAffineTransformBuilder = (...args) => {
|
|
5
|
+
return Proxies.guard(new FakeAffineTransformBuilder(...args));
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export class FakeAffineTransformBuilder {
|
|
9
|
+
constructor() {
|
|
10
|
+
// Defaults? Documentation doesn't explicitly specify, but identity matrix is reasonable.
|
|
11
|
+
// scaleX=1, scaleY=1, others 0.
|
|
12
|
+
this.__scaleX = 1;
|
|
13
|
+
this.__shearY = 0;
|
|
14
|
+
this.__shearX = 0;
|
|
15
|
+
this.__scaleY = 1;
|
|
16
|
+
this.__translateX = 0;
|
|
17
|
+
this.__translateY = 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
build() {
|
|
21
|
+
return newFakeAffineTransform(
|
|
22
|
+
this.__scaleX,
|
|
23
|
+
this.__shearY,
|
|
24
|
+
this.__shearX,
|
|
25
|
+
this.__scaleY,
|
|
26
|
+
this.__translateX,
|
|
27
|
+
this.__translateY
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
setScaleX(scaleX) {
|
|
32
|
+
this.__scaleX = scaleX;
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
setScaleY(scaleY) {
|
|
37
|
+
this.__scaleY = scaleY;
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
setShearX(shearX) {
|
|
42
|
+
this.__shearX = shearX;
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setShearY(shearY) {
|
|
47
|
+
this.__shearY = shearY;
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setTranslateX(translateX) {
|
|
52
|
+
this.__translateX = translateX;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
setTranslateY(translateY) {
|
|
57
|
+
this.__translateY = translateY;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
toString() {
|
|
62
|
+
return 'AffineTransformBuilder';
|
|
63
|
+
}
|
|
64
|
+
}
|