是否可以从 Google App Maker/Google Apps 脚本中查看目录 API 的变化?
Is it possible to watch Directory API changes from Google App Maker/Google Apps Script?
我正在 Google App Maker 中开发性能评估应用程序。我们当前工具面临的挑战之一是,当一个人的经理发生变化或一个人的名字发生变化时,它不会与我们的 G Suite 目录同步——他们现有的评估与该人的旧名字相关联,我们有手动更改。
在我的新应用程序中,我有一个员工数据源,其中包含与最初通过目录 API 填充的评估本身的关系。阅读文档 here,似乎我应该能够在 Users 资源上设置监视以查找用户更新并解析它们以在我的 Employees 数据源中进行适当的名称和经理更改。不过,我想不通的是接收 URL 应该用于手表请求。
如果有人在 Google App Maker 中成功完成此操作,或者甚至仅在 Google Apps 脚本中成功完成此操作,我很想知道您是如何做到的。
编辑添加:
我创建了一个愚蠢的小 GAS 测试函数,看看我是否可以让下面的 @dimu-designs 解决方案起作用。不幸的是,我刚收到一个 Bad Request 错误。这是我拥有的:
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);
}
地址是当前的网络应用URL。
编辑添加更多内容:
自 2014 年 9 月以来,使用 GAS 接收网络挂钩的(不)能力一直是一个活跃的 issue/feature 请求 -- https://issuetracker.google.com/issues/36761910 -- @dimu-designs 已经有一段时间了。
您可以使用 GAS 和 Admin SDK 执行此操作。目录 API 支持 Notifications(请注意,这将被弃用,因此不确定是什么替代了此功能)。然后您可以设置一个 GMAIL 脚本来执行您需要对通知执行的操作。
更新:还有 PUSH notifications 来自目录 API。
很遗憾,您不能,至少不能单独使用 Apps 脚本。
管理员目录推送通知需要 web-hook URL 端点来接收通知。您可能认为部署 GAS 网络应用程序并将其 URL 用作端点就足够了。但是 Admin Directory Push notifications 的问题在于它的数据负载驻留在自定义 HTTP headers 中,无法从 GAS Web App 访问。 (这也适用于跨其他 API 的推送通知,包括 Drive 和 Calendar API)
然而,您可以将 Google Cloud Functions(一项 GCP 服务)与 GAS 结合使用,但您必须了解 Node.js。
编辑
经过深思熟虑并查看您的要求后,我相信有一种方法可以通过使用 GAS 来实现。
您可以通过 setting the event parameter when initializing the watch 为每个 user/domain(您用例中的 'update' 事件)的给定事件设置唯一的推送通知渠道。因此,只有在发生更新事件时才会触发 GAS 网络应用程序;您真的不需要依赖 HTTP header 来确定事件类型。
如果您想跟踪多个事件,您只需为每个事件创建一个唯一的通道,并为每个事件使用相同的 GAS Web 应用端点。您可以通过检查 POST 请求中发送的事件参数来区分事件。这应该消除对 middle-man 服务的需求,例如 Heroku 或 Google Cloud Functions。
我能够使用 Heroku-based Node.js 应用程序作为中介 API 为本地资源(电子表格)设置推送通知。 Node 应用程序捕获自定义请求 headers 并构建要由 GAS 网络应用程序的 doPost(e) 函数使用的有效负载。
构造watch请求的代码很简单
//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);
挑战在于验证该域地址。有一些方法可以验证独立的(不是 file-bound!)GAS 网络应用程序,但是,正如之前的发帖者所提到的,Apps 脚本网络应用程序无法访问自定义 headers.
启用 Pub/Sub API 并创建主题和订阅后,转到 APIs & Services -> Credentials -> Domain verification。它为您提供了一些验证域的选项,包括提供 html 文件。下载 Google 生成的文件。值得庆幸的是,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);
}
然后在您的路由器 object 中包含处理程序,如下所示:
var router = {
"google_file.html": handlers.verifyDomain
}
最后,在您的服务器启动函数中,从 URL 获取路径(有多种方法),并执行处理程序;
var routeHandler = router(path);
routerHandler(function(statusCode, file){
//do something
});
返回域验证工具并加载 HTML 页面以验证 URL。验证后,剩下的唯一步骤就是创建 GAS 网络应用程序并发布到它。
返回节点应用。请注意,我的端点是 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);
}
Apps 脚本应用 - 不要忘记发布它。
function doPost(req) {
var postData = req.postData["contents"];
var headers = JSON.parse(postData)["headers"];
//take action
return 200;
}
这是一个更全面的答案。
Google 支持在他们的许多 API 中推送通知。然而,它们之间存在许多细微(而不是那么细微)的差异。一些利用 webhook 的人主要以 HTTP headers 的形式发送数据负载;例如驱动器 API 和日历 API。其他人将他们的有效负载混合在 HTTP headers 和 POST body(例如:AdminDirectory API)中。它变得更加疯狂,一些 API 完全使用不同的机制(例如:GMail API 利用 Cloud PubSub)。
每个都有细微差别,但您的目标是在 GAS 应用程序中利用 AdminDirectory 推送通知。为此,您需要一个 GAS Web 应用程序,其 URL 可以用作 web-hook 端点。
第 1 步 - 将 Stand-Alone 脚本部署为 Web 应用程序
让我们从以下模板脚本开始,并从 Apps 脚本编辑器菜单将其部署为 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 步 - Verify/Validate 域所有权和 Add/Register 域
NOTE: As of August 2019, GAS Web App URLs can no longer be verified using this method. Google Cloud Functions may be a viable
alternative.
部署网络应用程序后,您现在必须验证并注册接收域 url,在本例中也是网络应用程序 url。此 url 采用以下形式:
https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/exec
从技术上讲,您不能拥有 GAS 网络应用 url 的域。值得庆幸的是,Google 的 App Script Gods 确实提供了一种机制来验证和注册 GAS 网络应用程序 url。
来自 Apps 脚本编辑器菜单 select Publish > Register in Chrome Web Store
。在 Chrome 网上商店注册已发布的网络应用程序也会验证 URL 的域(无需 fiddle 使用搜索控制台)。
验证后,您需要 add the "domain" via the Domain verification page in the API Console。 "domain" 是 url 中没有 'exec' 的所有内容,因此您将添加如下所示的字符串:
https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/
第 3 步 - 提出观看请求
对于此步骤,应为您的 App 脚本项目和 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。通常,您可以使用 time-based 触发器每 5 小时左右调用一次此函数。
第 4 步 - 更新 doPost(e) 触发器以处理传入通知
与其他 API 的推送机制不同,目录 API 发送 POST body 及其通知,因此 doPost(e) 方法是保证在发送通知时触发。定制 doPost(e) 触发器以处理传入事件和 re-deploy 网络应用程序:
function doPost(e) {
switch(e.parameter.event) {
case "update":
// do update stuff
break;
case "add":
break;
case "delete":
break;
}
return ContentService.createTextOutput("POST message");
}
有一点需要牢记。更新事件的推送通知只会告诉您用户数据已更新,它不会告诉您确切的更改内容。但这是另一个问题的问题。
请注意,我遗漏了大量细节,但这应该足以让您振作起来 运行。
我正在 Google App Maker 中开发性能评估应用程序。我们当前工具面临的挑战之一是,当一个人的经理发生变化或一个人的名字发生变化时,它不会与我们的 G Suite 目录同步——他们现有的评估与该人的旧名字相关联,我们有手动更改。
在我的新应用程序中,我有一个员工数据源,其中包含与最初通过目录 API 填充的评估本身的关系。阅读文档 here,似乎我应该能够在 Users 资源上设置监视以查找用户更新并解析它们以在我的 Employees 数据源中进行适当的名称和经理更改。不过,我想不通的是接收 URL 应该用于手表请求。
如果有人在 Google App Maker 中成功完成此操作,或者甚至仅在 Google Apps 脚本中成功完成此操作,我很想知道您是如何做到的。
编辑添加:
我创建了一个愚蠢的小 GAS 测试函数,看看我是否可以让下面的 @dimu-designs 解决方案起作用。不幸的是,我刚收到一个 Bad Request 错误。这是我拥有的:
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);
}
地址是当前的网络应用URL。
编辑添加更多内容: 自 2014 年 9 月以来,使用 GAS 接收网络挂钩的(不)能力一直是一个活跃的 issue/feature 请求 -- https://issuetracker.google.com/issues/36761910 -- @dimu-designs 已经有一段时间了。
您可以使用 GAS 和 Admin SDK 执行此操作。目录 API 支持 Notifications(请注意,这将被弃用,因此不确定是什么替代了此功能)。然后您可以设置一个 GMAIL 脚本来执行您需要对通知执行的操作。
更新:还有 PUSH notifications 来自目录 API。
很遗憾,您不能,至少不能单独使用 Apps 脚本。
管理员目录推送通知需要 web-hook URL 端点来接收通知。您可能认为部署 GAS 网络应用程序并将其 URL 用作端点就足够了。但是 Admin Directory Push notifications 的问题在于它的数据负载驻留在自定义 HTTP headers 中,无法从 GAS Web App 访问。 (这也适用于跨其他 API 的推送通知,包括 Drive 和 Calendar API)
然而,您可以将 Google Cloud Functions(一项 GCP 服务)与 GAS 结合使用,但您必须了解 Node.js。
编辑
经过深思熟虑并查看您的要求后,我相信有一种方法可以通过使用 GAS 来实现。
您可以通过 setting the event parameter when initializing the watch 为每个 user/domain(您用例中的 'update' 事件)的给定事件设置唯一的推送通知渠道。因此,只有在发生更新事件时才会触发 GAS 网络应用程序;您真的不需要依赖 HTTP header 来确定事件类型。
如果您想跟踪多个事件,您只需为每个事件创建一个唯一的通道,并为每个事件使用相同的 GAS Web 应用端点。您可以通过检查 POST 请求中发送的事件参数来区分事件。这应该消除对 middle-man 服务的需求,例如 Heroku 或 Google Cloud Functions。
我能够使用 Heroku-based Node.js 应用程序作为中介 API 为本地资源(电子表格)设置推送通知。 Node 应用程序捕获自定义请求 headers 并构建要由 GAS 网络应用程序的 doPost(e) 函数使用的有效负载。
构造watch请求的代码很简单
//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);
挑战在于验证该域地址。有一些方法可以验证独立的(不是 file-bound!)GAS 网络应用程序,但是,正如之前的发帖者所提到的,Apps 脚本网络应用程序无法访问自定义 headers.
启用 Pub/Sub API 并创建主题和订阅后,转到 APIs & Services -> Credentials -> Domain verification。它为您提供了一些验证域的选项,包括提供 html 文件。下载 Google 生成的文件。值得庆幸的是,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);
}
然后在您的路由器 object 中包含处理程序,如下所示:
var router = {
"google_file.html": handlers.verifyDomain
}
最后,在您的服务器启动函数中,从 URL 获取路径(有多种方法),并执行处理程序;
var routeHandler = router(path);
routerHandler(function(statusCode, file){
//do something
});
返回域验证工具并加载 HTML 页面以验证 URL。验证后,剩下的唯一步骤就是创建 GAS 网络应用程序并发布到它。
返回节点应用。请注意,我的端点是 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);
}
Apps 脚本应用 - 不要忘记发布它。
function doPost(req) {
var postData = req.postData["contents"];
var headers = JSON.parse(postData)["headers"];
//take action
return 200;
}
这是一个更全面的答案。
Google 支持在他们的许多 API 中推送通知。然而,它们之间存在许多细微(而不是那么细微)的差异。一些利用 webhook 的人主要以 HTTP headers 的形式发送数据负载;例如驱动器 API 和日历 API。其他人将他们的有效负载混合在 HTTP headers 和 POST body(例如:AdminDirectory API)中。它变得更加疯狂,一些 API 完全使用不同的机制(例如:GMail API 利用 Cloud PubSub)。
每个都有细微差别,但您的目标是在 GAS 应用程序中利用 AdminDirectory 推送通知。为此,您需要一个 GAS Web 应用程序,其 URL 可以用作 web-hook 端点。
第 1 步 - 将 Stand-Alone 脚本部署为 Web 应用程序
让我们从以下模板脚本开始,并从 Apps 脚本编辑器菜单将其部署为 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 步 - Verify/Validate 域所有权和 Add/Register 域
NOTE: As of August 2019, GAS Web App URLs can no longer be verified using this method. Google Cloud Functions may be a viable alternative.
部署网络应用程序后,您现在必须验证并注册接收域 url,在本例中也是网络应用程序 url。此 url 采用以下形式:
https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/exec
从技术上讲,您不能拥有 GAS 网络应用 url 的域。值得庆幸的是,Google 的 App Script Gods 确实提供了一种机制来验证和注册 GAS 网络应用程序 url。
来自 Apps 脚本编辑器菜单 select Publish > Register in Chrome Web Store
。在 Chrome 网上商店注册已发布的网络应用程序也会验证 URL 的域(无需 fiddle 使用搜索控制台)。
验证后,您需要 add the "domain" via the Domain verification page in the API Console。 "domain" 是 url 中没有 'exec' 的所有内容,因此您将添加如下所示的字符串:
https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/
第 3 步 - 提出观看请求
对于此步骤,应为您的 App 脚本项目和 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。通常,您可以使用 time-based 触发器每 5 小时左右调用一次此函数。
第 4 步 - 更新 doPost(e) 触发器以处理传入通知
与其他 API 的推送机制不同,目录 API 发送 POST body 及其通知,因此 doPost(e) 方法是保证在发送通知时触发。定制 doPost(e) 触发器以处理传入事件和 re-deploy 网络应用程序:
function doPost(e) {
switch(e.parameter.event) {
case "update":
// do update stuff
break;
case "add":
break;
case "delete":
break;
}
return ContentService.createTextOutput("POST message");
}
有一点需要牢记。更新事件的推送通知只会告诉您用户数据已更新,它不会告诉您确切的更改内容。但这是另一个问题的问题。
请注意,我遗漏了大量细节,但这应该足以让您振作起来 运行。