Google Apps Script
Google Apps Script 是一种 JavaScript 云脚本语言,它提供便捷方式来跨 Google 产品和第三方服务自动化任务,并构建网络应用程序。
通过内置的Targetprocess REST API,您可以将Targetprocess账户中的数据导出至 Google 电子表格文档。 更新操作同样受支持,具体说明如下。
如何构建并运行您的首个集成脚本
打开您的 Google 电子表格。
按下工具脚本编辑器

重命名新创建的项目。

将源代码复制到文件的 Code.gs 编辑区域。 使用下文中的Targetprocess示例获取数据。
请将主机名和身份验证令牌的值替换为您在Targetprocess中自有客户账户的对应值。

警告: 如何获取令牌? 对于 isTokenSetFromUserProfileTab 参数,请使用以下两种选项之一。 若您的令牌是从 Targetprocess 中的
true “用户资料 > 访问令牌 ”选项卡中签发的,请使用此令牌。 当令牌从 /api/v1/authentication REST API 端点签发时 false 使用。在下拉菜单中 fetchTargetprocessData 选择名为 的函数进行执行。

按下运行键。

授予此脚本所需的权限。 此操作只需执行一次。

成功! 您的电子表格现已填入Targetprocess实体。

从Targetprocess获取数据
此脚本通过基于令牌的身份验证连接到 myaccount.tpondemand.com Targetprocess账户,并查询用户故事列表。 已加载故事的详细信息附加于最初清空的 Google 电子表格之后。
function fetchTargetprocessData() {
var hostname = 'https://myaccount.tpondemand.com';
var authenticationToken = 'MTpFQUVXMHdRVGRMN0x1OXJPYWRXZWZaRkc2aDJaSkRyVWdyWm9rK2tFcldBPS==';
var isTokenSetFromUserProfileTab = true;
//use 'true' if token is issued from User Profile > Access Tokens tab
//use 'false' when token is issued from /api/v1/Authentication API endpoint
var takeCount = 10;
var entityTypeResourceName = 'userstories';
var filter = '';
var includeFields = '';
//use the example below to specify exact set of fields to include
//var includeFields = '[ID,Name,Project[Name],EntityState[Name],CustomFields]';
var dateFormat = 'yyyy-MM-dd';
//to see times with dates, use 'yyyy-MM-dd HH:mm';
var dataUrl = hostname + '/api/v1/' + entityTypeResourceName + '?format=json' + '&where=' + filter + '&take=' + takeCount + (includeFields.length > 0 ? '&include=' + includeFields : '') + '&' + (isTokenSetFromUserProfileTab ? 'access_token' : 'token') + '=' + authenticationToken;
var options = {
'method': 'get'
};
var response = UrlFetchApp.fetch(dataUrl, options);
var json = response.getContentText();
var data = JSON.parse(json);
var entities = data.Items;
var sheet = SpreadsheetApp.getActiveSheet();
//initial cleanup of the sheet
sheet.clear();
//creates column names row
var entity = entities[0];
var columnNames = Object.keys(entity);
var customFieldsColumnIndex = 0;
for (var i = 0; i < columnNames.length; i++) {
if (columnNames[i] == 'CustomFields') {
customFieldsColumnIndex = i;
}
}
if (customFieldsColumnIndex > 0) {
var entityArray = Object.keys(entity).map(function(k) { return entity[k] });
var customFieldsData = entityArray[customFieldsColumnIndex];
for (var k = 0; k < customFieldsData.length; k++) {
var fieldsPairData = customFieldsData[k];
columnNames.push(fieldsPairData.Name);
}
}
sheet.appendRow(columnNames);
//appends data line by line
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
var entityArray = Object.keys(entity).map(function(k) { return entity[k] });
if (customFieldsColumnIndex > 0) {
//format custom fields
var customFieldsData = entityArray[customFieldsColumnIndex];
var fieldValues = '';
for (var j = 0; j < customFieldsData.length; j++) {
var fieldsPairData = customFieldsData[j];
entityArray.push(fieldsPairData.Value);
}
entityArray[customFieldsColumnIndex] = customFieldsData.length;
}
//add data formatting functions there
for (var j = 0; j < entityArray.length; j++) {
var cellValue = entityArray[j];
if (typeof cellValue == 'string') {
if (cellValue.indexOf("Date") > -1) {
var milliseconds = cellValue.substring(6, cellValue.length - 7);
var originTimeZone = cellValue.substring(cellValue.length - 7, cellValue.length - 4);
var dateObject = new Date(parseInt(milliseconds) + originTimeZone * 1000 * 60 * 60);
entityArray[j] = Utilities.formatDate(dateObject, originTimeZone, dateFormat);
}
}
if (typeof cellValue == 'object') {
var keys = [];
var resourceType = '';
var name = '';
var items = null;
for(var key in cellValue) {
keys.push(key);
if (key == "ResourceType") {
resourceType = cellValue[key];
}
if (key == "Name") {
name = cellValue[key];
}
};
if (
resourceType == "Project"
|| resourceType == "EntityState"
|| resourceType == "EntityType"
|| resourceType == "Priority"
|| resourceType == "Feature"
|| resourceType == "Epic"
|| resourceType == "UserStory"
|| resourceType == "Program"
|| resourceType == "Release"
|| resourceType == "Iteration"
|| resourceType == "TeamIteration"
) {
entityArray[j] = name;
}
}
}
sheet.appendRow(entityArray);
}
}
在Targetprocess中更新数据
此脚本通过基于令牌的身份验证连接到 myaccount.tpondemand.com Targetprocess账户,并在项目#2中创建新的用户故事实体。 用户故事的数字ID、名称、描述及创建时间戳将附加至初始清空 Google 的电子表格中。function updateTargetprocessData() {
var payload = {
"Project" : {"ID" : 2},
"Name": "Test Google Script Story Name",
"Description": "Test Google Script Story Description"
};
var hostname = 'https://myaccount.tpondemand.com';
var authenticationToken = 'MTozemxBMjI4dkNPMFVqbmlWV21WUVlSb0RYTTAzbkhQZ1lvaTJKanMvQWFBPS==';
var isTokenSetFromUserProfileTab = true;
//use 'true' if token is issued from User Profile > Access Tokens tab
//use 'false' when token is issued from /api/v1/Authentication API endpoint
var entityTypeResourceName = 'userstories';
var resultIncludeFields = '[Id,Name,Description,CreateDate]';
var dateFormat = 'yyyy-MM-dd HH:mm'; //to see no times with dates, use 'yyyy-MM-dd';
var dataUrl = hostname + '/api/v1/' + entityTypeResourceName + '/?format=json'
+ '&resultInclude=' + resultIncludeFields
+ '&' + (isTokenSetFromUserProfileTab ? 'access_token' : 'token') + '=' + authenticationToken;
var options = {
'method': 'POST',
'payload': JSON.stringify(payload),
'contentType' : 'application/json',
};
var response = UrlFetchApp.fetch(dataUrl, options);
var sheet = SpreadsheetApp.getActiveSheet();
//initial cleanup of the sheet
sheet.clear();
var json = response.getContentText();
var data = JSON.parse(json);
var entities = data;//data.Items; for multiple objects
var entity = entities;//entities[0]; for multiple objects
var columnNames = Object.keys(entity);
var customFieldsColumnIndex = 0;
for (var i = 0; i < columnNames.length; i++) {
if (columnNames[i] == 'CustomFields') {
customFieldsColumnIndex = i;
}
}
if (customFieldsColumnIndex > 0) {
var entityArray = Object.keys(entity).map(function(k) { return entity[k] });
var customFieldsData = entityArray[customFieldsColumnIndex];
for (var k = 0; k < customFieldsData.length; k++) {
var fieldsPairData = customFieldsData[k];
columnNames.push(fieldsPairData.Name);
}
}
sheet.appendRow(columnNames);
var entity = entities;//entities[i]; for multiple objects
var entityArray = Object.keys(entity).map(function(k) { return entity[k] });
if (customFieldsColumnIndex > 0) {
//format custom fields
var customFieldsData = entityArray[customFieldsColumnIndex];
var fieldValues = '';
for (var j = 0; j < customFieldsData.length; j++) {
var fieldsPairData = customFieldsData[j];
entityArray.push(fieldsPairData.Value);
}
entityArray[customFieldsColumnIndex] = customFieldsData.length;
}
//add data formatting functions there
for (var j = 0; j < entityArray.length; j++) {
var cellValue = entityArray[j];
if (typeof cellValue == 'string') {
if (cellValue.indexOf("Date") > -1) {
var milliseconds = cellValue.substring(6, cellValue.length - 7);
var originTimeZone = cellValue.substring(cellValue.length - 7, cellValue.length - 4);
var dateObject = new Date(parseInt(milliseconds) + originTimeZone * 1000 * 60 * 60);
entityArray[j] = Utilities.formatDate(dateObject, originTimeZone, dateFormat);
}
}
if (typeof cellValue == 'object') {
var keys = [];
var resourceType = '';
var name = '';
var items = null;
for(var key in cellValue) {
keys.push(key);
if (key == "ResourceType") {
resourceType = cellValue[key];
}
if (key == "Name") {
name = cellValue[key];
}
};
if (
resourceType == "Project"
|| resourceType == "EntityState"
|| resourceType == "EntityType"
|| resourceType == "Priority"
|| resourceType == "Feature"
|| resourceType == "Epic"
|| resourceType == "UserStory"
|| resourceType == "Program"
|| resourceType == "Release"
|| resourceType == "Iteration"
|| resourceType == "TeamIteration"
) {
entityArray[j] = name;
}
}
}
sheet.appendRow(entityArray);
}
响应中的实体计数
在演示样本中,我们检索前10个匹配的用户故事。 我们在脚本头部编码了查询实体的数量:var takeCount = 10;参数值可 takeCount 增大至1000。 如果查询结果超过1000个实体,则需要编写脚本,通过分页参数多次调用API,随后合并获取的数据。过滤
在与Excel集成时,还可采用更高级的REST API技术(例如过滤、附加字段和集合)。 有关过滤器的更多信息,请参阅Targetprocess REST API过滤器说明。 以下是支持过滤器的源代码修改示例: 在自定义字段中,日期范围为:var filter = '(\'CustomFields.Next Date\' gte \'2017-01-09\') and (\'CustomFields.Next Date\' lte \'2017-01-16\')';
延伸阅读
请使用 Google Apps Script 指南或联系我们的支持团队以获取进一步帮助。注: 替代方案:Zapier目标流程实体也可通过 Zapier连接器与 Google 电子表格文档同步。