ThingWorx Flow > Пакет SDK для ThingWorx Flow > Учебник B. Учебник по SDK соединителей ThingWorx Flow
Учебник B. Учебник по SDK соединителей ThingWorx Flow
Предварительные требования
Ниже перечислены предварительные требования для этого учебника:
LTS-версия Node.js, поддерживаемая установленной версией ThingWorx Flow
Чтобы узнать, какая версия Node.js сейчас используется, откройте Командную строку и выполните следующую команду:
node -v
Интегрированная среда разработки (IDE,·Integrated Development Environment), которая может обрабатывать проекты Node js.
В учебнике в качестве IDE используется WebStorm.
Знакомство с промежуточным уровнем кода Node.js
Папка Samples
* 
Для использования установленных компонентов рекомендуется использовать тот же компьютер, на котором установлено приложение ThingWorx Flow.
Введение 
В учебнике объясняются шаги, необходимые для построения типичного соединителя. Мы построим соединитель для Gmail, поскольку большинство разработчиков, как правило, знакомы с работой Gmail. Знакомство в процессе создания соединителя с применяемыми при этом инструментами, артефактами и процессами поможет вам построить соединитель для собственного приложения. Для построения нового соединителя не требуется развертывать ThingWorx Flow. После построения и локальной проверки соединителя он может быть развернут для проверки в тестовой локальной установке.
Учебник охватывает следующее:
1. Создание проекта соединителя.
2. Конфигурация OAuth2.
3. Создание обзора для поиска с фильтрами, созданными в учетной записи Gmail.
4. Создание действия получения идентификатора и темы сообщений эл. почты, соответствующих выбранному фильтру.
5. Создание триггера, позволяющего инициировать новый процесс при получении новой эл. почты.
6. Добавление значков
7. Развертывание соединителей в локальном экземпляре ThingWorx Flow.
Шаг 1. Создание проекта соединителя 
Соединитель представляет собой специализированный пакет NPM, содержащий различные артефакты, такие как конфигурация OAuth, действия, обзоры, триггеры. Проект должен соответствовать шаблонам построения пакета NPM. Он должен содержать файл package.json, папку lib, папку test и папки для каждого из артефактов и их версий.
Откройте окна terminal/cmd и перейдите в папку, в которой предполагается создать проект нового соединителя. В этом учебнике соединитель будет создаваться в папке c:\test
1. Перейдите в каталог test: cd c:\test
2. Для создания проекта выполните следующую команду: flow init <projectname>
Необходимо просмотреть следующее:
cd c:\test
[2018-10-21T15:35:11.519] [INFO] default - Project gmail created successfully in .
3. Откройте каталог проекта в IDE, чтобы просмотреть артефакты, созданные по умолчанию.
Каждый проект содержит файлы index.js и package.json. Не изменяйте файл index.js, так как этот файл требуется для загрузки соединителей на сервер ThingWorx Flow.
* 
Файл package.json содержит ссылку на ptc-flow-sdk. Без этой зависимости будет невозможно тестировать, развертывать или запускать соединитель. Также предоставляется несколько интерфейсов API, которые облегчают разработку соединителей и делают ее более согласованной.
1. Выполните шаги, приведенные в Учебнике A.
2. Установите пакет async, используя следующую команду:
npm install async
3. Установите модуль request с помощью следующих команд. Модуль запросов содержит интерфейс API для создания запросов HTTP.
npm install request
npm install request-promise
4. Установите модуль lodash, предоставляющий множество полезных функций:
npm install lodash
npm install ptc-flow-sdk@<Версия инструмента> -g
Проверьте <Версию инструмента> для вашей версии ThingWorx здесь.
* 
Все команды в учебнике выполняются из каталога проекта соединителя c:\test\gmail. Это избавляет от необходимости указывать полный путь к каталогу соединителя с использованием опций -d/--projectDir.
Шаг 2. Создание конфигурации OAuth2 
* 
Прежде чем начать, убедитесь, что выполнены все шаги, приведенные в разделе "Конфигурации для тестирования OAuth и триггеров".
Gmail использует для аутентификации OAuth 2.0. Поэтому в примере соединителя в качестве механизма аутентификации используется OAuth 2.0. Все поставщики OAuth2 требуют, чтобы приложение создавало идентификатор клиента и секретный ключ клиента. Тогда приложение может требовать, чтобы пользователи входили в систему поставщика OAuth с помощью этих учетных данных. Пользователь может предоставить приложению разрешения на доступ к данным от своего имени. Разрешения определяются контекстными областями. Пользователь может выборочно предоставить доступ приложению к своим данным. Дополнительные сведения о том, как это реализовано для Gmail и других приложений Google, см. по следующим ссылкам.
Предоставьте URL-адрес перенаправления. URL-адрес перенаправления:
https://<имя_хоста>:<порт>//Thingworx/Oauths/oauth/return, выглядит следующим образом:
https://flow.local.rnd.ptc.com/Thingworx/Oauths/oauth/return
В некоторых системах допускается несколько перенаправлений.
* 
Убедитесь, что используемый вами хост-компьютер добавлен в файл .flow\flow.json, находящийся в домашней папке пользователя. Если это не фактическое имя хост-компьютера, а псевдоним для локального хост-компьютера, добавьте его в файл hosts операционной системы. Пример файла flow.json приведен ниже.
{
"hostname": "localhost",
"port":443
}
Значением hostname должно быть localhost.
Значением port является номер порта хост-компьютераThingWorx Flow. По умолчанию: 443.
Например:
1. В Windows щелкните правой кнопкой мыши редактор и выберите "Запуск от имени администратора".
2. Измените файл hosts в папке c:\windows\system32\drivers\etc\hosts, добавив или изменив в нем запись следующим образом:
127.0.0.1 flow.local.rnd.ptc.com
где flow.local.rnd.ptc.com следует заменить на псевдоним.
После завершения предыдущих шагов будет создано приложение с идентификатором клиента и секретным ключом клиента для приложения.
1. Создайте конфигурацию OAuth с помощью следующей команды.
c:\test\gmail>flow add oauth gmail
[2018-10-21T16:26:54.398] [INFO] add-oauth - Oauth configuration gmail added successfully.
Эта команда создает папку \auth\oauth\gmail-gmail в папке проекта. Папка будет содержать единственный файл config.json.
В данном случае файл config.json - это шаблон, который должен быть настроен для работы с конкретным поставщиком OAuth, например с Google.
2. Откройте этот файл в текстовом редакторе или IDE и внесите следующие изменения. Убедитесь, что файл отредактирован правильно и остается допустимым файлом JSON.
3. Задайте категорию, имя, название и значки. Сведения о создании и настройке значков см. в разделе Добавление значков в соединитель ниже.
4. Выполните поиск ключа oauth2_params_other и замените его значение на
[
"{\"access_type\":\"offline\"}"
]
5. Выполните поиск ключа oauth2_params_scope и замените его значение на следующий массив JSON:
[
"{\"https://www.googleapis.com/auth/gmail.labels\":\"Manage mailbox labels\"}",
"{\"https://www.googleapis.com/auth/gmail.insert\":\"Insert mail into your mailbox\"}",
"{\"https://www.googleapis.com/auth/gmail.modify\":\"All read/write operations except immediate, permanent deletion of threads and messages, bypassing Trash.\"}",
"{\"https://www.googleapis.com/auth/gmail.readonly\":\"Read all resources and their metadata—no write operations.\"}",
"{\"https://www.googleapis.com/auth/gmail.compose\":\"Create, read, update, and delete drafts. Send messages and drafts.\"}",
"{\"https://www.googleapis.com/auth/gmail.send\":\"Send email on your behalf\"}"
]
Обратите внимание на значение env_local_params. Здесь local представляет наименование среды. Существует пять возможных сред, которые могут быть представлены ключами env_production_params, env_pre_prod_params, env_staging_params, env_local_params. Значения должны иметь следующий формат: {{{local.CLIENT_SECRET}}}. local.CLIENT_SECRET - это переменная, которая замещает наименование среды. Перед ней должно быть три таких открывающих, а после нее - три закрывающих скобки. Эти значения заменяются предоставленными клиентом значениями при выполнении сервиса LoadOAuthConfiguration в ThingWorx Composer для загрузки OAuth на сервер ThingWorx Flow. Эти значения указываются в файле JSON. Соответствующее значение подставляется при генерации конфигурации OAuth только для среды, в которой выполняется сервер ThingWorx Flow. Если на сервере задана переменная среды NODE_ENV для производства, производственное значение CLIENT_SECRET заполняется значениями, предоставленными в файле данных OAuth. Это позволяет настраивать конфигурацию OAuth для развертывания, выполняемого каждым потребителем.
6. Найдите параметр base_url и замените его значение на https://accounts.google.com/o/oauth2.
7. Найдите параметр oauth2_auth_url и замените его значение на /auth.
Шаг 3. Тестирование конфигурации OAuth 
Можно выполнить тестирование конфигурации OAuth до ее развертывания. Для этого интерфейс командной строки (CLI) ThingWorx Flow запускает браузер, предоставляющий возможность выполнить вход на сайт поставщика OAuth с использованием ваших учетных данных. При успешном завершении аутентификации генерируется лексема доступа, которую можно сохранить на диске для дальнейшего использования. Также можно выполнить тестирование каждой конфигурации развертывания, выбрав соответствующую конфигурацию в окне встроенного браузера Chrome.
Прежде чем можно будет выполнить команду тестирования, необходимо создать файл данных теста, содержащий фактические значения идентификатора клиента и ключа, которые будут подставлены вместо формальных параметров env_<наименование-среды>_params, как было описано выше. Для этого создайте новый файл JSON с именем testOauthData.json в папке c:\test и добавьте в него следующее содержимое.
{
"gmail-gmail": {
"Test Gmail Oauth": {
"CLIENT_ID": "<your-client-id-here>"
"CLIENT_SECRET": ""<your-client-secret-here>"
}
}
}
Убедитесь, что вы заменяете <your-client-id-here> и <your-client-secret-here> на значения, ранее загруженные из консоли Google.
Затем убедитесь, что файл .flow\flow.json, содержащийся в домашней папке пользователя, содержит правильные имя хост-компьютера, порт и идентификационную фразу сертификата. Это требуется только в том случае, если при создании самозаверяющегося сертификата было предоставлено одно из этих значений.
Выполните следующую команду из командной строки: set FLOW_ALLOW_UNTRUSTED_CERTIFICATES=true
Эта переменная является обязательной, поскольку для выполнения данного инструмента будет использоваться самоподписанный сертификат.
1. Для тестирования OAuth выполните следующую команду:
flow test oauth gmail-gmail -f ..\testOauthData.json -t "Test Gmail Oauth"
2. Выберите конфигурацию для тестирования и щелкните "Проверить конфигурацию Oauth".
3. Выберите контекстные области, к которым нужно разрешить доступ приложению, и щелкните Разрешить.
4. Введите имя пользователя для учетной записи Google. Она может быть любой учетной записью Google и не обязательно должна использоваться для создания ИД клиента и секретного ключа клиента.
5. Введите пароль. При успешном завершении аутентификации вы увидите лексему доступа.
6. Щелкните Сохранить и выйти, чтобы сохранить лексему доступа для будущего использования.
В консоли появляется следующее сообщение:
[2018-10-22T12:51:07.643] [INFO] oauth - Access token saved with ID :664ec37a-9720-460c-8536-fbf372198cb1
Идентификатор из этого сообщения будет использоваться для тестирования других артефактов, зависящих от лексемы доступа, таких как обзоры, действия и триггеры. Созданный выше идентификатор необходимо указывать во всех командах тестирования, используя опцию -a/--access_token.
* 
Если появляется сообщение об ошибке, например "Redirect URI mismatch", необходимо убедиться в правильности конфигурации flow.json и в том, что URL-адрес, используемый интерфейсом командной строки в программе Flow, соответствует URL-адресу, зарегистрированному в Google. URL-адрес перенаправления, используемый интерфейсом командной строки в программе Flow, печатается на консоли при запуске тестирования.
Например, [2018-10-22T11:07:53.868] [INFO] oauthServer- сервер запущен, а адрес redirect_uri, используемый для oauth, равен https://flow.local.rnd.ptc.com:443/Thingworx/Oauths/oauth/return
* 
Действие лексем доступа OAuth является кратковременным, перед использованием лексемы доступа для тестирования действия, обзора или триггера необходимо выполнить команду тестирования Flow в OAuth для регенерации новой лексемы.
Шаг 4. Создание обзора 
Обзоры представляют собой механизм поиска. Они обычно используются для динамического получения списка опций для некоторых полей входных данных для действий или триггеров. Например, сообщения электронной почты в Gmail могут иметь связанные с ними метки. Это помогает быстро находить связанные сообщения эл. почты, которые все помечены тегом с использованием данной метки. Однако конечный пользователь вряд ли будет помнить наименования всех меток, созданных в его учетной записи. Обзор, который будет здесь создан, должен генерировать пары идентификатор-значение для меток, обнаруженных в учетной записи Gmail. Затем некоторые из них можно использовать для получения идентификатора и темы из сообщений эл. почты с такими же метками.
Для обзоров не существует метаданных - они представлены одним файлом index.js. Также для них не создается версий. В файле index.js может существовать любое число методов обзора.
Чтобы создать обзор, выполните следующую команду:
c:\test\gmail>flow add lookup
[2018-10-22T14:41:52.298] [INFO] add-lookup - Lookup added successfully
При выполнении этой команды будет сгенерирован файл index.js в папке lookup\gmail.
Откройте файл index.js в IDE и добавьте в него приведенный ниже код.
В верхней части файла импортируйте следующие модули.
const async = require('async')
const request = require('request')
const logger = require('ptc-flow-sdk').getLogger('gmail-lookup')
Скопируйте приведенный ниже код после всего кода, находящегося в файле.

