Google Apps Script Calendar Service: Store and ret

2020-05-01 08:20发布

This code

var cal = CalendarApp.getCalendarById("Calendar Id");
var startTime = new Date(1850, 0, 1);
var endTime = new Date(2100, 0, 1);
var events = cal.getEvents(startTime, endTime);
Logger.log(events);
var sp = PropertiesService.getScriptProperties();
sp.setProperty("events", JSON.stringify(events));
events = JSON.parse(sp.getProperty("events"));
Logger.log(events);

returns:

Info [CalendarEvent, CalendarEvent, CalendarEvent, CalendarEvent, CalendarEvent]
Info [{}, {}, {}, {}, {}]

Why is that? What is wrong?

1条回答
等我变得足够好
2楼-- · 2020-05-01 08:41

Why is that?

CalendarEvent is a Google Apps Script class which events are instances of.

Checking property ownership and enumerability yields the following:

function stringified() {
  const event = CalendarApp.createAllDayEvent('Party', new Date());
  const eventToString = JSON.stringify(event);
  Logger.log(eventToString);                      // -> {}

  Logger.log(Object.keys(event));                 // -> []
  Logger.log(Object.getOwnPropertyNames(event));  // -> [toString,...]
  Logger.log(Object.getPrototypeOf(event));       // -> {}
  Logger.log(event.toString());                   // -> CalendarEvent
}

What does this tell us?

  1. there are no enumerable props we can access (see Object.keys()).
  2. there are own props (see getOwnPropertyNames()).
  3. CalendarEvent inherits from Object1 (see toString()).

Now, look at what JSON.stringify() does for objects (this is a description from MDN, but if you dig into the ECMAScript spec, you will see that SerializeJSONObject operation depends on abstract EnumerableOwnPropertyName):

All the other Object instances (including Map, Set, WeakMap, and WeakSet) will have only their enumerable properties serialized

Which leads us to your second question:

What is wrong?

Since there are no enumerable own properties, the serialization results in "{}".

What to do?

It does not make much sense to store events with PropertiesService - you will quickly get into quota issues on larger event collections even if you figure a way to store. What does, is to store a reference, so how about using getId() method to store and getEventById() to retrieve?

Sample

//...get event somehow

const store = PropertiesService.getUserProperties();

store.deleteProperty('events'); // demo only

const eventIds = store.getProperty('events') || '[]';

const id = event.getId();

const idList = JSON.parse(eventIds);
idList.push(id);
store.setProperty('events',JSON.stringify(idList));

Logger.log(store.getProperty('events'));

What else to do?

Use the Calendar API (don't forget to enablle it for your GCP project first by going to Resources -> Cloud Platform project -> APIs and Services -> Library). This API is a REST API that you can query with good old HTTP requests like that:

function listEvents() {

  const calendar = CalendarApp.getCalendarById('yourEmailHere');

  const endpoint = `https://www.googleapis.com/calendar/v3/calendars/${calendar.getId()}/events`;

  const query = {};

  const preparedQuery = Object
    .entries(query)
    .map(param =>`${param[0]}=${param[1]}`)
    .join('&');

  const resp = UrlFetchApp.fetch(`${endpoint}?${preparedQuery}`,{
    headers: {
      Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
    }
  });

  if(resp.getResponseCode() === 200) {
    //process the response
  }

}

Note that one would have to set the OAuth scope to be passed with the JWT token (obtained by getOAuthToken()). If there is an explicit scope list in application manifest (oauthScopes field of appscript.json), add "https://www.googleapis.com/auth/calendar.events.readonly" or a more appropriate one.

Notes

  1. By this I mean that an instance of CalendarEvent has an object as its prototype due to prototypal inheritance.
  2. Usage of getUserProperties() is preferrable to getScriptProperties() unless a script-wide setup is needed (see official guide in references). Script properties are shared across users and count toward quotas of the script owner.
  3. To use the second sample, V8 runtime has to be enabled (from the question sample it is unclear if it is used).

Reference

  1. Enumerability explanation on MDN
  2. JSON.stringify() docs on MDN
  3. Calendar events getId() docs
  4. getEventById() docs
  5. Calendar API reference
  6. OAuth scopes for Google APIs
  7. PropertiesService guide
查看更多
登录 后发表回答