日历服务:使用 PropertiesService 存储和检索事件

Calendar Service: Store and retrieve events using PropertiesService

这个代码

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 [{}, {}, {}, {}, {}]

这是为什么?怎么了?

这是为什么?

CalendarEvent 是一个 Google Apps 脚本 class,事件是其实例。

检查 属性 所有权和可枚举性产生以下结果:

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
}

这告诉我们什么?

  1. 没有我们可以访问的 enumerable 属性(参见 Object.keys())。
  2. 自己的道具(参见getOwnPropertyNames())。
  3. CalendarEvent 继承自 Object1(参见 toString())。

现在,看看 JSON.stringify() 对对象做了什么(这是来自 MDN 的描述,但是如果你深入研究 ECMAScript 规范,你会看到 SerializeJSONObject operation 取决于摘要 EnumerableOwnPropertyName):

所有其他对象实例(包括 Map、Set、WeakMap 和 WeakSet)将仅序列化它们的可枚举属性

这引出了您的第二个问题:

怎么了?

由于没有可枚举的自身属性,序列化结果为"{}"

怎么办?

使用 PropertiesService 存储事件没有多大意义 - 即使您想出了一种存储方法,您也会很快遇到较大事件集合的配额问题。什么,是存储一个reference,那么使用getId()方法存储和getEventById()检索怎么样?

样本

//...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'));

还能做什么?

使用日历 API(不要忘记首先通过转至 Resources -> Cloud Platform project -> APIs and Services -> 为您的 GCP 项目启用它Library)。这个 API 是一个 REST API,您可以像这样使用良好的旧 HTTP 请求进行查询:

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
  }

}

请注意,必须将 OAuth 范围设置为与 JWT 令牌(通过 getOAuthToken() 获得)一起传递。如果应用程序清单中有明确的范围列表(appscript.jsonoauthScopes 字段),请添加 "https://www.googleapis.com/auth/calendar.events.readonly" 或更合适的。

备注

  1. 我的意思是,由于原型继承,CalendarEvent 的一个实例有一个对象作为其原型。
  2. 使用 getUserProperties()getScriptProperties() 更可取,除非需要脚本范围的设置(请参阅参考资料中的官方指南)。脚本属性在用户之间共享,并计入脚本所有者的配额。
  3. 要使用第二个示例,V8 运行时必须是 enabled(从问题示例中不清楚是否使用它)。

参考

  1. 可枚举性 explanation MDN
  2. JSON.stringify() docs 在 MDN
  3. 日历事件 getId() docs
  4. getEventById() docs
  5. 日历APIreference
  6. OAuth scopes 对于 Google APIs
  7. PropertiesServiceguide