是否可以从Google App Maker/Google App Script中查看目录API更改



我正在Google app Maker中开发一款性能评估应用程序。我们目前使用的工具面临的挑战之一是,当一个人的经理更改或姓名更改时,它与我们的G Suite目录不同步——他们现有的评估与该人的旧名称相关联,我们必须手动更改。

在我的新应用程序中,我有一个Employees数据源,其中包括与最初通过Directory API填充的评估本身的关系。阅读这里的文档,我似乎应该能够在Users资源上设置一个监视,以查找用户更新并解析它们,从而在我的Employees数据源中进行适当的名称和经理更改。然而,我无法弄清楚的是,手表请求的接收URL应该是什么。

如果有人在Google App Maker中成功地做到了这一点,甚至只是在Google Apps脚本中,我很想知道你是如何做到的。

编辑后添加:

我创建了一个愚蠢的小GAS测试函数,看看我是否可以在下面获得@dimu设计的解决方案。不幸的是,我刚刚收到一个错误的请求。这是我的:

function setUserWatch() {
var optionalArgs = {
"event": "update"
};
var resource = {
"id": "10ff4786-4363-4681-abc8-28166022425b",
"type": "web_hook",
"address": "https://script.google.com/a/.../...hXlw/exec"
};
AdminDirectory.Users.watch(resource);
}

Address是当前web应用的URL。

已编辑以添加更多内容:自2014年9月以来,使用GAS接收web挂钩的能力一直是一个活跃的问题/功能请求——https://issuetracker.google.com/issues/36761910一段时间以来,这一直是@dimu的设计。

这是一个更全面的答案。

谷歌支持通过其许多API推送通知。然而,它们之间有许多微妙(也不那么微妙)的差异。一些利用webhook的用户主要以HTTP头的形式发送数据有效载荷;例如驱动器API和日历API。其他人则通过HTTP头和POST主体混合其有效负载(例如:AdminDirectory API)。它变得更加疯狂,一些API完全利用不同的机制(例如:GMail API利用Cloud PubSub)。

每个都有细微差别,但您的目标是在GAS应用程序中利用AdminDirectory推送通知。要做到这一点,您需要一个GAS Web应用程序,其URL可以作为Web挂钩端点。


步骤1-将独立脚本部署为Web应用程序

让我们从以下模板脚本开始,并从"应用程序脚本编辑器"菜单中将其部署为Web应用程序Publish > Deploy As Web App

/** HTTP GET request handler */
function doGet(e) {
return ContentService.createTextOutput("GET message");
}
/** HTTP POST request handler */
function doPost(e) {
return ContentService.createTextOutput("POST message");
}

步骤2-验证/验证域所有权并添加/注册域

注意:自2019年8月起,GAS Web应用程序URL无法再使用此方法进行验证。谷歌云功能可能是一个可行的替代方案

部署web应用程序后,您现在必须验证并注册接收url的域,在本例中,该域也是web应用程序url。此url采用以下形式:

https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/exec

从技术上讲,你不能拥有GAS网络应用url的域。值得庆幸的是,谷歌的App Script Gods确实提供了一种验证和注册GAS网络应用url的机制。

从"应用程序脚本编辑器"菜单中选择Publish > Register in Chrome Web Store。在Chrome网络商店注册已发布的网络应用程序也会验证URL的域(无需摆弄搜索控制台)。

验证后,您需要通过API控制台中的域验证页面添加"域"。"域"是url中没有"exec"的所有内容,因此您将添加一个字符串,如下所示:

https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/


步骤3-提出手表请求

对于此步骤,应该为应用程序脚本项目和API控制台启用AdminSDK/Directory API服务。

创建一个生成监视请求的函数(可以针对其他事件类型重新调整):

function startUpdateWatch() {
var channel = AdminDirectory.newChannel(),
receivingURL = "https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/exec",
gSuiteDomain = "[business-name].com",
event = "update";
channel.id = Utilities.getUuid();
channel.type = "web_hook";
channel.address = receivingURL + "?domain=" + gSuiteDomain + "&event=" + event;
channel.expiration = Date.now() + 21600000; // max of 6 hours in the future; Note: watch must be renew before expiration to keep sending notifications
AdminDirectory.Users.watch(
channel, 
{
"domain":gSuiteDomain,
"event":event
}
);
}

请注意,目录API推送通知会过期,最长为启动监视后6小时,因此必须定期续订,以确保通知发送到端点URL。通常情况下,您可以使用基于时间的触发器每隔5小时左右调用一次此函数


步骤4-更新doPost(e)触发器以处理传入通知

