google-apps-script - 使用 onEdit 触发器将 Google 日历事件自动刷新到 Google Sheers
问题描述
我正在尝试将 Google 日历中的时间事件抓取到 Google 电子表格中。
当在我的 Google 日历中创建新的时间事件时,该事件应自动同步到我的 Google 电子表格中。这应该由onEdit
事件触发器自动完成。
目前它只能通过刷新 Google 电子表格来运行。
也许有人对我的挑战有更好的解决方案。这是我的代码:
function createSpreadsheetEditTrigger() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('myCalendar')
.forSpreadsheet(ss)
.onEdit()
.create();
}
function myCalendar(){
var now=new Date();
// Startzeit
var startpoint=new Date(now.getTime()-60*60*24*365*1000);
// Endzeit
var endpoint=new Date(now.getTime()+60*60*24*1000*1000);
var events=CalendarApp.getCalendarById("your-calendar-ID").getEvents(startpoint, endpoint);
var ss=SpreadsheetApp.getActiveSpreadsheet().getSheetByName("TEST");
ss.clear();
for (var i=0;i<events.length;i++) {
ss.getRange(i+1,1 ).setValue(events[i].getTitle());
ss.getRange(i+1,2).setValue(events[i].getDescription());
ss.getRange(i+1,3).setValue(events[i].getStartTime());
ss.getRange(i+1,4).setValue(events[i].getEndTime());
}
}
解决方案
问题
在 Google 日历中创建事件时执行更新电子表格的功能。
解决方案
使用EventUpdated
每次在日历中修改事件时触发的可安装触发器(例如,创建、更新或删除 - 请参阅参考资料)。从那里,您可以采用简单的方式(使用内置CalendarApp
类更新电子表格中的所有数据)或困难的方式(更新通过增量同步更改的数据 - 请参阅官方指南)。
第 0 部分 - 安装触发器
/**
* Installs Calendar trigger;
*/
function calendarTrigger() {
var trigger = ScriptApp.newTrigger('callback name here')
.forUserCalendar('calendar owners email here')
.onEventUpdated()
.create();
}
第 1 部分 - 回调(日历 -> 电子表格)
/**
* Updates spreadsheet;
* @param {Object} e event object;
*/
function updateSpreadsheet(e) {
//access spreadsheet;
var ss = SpreadsheetApp.openById('target spreadsheet id');
var sh = ss.getSheetByName('target sheet name');
var datarng = sh.getDataRange(); //assumed that data is only calendar data;
//access calendar;
var calendar = CalendarApp.getCalendarById(e.calendarId);
//set timeframes;
var start = new Date();
var end =new Date();
//get year before and three after;
start.setFullYear(start.getFullYear()-1);
end.setFullYear(end.getFullYear()+3);
//get events;
var events = calendar.getEvents(start, end);
//map events Array to a two-dimensional array of values;
events = events.map(function(event){
return [event.getTitle(),event.getDescription(),event.getStartTime(),event.getEndTime()];
});
//clear values;
datarng.clear();
//setup range;
var rng = sh.getRange(1,1, events.length, events[0].length);
//apply changes;
rng.setValues(events);
}
笔记
- 根据 Tanaike 的评论 -如果事件是通过脚本或请求触发的,重要的是要考虑触发器(简单和可安装)以不触发(请参阅限制参考)。要启用此类功能,您必须引入轮询或与WebApp捆绑,脚本将在创建事件后调用该 WebApp(请参阅下面的捆绑示例)。
- 您的解决方案更适合反向流程:在电子表格中编辑 -> 在日历中编辑(如果您修改它以在日历上执行操作而不是更新电子表格,ofc)。
- 使用
Date
内置对象的方法,如getFullYear()
(参见其他方法的参考),使您的代码更灵活、更易于理解。顺便说一句,我会将“一天中的毫秒”数据存储为常数(86400000
)。 - 永远不要在循环中使用
getRange()
,getValue()
和setValue()
类似的方法(并且通常尽可能少地调用它们) - 它们是 I/O 方法,因此速度很慢(您可以通过尝试在循环中写入超过 200 行来亲眼看看)。在开始时获取所需的范围/值,执行修改并批量写入(例如使用setValues()
方法)。
参考
EventUpdated
事件参考;- 日历增量同步指南;
Date
内置对象引用;setValues()
方法参考;- 在 Google Apps Script 中使用批处理操作;
- 可安装且简单的触发限制;
WebApp 捆绑
第 0 部分 - 先决条件
如果您想通过脚本执行创建/更新/删除日历事件,您可以将目标脚本与一个简单的 WebApp 捆绑在一起。您需要确保:
- WebApp 部署的访问权限设置为 as
anyone, even anonymous
(强烈建议引入某种形式的请求认证); - WebApp 代码有一个函数,名为
doPost
接受事件对象(通常命名为e
,但由您决定)作为单个参数。
第 1 部分 - 构建 WebApp
此构建假定所有修改都在 WebApp 中进行,但是您可以,例如,返回回调名称以在成功请求时运行并在调用脚本中处理更新。由于calendarId
在上面的回调中只使用了事件对象的属性,我们可以向它传递一个只有这个属性集的自定义对象:
/**
* Callback for POST requests (always called "doPost");
* @param {Object} e event object;
* @return {Object} TextOutput;
*/
function doPost(e) {
//access request params;
var body = JSON.parse(e.postData.contents);
//access calendar id;
var calendarId = body.calendar;
if(calendarId) {
updateSpreadsheet({calendarId:calendarId}); //callback;
return ContentService.createTextOutput('Success');
}else {
return ContentService.createTextOutput('Invalid request');
}
}
第 2 部分 - 示例调用脚本
此构建假定调用脚本和 WebApp 是同一个脚本项目(因此它的 Url 可以通过 访问ScriptApp.getService().getUrl()
,否则粘贴在 WebApp 部署期间提供给您的那个)。构建需要熟悉UrlFetchApp
(参见参考资料)。
/**
* Creates event;
*/
function createEvent() {
var calendar = CalendarApp.getCalendarById('your calendar id here');
//modify whatever you need to (this build creates a simple event);
calendar.createEvent('TEST AUTO', new Date(), new Date());
//construct request parameters;
var params = {
method: 'post',
contentType: 'application/json',
muteHttpExceptions: true,
payload: JSON.stringify({
calendar: calendar.getId()
})
};
//send request and handle result;
var updated = UrlFetchApp.fetch(ScriptApp.getService().getUrl(),params);
Logger.log(updated); //should log "Success";
}
推荐阅读
- c++ - 在 std::string 的特定索引处开始循环?
- android - 未解决的参考:build.gradle.kts 中的 grgit
- java - 修改已经存在的bean
- c# - Xamarin 形式 最多一个元素
应使用命名空间“” - reactjs - Kubernetes/Docker/Create React App + nginx 不返回静态文件?
- java - 如何在 Java 中精确计算距离?
- sql-server - SQL Server:数据库用户访问模式
- java - 组件 tJavaFlex_1(时间)中的异常 java.lang.ArrayIndexOutOfBoundsException: 1 javatflex 和 tmemorizerows
- tensorflow - Tensorflow:对 LSTM 的期望
- python - 有没有办法在不声明的情况下调用变量