gmailAPIs.getLabels = function (input, options, output) {
logger.debug('Trying to fetch labels')
// Gmail API to fetch th labels in the gmail account
options.url = 'https://www.googleapis.com/gmail/v1/users/me/labels'
// Validating that the authorization is done and we have a access_token to //make a request else throw the error
options.validateDependencies(input.access_token, function (err, status) {
if (err) {
return output({
error: err
})
}
// If the authorization is proper then execute the request
execute(input, options, output)
})
}
// common function for api to execute the request module
function execute (input, options, output) {
async.waterfall([
function (cb) {
// In input we get auth code which we can use to get access token
getAccessToken(input, options, cb)
}
], function (err, accessToken) {
if (err) {
return output({
error: err
})
} else {
// Execute the request to get the labels from the gmail api
requestExecute(input, accessToken, options, output)
}
})
}
// Extract the acces_token from the input and return it
function getAccessToken (input, options, cb) {
options.getAccessToken(input.access_token, function (err, oauth) {
if (err) {
cb(err)
} else {
oauth = JSON.parse(oauth)
cb(null, oauth.access_token)
}
})
}
// Make a request to the gmail url to get the labels
function requestExecute (input, accessToken, options, output) {
request({
method: 'GET',
headers: {
'Authorization': 'Bearer ' + accessToken,
'Content-Type': 'application/json'
},
url: options.url
}, function (err, res, body) {
let result = []
if (err) {
return output({
error: err
})
}
if (res.statusCode === 401) {
return output({
error: 'Your access token is Invalid or Expired'
})
}
if (res.statusCode >= 200 && res.statusCode < 400) {
if (typeof (body) === 'string') {
body = JSON.parse(body)
}
result = filterResult(body.messages || body.labels || body, input)
var pageDetails = options.getPage(result, input, options)
var data = {
'results': result.slice(pageDetails.page, (pageDetails.page + options.maxResults))
}
data.next_page = options.getNextPage(data.results.length >= options.maxResults)
return output(null, data)
}
return output({
error: body
})
})
}
// filter result on the basis of output demand
function filterResult (body, input) {
var result = []
if (body && Array.isArray(body)) {
body.forEach(function (item, index) {
result.push({
'id': String(item.name),
'value': item.name
})
})
}
return result
}
Для тестирования обзора выполните следующие команды:
1. Получите новую лексему доступа с помощью следующей команды:
flow test oauth gmail-gmail -f ..\testOauthData.json -t "Test Gmail Oauth"
2. Сохраните лексему и выполните выход.
3. Проверьте обзор с помощью следующей команды:
flow test lookup gmail getLabels -a cecd33a3-8a33-4c0c-b298-178fd80a9261 -l trace. Теперь следует просмотреть выходные данные, созданные обзором. Выходные данные представляют массив JSON, содержащий идентификаторы и значения.
Шаг 5. Создание и тестирование действия 
Для выполнения некоторых операций действие взаимодействует с внешней подключенной системой. Обычно это операция создания, удаления, обновления или чтения. Действия получают входные данные и производят некоторые выходные данные. Входные данные и выходные данные, произведенные действием, должны быть определены в файле action.json. Свойства входа и вывода описываются специальной схемой JSON, используемой для рендеринга формы ввода, а схема вывода используется для рендеринга пользовательского интерфейса сопоставления. Другие полезные свойства включают тег и значок, используемые для группирования действий и отображения значка для действия в интерфейсе пользователя.
Чтобы создать новое действие, выполните команду
c:\test\gmail>flow add action get-messages
[2018-10-22T16:26:53.925] [INFO] add-action - Action get-messages, version v1 added successfully
Затем откройте файл action.json (C:\test\gmail\action\gmail-get-messages\v1\action.json) в IDE.
Задайте для свойств ввода и значка значение Gmail. Схема JSON свойства ввода показана в следующем коде:
Set the input property to {
"title": "Get email messages",
"type": "object",
"properties": {
"auth": {
"title": "Authorize gmail",
"type": "string",
"oauth": "gmail-gmail",
"minLength": 1
},
"label": {
"title": "Label",
"type": "string",
"minLength": 1,
"lookup": {
"id": "getLabels",
"service": "gmail",
"enabled": true,
"searchable": false,
"auth": "oauth",
"dependencies": [
"auth"
]
}
}
}
}
Схема ввода определяет одно поле входных данных. Это список, поскольку имеется указанный для него обзор. После выполнения обзора в компоновщике процесса возвращаемые значения отображаются в списке. Обратите внимание на способ описания зависимостей обзора. Это сообщает системе, что поле аутентификации должно быть заполнено перед вызовом обзора.
Свойство auth описывает метод аутентификации, используемый в этом действии. В этом случае мы используем конфигурацию OAuth для Gmail.
Set the “output” property to {
"messages": {
"title": "Messages",
"type": "array",
"items": {
"type": "object",
"properties": {
"messageId": {
"type": "string",
"title": "Message Detail ID"
},
"subject": {
"type": "string",
"title": "Message Detail Sub"
}
}
}
}
}
* 
Выходные данные, получающиеся в результате этого действия, представляют собой массив JSON объектов JSON. Каждый объект должен содержать поля messageId и subject.
Откройте файл index.js в IDE. В верхнюю часть файла добавьте следующий код:
const rp = require('request-promise')
const logger = require('ptc-flow-sdk').getLogger('gmail-get-messages')
Замените метод выполнения следующим кодом:
this.execute = function (input, output) {
// Create a request header to get messages under a label selected from
const options = {
method: 'GET',
url: 'https://www.googleapis.com/gmail/v1/users/me/messages',
useQuerystring: true,
qs: {labelIds: ['STARRED']},
headers:
{
'Authorization': 'Bearer ' + input.auth,
'Content-Type': 'application/json'
}
}
rp(options).then((rawData) => {
const data = JSON.parse(rawData)
let mailRequests = []
if (data && data.messages) {
data.messages.forEach((msg) => {
mailRequests.push(this.fetchMessage(msg.id, input.auth))
})
return Promise.all(mailRequests)
} else {
logger.warn('No messages found')
Promise.resolve()
}
}).then((results) => {
if (results) {
let arr = []
results.forEach((result) => {
let resData = JSON.parse(result)
let msgHeader = resData.payload.headers.find(header => header.name === 'Subject')
arr.push({messageId: resData.id, subject: msgHeader ? msgHeader.value : 'No subject'})
})
return output(null, {messages: arr})
} else {
return output(null)
}
}).catch(err => {
return output(err)
})
}
Добавьте новый метод, приведенный ниже:
this.fetchMessage = function (msgId, authToken) {
const options = {
method: 'GET',
url: 'https://www.googleapis.com/gmail/v1/users/me/messages/' + msgId,
qs: { format: 'metadata', metadataHeaders: 'Subject' },
headers:
{
'Authorization': 'Bearer ' + authToken,
'Content-Type': 'application/json'
}
}
return rp(options)
}
Убедитесь, что файл является допустимым файлом JavaScript.
1. Получите снова лексему доступа, выполнив следующие шаги.
Задайте FLOW_ALLOW_UNTRUSTED_CERTIFICATES=true.
Выполните следующую команду и отметьте идентификатор, который возвращается.
flow test oauth gmail-gmail -f ..\testOauthData.json -t "Test Gmail Oauth"
2. Создайте новый файл Javascript C:\test\gmail\test\actionTestData.js, добавьте в него следующий код и сохраните его.
module.exports = {
testInput: {
label: 'STARRED'//use a label that applies to a few emails.
},
testOutputFn: function (input, actualOutput) {
// validate the actualOutput against expected output
// return a rejected promise to fail the validation or a resolved promise for success
// return Promise.reject(new Error('Validation successful'))
return Promise.reject(new Error('Validation failed'))
}
}
* 
Параметры -i/--input и -o/--output принимают данные или функцию, которые возвращают объект promise.
При выполнении на сервере метка является частью входного параметра и может быть доступна как input.label. Утилита тестирования не выполняет обзор, поэтому выходные данные обзора должны передаваться в нее.
3. Выполните следующую тестовую команду:
C:\test\gmail>flow test action gmail-get-messages -a 685b7377-7000-
4a92-8679-8630c68a3265 -l debug -i testInput -f
C:\test\gmail\test\actionTestData.js -o testOutput
The test run should succeed.
Шаг 6. Создание и тестирование триггера опроса 
1. Чтобы создать новый триггер опроса, выполните следующую команду:
flow add trigger -p
[2019-02-28T17:03:23.823] [INFO] add-trigger - Trigger gmail, version v1 added successfully
2. В интерфейсе IDE откройте файл trigger.json, расположенный в C:\test\gmail\trigger\poll\gmail\v1\trigger.json.
3. Задайте свойство icon для Gmail следующим образом:
"icon": "gmail",
4. Задайте свойства ввода и вывода.

