在您从用户的 Google 云端硬盘中检索到 script projects 列表后,您必须首先从 Apps Script API 请求他们的项目元数据。目前获取项目的唯一途径就是一个一个地去,提供scriptId的请求。
诀窍是脚本项目 file 的 Id 恰好与脚本 Id 相同(如果您查看 CLASP 项目的源代码 @ 987654329@命令,你会看到他们utilize this fact显示项目ID)。
要获取Project资源,我们需要调用getmethod:
GET https://script.googleapis.com/v1/projects/{scriptId}
下面是一个简单的实用程序,用于从 API 检索单个 Project 资源。请注意,您的清单文件必须至少包含 https://www.googleapis.com/auth/script.projects.readonly 范围,否则 API 将返回 403 响应代码。
/**
* @typedef {{
* domain : string,
* email : string,
* name : string
* }} GSuiteUser
*
* @typedef {{
* scriptId : string,
* title : string,
* createTime : string,
* updateTime : string,
* creator : GSuiteUser,
* lastModifyUser : GSuiteUser
* }} ScriptProject
*
* @summary gets script project metadata
* @param {{
* id : string,
* token : string
* }}
* @returns {ScriptProject}
*/
const getProject = ({
id = ScriptApp.getScriptId(),
token = ScriptApp.getOAuthToken()
}) => {
const uri = `https://script.googleapis.com/v1/projects/${id}`;
/** @type {GoogleAppsScript.URL_Fetch.URLFetchRequestOptions} */
const params = {
contentType : "application/json",
headers : {
Authorization: `Bearer ${token}`
},
muteHttpExceptions : true,
method : "get"
};
const response = UrlFetchApp.fetch(uri, params);
const successChecker = getSuccessChecker();
const success = successChecker(response);
if(!success) {
return {};
}
return JSON.parse(response.getContentText());
};
将它映射到您使用 ziganotschka 方法获得的脚本文件列表上,您将获得有关项目的详细信息。接下来,如果 using 您的意思是 running 项目,您可以调用 processes.list API method 代替:
GET https://script.googleapis.com/v1/processes
要求的 OAuth 范围是 https://www.googleapis.com/auth/script.processes。
/**
* @typedef {{
* projectName : string,
* functionName : string,
* processType : string,
* processStatus : string,
* userAccessLevel : string,
* startTime : string,
* duration : string
* }} ScriptProcess
*
* @summary lists script processes for a user
* @param {{
* id : (string|"any"),
* pageSize : (number|50),
* token : string,
* start : (Date|undefined),
* end : (Date|undefined),
* statuses : string[],
* types : string[]
* }}
* @returns {ScriptProcess[]}
*/
const listScriptProcesses = ({
id = ScriptApp.getScriptId(),
token = ScriptApp.getOAuthToken(),
pageSize = 50,
start, end,
statuses = [],
types = []
} = {}) => {
const query = [
`pageSize=${pageSize}`,
`userProcessFilter.startTime=${toZuluTimestamp(start)}`,
`userProcessFilter.endTime=${toZuluTimestamp(end)}`
];
id !== "any" && query.push(`userProcessFilter.scriptId=${id}`);
types.length && query.push(`userProcessFilter.types=${types.join(",")}`);
statuses.length && query.push(`userProcessFilter.statuses=${statuses.join(",")}`);
const uri = `https://script.googleapis.com/v1/processes?${query.join("&")}`;
/** @type {GoogleAppsScript.URL_Fetch.URLFetchRequestOptions} */
const params = {
contentType: "application/json",
headers: {
Authorization: `Bearer ${token}`
},
muteHttpExceptions: true,
method: "get"
};
const response = UrlFetchApp.fetch(uri, params);
const content = response.getContentText();
const successChecker = getSuccessChecker();
const success = successChecker(response);
if (!success) {
console.warn(response.getResponseCode(), content);
return [];
}
const { processes = [] } = JSON.parse(content);
return processes;
};
作为响应,您将代表获取有关脚本执行的元数据,该用户的凭据与不记名令牌一起传递(您需要为每个用户提供一个服务帐户)。
剩下的很简单:如果响应不为空,则用户在某个时间点运行脚本项目(请注意,上面的实用程序默认start 和end 时间戳参数为now)。如果您提供 any 作为脚本 ID,请求将返回代表用户执行的每个。
该方法的另一个好处是返回每种类型的脚本项目执行,包括 Web 应用程序、附加组件和绑定项目(有关详细信息,请参阅 ProcessType 枚举)。 p>
这种方法的唯一困难是部署为“像我一样执行”的 Web 应用程序,它始终在脚本项目所有者的权限下运行,因此您必须单独跟踪 Web 应用程序的用户。
以上片段使用以下实用程序脚本:
/**
* @summary checks HTTPResponse for being successful
* @param {GoogleAppsScript.URL_Fetch.HTTPResponse} resp
* @returns {boolean}
*/
const getSuccessChecker = ({ successOn = [200] } = {}) => (resp) => {
const code = resp.getResponseCode();
return successOn.some(c => c === code);
};
/**
* @summary converts input into RFC3339 UTC "Zulu" format
* @param {Date|number|string} [date]
* @returns {string}
*/
const toZuluTimestamp = (date = Date.now()) => new Date(date).toISOString().replace('Z','000000Z');
您需要启用V8 runtime 以使上面的 sn-ps 工作(或将它们转换为 ES5 语法)。