@mcpher/gas-fakes 1.2.28 → 1.2.30
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 +2 -2
- package/src/services/calendarapp/fakecalendar.js +81 -11
- package/src/services/calendarapp/fakecalendarapp.js +133 -1
- package/src/services/calendarapp/fakecalendarevent.js +507 -1
- package/src/services/calendarapp/fakecalendareventseries.js +412 -0
- package/src/services/calendarapp/fakeeventguest.js +44 -0
- package/src/services/calendarapp/fakeeventrecurrence.js +38 -1
- package/src/services/calendarapp/fakerecurrencerule.js +48 -0
- package/src/services/enums/calendarenums.js +42 -37
- package/src/services/gmailapp/fakegmailapp.js +6 -10
- package/src/services/scriptapp/behavior.js +19 -25
- package/src/support/backoff.js +7 -1
- package/src/support/helpers.js +1 -1
- package/src/support/sxcalendar.js +15 -3
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Proxies } from '../../support/proxies.js';
|
|
2
|
+
import { newFakeEventGuest } from './fakeeventguest.js';
|
|
3
|
+
import * as CalendarEnums from '../enums/calendarenums.js';
|
|
2
4
|
|
|
3
5
|
export const newFakeCalendarEventSeries = (...args) => {
|
|
4
6
|
return Proxies.guard(new FakeCalendarEventSeries(...args));
|
|
@@ -30,6 +32,416 @@ export class FakeCalendarEventSeries {
|
|
|
30
32
|
return this.__resource.iCalUID || this.__resource.id;
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
getTitle() {
|
|
36
|
+
return this.__resource.summary || '';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setTitle(title) {
|
|
40
|
+
this.__checkWriteAccess();
|
|
41
|
+
Calendar.Events.patch({ summary: title }, this.__calendarId, this.__id);
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getDescription() {
|
|
46
|
+
return this.__resource.description || '';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setDescription(description) {
|
|
50
|
+
this.__checkWriteAccess();
|
|
51
|
+
Calendar.Events.patch({ description }, this.__calendarId, this.__id);
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getLocation() {
|
|
56
|
+
return this.__resource.location || '';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setLocation(location) {
|
|
60
|
+
this.__checkWriteAccess();
|
|
61
|
+
Calendar.Events.patch({ location }, this.__calendarId, this.__id);
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// --- Guests ---
|
|
66
|
+
|
|
67
|
+
addGuest(email) {
|
|
68
|
+
this.__checkWriteAccess();
|
|
69
|
+
// Assuming same guest whitelist logic applies to series
|
|
70
|
+
this.__checkGuestWhitelist(email);
|
|
71
|
+
|
|
72
|
+
const resource = this.__resource;
|
|
73
|
+
const attendees = resource.attendees || [];
|
|
74
|
+
if (!attendees.find(a => a.email === email)) {
|
|
75
|
+
attendees.push({ email });
|
|
76
|
+
Calendar.Events.patch({ attendees }, this.__calendarId, this.__id, { sendUpdates: 'all' });
|
|
77
|
+
}
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
removeGuest(email) {
|
|
82
|
+
this.__checkWriteAccess();
|
|
83
|
+
const resource = this.__resource;
|
|
84
|
+
const attendees = resource.attendees || [];
|
|
85
|
+
const newAttendees = attendees.filter(a => a.email !== email);
|
|
86
|
+
if (newAttendees.length !== attendees.length) {
|
|
87
|
+
Calendar.Events.patch({ attendees: newAttendees }, this.__calendarId, this.__id);
|
|
88
|
+
}
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
getGuestList(includeOwner = false) {
|
|
93
|
+
const r = this.__resource;
|
|
94
|
+
if (!r.attendees) return [];
|
|
95
|
+
return r.attendees.map(a => newFakeEventGuest(a)).filter(g => includeOwner || g.getEmail() !== r.creator.email);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
getGuestByEmail(email) {
|
|
99
|
+
const guests = this.getGuestList(true);
|
|
100
|
+
return guests.find(g => g.getEmail() === email) || null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getCreators() {
|
|
104
|
+
const r = this.__resource;
|
|
105
|
+
return r.creator ? [r.creator.email] : [];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// --- Reminders ---
|
|
109
|
+
|
|
110
|
+
addEmailReminder(minutesBefore) {
|
|
111
|
+
this.__checkWriteAccess();
|
|
112
|
+
this.__addReminder('email', minutesBefore);
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
addPopupReminder(minutesBefore) {
|
|
117
|
+
this.__checkWriteAccess();
|
|
118
|
+
this.__addReminder('popup', minutesBefore);
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
addSmsReminder(minutesBefore) {
|
|
123
|
+
this.__checkWriteAccess();
|
|
124
|
+
this.__addReminder('sms', minutesBefore);
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
__addReminder(method, minutes) {
|
|
129
|
+
const r = this.__resource;
|
|
130
|
+
const reminders = r.reminders || { useDefault: true, overrides: [] };
|
|
131
|
+
if (reminders.useDefault) {
|
|
132
|
+
reminders.useDefault = false;
|
|
133
|
+
reminders.overrides = [];
|
|
134
|
+
}
|
|
135
|
+
if (!reminders.overrides) reminders.overrides = [];
|
|
136
|
+
reminders.overrides.push({ method, minutes });
|
|
137
|
+
Calendar.Events.patch({ reminders }, this.__calendarId, this.__id);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
getReminders() {
|
|
141
|
+
const r = this.__resource;
|
|
142
|
+
if (r.reminders && r.reminders.useDefault) return [];
|
|
143
|
+
return (r.reminders && r.reminders.overrides) ? r.reminders.overrides.map(o => o.minutes) : [];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
getEmailReminders() {
|
|
147
|
+
return this.__getRemindersByMethod('email');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
getPopupReminders() {
|
|
151
|
+
return this.__getRemindersByMethod('popup');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
getSmsReminders() {
|
|
155
|
+
return this.__getRemindersByMethod('sms');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
__getRemindersByMethod(method) {
|
|
159
|
+
const r = this.__resource;
|
|
160
|
+
if (r.reminders && r.reminders.useDefault) return [];
|
|
161
|
+
if (!r.reminders || !r.reminders.overrides) return [];
|
|
162
|
+
return r.reminders.overrides.filter(o => o.method === method).map(o => o.minutes);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
removeAllReminders() {
|
|
166
|
+
this.__checkWriteAccess();
|
|
167
|
+
Calendar.Events.patch({ reminders: { useDefault: false, overrides: [] } }, this.__calendarId, this.__id);
|
|
168
|
+
return this;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
resetRemindersToDefault() {
|
|
172
|
+
this.__checkWriteAccess();
|
|
173
|
+
Calendar.Events.patch({ reminders: { useDefault: true } }, this.__calendarId, this.__id);
|
|
174
|
+
return this;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// --- Tags (Extended Properties) ---
|
|
178
|
+
|
|
179
|
+
setTag(key, value) {
|
|
180
|
+
this.__checkWriteAccess();
|
|
181
|
+
const r = this.__resource;
|
|
182
|
+
const extendedProperties = r.extendedProperties || { shared: {} };
|
|
183
|
+
if (!extendedProperties.shared) extendedProperties.shared = {};
|
|
184
|
+
extendedProperties.shared[key] = value;
|
|
185
|
+
Calendar.Events.patch({ extendedProperties }, this.__calendarId, this.__id);
|
|
186
|
+
return this;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
getTag(key) {
|
|
190
|
+
const r = this.__resource;
|
|
191
|
+
return (r.extendedProperties && r.extendedProperties.shared && r.extendedProperties.shared[key]) || null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
getAllTagKeys() {
|
|
195
|
+
const r = this.__resource;
|
|
196
|
+
return (r.extendedProperties && r.extendedProperties.shared) ? Object.keys(r.extendedProperties.shared) : [];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
deleteTag(key) {
|
|
200
|
+
this.__checkWriteAccess();
|
|
201
|
+
const r = this.__resource;
|
|
202
|
+
if (r.extendedProperties && r.extendedProperties.shared && r.extendedProperties.shared[key]) {
|
|
203
|
+
delete r.extendedProperties.shared[key];
|
|
204
|
+
Calendar.Events.patch({ extendedProperties: r.extendedProperties }, this.__calendarId, this.__id);
|
|
205
|
+
}
|
|
206
|
+
return this;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// --- Metadata & Permissions ---
|
|
210
|
+
|
|
211
|
+
getDateCreated() {
|
|
212
|
+
return new Date(this.__resource.created);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
getLastUpdated() {
|
|
216
|
+
return new Date(this.__resource.updated);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
isOwnedByMe() {
|
|
220
|
+
const r = this.__resource;
|
|
221
|
+
const currentUserEmail = Session.getEffectiveUser().getEmail();
|
|
222
|
+
return r.creator && r.creator.email === currentUserEmail;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
getOriginalCalendarId() {
|
|
226
|
+
return this.__calendarId;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
getVisibility() {
|
|
230
|
+
const r = this.__resource;
|
|
231
|
+
const v = r.visibility || 'default';
|
|
232
|
+
return CalendarEnums.Visibility[v.toUpperCase()] || CalendarEnums.Visibility.DEFAULT;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
setVisibility(visibility) {
|
|
236
|
+
this.__checkWriteAccess();
|
|
237
|
+
const v = visibility.toString().toLowerCase();
|
|
238
|
+
Calendar.Events.patch({ visibility: v }, this.__calendarId, this.__id);
|
|
239
|
+
return this;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
getColor() {
|
|
243
|
+
return this.__resource.colorId || '';
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
setColor(color) {
|
|
247
|
+
this.__checkWriteAccess();
|
|
248
|
+
// color should be an enum value or a colorId string
|
|
249
|
+
const colorId = color.toString();
|
|
250
|
+
Calendar.Events.patch({ colorId }, this.__calendarId, this.__id);
|
|
251
|
+
return this;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
getEventType() {
|
|
255
|
+
const r = this.__resource;
|
|
256
|
+
const typeMap = {
|
|
257
|
+
'default': CalendarEnums.EventType.DEFAULT,
|
|
258
|
+
'outOfOffice': CalendarEnums.EventType.OUT_OF_OFFICE,
|
|
259
|
+
'focusTime': CalendarEnums.EventType.FOCUS_TIME,
|
|
260
|
+
'workingLocation': CalendarEnums.EventType.WORKING_LOCATION
|
|
261
|
+
};
|
|
262
|
+
return typeMap[r.eventType] || CalendarEnums.EventType.DEFAULT;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
getMyStatus() {
|
|
266
|
+
const r = this.__resource;
|
|
267
|
+
const me = Session.getEffectiveUser().getEmail();
|
|
268
|
+
const attendee = (r.attendees || []).find(a => a.email === me);
|
|
269
|
+
if (!attendee) return CalendarEnums.GuestStatus.NO; // Or maybe INVITED if explicitly?
|
|
270
|
+
|
|
271
|
+
const map = {
|
|
272
|
+
'accepted': CalendarEnums.GuestStatus.YES,
|
|
273
|
+
'declined': CalendarEnums.GuestStatus.NO,
|
|
274
|
+
'tentative': CalendarEnums.GuestStatus.MAYBE,
|
|
275
|
+
'needsAction': CalendarEnums.GuestStatus.INVITED
|
|
276
|
+
};
|
|
277
|
+
return map[attendee.responseStatus] || CalendarEnums.GuestStatus.INVITED;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
setMyStatus(status) {
|
|
281
|
+
this.__checkWriteAccess();
|
|
282
|
+
// In API, patching your own response status is done via events.patch/update usually
|
|
283
|
+
const me = Session.getEffectiveUser().getEmail();
|
|
284
|
+
const r = this.__resource;
|
|
285
|
+
const attendees = r.attendees || [];
|
|
286
|
+
let attendee = attendees.find(a => a.email === me);
|
|
287
|
+
|
|
288
|
+
// Map Enum to API string
|
|
289
|
+
const map = {};
|
|
290
|
+
map[CalendarEnums.GuestStatus.YES] = 'accepted';
|
|
291
|
+
map[CalendarEnums.GuestStatus.NO] = 'declined';
|
|
292
|
+
map[CalendarEnums.GuestStatus.MAYBE] = 'tentative';
|
|
293
|
+
map[CalendarEnums.GuestStatus.INVITED] = 'needsAction';
|
|
294
|
+
|
|
295
|
+
const apiStatus = map[status];
|
|
296
|
+
if (!apiStatus) return this;
|
|
297
|
+
|
|
298
|
+
if (!attendee) {
|
|
299
|
+
// If I'm not on the list, can I set my status? Maybe adding myself?
|
|
300
|
+
attendee = { email: me, responseStatus: apiStatus };
|
|
301
|
+
attendees.push(attendee);
|
|
302
|
+
} else {
|
|
303
|
+
attendee.responseStatus = apiStatus;
|
|
304
|
+
}
|
|
305
|
+
Calendar.Events.patch({ attendees }, this.__calendarId, this.__id);
|
|
306
|
+
return this;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
getTransparency() {
|
|
310
|
+
const r = this.__resource;
|
|
311
|
+
const t = r.transparency || 'opaque';
|
|
312
|
+
return t === 'transparent' ? CalendarEnums.EventTransparency.TRANSPARENT : CalendarEnums.EventTransparency.OPAQUE;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
setTransparency(transparency) {
|
|
316
|
+
this.__checkWriteAccess();
|
|
317
|
+
const t = transparency === CalendarEnums.EventTransparency.TRANSPARENT ? 'transparent' : 'opaque';
|
|
318
|
+
Calendar.Events.patch({ transparency: t }, this.__calendarId, this.__id);
|
|
319
|
+
return this;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
guestsCanInviteOthers() {
|
|
323
|
+
return !!this.__resource.guestsCanInviteOthers;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
setGuestsCanInviteOthers(guestsCanInviteOthers) {
|
|
327
|
+
this.__checkWriteAccess();
|
|
328
|
+
Calendar.Events.patch({ guestsCanInviteOthers }, this.__calendarId, this.__id);
|
|
329
|
+
return this;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
guestsCanModify() {
|
|
333
|
+
return !!this.__resource.guestsCanModify;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
setGuestsCanModify(guestsCanModify) {
|
|
337
|
+
this.__checkWriteAccess();
|
|
338
|
+
Calendar.Events.patch({ guestsCanModify }, this.__calendarId, this.__id);
|
|
339
|
+
return this;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
guestsCanSeeGuests() {
|
|
343
|
+
return !!this.__resource.guestsCanSeeGuests;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
setGuestsCanSeeGuests(guestsCanSeeGuests) {
|
|
347
|
+
this.__checkWriteAccess();
|
|
348
|
+
Calendar.Events.patch({ guestsCanSeeGuests }, this.__calendarId, this.__id);
|
|
349
|
+
return this;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
anyoneCanAddSelf() {
|
|
353
|
+
return !!this.__resource.anyoneCanAddSelf;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
setAnyoneCanAddSelf(anyoneCanAddSelf) {
|
|
357
|
+
this.__checkWriteAccess();
|
|
358
|
+
Calendar.Events.patch({ anyoneCanAddSelf }, this.__calendarId, this.__id);
|
|
359
|
+
return this;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// --- Recurrence ---
|
|
363
|
+
|
|
364
|
+
setRecurrence(recurrence, startTime, endTime) {
|
|
365
|
+
this.__checkWriteAccess();
|
|
366
|
+
// This is complex. Recurrence object logic needs to be fully implemented to convert to RRULE.
|
|
367
|
+
// For now, we will just update start/end time as a placeholder if provided.
|
|
368
|
+
// Ideally, `recurrence` (EventRecurrence) should provide RRULEs.
|
|
369
|
+
// TODO: Implement recurrence conversion.
|
|
370
|
+
const resource = {};
|
|
371
|
+
if (startTime) resource.start = { dateTime: startTime.toISOString() };
|
|
372
|
+
if (endTime) resource.end = { dateTime: endTime.toISOString() };
|
|
373
|
+
|
|
374
|
+
// resource.recurrence = [ recurrence.toRRule() ]; // Hypothetical method on FakeEventRecurrence
|
|
375
|
+
|
|
376
|
+
Calendar.Events.patch(resource, this.__calendarId, this.__id);
|
|
377
|
+
return this;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
deleteEventSeries() {
|
|
381
|
+
this.__checkWriteAccess();
|
|
382
|
+
Calendar.Events.delete(this.__calendarId, this.__id);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// --- Helpers (Duplicated from FakeCalendarEvent) ---
|
|
386
|
+
|
|
387
|
+
__checkWriteAccess() {
|
|
388
|
+
this.__checkUsage('write');
|
|
389
|
+
this.__checkPermission('write');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
__checkUsage(type) {
|
|
393
|
+
const serviceName = 'CalendarApp';
|
|
394
|
+
const behavior = ScriptApp.__behavior;
|
|
395
|
+
if (behavior && behavior.sandboxMode) {
|
|
396
|
+
const settings = behavior.sandboxService[serviceName];
|
|
397
|
+
if (settings) {
|
|
398
|
+
settings.incrementUsage(type);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
__checkPermission(accessType) {
|
|
404
|
+
// Basic check relying on FakeCalendar implementation logic or just mimicking it here.
|
|
405
|
+
// Ideally this logic resides in a shared helper or the CalendarApp/Calendar object.
|
|
406
|
+
// For now, we assume if we can get the resource, we can try to patch it, and let API handle permissions
|
|
407
|
+
// UNLESS sandbox mode is on.
|
|
408
|
+
const behavior = ScriptApp.__behavior;
|
|
409
|
+
if (!behavior || !behavior.sandboxMode) return;
|
|
410
|
+
|
|
411
|
+
// ... (Same logic as FakeCalendarEvent) ...
|
|
412
|
+
// Simplified: Check if calendar is writable in whitelist.
|
|
413
|
+
const settings = behavior.sandboxService.CalendarApp;
|
|
414
|
+
const whitelist = settings && settings.calendarWhitelist;
|
|
415
|
+
|
|
416
|
+
if (!whitelist) throw new Error('Sandbox access denied (no whitelist)');
|
|
417
|
+
|
|
418
|
+
// Fetch calendar summary for name check
|
|
419
|
+
let calendarName = '';
|
|
420
|
+
try {
|
|
421
|
+
const cal = Calendar.Calendars.get(this.__calendarId);
|
|
422
|
+
calendarName = cal.summary;
|
|
423
|
+
} catch(e) {}
|
|
424
|
+
|
|
425
|
+
if (this.__calendarId === 'primary') {
|
|
426
|
+
const entry = whitelist.find(item => item.name === 'Primary' || item.name === 'primary');
|
|
427
|
+
if (entry && entry[accessType]) return;
|
|
428
|
+
}
|
|
429
|
+
const entry = whitelist.find(item => item.name === calendarName);
|
|
430
|
+
if (entry && entry[accessType]) return;
|
|
431
|
+
|
|
432
|
+
throw new Error(`Sandbox ${accessType} access to calendar ${this.__calendarId} denied`);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
__checkGuestWhitelist(email) {
|
|
436
|
+
const behavior = ScriptApp.__behavior;
|
|
437
|
+
if (!behavior || !behavior.sandboxMode) return;
|
|
438
|
+
const gmailSettings = behavior.sandboxService.GmailApp;
|
|
439
|
+
const whitelist = gmailSettings && gmailSettings.emailWhitelist;
|
|
440
|
+
if (whitelist && !whitelist.includes(email)) {
|
|
441
|
+
throw new Error(`Adding guest ${email} is denied by Gmail sandbox whitelist`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
33
445
|
toString() {
|
|
34
446
|
return 'CalendarEventSeries';
|
|
35
447
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Proxies } from '../../support/proxies.js';
|
|
2
|
+
import * as CalendarEnums from '../enums/calendarenums.js';
|
|
3
|
+
|
|
4
|
+
export const newFakeEventGuest = (...args) => {
|
|
5
|
+
return Proxies.guard(new FakeEventGuest(...args));
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Represents a guest of an event.
|
|
10
|
+
* @see https://developers.google.com/apps-script/reference/calendar/event-guest
|
|
11
|
+
*/
|
|
12
|
+
export class FakeEventGuest {
|
|
13
|
+
constructor(resource) {
|
|
14
|
+
this.__resource = resource;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getEmail() {
|
|
18
|
+
return this.__resource.email;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getName() {
|
|
22
|
+
return this.__resource.displayName || '';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getGuestStatus() {
|
|
26
|
+
const status = this.__resource.responseStatus;
|
|
27
|
+
// Map API status to Enum
|
|
28
|
+
const map = {
|
|
29
|
+
'accepted': CalendarEnums.GuestStatus.YES,
|
|
30
|
+
'declined': CalendarEnums.GuestStatus.NO,
|
|
31
|
+
'tentative': CalendarEnums.GuestStatus.MAYBE,
|
|
32
|
+
'needsAction': CalendarEnums.GuestStatus.INVITED
|
|
33
|
+
};
|
|
34
|
+
return map[status] || CalendarEnums.GuestStatus.INVITED;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getAdditionalGuests() {
|
|
38
|
+
return this.__resource.additionalGuests || 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
toString() {
|
|
42
|
+
return 'EventGuest';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Proxies } from '../../support/proxies.js';
|
|
2
|
+
import { newFakeRecurrenceRule } from './fakerecurrencerule.js';
|
|
2
3
|
|
|
3
4
|
export const newFakeEventRecurrence = (...args) => {
|
|
4
5
|
return Proxies.guard(new FakeEventRecurrence(...args));
|
|
@@ -10,7 +11,43 @@ export const newFakeEventRecurrence = (...args) => {
|
|
|
10
11
|
*/
|
|
11
12
|
export class FakeEventRecurrence {
|
|
12
13
|
constructor() {
|
|
13
|
-
|
|
14
|
+
this.rules = [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
addDailyExclusion() { return this.__addRule(); }
|
|
18
|
+
addDailyRule() { return this.__addRule(); }
|
|
19
|
+
addMonthlyExclusion() { return this.__addRule(); }
|
|
20
|
+
addMonthlyRule() { return this.__addRule(); }
|
|
21
|
+
addWeeklyExclusion() { return this.__addRule(); }
|
|
22
|
+
addWeeklyRule() { return this.__addRule(); }
|
|
23
|
+
addYearlyExclusion() { return this.__addRule(); }
|
|
24
|
+
addYearlyRule() { return this.__addRule(); }
|
|
25
|
+
|
|
26
|
+
addDate(date) {
|
|
27
|
+
// RDATE support
|
|
28
|
+
// This isn't a rule in the same sense, but part of the recurrence definition
|
|
29
|
+
// For now we store it.
|
|
30
|
+
if (!this.rDates) this.rDates = [];
|
|
31
|
+
this.rDates.push(date);
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
addDateExclusion(date) {
|
|
36
|
+
// EXDATE support
|
|
37
|
+
if (!this.exDates) this.exDates = [];
|
|
38
|
+
this.exDates.push(date);
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setTimeZone(timeZone) {
|
|
43
|
+
this.timeZone = timeZone;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
__addRule() {
|
|
48
|
+
const rule = newFakeRecurrenceRule();
|
|
49
|
+
this.rules.push(rule);
|
|
50
|
+
return rule;
|
|
14
51
|
}
|
|
15
52
|
|
|
16
53
|
toString() {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Proxies } from '../../support/proxies.js';
|
|
2
|
+
|
|
3
|
+
export const newFakeRecurrenceRule = (...args) => {
|
|
4
|
+
return Proxies.guard(new FakeRecurrenceRule(...args));
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents a recurrence rule for an event series.
|
|
9
|
+
* @see https://developers.google.com/apps-script/reference/calendar/recurrence-rule
|
|
10
|
+
*/
|
|
11
|
+
export class FakeRecurrenceRule {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.rule = {};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
addDailyExclusion() { return this; }
|
|
17
|
+
addDailyRule() { return this; }
|
|
18
|
+
addMonthlyExclusion() { return this; }
|
|
19
|
+
addMonthlyRule() { return this; }
|
|
20
|
+
addWeeklyExclusion() { return this; }
|
|
21
|
+
addWeeklyRule() { return this; }
|
|
22
|
+
addYearlyExclusion() { return this; }
|
|
23
|
+
addYearlyRule() { return this; }
|
|
24
|
+
|
|
25
|
+
addDate(date) { return this; }
|
|
26
|
+
addDateExclusion(date) { return this; }
|
|
27
|
+
|
|
28
|
+
interval(interval) { return this; }
|
|
29
|
+
onlyInMonth(month) { return this; }
|
|
30
|
+
onlyInMonths(months) { return this; }
|
|
31
|
+
onlyOnMonthDay(day) { return this; }
|
|
32
|
+
onlyOnMonthDays(days) { return this; }
|
|
33
|
+
onlyOnMonths(months) { return this; }
|
|
34
|
+
onlyOnWeek(week) { return this; }
|
|
35
|
+
onlyOnWeekday(day) { return this; }
|
|
36
|
+
onlyOnWeekdays(days) { return this; }
|
|
37
|
+
onlyOnWeeks(weeks) { return this; }
|
|
38
|
+
onlyOnYearDay(day) { return this; }
|
|
39
|
+
onlyOnYearDays(days) { return this; }
|
|
40
|
+
times(times) { return this; }
|
|
41
|
+
until(date) { return this; }
|
|
42
|
+
weekStartsOn(day) { return this; }
|
|
43
|
+
setTimeZone(timeZone) { return this; }
|
|
44
|
+
|
|
45
|
+
toString() {
|
|
46
|
+
return 'RecurrenceRule';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1,40 +1,45 @@
|
|
|
1
|
-
import { newFakeGasenum} from "@mcpher/fake-gasenum";
|
|
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
|
-
|
|
1
|
+
import { newFakeGasenum } from "@mcpher/fake-gasenum";
|
|
2
|
+
|
|
3
|
+
export const Color = newFakeGasenum(
|
|
4
|
+
{
|
|
5
|
+
BLUE: "#2952A3",
|
|
6
|
+
BROWN: "#8D6F47",
|
|
7
|
+
CHARCOAL: "#4E5D6C",
|
|
8
|
+
CHESTNUT: "#865A5A",
|
|
9
|
+
GRAY: "#5A6986",
|
|
10
|
+
GREEN: "#0D7813",
|
|
11
|
+
INDIGO: "#5229A3",
|
|
12
|
+
LIME: "#528800",
|
|
13
|
+
MUSTARD: "#88880E",
|
|
14
|
+
OLIVE: "#6E6E41",
|
|
15
|
+
ORANGE: "#BE6D00",
|
|
16
|
+
PINK: "#B1365F",
|
|
17
|
+
PLUM: "#705770",
|
|
18
|
+
PURPLE: "#7A367A",
|
|
19
|
+
RED: "#A32929",
|
|
20
|
+
RED_ORANGE: "#B1440E",
|
|
21
|
+
SEA_BLUE: "#29527A",
|
|
22
|
+
SLATE: "#4A716C",
|
|
23
|
+
TEAL: "#28754E",
|
|
24
|
+
TURQOISE: "#1B887A",
|
|
25
|
+
YELLOW: "#AB8B00"
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
export const EventColor = newFakeGasenum(
|
|
29
|
+
{
|
|
30
|
+
BLUE: "9",
|
|
31
|
+
CYAN: "7",
|
|
32
|
+
GRAY: "8",
|
|
33
|
+
GREEN: "10",
|
|
34
|
+
MAUVE: "3",
|
|
35
|
+
ORANGE: "6",
|
|
36
|
+
PALE_BLUE: "1",
|
|
37
|
+
PALE_GREEN: "2",
|
|
38
|
+
PALE_RED: "4",
|
|
39
|
+
RED: "11",
|
|
40
|
+
YELLOW: "5"
|
|
41
|
+
})
|
|
42
|
+
|
|
38
43
|
export const EventTransparency = newFakeGasenum([
|
|
39
44
|
"OPAQUE",
|
|
40
45
|
"TRANSPARENT"
|
|
@@ -32,11 +32,9 @@ class FakeGmailApp {
|
|
|
32
32
|
.replace(/\+/g, '-').replace(/\//g, '_');
|
|
33
33
|
|
|
34
34
|
const draft = Gmail.Users.Drafts.create({ message: { raw: encoded } }, 'me');
|
|
35
|
-
if (ScriptApp.__behavior.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (draft.message && draft.message.threadId) ScriptApp.__behavior.addGmailId(draft.message.threadId);
|
|
39
|
-
}
|
|
35
|
+
if (draft.id) ScriptApp.__behavior.addGmailId(draft.id);
|
|
36
|
+
if (draft.message && draft.message.id) ScriptApp.__behavior.addGmailId(draft.message.id);
|
|
37
|
+
if (draft.message && draft.message.threadId) ScriptApp.__behavior.addGmailId(draft.message.threadId);
|
|
40
38
|
return newFakeGmailDraft(draft);
|
|
41
39
|
}
|
|
42
40
|
|
|
@@ -61,7 +59,7 @@ class FakeGmailApp {
|
|
|
61
59
|
}
|
|
62
60
|
const newLabelResource = Gmail.newLabel().setName(name);
|
|
63
61
|
const createdLabelResource = Gmail.Users.Labels.create(newLabelResource, 'me');
|
|
64
|
-
|
|
62
|
+
behavior.addGmailId(createdLabelResource.id);
|
|
65
63
|
return newFakeGmailLabel(createdLabelResource);
|
|
66
64
|
}
|
|
67
65
|
|
|
@@ -456,10 +454,8 @@ class FakeGmailApp {
|
|
|
456
454
|
.replace(/\+/g, '-').replace(/\//g, '_');
|
|
457
455
|
|
|
458
456
|
const res = Gmail.Users.Messages.send({ raw: encoded }, 'me');
|
|
459
|
-
if (behavior.
|
|
460
|
-
|
|
461
|
-
if (res.threadId) behavior.addGmailId(res.threadId);
|
|
462
|
-
}
|
|
457
|
+
if (res.id) behavior.addGmailId(res.id);
|
|
458
|
+
if (res.threadId) behavior.addGmailId(res.threadId);
|
|
463
459
|
return this;
|
|
464
460
|
}
|
|
465
461
|
|