Set the input property to
{
"properties": {
"auth": {
"type": "string",
"title": "Authorize gmail",
"minLength": 1,
"oauth": "gmail-gmail",
"propertyOrder": 1
},
"search": {
"type": "string",
"title": "Search Text",
"propertyOrder": 2,
"description": "Enter the search text to search for a specific email. E.g., from:john or subject:Christmas"
},
"customFilters": {
"type": "array",
"propertyOrder": 5,
"title": "Custom Filters",
"items": {
"type": "object",
"title": "Filter",
"properties": {
"input": {
"type": "string",
"title": "Input",
"minLength": 1
},
"operator": {
"type": "string",
"title": "Condition",
"enum": [
"Equals",
"GreaterThan"
],
"enumNames": [
"Equals",
"Greater Than"
]
},
"expected": {
"type": "string",
"title": "Expected",
"minLength": 1
}
}
}
}
},
"oneOf": [
{
"type": "object",
"title": "New Email",
"description": "Triggers when a new email is received",
"properties": {
"event": {
"type": "string",
"readonly": true,
"enum": [
"new_mail"
],
"options": {
"hidden": true
},
"propertyOrder": 3
},
"label": {
"type": "string",
"title": "Label",
"propertyOrder": 4,
"description": "Select a label for which you wish to set a trigger. E.g., If you select label as ‘Trash’, the trigger will fire off every time a new mail is moved to label named ‘Trash’ in your Gmail account."
}
}
},
{
"type": "object",
"title": "New Attachment",
"description": "Triggers when a new attachment is received",
"properties": {
"event": {
"type": "string",
"readonly": true,
"enum": [
"new_attachment"
],
"options": {
"hidden": true
},
"propertyOrder": 3
},
"label": {
"type": "string",
"title": "Label",
"propertyOrder": 4,
"description": "Select a label for which you wish to set a trigger. E.g., If you select label as ‘Trash’, the trigger will fire off every time a new mail is moved to label named ‘Trash’ in your Gmail account."
}
}
}
]
}
Схема ввода определяет одно поле входных данных. Объект oneOf определяет события, поддерживаемые триггером. В приведенной выше схеме определены два события триггера:
Новая эл. почта
Новое вложение
Свойство аутентификации описывает метод аутентификации, используемый этим триггером. В этом случае мы используем конфигурацию OAuth для Gmail.
Set the “output” property to
{
"new_mail": {
"type": "object",
"properties": {
"messageId": {
"type": "string",
"title": "ID",
"displayTitle": "ID"
},
"subject": {
"title": "Subject",
"displayTitle": "Subject",
"type": "string"
}
}
},
"new_attachment": {
"type": "object",
"properties": {
"attachments": {
"title": "Attachments",
"displayTitle": "Attachments",
"type": "array",
"items": {
"type": "object",
"properties": {
"mimeType": {
"title": "Mime Type",
"displayTitle": "Mime Type",
"type": "string"
},
"filename": {
"title": "File Name",
"displayTitle": "File Name",
"type": "string"
},
"attachmentId": {
"title": "Attachment ID",
"displayTitle": "Attachment ID",
"type": "string"
}
}
}
}
}
}
}
В приведенной выше схеме вывода определены выходные свойства для двух событий триггера, определенных в схеме ввода для триггера.
1. Откройте файл index.js в интерфейсе IDE и добавьте следующий код в начало файла:
const rp = require('request-promise')
const logger = require('ptc-flow-sdk').getLogger('gmail-trigger')
2. Замените метод выполнения следующим кодом:
Trigger.execute = function (input, options, output) {
// Create a request header to get messages under a label selected from
var date = new Date(options.unixTime * 1000)
const httpOpts = {
method: 'GET',
url: 'https://www.googleapis.com/gmail/v1/users/me/messages',
useQuerystring: true,
qs: { q: 'newer:' + date.getFullYear() + '/' + date.getMonth() + '/' + date.getDay() },
headers:
{
'Authorization': 'Bearer ' + input.auth,
'Content-Type': 'application/json'
}
}
rp(httpOpts).then((rawData) => {
const data = JSON.parse(rawData)
let mailRequests = []
if (data && data.messages) {
data.messages.forEach((msg) => {
mailRequests.push(this.fetchMessage(msg.id, input.auth))
})
return Promise.all(mailRequests)
} else {
logger.warn('No messages found')
Promise.resolve()
}
}).then((results) => {
if (results) {
let arr = []
results.forEach((result) => {
let resData = JSON.parse(result)
let msgHeader = resData.payload.headers.find(header => header.name === 'Subject')
arr.push({ messageId: resData.id, subject: msgHeader ? msgHeader.value : 'No subject' })
})
return output(null, { messages: arr })
} else {
return output(null)
}
}).catch(err => {
return output(err)
})
}
3. Добавьте новый метод, приведенный ниже:
Trigger.fetchMessage = function (msgId, authToken) {
const options = {
method: 'GET',
url: 'https://www.googleapis.com/gmail/v1/users/me/messages/' + msgId,
qs: { format: 'metadata', metadataHeaders: 'Subject' },
headers:
{
'Authorization': 'Bearer ' + authToken,
'Content-Type': 'application/json'
}
}
return rp(options)
}
* 
Убедитесь, что файл является допустимым файлом JavaScript.
Шаг 7. Получение лексемы доступа 
Чтобы снова получить лексему доступа, выполните следующие действия.
1. Задайте следующее свойство: FLOW_ALLOW_UNTRUSTED_CERTIFICATES=true
2. Выполните следующую команду и отметьте идентификатор, который возвращается.
flow test oauth gmail-gmail -f ..\testOauthData.json -t "Test Gmail Oauth"
3. Выполните следующую тестовую команду:
flow test trigger gmail execute -p -e new_mail -a e0d56340-2fc4-4618-931c-ad6c983ae0e5 --stopAfter 1 --unixTime 1551312000
Шаг 8. Добавление значков в соединитель 
1. Создайте папку common в проекте соединителя.
2. В папке common создайте папку с именем css
3. Добавьте файл JSON, имеющий следующий формат:
{ "name": "connector-name",
"background": "#FFFFFF",
"png128pxBase64": "base64encodedbinarydata"
}
Свойство name должно обозначать наименование соединителя и должно соответствовать свойству icon действий в их файлах metadata json.
Фон должен быть представлен шестнадцатеричным кодом цвета, как показано в примере.
Изображения значка должны иметь формат PNG, а двоичные данные должны иметь кодировку base64. Дополнительную информацию о преобразовании PNG в его закодированное двоичное представление base64 ищите в Интернете.
Было ли это полезно?