Add uProc Node (#1263)

* + adding new uProc integration

* + capitalize tool name
+ fix parameter display name
+ add placeholders for parameter
+ add tool description
+ optimize generated .ts for groups and tools

* + remove old functions

* + added new tools

* + add new tools + fix Info on tool

* + fixed Info

* + fix tools description

* + add UProc node to package.json

* + added new tools

* + added new tools

* + fix tool description

* + fix CamelCase subtitle
+ fix node displayName
+ add new tools

* + fix info link

* + add start, data and end callbacks to decouple response

* + added new tools

* + change display name on selected

* + added new tools

* + added new tools

* + added new tools

* + added new tools

* + remove old folder + fix param

* + added new tools

*  Some improvements to uproc Node

* 🐛 Fix docker image naming #1250

Co-authored-by: Miquel Colomer <mcolomer@gmail.com>
This commit is contained in:
Jan
2020-12-19 18:22:41 +01:00
committed by GitHub
parent aafbe5af40
commit 63452e7878
13 changed files with 418 additions and 8 deletions

View File

@@ -28,7 +28,7 @@ jobs:
- name: Push docker images of latest - name: Push docker images of latest
run: docker push n8nio/n8n:latest run: docker push n8nio/n8n:latest
- name: Build the Docker image of version (Ubuntu) - name: Build the Docker image of version (Debian)
run: docker build --build-arg N8N_VERSION=${{steps.vars.outputs.tag}} -t n8nio/n8n:${{steps.vars.outputs.tag}}-ubuntu docker/images/n8n-ubuntu run: docker build --build-arg N8N_VERSION=${{steps.vars.outputs.tag}} -t n8nio/n8n:${{steps.vars.outputs.tag}}-debian docker/images/n8n-debian
- name: Push Docker image of version (Ubuntu) - name: Push Docker image of version (Debian)
run: docker push n8nio/n8n:${{steps.vars.outputs.tag}}-ubuntu run: docker push n8nio/n8n:${{steps.vars.outputs.tag}}-debian

View File

@@ -1,6 +1,6 @@
## n8n - Ubuntu Docker Image ## n8n - Debian Docker Image
Dockerfile to build n8n with Ubuntu. Dockerfile to build n8n with Debian.
For information about how to run n8n with Docker check the generic For information about how to run n8n with Docker check the generic
[Docker-Readme](https://github.com/n8n-io/n8n/tree/master/docker/images/n8n/README.md) [Docker-Readme](https://github.com/n8n-io/n8n/tree/master/docker/images/n8n/README.md)
@@ -10,12 +10,12 @@ For information about how to run n8n with Docker check the generic
docker build --build-arg N8N_VERSION=<VERSION> -t n8nio/n8n:<VERSION> . docker build --build-arg N8N_VERSION=<VERSION> -t n8nio/n8n:<VERSION> .
# For example: # For example:
docker build --build-arg N8N_VERSION=0.43.0 -t n8nio/n8n:0.43.0-ubuntu . docker build --build-arg N8N_VERSION=0.43.0 -t n8nio/n8n:0.43.0-debian .
``` ```
``` ```
docker run -it --rm \ docker run -it --rm \
--name n8n \ --name n8n \
-p 5678:5678 \ -p 5678:5678 \
n8nio/n8n:0.43.0-ubuntu n8nio/n8n:0.43.0-debian
``` ```

View File

@@ -0,0 +1,23 @@
import {
ICredentialType,
NodePropertyTypes,
} from 'n8n-workflow';
export class UProcApi implements ICredentialType {
name = 'uprocApi';
displayName = 'uProc API';
properties = [
{
displayName: 'Email',
name: 'email',
type: 'string' as NodePropertyTypes,
default: '',
},
{
displayName: 'API Key',
name: 'apiKey',
type: 'string' as NodePropertyTypes,
default: '',
},
];
}

View File

@@ -0,0 +1,47 @@
import {
OptionsWithUri,
} from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
IHookFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import {
IDataObject,
} from 'n8n-workflow';
export async function uprocApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
const credentials = this.getCredentials('uprocApi');
if (credentials === undefined) {
throw new Error('No credentials got returned!');
}
const token = Buffer.from(`${credentials.email}:${credentials.apiKey}`).toString('base64');
const options: OptionsWithUri = {
headers: { Authorization: `Basic ${token}` },
method,
qs,
body,
uri: uri || `https://api.uproc.io/api/v2/process`,
json: true,
};
try {
return await this.helpers.request!(options);
} catch (error) {
if (error.statusCode === 403) {
// Return a clear error
throw new Error('The uProc credentials are not valid!');
}
if (error.response.body && error.response.body.error && error.response.body.error.message) {
// Try to return the error prettier
throw new Error(`uProc Error [${error.statusCode}]: ${error.response.body.error.message}`);
}
// If that data does not exist for some reason return the actual error
throw new Error('uProc Error: ' + error.message);
}
}

View File

@@ -0,0 +1,34 @@
import {
IDataObject,
INodeProperties,
} from 'n8n-workflow';
import {
groups,
} from './Json/Groups';
const finalGroups = {
displayName: 'Resource',
name: 'group',
type: 'options',
default: 'communication',
description: 'The Resource to consume.',
options: [],
};
const options = [];
for (const group of (groups as IDataObject).groups as IDataObject[]) {
const item = {
name: group.translated,
value: group.name,
description: 'The ' + group.translated + ' Resource allows you to get tools from this resource',
};
options.push(item);
}
//@ts-ignore
finalGroups.options = options;
const mappedGroups = [finalGroups];
export const groupOptions = mappedGroups as INodeProperties[];

View File

@@ -0,0 +1,36 @@
export const groups = {
groups: [{
"translated": "Audio",
"name": "audio",
}, {
"translated": "Communication",
"name": "communication",
}, {
"translated": "Company",
"name": "company",
}, {
"translated": "Finance",
"name": "finance",
}, {
"translated": "Geographical",
"name": "geographic",
}, {
"translated": "Image",
"name": "image",
}, {
"translated": "Internet",
"name": "internet",
}, {
"translated": "Personal",
"name": "personal",
}, {
"translated": "Product",
"name": "product",
}, {
"translated": "Security",
"name": "security",
}, {
"translated": "Text",
"name": "text",
}],
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,124 @@
import {
IDataObject,
INodeProperties,
} from 'n8n-workflow';
import {
groups,
} from './Json/Groups';
import {
tools,
} from './Json/Tools';
function capitalize(str: string): string {
if (!str) {
return '';
} else {
return str.charAt(0).toUpperCase() + str.slice(1);
}
}
const operations = [];
for (const group of (groups as IDataObject).groups as IDataObject[]) {
const item = {
displayName: 'Operation',
name: 'tool',
type: 'options',
description: 'The Operation to consume.',
displayOptions: {
show: {
group: [
group.name,
],
},
},
default: '',
options: [],
};
const options = [];
for (const tool of (tools as IDataObject).processors as IDataObject[]) {
if (tool.g === group.name) {
const link = 'https://app.uproc.io/#/tools/processor/' + (tool.k as string).replace(/([A-Z]+)/g, '-$1').toLowerCase().replace('-', '/').replace('-', '/');
const option = {
name: tool.d as string,
value: tool.k,
description: (tool.ed as string) + ` <a href="${link}" target='_blank'>Info</a>`,
};
options.push(option);
}
}
//Tool
item.options = (options.sort((a, b) => (a.name > b.name) ? 1 : -1) as any); // tslint:disable-line:no-any
item.default = (options[0].value as string);
operations.push(item);
}
export const toolOperations = operations as INodeProperties[];
let parameters = [];
//all tools
for (const tool of (tools as IDataObject).processors as IDataObject[]) {
//all parameters in tool
for (const param of (tool as IDataObject).p as IDataObject[]) {
const displayName = param.n as string;
const capitalizedDisplayName = capitalize(displayName.replace(/_/g, ' '));
const description = `The "${capitalizedDisplayName}" value to use as a parameter for this Operation`;
const parameter = {
displayName: capitalizedDisplayName,
name: param.n,
type: param.t,
default: '',
placeholder: param.p,
required: param.r,
options: param.o,
displayOptions: {
show: {
group: [
//@ts-ignore
tool.g,
],
tool: [
tool.k,
],
},
},
description: JSON.parse(JSON.stringify(description)),
};
let modifiedParam = null;
//Check if param exists previously
for (const currentParam of parameters) {
//Get old param in parameters array
if (currentParam.name === param.n) {
modifiedParam = currentParam;
}
}
//if exists, other wise
if (modifiedParam) {
//Assign new group and tool
//@ts-ignore
modifiedParam.displayOptions.show.group.push(tool.g);
modifiedParam.displayOptions.show.tool.push(tool.k);
//build new array
const newParameters = [];
for (const currentParam of parameters) {
//Get old param in parameters array
if (currentParam.name === modifiedParam.name) {
newParameters.push(modifiedParam);
} else {
newParameters.push(currentParam);
}
}
parameters = JSON.parse(JSON.stringify(newParameters));
} else {
parameters.push(parameter);
}
}
}
export const toolParameters = parameters as INodeProperties[];

View File

@@ -0,0 +1,143 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import {
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import {
uprocApiRequest,
} from './GenericFunctions';
import {
groupOptions,
} from './GroupDescription';
import {
toolOperations,
toolParameters,
} from './ToolDescription';
export class UProc implements INodeType {
description: INodeTypeDescription = {
displayName: 'uProc',
name: 'uproc',
icon: 'file:uproc.png',
group: ['output'],
version: 1,
subtitle: '={{$parameter["tool"]}}',
description: 'Consume uProc API',
defaults: {
name: 'uProc',
color: '#219ef9',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'uprocApi',
required: true,
},
],
properties: [
...groupOptions,
...toolOperations,
...toolParameters,
{
displayName: 'Additional Options',
name: 'additionalOptions',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
group: [
'audio',
'communication',
'company',
'finance',
'geographic',
'image',
'internet',
'personal',
'product',
'security',
'text',
],
},
},
options: [
{
displayName: 'Data Webhook',
name: 'dataWebhook',
type: 'string',
description: 'URL to send tool response when tool has resolved your request. You can create your own webhook at <a href="https://beeceptor.com" target="_blank">Beeceptor</a>, <a href="https://www.integromat.com/" target="_blank">Integromat</a>, <a href="https://zapier.com/" target="_blank">Zapier</a> or <a href="https://n8n.io/" target="_blank">n8n</a>',
default: '',
},
],
},
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: IDataObject[] = [];
const length = items.length as unknown as number;
let responseData;
const group = this.getNodeParameter('group', 0) as string;
const tool = this.getNodeParameter('tool', 0) as string;
const additionalOptions = this.getNodeParameter('additionalOptions', 0) as IDataObject;
const dataWebhook = additionalOptions.dataWebhook as string;
interface LooseObject {
[key: string]: any; // tslint:disable-line:no-any
}
const fields = toolParameters.filter((field) => {
return field && field.displayOptions && field.displayOptions.show && field.displayOptions.show.group && field.displayOptions.show.tool &&
field.displayOptions.show.group.indexOf(group) !== -1 && field.displayOptions.show.tool.indexOf(tool) !== -1;
}).map((field) => {
return field.name;
});
const requestPromises = [];
for (let i = 0; i < length; i++) {
const toolKey = tool.replace(/([A-Z]+)/g, '-$1').toLowerCase();
const body: LooseObject = {
processor: toolKey,
params: {},
};
fields.forEach((field) => {
if (field && field.length) {
const data = this.getNodeParameter(field, i) as string;
body.params[field] = data + '';
}
});
if (dataWebhook && dataWebhook.length) {
body.callback = {};
}
if (dataWebhook && dataWebhook.length) {
body.callback.data = dataWebhook;
}
//Change to multiple requests
responseData = await uprocApiRequest.call(this, 'POST', body);
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else {
returnData.push(responseData as IDataObject);
}
}
return [this.helpers.returnJsonArray(returnData)];
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -219,6 +219,7 @@
"dist/credentials/TwakeServerApi.credentials.js", "dist/credentials/TwakeServerApi.credentials.js",
"dist/credentials/UnleashedSoftwareApi.credentials.js", "dist/credentials/UnleashedSoftwareApi.credentials.js",
"dist/credentials/UpleadApi.credentials.js", "dist/credentials/UpleadApi.credentials.js",
"dist/credentials/UProcApi.credentials.js",
"dist/credentials/VeroApi.credentials.js", "dist/credentials/VeroApi.credentials.js",
"dist/credentials/VonageApi.credentials.js", "dist/credentials/VonageApi.credentials.js",
"dist/credentials/WebflowApi.credentials.js", "dist/credentials/WebflowApi.credentials.js",
@@ -456,6 +457,7 @@
"dist/nodes/Twake/Twake.node.js", "dist/nodes/Twake/Twake.node.js",
"dist/nodes/UnleashedSoftware/UnleashedSoftware.node.js", "dist/nodes/UnleashedSoftware/UnleashedSoftware.node.js",
"dist/nodes/Uplead/Uplead.node.js", "dist/nodes/Uplead/Uplead.node.js",
"dist/nodes/UProc/UProc.node.js",
"dist/nodes/Vero/Vero.node.js", "dist/nodes/Vero/Vero.node.js",
"dist/nodes/Vonage/Vonage.node.js", "dist/nodes/Vonage/Vonage.node.js",
"dist/nodes/Webflow/WebflowTrigger.node.js", "dist/nodes/Webflow/WebflowTrigger.node.js",