与其他API的推送机制不同,Directory API在发送通知的同时发送POST主体,因此doPost(e)方法保证在发送通知时被触发。定制doPost(e)触发器以处理传入事件并重新部署web应用程序:

function doPost(e) {
switch(e.parameter.event) {
case "update":
// do update stuff
break;
case "add":
break;
case "delete":
break;
}
return ContentService.createTextOutput("POST message");
}

有一点需要牢记。更新事件的推送通知只会告诉你用户的数据已更新,不会告诉你更改了什么。但这是另一个问题的问题。

请注意,我遗漏了很多细节,但这应该足以让你开始工作。

您可以使用GAS和Admin SDK来完成此操作。目录API支持通知(请注意,计划不赞成使用此功能,因此不确定替换此功能的是什么)。然后,您可以设置一个GMAIL脚本来处理通知。

更新:还有来自目录API的PUSH通知。

我能够使用基于Heroku的Node.js应用程序作为中间API为本地资源(电子表格)设置推送通知。Node应用程序捕获自定义请求标头,并构建GAS web应用程序的doPost(e)函数所使用的有效负载。

构建监视请求的代码是简单的

//get the unique id
var channelId = Utilities.getUuid();  
//build the resource object    
var resource = {  
"id": channelId,
"type": "web_hook",
"address": "https://yourapp.herokuapp.com/drivesub    
}
//watch the resource
Drive.Files.watch(resource, fileId);

挑战在于验证该域名。有一些方法可以验证独立的(非文件绑定!)GAS web应用程序,但是,正如之前的海报所提到的,Apps Script web应用程序无法访问自定义标头。

在您启用Pub/Sub API并创建主题&订阅,转到API&服务->凭据->域验证。它为您提供了一些验证域的选项,包括提供html文件。下载谷歌生成的文件。值得庆幸的是,Heroku使部署Node应用变得非常容易

https://devcenter.heroku.com/articles/getting-started-with-nodejs

验证您的域名后,您可以将订阅推送数据发送到Heroku上的端点URL。

我只是为路由处理程序创建了js文件,并专门为域验证创建了一个文件

handlers.verifyDomain = function(callback){
//Synchronously read from the static html file. Async method fs.readFile() doesn't make the file available to the router callback
var file = fs.readFileSync('./google/google_file.html');
callback(200, file); 
}

然后在路由器对象中包含处理程序,如下所示:

var router = {
"google_file.html": handlers.verifyDomain
}

最后,在服务器启动函数中,从URL获取路径(有多种方法),并执行处理程序;

var routeHandler = router(path);
routerHandler(function(statusCode, file){ 
//do something 
});

返回域验证工具并加载HTML页面以验证URL。经过验证后,剩下的唯一步骤就是创建GAS网络应用程序并发布到它

返回Node应用程序。请注意,我的端点是https://yourapp.herokuapp.com/drivesub

//The code for posting data to GAS web app. Of course, you need to
// update your router with router['driveSub'] = handlers.driveSub
handlers.driveSub = function(data, callback){
var headers = data.headers;
var options = {
method:"POST",
uri: your_gas_app_url, 
json:{"headers":headers}
};
//Use NPM to install the request module
request.post(options, function(err, httpResponse, body){
console.log(err, body);
});
callback(200, data);
}

应用程序脚本应用程序-不要忘记发布它。

function doPost(req) {
var postData = req.postData["contents"];
var headers = JSON.parse(postData)["headers"];
//take action
return 200;
}

不幸的是,您不能,至少不能仅使用Apps Script。

管理目录推送通知需要web挂钩URL端点来接收通知。您可能认为部署GAS web应用程序并使用其URL作为端点就足够了。但管理目录推送通知的问题是,它的数据负载驻留在自定义HTTP头中,无法从GAS Web应用程序访问。(这也适用于跨其他API的推送通知,包括驱动器和日历API)

然而,你可以将谷歌云功能(一种GCP服务)与GAS结合使用,但你必须了解Node.js.


编辑

经过思考,并审查了您的需求,我相信有一种方法可以通过使用GAS来实现这一点。

通过在初始化手表时设置事件参数,您可以为每个用户/域的给定事件(在您的用例中为"更新"事件)设置唯一的推送通知通道。因此,GAS网络应用程序只有在发生更新事件时才会被触发;您实际上不需要依赖HTTP标头来确定事件类型。

如果您想跟踪多个事件,只需为每个事件创建一个唯一的通道,并为每个事件使用相同的GAS Web应用程序端点。您可以通过检查POST请求中发送的事件参数来区分事件。这将消除对Heroku或谷歌云功能等中间人服务的需求。

最新更新