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



此代码

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);

退货:

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

为什么?怎么了?

为什么

CalendarEvent是一个Google应用程序脚本类,事件是该类的实例。

检查财产所有权和可枚举性得出以下结果:

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. 我们无法访问可枚举道具(请参阅Object.keys()(
  2. 自己的道具(参见getOwnPropertyNames()(
  3. CalendarEvent继承自Object1(参见toString()(

现在,看看JSON.stringify()对对象的作用(这是MDN的描述,但如果深入研究ECMAScript规范,您会发现SerializeJSONObject操作依赖于抽象的EnumerableOwnPropertyName(:

所有其他Object实例(包括Map、Set、WeakMap和WeakSet(将只序列化其可枚举属性

这就引出了你的第二个问题:

怎么了

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

该怎么办

PropertiesService存储事件没有多大意义——即使你想好了存储的方法,你也会很快遇到较大事件集合的配额问题。什么是存储引用,那么使用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->Library为GCP项目启用它(。这个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
}
}

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

票据

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

参考

  1. MDN的可枚举性解释
  2. MDN上的JSON.stringify()文档
  3. 日历事件getId()文档
  4. getEventById()文档
  5. 日历API参考
  6. Google API的OAuth作用域
  7. PropertiesService指南

最新更新