mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-10 06:34:05 -08:00
Merge branch 'master' into feature/clearbit-node
This commit is contained in:
commit
2f3c4d2a32
|
@ -17,7 +17,7 @@ received or lost a star.
|
|||
|
||||
## Available integrations
|
||||
|
||||
n8n has 80+ different nodes to automate workflows. The list can be found on: [https://n8n.io/nodes](https://n8n.io/nodes)
|
||||
n8n has 100+ different nodes to automate workflows. The list can be found on: [https://n8n.io/nodes](https://n8n.io/nodes)
|
||||
|
||||
|
||||
## Documentation
|
||||
|
|
|
@ -34,7 +34,7 @@ Slack notification every time a Github repository received or lost a star.
|
|||
|
||||
## Available integrations
|
||||
|
||||
n8n has 50+ different nodes to automate workflows. The list can be found on: [https://n8n.io/nodes](https://n8n.io/nodes)
|
||||
n8n has 100+ different nodes to automate workflows. The list can be found on: [https://n8n.io/nodes](https://n8n.io/nodes)
|
||||
|
||||
|
||||
## Documentation
|
||||
|
|
|
@ -32,7 +32,7 @@ Slack notification every time a Github repository received or lost a star.
|
|||
|
||||
## Available integrations
|
||||
|
||||
n8n has 80+ different nodes to automate workflows. The list can be found on: [https://n8n.io/nodes](https://n8n.io/nodes)
|
||||
n8n has 100+ different nodes to automate workflows. The list can be found on: [https://n8n.io/nodes](https://n8n.io/nodes)
|
||||
|
||||
|
||||
## Documentation
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "n8n",
|
||||
"version": "0.49.0",
|
||||
"version": "0.50.1",
|
||||
"description": "n8n Workflow Automation Tool",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
|
@ -93,10 +93,10 @@
|
|||
"localtunnel": "^2.0.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
"mongodb": "^3.2.3",
|
||||
"n8n-core": "~0.22.0",
|
||||
"n8n-editor-ui": "~0.33.0",
|
||||
"n8n-nodes-base": "~0.44.0",
|
||||
"n8n-workflow": "~0.20.0",
|
||||
"n8n-core": "~0.23.0",
|
||||
"n8n-editor-ui": "~0.34.0",
|
||||
"n8n-nodes-base": "~0.45.1",
|
||||
"n8n-workflow": "~0.21.0",
|
||||
"open": "^7.0.0",
|
||||
"pg": "^7.11.0",
|
||||
"request-promise-native": "^1.0.7",
|
||||
|
|
|
@ -117,22 +117,24 @@ export class ActiveWorkflowRunner {
|
|||
throw new ResponseHelper.ResponseError('The requested webhook is not registred.', 404, 404);
|
||||
}
|
||||
|
||||
const workflowData = await Db.collections.Workflow!.findOne(webhookData.workflowId);
|
||||
if (workflowData === undefined) {
|
||||
throw new ResponseHelper.ResponseError(`Could not find workflow with id "${webhookData.workflowId}"`, 404, 404);
|
||||
}
|
||||
|
||||
const nodeTypes = NodeTypes();
|
||||
const workflow = new Workflow(webhookData.workflowId, workflowData.nodes, workflowData.connections, workflowData.active, nodeTypes, workflowData.staticData, workflowData.settings);
|
||||
|
||||
// Get the node which has the webhook defined to know where to start from and to
|
||||
// get additional data
|
||||
const workflowStartNode = webhookData.workflow.getNode(webhookData.node);
|
||||
const workflowStartNode = workflow.getNode(webhookData.node);
|
||||
if (workflowStartNode === null) {
|
||||
throw new ResponseHelper.ResponseError('Could not find node to process webhook.', 404, 404);
|
||||
}
|
||||
const executionMode = 'webhook';
|
||||
|
||||
const workflowData = await Db.collections.Workflow!.findOne(webhookData.workflow.id!);
|
||||
|
||||
if (workflowData === undefined) {
|
||||
throw new ResponseHelper.ResponseError(`Could not find workflow with id "${webhookData.workflow.id}"`, 404, 404);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
WebhookHelpers.executeWebhook(webhookData, workflowData, workflowStartNode, executionMode, undefined, req, res, (error: Error | null, data: object) => {
|
||||
const executionMode = 'webhook';
|
||||
WebhookHelpers.executeWebhook(workflow, webhookData, workflowData, workflowStartNode, executionMode, undefined, req, res, (error: Error | null, data: object) => {
|
||||
if (error !== null) {
|
||||
return reject(error);
|
||||
}
|
||||
|
@ -202,7 +204,9 @@ export class ActiveWorkflowRunner {
|
|||
const webhooks = WebhookHelpers.getWorkflowWebhooks(workflow, additionalData);
|
||||
|
||||
for (const webhookData of webhooks) {
|
||||
await this.activeWebhooks!.add(webhookData, mode);
|
||||
await this.activeWebhooks!.add(workflow, webhookData, mode);
|
||||
// Save static data!
|
||||
await WorkflowHelpers.saveStaticData(workflow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,8 +218,19 @@ export class ActiveWorkflowRunner {
|
|||
* @returns
|
||||
* @memberof ActiveWorkflowRunner
|
||||
*/
|
||||
removeWorkflowWebhooks(workflowId: string): Promise<boolean> {
|
||||
return this.activeWebhooks!.removeByWorkflowId(workflowId);
|
||||
async removeWorkflowWebhooks(workflowId: string): Promise<void> {
|
||||
const workflowData = await Db.collections.Workflow!.findOne(workflowId);
|
||||
if (workflowData === undefined) {
|
||||
throw new Error(`Could not find workflow with id "${workflowId}"`);
|
||||
}
|
||||
|
||||
const nodeTypes = NodeTypes();
|
||||
const workflow = new Workflow(workflowId, workflowData.nodes, workflowData.connections, workflowData.active, nodeTypes, workflowData.staticData, workflowData.settings);
|
||||
|
||||
await this.activeWebhooks!.removeWorkflow(workflow);
|
||||
|
||||
// Save the static workflow data if needed
|
||||
await WorkflowHelpers.saveStaticData(workflow);
|
||||
}
|
||||
|
||||
|
||||
|
@ -348,7 +363,7 @@ export class ActiveWorkflowRunner {
|
|||
await this.activeWorkflows.add(workflowId, workflowInstance, additionalData, getTriggerFunctions, getPollFunctions);
|
||||
|
||||
if (this.activationErrors[workflowId] !== undefined) {
|
||||
// If there were any activation errors delete them
|
||||
// If there were activation errors delete them
|
||||
delete this.activationErrors[workflowId];
|
||||
}
|
||||
} catch (error) {
|
||||
|
@ -380,16 +395,9 @@ export class ActiveWorkflowRunner {
|
|||
*/
|
||||
async remove(workflowId: string): Promise<void> {
|
||||
if (this.activeWorkflows !== null) {
|
||||
const workflowData = this.activeWorkflows.get(workflowId);
|
||||
|
||||
// Remove all the webhooks of the workflow
|
||||
await this.removeWorkflowWebhooks(workflowId);
|
||||
|
||||
if (workflowData) {
|
||||
// Save the static workflow data if needed
|
||||
await WorkflowHelpers.saveStaticData(workflowData.workflow);
|
||||
}
|
||||
|
||||
if (this.activationErrors[workflowId] !== undefined) {
|
||||
// If there were any activation errors delete them
|
||||
delete this.activationErrors[workflowId];
|
||||
|
|
|
@ -132,7 +132,7 @@ class App {
|
|||
const authIgnoreRegex = new RegExp(`^\/(rest|healthz|${this.endpointWebhook}|${this.endpointWebhookTest})\/?.*$`);
|
||||
|
||||
// Check for basic auth credentials if activated
|
||||
const basicAuthActive = config.get('security.basicAuth.active') as boolean;
|
||||
const basicAuthActive = config.get('security.basicAuth.active') as boolean;
|
||||
if (basicAuthActive === true) {
|
||||
const basicAuthUser = await GenericHelpers.getConfigValue('security.basicAuth.user') as string;
|
||||
if (basicAuthUser === '') {
|
||||
|
@ -1072,7 +1072,16 @@ class App {
|
|||
// Removes a test webhook
|
||||
this.app.delete('/rest/test-webhook/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => {
|
||||
const workflowId = req.params.id;
|
||||
return this.testWebhooks.cancelTestWebhook(workflowId);
|
||||
|
||||
const workflowData = await Db.collections.Workflow!.findOne(workflowId);
|
||||
if (workflowData === undefined) {
|
||||
throw new ResponseHelper.ResponseError(`Could not find workflow with id "${workflowId}" so webhook could not be deleted!`);
|
||||
}
|
||||
|
||||
const nodeTypes = NodeTypes();
|
||||
const workflow = new Workflow(workflowId.toString(), workflowData.nodes, workflowData.connections, workflowData.active, nodeTypes, workflowData.staticData, workflowData.settings);
|
||||
|
||||
return this.testWebhooks.cancelTestWebhook(workflowId, workflow);
|
||||
}));
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
import * as express from 'express';
|
||||
import {
|
||||
In as findIn,
|
||||
FindManyOptions,
|
||||
} from 'typeorm';
|
||||
|
||||
import {
|
||||
Db,
|
||||
IResponseCallbackData,
|
||||
IWorkflowDb,
|
||||
NodeTypes,
|
||||
Push,
|
||||
ResponseHelper,
|
||||
WebhookHelpers,
|
||||
IWorkflowDb,
|
||||
WorkflowHelpers,
|
||||
} from './';
|
||||
|
||||
import {
|
||||
|
@ -60,9 +67,17 @@ export class TestWebhooks {
|
|||
throw new ResponseHelper.ResponseError('The requested webhook is not registred.', 404, 404);
|
||||
}
|
||||
|
||||
const workflowData = await Db.collections.Workflow!.findOne(webhookData.workflowId);
|
||||
if (workflowData === undefined) {
|
||||
throw new ResponseHelper.ResponseError(`Could not find workflow with id "${webhookData.workflowId}"`, 404, 404);
|
||||
}
|
||||
|
||||
const nodeTypes = NodeTypes();
|
||||
const workflow = new Workflow(webhookData.workflowId, workflowData.nodes, workflowData.connections, workflowData.active, nodeTypes, workflowData.staticData, workflowData.settings);
|
||||
|
||||
// Get the node which has the webhook defined to know where to start from and to
|
||||
// get additional data
|
||||
const workflowStartNode = webhookData.workflow.getNode(webhookData.node);
|
||||
const workflowStartNode = workflow.getNode(webhookData.node);
|
||||
if (workflowStartNode === null) {
|
||||
throw new ResponseHelper.ResponseError('Could not find node to process webhook.', 404, 404);
|
||||
}
|
||||
|
@ -72,8 +87,7 @@ export class TestWebhooks {
|
|||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const executionMode = 'manual';
|
||||
|
||||
const executionId = await WebhookHelpers.executeWebhook(webhookData, this.testWebhookData[webhookKey].workflowData, workflowStartNode, executionMode, this.testWebhookData[webhookKey].sessionId, request, response, (error: Error | null, data: IResponseCallbackData) => {
|
||||
const executionId = await WebhookHelpers.executeWebhook(workflow, webhookData, this.testWebhookData[webhookKey].workflowData, workflowStartNode, executionMode, this.testWebhookData[webhookKey].sessionId, request, response, (error: Error | null, data: IResponseCallbackData) => {
|
||||
if (error !== null) {
|
||||
return reject(error);
|
||||
}
|
||||
|
@ -90,7 +104,7 @@ export class TestWebhooks {
|
|||
// Inform editor-ui that webhook got received
|
||||
if (this.testWebhookData[webhookKey].sessionId !== undefined) {
|
||||
const pushInstance = Push.getInstance();
|
||||
pushInstance.send('testWebhookReceived', { workflowId: webhookData.workflow.id, executionId }, this.testWebhookData[webhookKey].sessionId!);
|
||||
pushInstance.send('testWebhookReceived', { workflowId: webhookData.workflowId, executionId }, this.testWebhookData[webhookKey].sessionId!);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
|
@ -100,7 +114,7 @@ export class TestWebhooks {
|
|||
// Remove the webhook
|
||||
clearTimeout(this.testWebhookData[webhookKey].timeout);
|
||||
delete this.testWebhookData[webhookKey];
|
||||
this.activeWebhooks!.removeByWorkflowId(webhookData.workflow.id!.toString());
|
||||
this.activeWebhooks!.removeWorkflow(workflow);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -125,7 +139,7 @@ export class TestWebhooks {
|
|||
|
||||
// Remove test-webhooks automatically if they do not get called (after 120 seconds)
|
||||
const timeout = setTimeout(() => {
|
||||
this.cancelTestWebhook(workflowData.id.toString());
|
||||
this.cancelTestWebhook(workflowData.id.toString(), workflow);
|
||||
}, 120000);
|
||||
|
||||
let key: string;
|
||||
|
@ -136,9 +150,12 @@ export class TestWebhooks {
|
|||
timeout,
|
||||
workflowData,
|
||||
};
|
||||
await this.activeWebhooks!.add(webhookData, mode);
|
||||
await this.activeWebhooks!.add(workflow, webhookData, mode);
|
||||
}
|
||||
|
||||
// Save static data!
|
||||
await WorkflowHelpers.saveStaticData(workflow);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -150,7 +167,7 @@ export class TestWebhooks {
|
|||
* @returns {boolean}
|
||||
* @memberof TestWebhooks
|
||||
*/
|
||||
cancelTestWebhook(workflowId: string): boolean {
|
||||
cancelTestWebhook(workflowId: string, workflow: Workflow): boolean {
|
||||
let foundWebhook = false;
|
||||
for (const webhookKey of Object.keys(this.testWebhookData)) {
|
||||
const webhookData = this.testWebhookData[webhookKey];
|
||||
|
@ -175,7 +192,7 @@ export class TestWebhooks {
|
|||
|
||||
// Remove the webhook
|
||||
delete this.testWebhookData[webhookKey];
|
||||
this.activeWebhooks!.removeByWorkflowId(workflowId);
|
||||
this.activeWebhooks!.removeWorkflow(workflow);
|
||||
}
|
||||
|
||||
return foundWebhook;
|
||||
|
@ -189,8 +206,22 @@ export class TestWebhooks {
|
|||
if (this.activeWebhooks === null) {
|
||||
return;
|
||||
}
|
||||
const nodeTypes = NodeTypes();
|
||||
|
||||
return this.activeWebhooks.removeAll();
|
||||
const findQuery = {
|
||||
where: {
|
||||
id: findIn(this.activeWebhooks.getWorkflowIds())
|
||||
},
|
||||
} as FindManyOptions;
|
||||
|
||||
const workflowsDb = await Db.collections.Workflow!.find(findQuery);
|
||||
const workflows: Workflow[] = [];
|
||||
for (const workflowData of workflowsDb) {
|
||||
const workflow = new Workflow(workflowData.id.toString(), workflowData.nodes, workflowData.connections, workflowData.active, nodeTypes, workflowData.staticData, workflowData.settings);
|
||||
workflows.push(workflow);
|
||||
}
|
||||
|
||||
return this.activeWebhooks.removeAll(workflows);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -84,9 +84,9 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
|||
* @param {((error: Error | null, data: IResponseCallbackData) => void)} responseCallback
|
||||
* @returns {(Promise<string | undefined>)}
|
||||
*/
|
||||
export async function executeWebhook(webhookData: IWebhookData, workflowData: IWorkflowDb, workflowStartNode: INode, executionMode: WorkflowExecuteMode, sessionId: string | undefined, req: express.Request, res: express.Response, responseCallback: (error: Error | null, data: IResponseCallbackData) => void): Promise<string | undefined> {
|
||||
export async function executeWebhook(workflow: Workflow, webhookData: IWebhookData, workflowData: IWorkflowDb, workflowStartNode: INode, executionMode: WorkflowExecuteMode, sessionId: string | undefined, req: express.Request, res: express.Response, responseCallback: (error: Error | null, data: IResponseCallbackData) => void): Promise<string | undefined> {
|
||||
// Get the nodeType to know which responseMode is set
|
||||
const nodeType = webhookData.workflow.nodeTypes.getByName(workflowStartNode.type);
|
||||
const nodeType = workflow.nodeTypes.getByName(workflowStartNode.type);
|
||||
if (nodeType === undefined) {
|
||||
const errorMessage = `The type of the webhook node "${workflowStartNode.name}" is not known.`;
|
||||
responseCallback(new Error(errorMessage), {});
|
||||
|
@ -94,8 +94,8 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
|||
}
|
||||
|
||||
// Get the responseMode
|
||||
const responseMode = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseMode'], 'onReceived');
|
||||
const responseCode = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseCode'], 200) as number;
|
||||
const responseMode = workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseMode'], 'onReceived');
|
||||
const responseCode = workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseCode'], 200) as number;
|
||||
|
||||
if (!['onReceived', 'lastNode'].includes(responseMode as string)) {
|
||||
// If the mode is not known we error. Is probably best like that instead of using
|
||||
|
@ -122,7 +122,7 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
|||
let webhookResultData: IWebhookResponseData;
|
||||
|
||||
try {
|
||||
webhookResultData = await webhookData.workflow.runWebhook(webhookData, workflowStartNode, additionalData, NodeExecuteFunctions, executionMode);
|
||||
webhookResultData = await workflow.runWebhook(webhookData, workflowStartNode, additionalData, NodeExecuteFunctions, executionMode);
|
||||
} catch (e) {
|
||||
// Send error response to webhook caller
|
||||
const errorMessage = 'Workflow Webhook Error: Workflow could not be started!';
|
||||
|
@ -287,7 +287,7 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
|||
return data;
|
||||
}
|
||||
|
||||
const responseData = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseData'], 'firstEntryJson');
|
||||
const responseData = workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseData'], 'firstEntryJson');
|
||||
|
||||
if (didSendResponse === false) {
|
||||
let data: IDataObject | IDataObject[];
|
||||
|
@ -296,13 +296,13 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
|||
// Return the JSON data of the first entry
|
||||
data = returnData.data!.main[0]![0].json;
|
||||
|
||||
const responsePropertyName = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responsePropertyName'], undefined);
|
||||
const responsePropertyName = workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responsePropertyName'], undefined);
|
||||
|
||||
if (responsePropertyName !== undefined) {
|
||||
data = get(data, responsePropertyName as string) as IDataObject;
|
||||
}
|
||||
|
||||
const responseContentType = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseContentType'], undefined);
|
||||
const responseContentType = workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseContentType'], undefined);
|
||||
|
||||
if (responseContentType !== undefined) {
|
||||
// Send the webhook response manually to be able to set the content-type
|
||||
|
@ -329,7 +329,7 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
|||
didSendResponse = true;
|
||||
}
|
||||
|
||||
const responseBinaryPropertyName = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseBinaryPropertyName'], 'data');
|
||||
const responseBinaryPropertyName = workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseBinaryPropertyName'], 'data');
|
||||
|
||||
if (responseBinaryPropertyName === undefined && didSendResponse === false) {
|
||||
responseCallback(new Error('No "responseBinaryPropertyName" is set.'), {});
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
Push,
|
||||
ResponseHelper,
|
||||
WebhookHelpers,
|
||||
WorkflowCredentials,
|
||||
WorkflowHelpers,
|
||||
} from './';
|
||||
|
||||
|
@ -306,6 +307,10 @@ export async function executeWorkflow(workflowInfo: IExecuteWorkflowInfo, additi
|
|||
const additionalDataIntegrated = await getBase(additionalData.credentials);
|
||||
additionalDataIntegrated.hooks = getWorkflowHooksIntegrated(mode, executionId, workflowData!, { parentProcessMode: additionalData.hooks!.mode });
|
||||
|
||||
// Get the needed credentials for the current workflow as they will differ to the ones of the
|
||||
// calling workflow.
|
||||
additionalDataIntegrated.credentials = await WorkflowCredentials(workflowData!.nodes);
|
||||
|
||||
// Find Start-Node
|
||||
const requiredNodeTypes = ['n8n-nodes-base.start'];
|
||||
let startNode: INode | undefined;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "n8n-core",
|
||||
"version": "0.22.0",
|
||||
"version": "0.23.0",
|
||||
"description": "Core functionality of n8n",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
|
@ -43,7 +43,7 @@
|
|||
"crypto-js": "^3.1.9-1",
|
||||
"lodash.get": "^4.4.2",
|
||||
"mmmagic": "^0.5.2",
|
||||
"n8n-workflow": "~0.20.0",
|
||||
"n8n-workflow": "~0.21.0",
|
||||
"p-cancelable": "^2.0.0",
|
||||
"request-promise-native": "^1.0.7"
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
IWebhookData,
|
||||
WebhookHttpMethod,
|
||||
Workflow,
|
||||
WorkflowExecuteMode,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
|
@ -29,29 +30,26 @@ export class ActiveWebhooks {
|
|||
* @returns {Promise<void>}
|
||||
* @memberof ActiveWebhooks
|
||||
*/
|
||||
async add(webhookData: IWebhookData, mode: WorkflowExecuteMode): Promise<void> {
|
||||
if (webhookData.workflow.id === undefined) {
|
||||
async add(workflow: Workflow, webhookData: IWebhookData, mode: WorkflowExecuteMode): Promise<void> {
|
||||
if (workflow.id === undefined) {
|
||||
throw new Error('Webhooks can only be added for saved workflows as an id is needed!');
|
||||
}
|
||||
|
||||
if (this.workflowWebhooks[webhookData.workflow.id] === undefined) {
|
||||
this.workflowWebhooks[webhookData.workflow.id] = [];
|
||||
if (this.workflowWebhooks[webhookData.workflowId] === undefined) {
|
||||
this.workflowWebhooks[webhookData.workflowId] = [];
|
||||
}
|
||||
|
||||
// Make the webhook available directly because sometimes to create it successfully
|
||||
// it gets called
|
||||
this.webhookUrls[this.getWebhookKey(webhookData.httpMethod, webhookData.path)] = webhookData;
|
||||
|
||||
const webhookExists = await webhookData.workflow.runWebhookMethod('checkExists', webhookData, NodeExecuteFunctions, mode, this.testWebhooks);
|
||||
const webhookExists = await workflow.runWebhookMethod('checkExists', webhookData, NodeExecuteFunctions, mode, this.testWebhooks);
|
||||
if (webhookExists === false) {
|
||||
// If webhook does not exist yet create it
|
||||
await webhookData.workflow.runWebhookMethod('create', webhookData, NodeExecuteFunctions, mode, this.testWebhooks);
|
||||
await workflow.runWebhookMethod('create', webhookData, NodeExecuteFunctions, mode, this.testWebhooks);
|
||||
}
|
||||
|
||||
// Run the "activate" hooks on the nodes
|
||||
await webhookData.workflow.runNodeHooks('activate', webhookData, NodeExecuteFunctions, mode);
|
||||
|
||||
this.workflowWebhooks[webhookData.workflow.id].push(webhookData);
|
||||
this.workflowWebhooks[webhookData.workflowId].push(webhookData);
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,6 +71,17 @@ export class ActiveWebhooks {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the ids of all the workflows which have active webhooks
|
||||
*
|
||||
* @returns {string[]}
|
||||
* @memberof ActiveWebhooks
|
||||
*/
|
||||
getWorkflowIds(): string[] {
|
||||
return Object.keys(this.workflowWebhooks);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns key to uniquely identify a webhook
|
||||
*
|
||||
|
@ -89,11 +98,13 @@ export class ActiveWebhooks {
|
|||
/**
|
||||
* Removes all webhooks of a workflow
|
||||
*
|
||||
* @param {string} workflowId
|
||||
* @param {Workflow} workflow
|
||||
* @returns {boolean}
|
||||
* @memberof ActiveWebhooks
|
||||
*/
|
||||
async removeByWorkflowId(workflowId: string): Promise<boolean> {
|
||||
async removeWorkflow(workflow: Workflow): Promise<boolean> {
|
||||
const workflowId = workflow.id!.toString();
|
||||
|
||||
if (this.workflowWebhooks[workflowId] === undefined) {
|
||||
// If it did not exist then there is nothing to remove
|
||||
return false;
|
||||
|
@ -105,10 +116,7 @@ export class ActiveWebhooks {
|
|||
|
||||
// Go through all the registered webhooks of the workflow and remove them
|
||||
for (const webhookData of webhooks) {
|
||||
await webhookData.workflow.runWebhookMethod('delete', webhookData, NodeExecuteFunctions, mode, this.testWebhooks);
|
||||
|
||||
// Run the "deactivate" hooks on the nodes
|
||||
await webhookData.workflow.runNodeHooks('deactivate', webhookData, NodeExecuteFunctions, mode);
|
||||
await workflow.runWebhookMethod('delete', webhookData, NodeExecuteFunctions, mode, this.testWebhooks);
|
||||
|
||||
delete this.webhookUrls[this.getWebhookKey(webhookData.httpMethod, webhookData.path)];
|
||||
}
|
||||
|
@ -121,55 +129,16 @@ export class ActiveWebhooks {
|
|||
|
||||
|
||||
/**
|
||||
* Removes all the currently active webhooks
|
||||
* Removes all the webhooks of the given workflow
|
||||
*/
|
||||
async removeAll(): Promise<void> {
|
||||
const workflowIds = Object.keys(this.workflowWebhooks);
|
||||
|
||||
async removeAll(workflows: Workflow[]): Promise<void> {
|
||||
const removePromises = [];
|
||||
for (const workflowId of workflowIds) {
|
||||
removePromises.push(this.removeByWorkflowId(workflowId));
|
||||
for (const workflow of workflows) {
|
||||
removePromises.push(this.removeWorkflow(workflow));
|
||||
}
|
||||
|
||||
await Promise.all(removePromises);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * Removes a single webhook by its key.
|
||||
// * Currently not used, runNodeHooks for "deactivate" is missing
|
||||
// *
|
||||
// * @param {string} webhookKey
|
||||
// * @returns {boolean}
|
||||
// * @memberof ActiveWebhooks
|
||||
// */
|
||||
// removeByWebhookKey(webhookKey: string): boolean {
|
||||
// if (this.webhookUrls[webhookKey] === undefined) {
|
||||
// // If it did not exist then there is nothing to remove
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// const webhookData = this.webhookUrls[webhookKey];
|
||||
|
||||
// // Remove from workflow-webhooks
|
||||
// const workflowWebhooks = this.workflowWebhooks[webhookData.workflowId];
|
||||
// for (let index = 0; index < workflowWebhooks.length; index++) {
|
||||
// if (workflowWebhooks[index].path === webhookData.path) {
|
||||
// workflowWebhooks.splice(index, 1);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (workflowWebhooks.length === 0) {
|
||||
// // When there are no webhooks left for any workflow remove it totally
|
||||
// delete this.workflowWebhooks[webhookData.workflowId];
|
||||
// }
|
||||
|
||||
// // Remove from webhook urls
|
||||
// delete this.webhookUrls[webhookKey];
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -69,9 +69,7 @@ export class ActiveWorkflows {
|
|||
async add(id: string, workflow: Workflow, additionalData: IWorkflowExecuteAdditionalData, getTriggerFunctions: IGetExecuteTriggerFunctions, getPollFunctions: IGetExecutePollFunctions): Promise<void> {
|
||||
console.log('ADD ID (active): ' + id);
|
||||
|
||||
this.workflowData[id] = {
|
||||
workflow
|
||||
};
|
||||
this.workflowData[id] = {};
|
||||
const triggerNodes = workflow.getTriggerNodes();
|
||||
|
||||
let triggerResponse: ITriggerResponse | undefined;
|
||||
|
@ -170,7 +168,6 @@ export class ActiveWorkflows {
|
|||
const pollResponse = await workflow.runPoll(node, pollFunctions);
|
||||
|
||||
if (pollResponse !== null) {
|
||||
// TODO: Run workflow
|
||||
pollFunctions.__emit(pollResponse);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,7 +14,6 @@ import {
|
|||
ITriggerResponse,
|
||||
IWebhookFunctions as IWebhookFunctionsBase,
|
||||
IWorkflowSettings as IWorkflowSettingsWorkflow,
|
||||
Workflow,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
|
||||
|
@ -125,5 +124,4 @@ export interface INodeInputDataConnections {
|
|||
export interface IWorkflowData {
|
||||
pollResponses?: IPollResponse[];
|
||||
triggerResponses?: ITriggerResponse[];
|
||||
workflow: Workflow;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "n8n-editor-ui",
|
||||
"version": "0.33.0",
|
||||
"version": "0.34.0",
|
||||
"description": "Workflow Editor UI for n8n",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
|
@ -63,7 +63,7 @@
|
|||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.set": "^4.3.2",
|
||||
"n8n-workflow": "~0.20.0",
|
||||
"n8n-workflow": "~0.21.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"prismjs": "^1.17.1",
|
||||
"quill": "^2.0.0-dev.3",
|
||||
|
|
|
@ -57,7 +57,7 @@ import ParameterInputFull from '@/components/ParameterInputFull.vue';
|
|||
import ParameterInputList from '@/components/ParameterInputList.vue';
|
||||
import NodeCredentials from '@/components/NodeCredentials.vue';
|
||||
import NodeWebhooks from '@/components/NodeWebhooks.vue';
|
||||
import { get, set } from 'lodash';
|
||||
import { get, set, unset } from 'lodash';
|
||||
|
||||
import { genericHelpers } from '@/components/mixins/genericHelpers';
|
||||
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
|
||||
|
@ -369,8 +369,11 @@ export default mixins(
|
|||
Vue.set(nodeParameters as object, path, data);
|
||||
}
|
||||
} else {
|
||||
// For everything else
|
||||
set(nodeParameters as object, parameterPath, newValue);
|
||||
if (newValue === undefined) {
|
||||
unset(nodeParameters as object, parameterPath);
|
||||
} else {
|
||||
set(nodeParameters as object, parameterPath, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the parameters with the now new defaults according to the
|
||||
|
|
|
@ -30,6 +30,9 @@ export default Vue
|
|||
},
|
||||
computed: {
|
||||
isMultiLineParameter () {
|
||||
if (this.level > 4) {
|
||||
return true;
|
||||
}
|
||||
const rows = this.getArgument('rows');
|
||||
if (rows !== undefined && rows > 1) {
|
||||
return true;
|
||||
|
@ -37,6 +40,9 @@ export default Vue
|
|||
|
||||
return false;
|
||||
},
|
||||
level (): number {
|
||||
return this.path.split('.').length;
|
||||
},
|
||||
},
|
||||
props: [
|
||||
'displayOptions',
|
||||
|
|
|
@ -376,7 +376,7 @@ export default mixins(
|
|||
this.createNodeActive = false;
|
||||
this.$store.commit('setActiveNode', null);
|
||||
} else if (e.key === 'Tab') {
|
||||
this.createNodeActive = !this.createNodeActive;
|
||||
this.createNodeActive = !this.createNodeActive && !this.isReadOnly;
|
||||
} else if (e.key === this.controlKeyCode) {
|
||||
this.ctrlKeyPressed = true;
|
||||
} else if (e.key === 'F2') {
|
||||
|
|
18
packages/nodes-base/credentials/DisqusApi.credentials.ts
Normal file
18
packages/nodes-base/credentials/DisqusApi.credentials.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class DisqusApi implements ICredentialType {
|
||||
name = 'disqusApi';
|
||||
displayName = 'Disqus API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
description: 'Visit your account details page, and grab the Access Token. See <a href="https://disqus.com/api/docs/auth/">Disqus auth</a>.'
|
||||
},
|
||||
];
|
||||
}
|
17
packages/nodes-base/credentials/HunterApi.credentials.ts
Normal file
17
packages/nodes-base/credentials/HunterApi.credentials.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class HunterApi implements ICredentialType {
|
||||
name = 'hunterApi';
|
||||
displayName = 'Hunter API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
17
packages/nodes-base/credentials/SegmentApi.credentials.ts
Normal file
17
packages/nodes-base/credentials/SegmentApi.credentials.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class SegmentApi implements ICredentialType {
|
||||
name = 'segmentApi';
|
||||
displayName = 'Segment API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Write Key',
|
||||
name: 'writekey',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -125,6 +125,22 @@ export class ClickUp implements INodeType {
|
|||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available lists without a folder to display them to user so that he can
|
||||
// select them easily
|
||||
async getFolderlessLists(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const spaceId = this.getCurrentNodeParameter('space') as string;
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const { lists } = await clickupApiRequest.call(this, 'GET', `/space/${spaceId}/list`);
|
||||
for (const list of lists) {
|
||||
const listName = list.name;
|
||||
const listId = list.id;
|
||||
returnData.push({
|
||||
name: listName,
|
||||
value: listId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available assignees to display them to user so that he can
|
||||
// select them easily
|
||||
async getAssignees(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
|
|
|
@ -87,6 +87,23 @@ export const taskFields = [
|
|||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Folderless List',
|
||||
name: 'folderless',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'task',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Folder',
|
||||
name: 'folder',
|
||||
|
@ -100,13 +117,16 @@ export const taskFields = [
|
|||
operation: [
|
||||
'create',
|
||||
],
|
||||
folderless: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getFolders',
|
||||
loadOptionsDependsOn: [
|
||||
'space',
|
||||
]
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
|
@ -123,6 +143,35 @@ export const taskFields = [
|
|||
operation: [
|
||||
'create',
|
||||
],
|
||||
folderless: [
|
||||
true,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getFolderlessLists',
|
||||
loadOptionsDependsOn: [
|
||||
'space',
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'List',
|
||||
name: 'list',
|
||||
type: 'options',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'task',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
folderless: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
|
@ -225,6 +274,7 @@ export const taskFields = [
|
|||
name: 'priority',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 4,
|
||||
},
|
||||
description: 'Integer mapping as 1 : Urgent, 2 : High, 3 : Normal, 4 : Low',
|
||||
|
@ -358,6 +408,7 @@ export const taskFields = [
|
|||
name: 'priority',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 4,
|
||||
},
|
||||
description: 'Integer mapping as 1 : Urgent, 2 : High, 3 : Normal, 4 : Low',
|
||||
|
|
784
packages/nodes-base/nodes/Disqus/Disqus.node.ts
Normal file
784
packages/nodes-base/nodes/Disqus/Disqus.node.ts
Normal file
|
@ -0,0 +1,784 @@
|
|||
import {
|
||||
IExecuteFunctions,
|
||||
} from 'n8n-core';
|
||||
import {
|
||||
IDataObject,
|
||||
INodeTypeDescription,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { disqusApiRequest, disqusApiRequestAllItems } from './GenericFunctions';
|
||||
|
||||
|
||||
export class Disqus implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Disqus',
|
||||
name: 'disqus',
|
||||
icon: 'file:disqus.png',
|
||||
group: ['input'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Access data on Disqus',
|
||||
defaults: {
|
||||
name: 'Disqus',
|
||||
color: '#22BB44',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'disqusApi',
|
||||
required: true,
|
||||
}
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Forum',
|
||||
value: 'forum',
|
||||
},
|
||||
],
|
||||
default: 'forum',
|
||||
description: 'The resource to operate on.',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// forum
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Returns forum details.',
|
||||
},
|
||||
{
|
||||
name: 'Get All Categories',
|
||||
value: 'getCategories',
|
||||
description: 'Returns a list of categories within a forum.',
|
||||
},
|
||||
{
|
||||
name: 'Get All Threads',
|
||||
value: 'getThreads',
|
||||
description: 'Returns a list of threads within a forum.',
|
||||
},
|
||||
{
|
||||
name: 'Get All Posts',
|
||||
value: 'getPosts',
|
||||
description: 'Returns a list of posts within a forum.',
|
||||
}
|
||||
],
|
||||
default: 'get',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// forum:get
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Forum name',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The short name(aka ID) of the forum to get.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Attach',
|
||||
name: 'attach',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{
|
||||
name: 'counters',
|
||||
value: 'counters',
|
||||
},
|
||||
{
|
||||
name: 'followsForum',
|
||||
value: 'followsForum',
|
||||
},
|
||||
{
|
||||
name: 'forumCanDisableAds',
|
||||
value: 'forumCanDisableAds',
|
||||
},
|
||||
{
|
||||
name: 'forumDaysAlive',
|
||||
value: 'forumDaysAlive',
|
||||
},
|
||||
{
|
||||
name: 'forumFeatures',
|
||||
value: 'forumFeatures',
|
||||
},
|
||||
{
|
||||
name: 'forumForumCategory',
|
||||
value: 'forumForumCategory',
|
||||
},
|
||||
{
|
||||
name: 'forumIntegration',
|
||||
value: 'forumIntegration',
|
||||
},
|
||||
{
|
||||
name: 'forumNewPolicy',
|
||||
value: 'forumNewPolicy',
|
||||
},
|
||||
{
|
||||
name: 'forumPermissions',
|
||||
value: 'forumPermissions',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description: 'The resource to operate on.',
|
||||
},
|
||||
{
|
||||
displayName: 'Related',
|
||||
name: 'related',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{
|
||||
name: 'author',
|
||||
value: 'author',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description: 'You may specify relations to include with your response',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// forum:getPosts
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Forum name',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getPosts',
|
||||
],
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The short name(aka ID) of the forum to get.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
operation: [
|
||||
'getPosts',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
operation: [
|
||||
'getPosts',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 100,
|
||||
},
|
||||
default: 100,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getPosts',
|
||||
],
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{
|
||||
name: 'Has_Bad_Word',
|
||||
value: 'Has_Bad_Word',
|
||||
},
|
||||
{
|
||||
name: 'Has_Link',
|
||||
value: 'Has_Link',
|
||||
},
|
||||
{
|
||||
name: 'Has_Low_Rep_Author',
|
||||
value: 'Has_Low_Rep_Author',
|
||||
},
|
||||
{
|
||||
name: 'Has_Media',
|
||||
value: 'Has_Media',
|
||||
},
|
||||
{
|
||||
name: 'Is_Anonymous',
|
||||
value: 'Is_Anonymous',
|
||||
},
|
||||
{
|
||||
name: 'Is_Flagged',
|
||||
value: 'Is_Flagged',
|
||||
},
|
||||
{
|
||||
name: 'No_Issue',
|
||||
value: 'No_Issue',
|
||||
},
|
||||
{
|
||||
name: 'Is_At_Flag_Limit',
|
||||
value: 'Is_At_Flag_Limit',
|
||||
},
|
||||
{
|
||||
name: 'Is_Toxic',
|
||||
value: 'Is_Toxic',
|
||||
},
|
||||
{
|
||||
name: 'Modified_By_Rule',
|
||||
value: 'Modified_By_Rule',
|
||||
},
|
||||
{
|
||||
name: 'Shadow_Banned',
|
||||
value: 'Shadow_Banned',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description: 'You may specify filters for your response.'
|
||||
},
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{
|
||||
name: 'approved',
|
||||
value: 'approved',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description: 'You may specify relations to include with your response.',
|
||||
},
|
||||
{
|
||||
displayName: 'Order',
|
||||
name: 'order',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'ASC',
|
||||
value: 'asc',
|
||||
},
|
||||
{
|
||||
name: 'DESC',
|
||||
value: 'desc',
|
||||
}
|
||||
],
|
||||
default: 'asc',
|
||||
description: 'You may specify order to sort your response.',
|
||||
},
|
||||
{
|
||||
displayName: 'Query',
|
||||
name: 'query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'You may specify query forChoices: asc, desc your response.',
|
||||
},
|
||||
{
|
||||
displayName: 'Related',
|
||||
name: 'related',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{
|
||||
name: 'thread',
|
||||
value: 'thread',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description: 'You may specify relations to include with your response',
|
||||
},
|
||||
{
|
||||
displayName: 'Since',
|
||||
name: 'since',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Unix timestamp (or ISO datetime standard)',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// forum:getCategories
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Forum name',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getCategories',
|
||||
],
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The short name(aka ID) of the forum to get Categories.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
operation: [
|
||||
'getCategories',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
operation: [
|
||||
'getCategories',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 100,
|
||||
},
|
||||
default: 100,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getCategories',
|
||||
],
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Order',
|
||||
name: 'order',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'ASC',
|
||||
value: 'asc',
|
||||
},
|
||||
{
|
||||
name: 'DESC',
|
||||
value: 'desc',
|
||||
}
|
||||
],
|
||||
default: 'asc',
|
||||
description: 'You may specify order to sort your response.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// forum:getThreads
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Forum name',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getThreads',
|
||||
],
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The short name(aka ID) of the forum to get Threads.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
operation: [
|
||||
'getThreads',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
operation: [
|
||||
'getThreads',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 100,
|
||||
},
|
||||
default: 100,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getThreads',
|
||||
],
|
||||
resource: [
|
||||
'forum',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Related',
|
||||
name: 'related',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{
|
||||
name: 'author',
|
||||
value: 'author',
|
||||
},
|
||||
{
|
||||
name: 'forum',
|
||||
value: 'forum',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description: 'You may specify relations to include with your response',
|
||||
},
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{
|
||||
name: 'closed',
|
||||
value: 'closed',
|
||||
},
|
||||
{
|
||||
name: 'open',
|
||||
value: 'open',
|
||||
},
|
||||
{
|
||||
name: 'killed',
|
||||
value: 'killed',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description: 'You may specify relations to include with your response.',
|
||||
},
|
||||
{
|
||||
displayName: 'Order',
|
||||
name: 'order',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'ASC',
|
||||
value: 'asc',
|
||||
},
|
||||
{
|
||||
name: 'DESC',
|
||||
value: 'desc',
|
||||
}
|
||||
],
|
||||
default: 'asc',
|
||||
description: 'You may specify order to sort your response.',
|
||||
},
|
||||
{
|
||||
displayName: 'Since',
|
||||
name: 'since',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Unix timestamp (or ISO datetime standard)',
|
||||
},
|
||||
{
|
||||
displayName: 'Thread',
|
||||
name: 'threadId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Looks up a thread by ID. You may pass us the "ident"<br />query type instead of an ID by including "forum". You may<br />pass us the "link" query type to filter by URL. You must pass<br />the "forum" if you do not have the Pro API Access addon.',
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
|
||||
let endpoint = '';
|
||||
let requestMethod = '';
|
||||
let body: IDataObject | Buffer;
|
||||
let qs: IDataObject;
|
||||
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
body = {};
|
||||
qs = {};
|
||||
|
||||
if (resource === 'forum') {
|
||||
if (operation === 'get') {
|
||||
// ----------------------------------
|
||||
// get
|
||||
// ----------------------------------
|
||||
|
||||
requestMethod = 'GET';
|
||||
|
||||
endpoint = 'forums/details.json';
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
qs.forum = id;
|
||||
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
|
||||
Object.assign(qs, additionalFields);
|
||||
|
||||
try {
|
||||
const responseData = await disqusApiRequest.call(this, requestMethod, qs, endpoint);
|
||||
returnData.push(responseData.response);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
} else if (operation === 'getPosts') {
|
||||
// ----------------------------------
|
||||
// getPosts
|
||||
// ----------------------------------
|
||||
|
||||
requestMethod = 'GET';
|
||||
|
||||
endpoint = 'forums/listPosts.json';
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
Object.assign(qs, additionalFields);
|
||||
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
|
||||
qs.forum = id;
|
||||
qs.limit = 100;
|
||||
|
||||
try {
|
||||
let responseData: IDataObject = {};
|
||||
if(returnAll) {
|
||||
responseData.response = await disqusApiRequestAllItems.call(this, requestMethod, qs, endpoint);
|
||||
} else {
|
||||
const limit = this.getNodeParameter('limit', i) as string;
|
||||
qs.limit = limit;
|
||||
responseData = await disqusApiRequest.call(this, requestMethod, qs, endpoint);
|
||||
}
|
||||
returnData.push.apply(returnData, responseData.response as IDataObject[]);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
} else if (operation === 'getCategories') {
|
||||
// ----------------------------------
|
||||
// getCategories
|
||||
// ----------------------------------
|
||||
|
||||
requestMethod = 'GET';
|
||||
|
||||
endpoint = 'forums/listCategories.json';
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
Object.assign(qs, additionalFields);
|
||||
|
||||
qs.forum = id;
|
||||
qs.limit = 100;
|
||||
|
||||
try {
|
||||
let responseData: IDataObject = {};
|
||||
|
||||
if(returnAll) {
|
||||
responseData.response = await disqusApiRequestAllItems.call(this, requestMethod, qs, endpoint);
|
||||
} else {
|
||||
const limit = this.getNodeParameter('limit', i) as string;
|
||||
qs.limit = limit;
|
||||
responseData = await disqusApiRequest.call(this, requestMethod, qs, endpoint) as IDataObject;
|
||||
}
|
||||
returnData.push.apply(returnData, responseData.response as IDataObject[]) ;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
} else if (operation === 'getThreads') {
|
||||
// ----------------------------------
|
||||
// getThreads
|
||||
// ----------------------------------
|
||||
|
||||
requestMethod = 'GET';
|
||||
|
||||
endpoint = 'forums/listThreads.json';
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
|
||||
qs.forum = id;
|
||||
qs.limit = 100;
|
||||
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
|
||||
Object.assign(qs, additionalFields);
|
||||
|
||||
try {
|
||||
let responseData: IDataObject = {};
|
||||
if(returnAll) {
|
||||
responseData.response = await disqusApiRequestAllItems.call(this, requestMethod, qs, endpoint);
|
||||
} else {
|
||||
const limit = this.getNodeParameter('limit', i) as string;
|
||||
qs.limit = limit;
|
||||
responseData = await disqusApiRequest.call(this, requestMethod, qs, endpoint);
|
||||
}
|
||||
returnData.push.apply(returnData, responseData.response as IDataObject[]);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new Error(`The operation "${operation}" is not known!`);
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new Error(`The resource "${resource}" is not known!`);
|
||||
}
|
||||
}
|
||||
|
||||
return [this.helpers.returnJsonArray(returnData)];
|
||||
}
|
||||
}
|
97
packages/nodes-base/nodes/Disqus/GenericFunctions.ts
Normal file
97
packages/nodes-base/nodes/Disqus/GenericFunctions.ts
Normal file
|
@ -0,0 +1,97 @@
|
|||
import { OptionsWithUri } from 'request';
|
||||
import {
|
||||
IExecuteFunctions,
|
||||
IExecuteSingleFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
} from 'n8n-core';
|
||||
import { IDataObject } from 'n8n-workflow';
|
||||
|
||||
export async function disqusApiRequest(
|
||||
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
||||
method: string,
|
||||
qs: IDataObject = {},
|
||||
uri?: string,
|
||||
body: IDataObject = {},
|
||||
option: IDataObject = {},
|
||||
): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const credentials = this.getCredentials('disqusApi') as IDataObject;
|
||||
qs.api_key = credentials.accessToken;
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
|
||||
// Convert to query string into a format the API can read
|
||||
const queryStringElements: string[] = [];
|
||||
for (const key of Object.keys(qs)) {
|
||||
if (Array.isArray(qs[key])) {
|
||||
(qs[key] as string[]).forEach(value => {
|
||||
queryStringElements.push(`${key}=${value}`);
|
||||
});
|
||||
} else {
|
||||
queryStringElements.push(`${key}=${qs[key]}`);
|
||||
}
|
||||
}
|
||||
|
||||
let options: OptionsWithUri = {
|
||||
method,
|
||||
body,
|
||||
uri: `https://disqus.com/api/3.0/${uri}?${queryStringElements.join('&')}`,
|
||||
json: true
|
||||
};
|
||||
|
||||
options = Object.assign({}, options, option);
|
||||
if (Object.keys(options.body).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
try {
|
||||
const result = await this.helpers.request!(options);
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (error.statusCode === 401) {
|
||||
// Return a clear error
|
||||
throw new Error('The Disqus credentials are not valid!');
|
||||
}
|
||||
|
||||
if (error.error && error.error.error_summary) {
|
||||
// Try to return the error prettier
|
||||
throw new Error(`Disqus error response [${error.statusCode}]: ${error.error.error_summary}`);
|
||||
}
|
||||
|
||||
// If that data does not exist for some reason return the actual error
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an API request to paginated flow endpoint
|
||||
* and return all results
|
||||
*/
|
||||
export async function disqusApiRequestAllItems(
|
||||
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
||||
method: string,
|
||||
qs: IDataObject = {},
|
||||
uri?: string,
|
||||
body: IDataObject = {},
|
||||
option: IDataObject = {},
|
||||
): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
|
||||
try {
|
||||
do {
|
||||
responseData = await disqusApiRequest.call(this, method, qs, uri, body, option);
|
||||
qs.cursor = responseData.cursor.id;
|
||||
returnData.push.apply(returnData, responseData.response);
|
||||
} while (
|
||||
responseData.cursor.more === true &&
|
||||
responseData.cursor.hasNext === true
|
||||
);
|
||||
return returnData;
|
||||
} catch(error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
BIN
packages/nodes-base/nodes/Disqus/disqus.png
Normal file
BIN
packages/nodes-base/nodes/Disqus/disqus.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -84,7 +84,7 @@ export class Function implements INodeType {
|
|||
|
||||
try {
|
||||
// Execute the function code
|
||||
items = (await vm.run(`module.exports = async function() {${functionCode}}()`, './'));
|
||||
items = (await vm.run(`module.exports = async function() {${functionCode}}()`, __dirname));
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ export class FunctionItem implements INodeType {
|
|||
let jsonData: IDataObject;
|
||||
try {
|
||||
// Execute the function code
|
||||
jsonData = await vm.run(`module.exports = async function() {${functionCode}}()`, './');
|
||||
jsonData = await vm.run(`module.exports = async function() {${functionCode}}()`, __dirname);
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
|
|
56
packages/nodes-base/nodes/Hunter/GenericFunctions.ts
Normal file
56
packages/nodes-base/nodes/Hunter/GenericFunctions.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
import { OptionsWithUri } from 'request';
|
||||
import {
|
||||
IExecuteFunctions,
|
||||
IExecuteSingleFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
} from 'n8n-core';
|
||||
import { IDataObject } from 'n8n-workflow';
|
||||
|
||||
export async function hunterApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
const credentials = this.getCredentials('hunterApi');
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
qs = Object.assign({ api_key: credentials.apiKey }, qs);
|
||||
let options: OptionsWithUri = {
|
||||
method,
|
||||
qs,
|
||||
body,
|
||||
uri: uri ||`https://api.hunter.io/v2${resource}`,
|
||||
json: true
|
||||
};
|
||||
options = Object.assign({}, options, option);
|
||||
if (Object.keys(options.body).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an API request to paginated flow endpoint
|
||||
* and return all results
|
||||
*/
|
||||
export async function hunterApiRequestAllItems(this: IHookFunctions | IExecuteFunctions| ILoadOptionsFunctions, propertyName: string, method: string, resource: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
query.offset = 0;
|
||||
query.limit = 100;
|
||||
|
||||
do {
|
||||
responseData = await hunterApiRequest.call(this, method, resource, body, query);
|
||||
returnData.push(responseData[propertyName]);
|
||||
query.offset += query.limit;
|
||||
} while (
|
||||
responseData.meta !== undefined &&
|
||||
responseData.meta.results !== undefined &&
|
||||
responseData.meta.offset <= responseData.meta.results
|
||||
);
|
||||
return returnData;
|
||||
}
|
378
packages/nodes-base/nodes/Hunter/Hunter.node.ts
Normal file
378
packages/nodes-base/nodes/Hunter/Hunter.node.ts
Normal file
|
@ -0,0 +1,378 @@
|
|||
import {
|
||||
IExecuteFunctions,
|
||||
} from 'n8n-core';
|
||||
import {
|
||||
IDataObject,
|
||||
INodeTypeDescription,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
hunterApiRequest,
|
||||
hunterApiRequestAllItems,
|
||||
} from './GenericFunctions';
|
||||
|
||||
export class Hunter implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Hunter',
|
||||
name: 'hunter',
|
||||
icon: 'file:hunter.png',
|
||||
group: ['output'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"]}}',
|
||||
description: 'Consume Hunter API',
|
||||
defaults: {
|
||||
name: 'Hunter',
|
||||
color: '#ff3807',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'hunterApi',
|
||||
required: true,
|
||||
}
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: ' Domain Search',
|
||||
value: 'domainSearch',
|
||||
description: 'Get every email address found on the internet using a given domain name, with sources.',
|
||||
},
|
||||
{
|
||||
name: ' Email Finder',
|
||||
value: 'emailFinder',
|
||||
description: 'Generates or retrieves the most likely email address from a domain name, a first name and a last name.',
|
||||
},
|
||||
{
|
||||
name: 'Email Verifier',
|
||||
value: 'emailVerifier',
|
||||
description: 'Allows you to verify the deliverability of an email address.',
|
||||
},
|
||||
],
|
||||
default: 'domainSearch',
|
||||
description: 'operation to consume.',
|
||||
},
|
||||
{
|
||||
displayName: 'Domain',
|
||||
name: 'domain',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'domainSearch',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Domain name from which you want to find the email addresses. For example, "stripe.com".',
|
||||
},
|
||||
{
|
||||
displayName: 'Only Emails',
|
||||
name: 'onlyEmails',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'domainSearch',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: true,
|
||||
description: 'Return only the the found emails.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'domainSearch',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'domainSearch',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 100,
|
||||
},
|
||||
default: 100,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'domainSearch',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
default: '',
|
||||
options: [
|
||||
{
|
||||
name: 'Personal',
|
||||
value: 'personal',
|
||||
},
|
||||
{
|
||||
name: 'Generic',
|
||||
value: 'generic',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
displayName: 'Seniority',
|
||||
name: 'seniority',
|
||||
type: 'multiOptions',
|
||||
default: [],
|
||||
options: [
|
||||
{
|
||||
name: 'Junior',
|
||||
value: 'junior',
|
||||
},
|
||||
{
|
||||
name: 'Senior',
|
||||
value: 'senior',
|
||||
},
|
||||
{
|
||||
name: 'Executive',
|
||||
value: 'executive',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
displayName: 'Department',
|
||||
name: 'department',
|
||||
type: 'multiOptions',
|
||||
default: [],
|
||||
options: [
|
||||
{
|
||||
name: 'Executive',
|
||||
value: 'executive',
|
||||
},
|
||||
{
|
||||
name: 'IT',
|
||||
value: 'it',
|
||||
},
|
||||
{
|
||||
name: 'Finance',
|
||||
value: 'finance',
|
||||
},
|
||||
{
|
||||
name: 'Management',
|
||||
value: 'management',
|
||||
},
|
||||
{
|
||||
name: 'Sales',
|
||||
value: 'sales',
|
||||
},
|
||||
{
|
||||
name: 'Legal',
|
||||
value: 'legal',
|
||||
},
|
||||
{
|
||||
name: 'Support',
|
||||
value: 'support',
|
||||
},
|
||||
{
|
||||
name: 'HR',
|
||||
value: 'hr',
|
||||
},
|
||||
{
|
||||
name: 'Marketing',
|
||||
value: 'marketing',
|
||||
},
|
||||
{
|
||||
name: 'Communication',
|
||||
value: 'communication',
|
||||
},
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Domain',
|
||||
name: 'domain',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'emailFinder',
|
||||
],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
description: 'Domain name from which you want to find the email addresses. For example, "stripe.com".',
|
||||
},
|
||||
{
|
||||
displayName: 'First Name',
|
||||
name: 'firstname',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'emailFinder',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
description: `The person's first name. It doesn't need to be in lowercase.`,
|
||||
},
|
||||
{
|
||||
displayName: 'Last Name',
|
||||
name: 'lastname',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'emailFinder',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
description: `The person's last name. It doesn't need to be in lowercase.`,
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'emailVerifier',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'The email address you want to verify.',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
const length = items.length as unknown as number;
|
||||
const qs: IDataObject = {};
|
||||
let responseData;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
//https://hunter.io/api-documentation/v2#domain-search
|
||||
if (operation === 'domainSearch') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
const filters = this.getNodeParameter('filters', i) as IDataObject;
|
||||
const domain = this.getNodeParameter('domain', i) as string;
|
||||
const onlyEmails = this.getNodeParameter('onlyEmails', i, false) as boolean;
|
||||
|
||||
qs.domain = domain;
|
||||
if (filters.type){
|
||||
qs.type = filters.type;
|
||||
}
|
||||
if (filters.seniority){
|
||||
qs.seniority = (filters.seniority as string[]).join(',');
|
||||
}
|
||||
if (filters.department){
|
||||
qs.department = (filters.department as string[]).join(',');
|
||||
}
|
||||
if (returnAll) {
|
||||
responseData = await hunterApiRequestAllItems.call(this, 'data', 'GET', '/domain-search', {}, qs);
|
||||
|
||||
// Make sure that the company information is there only once and
|
||||
// the emails are combined underneath it.
|
||||
if (onlyEmails === false) {
|
||||
let tempReturnData: IDataObject = {};
|
||||
|
||||
for (let i = 0; i < responseData.length; i++) {
|
||||
if (i === 0) {
|
||||
tempReturnData = responseData[i];
|
||||
continue;
|
||||
}
|
||||
((tempReturnData as IDataObject).emails as IDataObject[]).push.apply(tempReturnData.emails, responseData[i].emails);
|
||||
}
|
||||
|
||||
responseData = tempReturnData;
|
||||
}
|
||||
} else {
|
||||
const limit = this.getNodeParameter('limit', i) as number;
|
||||
qs.limit = limit;
|
||||
responseData = await hunterApiRequest.call(this, 'GET', '/domain-search', {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
|
||||
if (onlyEmails === true) {
|
||||
let tempReturnData: IDataObject[] = [];
|
||||
|
||||
if (Array.isArray(responseData)) {
|
||||
for (const data of responseData) {
|
||||
tempReturnData.push.apply(tempReturnData, data.emails);
|
||||
}
|
||||
} else {
|
||||
tempReturnData = responseData.emails;
|
||||
}
|
||||
|
||||
responseData = tempReturnData;
|
||||
}
|
||||
}
|
||||
//https://hunter.io/api-documentation/v2#email-finder
|
||||
if (operation === 'emailFinder') {
|
||||
const domain = this.getNodeParameter('domain', i) as string;
|
||||
const firstname = this.getNodeParameter('firstname', i) as string;
|
||||
const lastname = this.getNodeParameter('lastname', i) as string;
|
||||
qs.first_name = firstname;
|
||||
qs.last_name = lastname;
|
||||
qs.domain = domain;
|
||||
responseData = await hunterApiRequest.call(this, 'GET', '/email-finder', {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
//https://hunter.io/api-documentation/v2#email-verifier
|
||||
if (operation === 'emailVerifier') {
|
||||
const email = this.getNodeParameter('email', i) as string;
|
||||
qs.email = email;
|
||||
responseData = await hunterApiRequest.call(this, 'GET', '/email-verifier', {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (Array.isArray(responseData)) {
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
} else {
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
}
|
||||
return [this.helpers.returnJsonArray(returnData)];
|
||||
}
|
||||
}
|
BIN
packages/nodes-base/nodes/Hunter/hunter.png
Normal file
BIN
packages/nodes-base/nodes/Hunter/hunter.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
|
@ -19,9 +19,9 @@ export const activityOperations = [
|
|||
description: 'Create a activity',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a activity',
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a activity',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
|
@ -34,9 +34,9 @@ export const activityOperations = [
|
|||
description: 'Get all companies',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a activity',
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a activity',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
|
@ -427,12 +427,14 @@ export const activityFields = [
|
|||
name: 'fields',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Comma separated list of fields to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort By',
|
||||
name: 'sortBy',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The field to sort by.',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Order',
|
||||
|
@ -440,11 +442,11 @@ export const activityFields = [
|
|||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Asc',
|
||||
name: 'ASC',
|
||||
value: 'asc',
|
||||
},
|
||||
{
|
||||
name: 'Desc',
|
||||
name: 'DESC',
|
||||
value: 'desc',
|
||||
},
|
||||
],
|
||||
|
@ -508,11 +510,11 @@ export const activityFields = [
|
|||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'And',
|
||||
name: 'AND',
|
||||
value: 'AND',
|
||||
},
|
||||
{
|
||||
name: 'Or',
|
||||
name: 'OR',
|
||||
value: 'OR',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -19,9 +19,9 @@ export const companyOperations = [
|
|||
description: 'Create a company',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a company',
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a company',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
|
@ -34,9 +34,9 @@ export const companyOperations = [
|
|||
description: 'Get all companies',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a company',
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a company',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
|
@ -520,12 +520,14 @@ export const companyFields = [
|
|||
name: 'fields',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Comma separated list of fields to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort By',
|
||||
name: 'sortBy',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The field to sort by.',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Order',
|
||||
|
@ -533,11 +535,11 @@ export const companyFields = [
|
|||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Asc',
|
||||
name: 'ASC',
|
||||
value: 'asc',
|
||||
},
|
||||
{
|
||||
name: 'Desc',
|
||||
name: 'DESC',
|
||||
value: 'desc',
|
||||
},
|
||||
],
|
||||
|
@ -601,11 +603,11 @@ export const companyFields = [
|
|||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'And',
|
||||
name: 'AND',
|
||||
value: 'AND',
|
||||
},
|
||||
{
|
||||
name: 'Or',
|
||||
name: 'OR',
|
||||
value: 'OR',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -19,9 +19,9 @@ export const dealOperations = [
|
|||
description: 'Create a deal',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a deal',
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a deal',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
|
@ -34,9 +34,9 @@ export const dealOperations = [
|
|||
description: 'Get all companies',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a deal',
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a deal',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
|
@ -691,12 +691,14 @@ export const dealFields = [
|
|||
name: 'fields',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Comma separated list of fields to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort By',
|
||||
name: 'sortBy',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The field to sort by.',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Order',
|
||||
|
@ -704,11 +706,11 @@ export const dealFields = [
|
|||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Asc',
|
||||
name: 'ASC',
|
||||
value: 'asc',
|
||||
},
|
||||
{
|
||||
name: 'Desc',
|
||||
name: 'DESC',
|
||||
value: 'desc',
|
||||
},
|
||||
],
|
||||
|
@ -772,11 +774,11 @@ export const dealFields = [
|
|||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'And',
|
||||
name: 'AND',
|
||||
value: 'AND',
|
||||
},
|
||||
{
|
||||
name: 'Or',
|
||||
name: 'OR',
|
||||
value: 'OR',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -65,3 +65,21 @@ export function validateJSON(json: string | undefined): any { // tslint:disable-
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts data from the Salesmate format into a simple object
|
||||
*
|
||||
* @export
|
||||
* @param {IDataObject[]} data
|
||||
* @returns {IDataObject}
|
||||
*/
|
||||
export function simplifySalesmateData(data: IDataObject[]): IDataObject {
|
||||
const returnData: IDataObject = {};
|
||||
|
||||
for (const item of data) {
|
||||
returnData[item.fieldName as string] = item.value;
|
||||
}
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
import {
|
||||
salesmateApiRequest,
|
||||
salesmateApiRequestAllItems,
|
||||
simplifySalesmateData,
|
||||
validateJSON,
|
||||
} from './GenericFunctions';
|
||||
import {
|
||||
|
@ -289,12 +290,9 @@ export class Salesmate implements INodeType {
|
|||
const rawData = this.getNodeParameter('rawData', i) as boolean;
|
||||
responseData = await salesmateApiRequest.call(this, 'GET', `/v1/companies/${companyId}`);
|
||||
responseData = responseData.Data;
|
||||
|
||||
if (!rawData) {
|
||||
responseData = responseData.map((company: IDataObject) => {
|
||||
const aux: IDataObject = {};
|
||||
aux[company.fieldName as string] = company.value;
|
||||
return aux;
|
||||
});
|
||||
responseData = simplifySalesmateData(responseData);
|
||||
}
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
|
@ -314,9 +312,26 @@ export class Salesmate implements INodeType {
|
|||
qs.sortOrder = options.sortOrder as string;
|
||||
}
|
||||
if (options.fields) {
|
||||
if ((options.fields as string).trim() === '') {
|
||||
throw new Error('You have to add at least one field');
|
||||
}
|
||||
body.fields = (options.fields as string).split(',') as string[];
|
||||
} else {
|
||||
throw new Error('You have to add at least one field');
|
||||
body.fields = [
|
||||
'name',
|
||||
'description',
|
||||
'billingAddressLine1',
|
||||
'billingAddressLine2',
|
||||
'billingCity',
|
||||
'billingZipCode',
|
||||
'billingState',
|
||||
'billingCountry',
|
||||
'website',
|
||||
'owner',
|
||||
'tags',
|
||||
'photo',
|
||||
'createdAt',
|
||||
];
|
||||
}
|
||||
if (!jsonActive) {
|
||||
const filters: IDataObject[] = [];
|
||||
|
@ -332,7 +347,7 @@ export class Salesmate implements INodeType {
|
|||
};
|
||||
filter.condition = condition.condition;
|
||||
filter.data = condition.value;
|
||||
filters.push(filter)
|
||||
filters.push(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -440,12 +455,9 @@ export class Salesmate implements INodeType {
|
|||
const rawData = this.getNodeParameter('rawData', i) as boolean;
|
||||
responseData = await salesmateApiRequest.call(this, 'GET', `/v1/activities/${activityId}`);
|
||||
responseData = responseData.Data;
|
||||
|
||||
if (!rawData) {
|
||||
responseData = responseData.map((activity: IDataObject) => {
|
||||
const aux: IDataObject = {};
|
||||
aux[activity.fieldName as string] = activity.value;
|
||||
return aux;
|
||||
});
|
||||
responseData = simplifySalesmateData(responseData);
|
||||
}
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
|
@ -465,9 +477,27 @@ export class Salesmate implements INodeType {
|
|||
qs.sortOrder = options.sortOrder as string;
|
||||
}
|
||||
if (options.fields) {
|
||||
if ((options.fields as string).trim() === '') {
|
||||
throw new Error('You have to add at least one field');
|
||||
}
|
||||
body.fields = (options.fields as string).split(',') as string[];
|
||||
} else {
|
||||
throw new Error('You have to add at least one field');
|
||||
body.fields = [
|
||||
'title',
|
||||
'dueDate',
|
||||
'description',
|
||||
'duration',
|
||||
'owner',
|
||||
'Deal.title',
|
||||
'PrimaryContact.name',
|
||||
'PrimaryContact.email',
|
||||
'PrimaryCompany.name',
|
||||
'PrimaryCompany.email',
|
||||
'tags',
|
||||
'type',
|
||||
'createdAt',
|
||||
'isCompleted',
|
||||
];
|
||||
}
|
||||
if (!jsonActive) {
|
||||
const filters: IDataObject[] = [];
|
||||
|
@ -483,7 +513,7 @@ export class Salesmate implements INodeType {
|
|||
};
|
||||
filter.condition = condition.condition;
|
||||
filter.data = condition.value;
|
||||
filters.push(filter)
|
||||
filters.push(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -617,12 +647,9 @@ export class Salesmate implements INodeType {
|
|||
const rawData = this.getNodeParameter('rawData', i) as boolean;
|
||||
responseData = await salesmateApiRequest.call(this, 'GET', `/v1/deals/${dealId}`);
|
||||
responseData = responseData.Data;
|
||||
|
||||
if (!rawData) {
|
||||
responseData = responseData.map((deal: IDataObject) => {
|
||||
const aux: IDataObject = {};
|
||||
aux[deal.fieldName as string] = deal.value;
|
||||
return aux;
|
||||
});
|
||||
responseData = simplifySalesmateData(responseData);
|
||||
}
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
|
@ -641,10 +668,26 @@ export class Salesmate implements INodeType {
|
|||
if (options.sortOrder) {
|
||||
qs.sortOrder = options.sortOrder as string;
|
||||
}
|
||||
if (options.fields) {
|
||||
if (options.fields !== undefined) {
|
||||
if ((options.fields as string).trim() === '') {
|
||||
throw new Error('You have to add at least one field');
|
||||
}
|
||||
body.fields = (options.fields as string).split(',') as string[];
|
||||
} else {
|
||||
throw new Error('You have to add at least one field');
|
||||
body.fields = [
|
||||
'title',
|
||||
'PrimaryContact.name',
|
||||
'PrimaryContact.email',
|
||||
'PrimaryCompany.name',
|
||||
'PrimaryCompany.email',
|
||||
'dealValue',
|
||||
'priority',
|
||||
'stage',
|
||||
'status',
|
||||
'owner',
|
||||
'tags',
|
||||
'createdAt',
|
||||
];
|
||||
}
|
||||
if (!jsonActive) {
|
||||
const filters: IDataObject[] = [];
|
||||
|
@ -660,7 +703,7 @@ export class Salesmate implements INodeType {
|
|||
};
|
||||
filter.condition = condition.condition;
|
||||
filter.data = condition.value;
|
||||
filters.push(filter)
|
||||
filters.push(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
36
packages/nodes-base/nodes/Segment/GenericFunctions.ts
Normal file
36
packages/nodes-base/nodes/Segment/GenericFunctions.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { OptionsWithUri } from 'request';
|
||||
import {
|
||||
IExecuteFunctions,
|
||||
IExecuteSingleFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
IWebhookFunctions,
|
||||
} from 'n8n-core';
|
||||
import { IDataObject } from 'n8n-workflow';
|
||||
|
||||
export async function segmentApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
const credentials = this.getCredentials('segmentApi');
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
const base64Key = Buffer.from(`${credentials.writekey}:`).toString('base64');
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
Authorization: `Basic ${base64Key}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method,
|
||||
qs,
|
||||
body,
|
||||
uri: uri ||`https://api.segment.io/v1${resource}`,
|
||||
json: true
|
||||
};
|
||||
if (!Object.keys(body).length) {
|
||||
delete options.body;
|
||||
}
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
} catch (error) {
|
||||
throw new Error('Segment Error: ' + error);
|
||||
}
|
||||
}
|
508
packages/nodes-base/nodes/Segment/IdentifyDescription.ts
Normal file
508
packages/nodes-base/nodes/Segment/IdentifyDescription.ts
Normal file
|
@ -0,0 +1,508 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const identifyOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'identify',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create an identity',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const identifyFields = [
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* identify:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'User ID',
|
||||
name: 'userId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'identify',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Traits',
|
||||
name: 'traits',
|
||||
placeholder: 'Add Trait',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'identify',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'traitsUi',
|
||||
displayName: 'Trait',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Email address of a user',
|
||||
},
|
||||
{
|
||||
displayName: 'First Name',
|
||||
name: 'firstname',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'First name of a user',
|
||||
},
|
||||
{
|
||||
displayName: 'Last Name',
|
||||
name: 'lastname',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Last name of a user',
|
||||
},
|
||||
{
|
||||
displayName: 'Gender',
|
||||
name: 'gender',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Gender of a user',
|
||||
},
|
||||
{
|
||||
displayName: 'Phone',
|
||||
name: 'phone',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Phone number of a user',
|
||||
},
|
||||
{
|
||||
displayName: 'Username',
|
||||
name: 'username',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'User’s username',
|
||||
},
|
||||
{
|
||||
displayName: 'Website',
|
||||
name: 'website',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Website of a user',
|
||||
},
|
||||
{
|
||||
displayName: 'Age',
|
||||
name: 'age',
|
||||
type: 'number',
|
||||
default: 1,
|
||||
description: 'Age of a user',
|
||||
},
|
||||
{
|
||||
displayName: 'Avatar',
|
||||
name: 'avatar',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'URL to an avatar image for the user',
|
||||
},
|
||||
{
|
||||
displayName: 'Birthday',
|
||||
name: 'birthday',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'User’s birthday',
|
||||
},
|
||||
{
|
||||
displayName: 'Created At',
|
||||
name: 'createdAt',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Date the user’s account was first created',
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
description: 'Description of the user',
|
||||
},
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Unique ID in your database for a user',
|
||||
},
|
||||
{
|
||||
displayName: 'Company',
|
||||
name: 'company',
|
||||
placeholder: 'Add Company',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'companyUi',
|
||||
displayName: 'Company',
|
||||
values: [
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Industry',
|
||||
name: 'industry',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Employee Count',
|
||||
name: 'employeeCount',
|
||||
type: 'number',
|
||||
default: 1,
|
||||
},
|
||||
{
|
||||
displayName: 'Plan',
|
||||
name: 'plan',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Address',
|
||||
name: 'address',
|
||||
placeholder: 'Add Address',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'addressUi',
|
||||
displayName: 'Address',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Street',
|
||||
name: 'street',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'City',
|
||||
name: 'city',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'State',
|
||||
name: 'state',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Postal Code',
|
||||
name: 'postalCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Country',
|
||||
name: 'country',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Context',
|
||||
name: 'context',
|
||||
placeholder: 'Add Context',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'identify',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'contextUi',
|
||||
displayName: 'Context',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Active',
|
||||
name: 'active',
|
||||
type: 'boolean',
|
||||
default: '',
|
||||
description: 'Whether a user is active',
|
||||
},
|
||||
{
|
||||
displayName: 'IP',
|
||||
name: 'ip',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Current user’s IP address.',
|
||||
},
|
||||
{
|
||||
displayName: 'Locale',
|
||||
name: 'locate',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Locale string for the current user, for example en-US.',
|
||||
},
|
||||
{
|
||||
displayName: 'Page',
|
||||
name: 'page',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Dictionary of information about the current page in the browser, containing hash, path, referrer, search, title and url',
|
||||
},
|
||||
{
|
||||
displayName: 'Timezone',
|
||||
name: 'timezone',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Timezones are sent as tzdata strings to add user timezone information which might be stripped from the timestamp, for example America/New_York',
|
||||
},
|
||||
{
|
||||
displayName: 'App',
|
||||
name: 'app',
|
||||
placeholder: 'Add App',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'appUi',
|
||||
displayName: 'App',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Version',
|
||||
name: 'version',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Build',
|
||||
name: 'build',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Campaign',
|
||||
name: 'campaign',
|
||||
placeholder: 'Campaign App',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'campaignUi',
|
||||
displayName: 'Campaign',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Source',
|
||||
name: 'source',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Medium',
|
||||
name: 'medium',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Term',
|
||||
name: 'term',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Content',
|
||||
name: 'content',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Device',
|
||||
name: 'device',
|
||||
placeholder: 'Add Device',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'deviceUi',
|
||||
displayName: 'Device',
|
||||
values: [
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Manufacturer',
|
||||
name: 'manufacturer',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Model',
|
||||
name: 'model',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Version',
|
||||
name: 'version',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Integration',
|
||||
name: 'integrations',
|
||||
placeholder: 'Add Integration',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'identify',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'integrationsUi',
|
||||
displayName: 'Integration',
|
||||
values: [
|
||||
{
|
||||
displayName: 'All',
|
||||
name: 'all',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Salesforce',
|
||||
name: 'salesforce',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
] as INodeProperties[];
|
10
packages/nodes-base/nodes/Segment/IdentifyInterface.ts
Normal file
10
packages/nodes-base/nodes/Segment/IdentifyInterface.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { IDataObject } from "n8n-workflow";
|
||||
|
||||
export interface IIdentify {
|
||||
userId?: string;
|
||||
anonymousId?: string;
|
||||
traits?: IDataObject;
|
||||
context?: IDataObject;
|
||||
integrations?: IDataObject;
|
||||
timestamp?: string;
|
||||
}
|
774
packages/nodes-base/nodes/Segment/Segment.node.ts
Normal file
774
packages/nodes-base/nodes/Segment/Segment.node.ts
Normal file
|
@ -0,0 +1,774 @@
|
|||
import {
|
||||
IExecuteFunctions,
|
||||
} from 'n8n-core';
|
||||
import {
|
||||
IDataObject,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
segmentApiRequest,
|
||||
} from './GenericFunctions';
|
||||
import {
|
||||
identifyFields,
|
||||
identifyOperations,
|
||||
} from './IdentifyDescription';
|
||||
import {
|
||||
IIdentify,
|
||||
} from './IdentifyInterface';
|
||||
import {
|
||||
trackOperations,
|
||||
trackFields,
|
||||
} from './TrackDescription';
|
||||
import { ITrack } from './TrackInterface';
|
||||
import * as uuid from 'uuid/v4';
|
||||
|
||||
export class Segment implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Segment',
|
||||
name: 'segment',
|
||||
icon: 'file:segment.png',
|
||||
group: ['output'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ":" + $parameter["resource"]}}',
|
||||
description: 'Consume Segment API',
|
||||
defaults: {
|
||||
name: 'Segment',
|
||||
color: '#6ebb99',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'segmentApi',
|
||||
required: true,
|
||||
}
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Identify',
|
||||
value: 'identify',
|
||||
description: 'Identify lets you tie a user to their actions.'
|
||||
},
|
||||
{
|
||||
name: 'Track',
|
||||
value: 'track',
|
||||
description: 'Track lets you record events',
|
||||
},
|
||||
],
|
||||
default: 'identify',
|
||||
description: 'Resource to consume.',
|
||||
},
|
||||
...identifyOperations,
|
||||
...trackOperations,
|
||||
...identifyFields,
|
||||
...trackFields,
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
const length = items.length as unknown as number;
|
||||
const qs: IDataObject = {};
|
||||
let responseData;
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (resource === 'identify') {
|
||||
//https://segment.com/docs/connections/sources/catalog/libraries/server/http-api/#identify
|
||||
if (operation === 'create') {
|
||||
const userId = this.getNodeParameter('userId', i) as string;
|
||||
const traits = (this.getNodeParameter('traits', i) as IDataObject).traitsUi as IDataObject;
|
||||
const context = (this.getNodeParameter('context', i) as IDataObject).contextUi as IDataObject;
|
||||
const integrations = (this.getNodeParameter('integrations', i) as IDataObject).integrationsUi as IDataObject;
|
||||
const body: IIdentify = {
|
||||
traits: {
|
||||
company: {},
|
||||
address: {},
|
||||
},
|
||||
context: {
|
||||
app: {},
|
||||
campaign: {},
|
||||
device: {},
|
||||
},
|
||||
integrations: {},
|
||||
};
|
||||
if (userId) {
|
||||
body.userId = userId as string;
|
||||
} else {
|
||||
body.anonymousId = uuid();
|
||||
}
|
||||
if (traits) {
|
||||
if (traits.email) {
|
||||
body.traits!.email = traits.email as string;
|
||||
}
|
||||
if (traits.firstname) {
|
||||
body.traits!.firstname = traits.firstname as string;
|
||||
}
|
||||
if (traits.lastname) {
|
||||
body.traits!.lastname = traits.lastname as string;
|
||||
}
|
||||
if (traits.gender) {
|
||||
body.traits!.gender = traits.gender as string;
|
||||
}
|
||||
if (traits.phone) {
|
||||
body.traits!.phone = traits.phone as string;
|
||||
}
|
||||
if (traits.username) {
|
||||
body.traits!.username = traits.username as string;
|
||||
}
|
||||
if (traits.website) {
|
||||
body.traits!.website = traits.website as string;
|
||||
}
|
||||
if (traits.age) {
|
||||
body.traits!.age = traits.age as number;
|
||||
}
|
||||
if (traits.avatar) {
|
||||
body.traits!.avatar = traits.avatar as string;
|
||||
}
|
||||
if (traits.birthday) {
|
||||
body.traits!.birthday = traits.birthday as string;
|
||||
}
|
||||
if (traits.createdAt) {
|
||||
body.traits!.createdAt = traits.createdAt as string;
|
||||
}
|
||||
if (traits.description) {
|
||||
body.traits!.description = traits.description as string;
|
||||
}
|
||||
if (traits.id) {
|
||||
body.traits!.id = traits.id as string;
|
||||
}
|
||||
if (traits.company) {
|
||||
const company = (traits.company as IDataObject).companyUi as IDataObject;
|
||||
if (company) {
|
||||
if (company.id) {
|
||||
//@ts-ignore
|
||||
body.traits.company.id = company.id as string;
|
||||
}
|
||||
if (company.name) {
|
||||
//@ts-ignore
|
||||
body.traits.company.name = company.name as string;
|
||||
}
|
||||
if (company.industry) {
|
||||
//@ts-ignore
|
||||
body.traits.company.industry = company.industry as string;
|
||||
}
|
||||
if (company.employeeCount) {
|
||||
//@ts-ignore
|
||||
body.traits.company.employeeCount = company.employeeCount as number;
|
||||
}
|
||||
if (company.plan) {
|
||||
//@ts-ignore
|
||||
body.traits.company.plan = company.plan as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (traits.address) {
|
||||
const address = (traits.address as IDataObject).addressUi as IDataObject;
|
||||
if (address) {
|
||||
if (address.street) {
|
||||
//@ts-ignore
|
||||
body.traits.address.street = address.street as string;
|
||||
}
|
||||
if (address.city) {
|
||||
//@ts-ignore
|
||||
body.traits.address.city = address.city as string;
|
||||
}
|
||||
if (address.state) {
|
||||
//@ts-ignore
|
||||
body.traits.address.state = address.state as string;
|
||||
}
|
||||
if (address.postalCode) {
|
||||
//@ts-ignore
|
||||
body.traits.address.postalCode = address.postalCode as string;
|
||||
}
|
||||
if (address.country) {
|
||||
//@ts-ignore
|
||||
body.traits.address.country = address.country as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (context) {
|
||||
if (context.active) {
|
||||
body.context!.active = context.active as boolean;
|
||||
}
|
||||
if (context.ip) {
|
||||
body.context!.ip = context.ip as string;
|
||||
}
|
||||
if (context.locate) {
|
||||
body.context!.locate = context.locate as string;
|
||||
}
|
||||
if (context.page) {
|
||||
body.context!.page = context.page as string;
|
||||
}
|
||||
if (context.timezone) {
|
||||
body.context!.timezone = context.timezone as string;
|
||||
}
|
||||
if (context.timezone) {
|
||||
body.context!.timezone = context.timezone as string;
|
||||
}
|
||||
if (context.app) {
|
||||
const app = (context.app as IDataObject).appUi as IDataObject;
|
||||
if (app) {
|
||||
if (app.name) {
|
||||
//@ts-ignore
|
||||
body.context.app.name = app.name as string;
|
||||
}
|
||||
if (app.version) {
|
||||
//@ts-ignore
|
||||
body.context.app.version = app.version as string;
|
||||
}
|
||||
if (app.build) {
|
||||
//@ts-ignore
|
||||
body.context.app.build = app.build as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (context.campaign) {
|
||||
const campaign = (context.campaign as IDataObject).campaignUi as IDataObject;
|
||||
if (campaign) {
|
||||
if (campaign.name) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.name = campaign.name as string;
|
||||
}
|
||||
if (campaign.source) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.source = campaign.source as string;
|
||||
}
|
||||
if (campaign.medium) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.medium = campaign.medium as string;
|
||||
}
|
||||
if (campaign.term) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.term = campaign.term as string;
|
||||
}
|
||||
if (campaign.content) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.content = campaign.content as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context.device) {
|
||||
const device = (context.device as IDataObject).deviceUi as IDataObject;
|
||||
if (device) {
|
||||
if (device.id) {
|
||||
//@ts-ignore
|
||||
body.context.device.id = device.id as string;
|
||||
}
|
||||
if (device.manufacturer) {
|
||||
//@ts-ignore
|
||||
body.context.device.manufacturer = device.manufacturer as string;
|
||||
}
|
||||
if (device.model) {
|
||||
//@ts-ignore
|
||||
body.context.device.model = device.model as string;
|
||||
}
|
||||
if (device.type) {
|
||||
//@ts-ignore
|
||||
body.context.device.type = device.type as string;
|
||||
}
|
||||
if (device.version) {
|
||||
//@ts-ignore
|
||||
body.context.device.version = device.version as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (integrations) {
|
||||
if (integrations.all) {
|
||||
body.integrations!.all = integrations.all as boolean;
|
||||
}
|
||||
if (integrations.salesforce) {
|
||||
body.integrations!.salesforce = integrations.salesforce as boolean;
|
||||
}
|
||||
}
|
||||
responseData = await segmentApiRequest.call(this, 'POST', '/identify', body);
|
||||
}
|
||||
}
|
||||
if (resource === 'track') {
|
||||
//https://segment.com/docs/connections/sources/catalog/libraries/server/http-api/#track
|
||||
if (operation === 'event') {
|
||||
const userId = this.getNodeParameter('userId', i) as string;
|
||||
const event = this.getNodeParameter('event', i) as string;
|
||||
const traits = (this.getNodeParameter('traits', i) as IDataObject).traitsUi as IDataObject;
|
||||
const context = (this.getNodeParameter('context', i) as IDataObject).contextUi as IDataObject;
|
||||
const integrations = (this.getNodeParameter('integrations', i) as IDataObject).integrationsUi as IDataObject;
|
||||
const properties = (this.getNodeParameter('properties', i) as IDataObject).propertiesUi as IDataObject;
|
||||
const body: ITrack = {
|
||||
event,
|
||||
traits: {
|
||||
company: {},
|
||||
address: {},
|
||||
},
|
||||
context: {
|
||||
app: {},
|
||||
campaign: {},
|
||||
device: {},
|
||||
},
|
||||
integrations: {},
|
||||
properties: {},
|
||||
};
|
||||
if (userId) {
|
||||
body.userId = userId as string;
|
||||
} else {
|
||||
body.anonymousId = uuid();
|
||||
}
|
||||
if (traits) {
|
||||
if (traits.email) {
|
||||
body.traits!.email = traits.email as string;
|
||||
}
|
||||
if (traits.firstname) {
|
||||
body.traits!.firstname = traits.firstname as string;
|
||||
}
|
||||
if (traits.lastname) {
|
||||
body.traits!.lastname = traits.lastname as string;
|
||||
}
|
||||
if (traits.gender) {
|
||||
body.traits!.gender = traits.gender as string;
|
||||
}
|
||||
if (traits.phone) {
|
||||
body.traits!.phone = traits.phone as string;
|
||||
}
|
||||
if (traits.username) {
|
||||
body.traits!.username = traits.username as string;
|
||||
}
|
||||
if (traits.website) {
|
||||
body.traits!.website = traits.website as string;
|
||||
}
|
||||
if (traits.age) {
|
||||
body.traits!.age = traits.age as number;
|
||||
}
|
||||
if (traits.avatar) {
|
||||
body.traits!.avatar = traits.avatar as string;
|
||||
}
|
||||
if (traits.birthday) {
|
||||
body.traits!.birthday = traits.birthday as string;
|
||||
}
|
||||
if (traits.createdAt) {
|
||||
body.traits!.createdAt = traits.createdAt as string;
|
||||
}
|
||||
if (traits.description) {
|
||||
body.traits!.description = traits.description as string;
|
||||
}
|
||||
if (traits.id) {
|
||||
body.traits!.id = traits.id as string;
|
||||
}
|
||||
if (traits.company) {
|
||||
const company = (traits.company as IDataObject).companyUi as IDataObject;
|
||||
if (company) {
|
||||
if (company.id) {
|
||||
//@ts-ignore
|
||||
body.traits.company.id = company.id as string;
|
||||
}
|
||||
if (company.name) {
|
||||
//@ts-ignore
|
||||
body.traits.company.name = company.name as string;
|
||||
}
|
||||
if (company.industry) {
|
||||
//@ts-ignore
|
||||
body.traits.company.industry = company.industry as string;
|
||||
}
|
||||
if (company.employeeCount) {
|
||||
//@ts-ignore
|
||||
body.traits.company.employeeCount = company.employeeCount as number;
|
||||
}
|
||||
if (company.plan) {
|
||||
//@ts-ignore
|
||||
body.traits.company.plan = company.plan as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (traits.address) {
|
||||
const address = (traits.address as IDataObject).addressUi as IDataObject;
|
||||
if (address) {
|
||||
if (address.street) {
|
||||
//@ts-ignore
|
||||
body.traits.address.street = address.street as string;
|
||||
}
|
||||
if (address.city) {
|
||||
//@ts-ignore
|
||||
body.traits.address.city = address.city as string;
|
||||
}
|
||||
if (address.state) {
|
||||
//@ts-ignore
|
||||
body.traits.address.state = address.state as string;
|
||||
}
|
||||
if (address.postalCode) {
|
||||
//@ts-ignore
|
||||
body.traits.address.postalCode = address.postalCode as string;
|
||||
}
|
||||
if (address.country) {
|
||||
//@ts-ignore
|
||||
body.traits.address.country = address.country as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (context) {
|
||||
if (context.active) {
|
||||
body.context!.active = context.active as boolean;
|
||||
}
|
||||
if (context.ip) {
|
||||
body.context!.ip = context.ip as string;
|
||||
}
|
||||
if (context.locate) {
|
||||
body.context!.locate = context.locate as string;
|
||||
}
|
||||
if (context.page) {
|
||||
body.context!.page = context.page as string;
|
||||
}
|
||||
if (context.timezone) {
|
||||
body.context!.timezone = context.timezone as string;
|
||||
}
|
||||
if (context.timezone) {
|
||||
body.context!.timezone = context.timezone as string;
|
||||
}
|
||||
if (context.app) {
|
||||
const app = (context.app as IDataObject).appUi as IDataObject;
|
||||
if (app) {
|
||||
if (app.name) {
|
||||
//@ts-ignore
|
||||
body.context.app.name = app.name as string;
|
||||
}
|
||||
if (app.version) {
|
||||
//@ts-ignore
|
||||
body.context.app.version = app.version as string;
|
||||
}
|
||||
if (app.build) {
|
||||
//@ts-ignore
|
||||
body.context.app.build = app.build as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (context.campaign) {
|
||||
const campaign = (context.campaign as IDataObject).campaignUi as IDataObject;
|
||||
if (campaign) {
|
||||
if (campaign.name) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.name = campaign.name as string;
|
||||
}
|
||||
if (campaign.source) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.source = campaign.source as string;
|
||||
}
|
||||
if (campaign.medium) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.medium = campaign.medium as string;
|
||||
}
|
||||
if (campaign.term) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.term = campaign.term as string;
|
||||
}
|
||||
if (campaign.content) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.content = campaign.content as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context.device) {
|
||||
const device = (context.device as IDataObject).deviceUi as IDataObject;
|
||||
if (device) {
|
||||
if (device.id) {
|
||||
//@ts-ignore
|
||||
body.context.device.id = device.id as string;
|
||||
}
|
||||
if (device.manufacturer) {
|
||||
//@ts-ignore
|
||||
body.context.device.manufacturer = device.manufacturer as string;
|
||||
}
|
||||
if (device.model) {
|
||||
//@ts-ignore
|
||||
body.context.device.model = device.model as string;
|
||||
}
|
||||
if (device.type) {
|
||||
//@ts-ignore
|
||||
body.context.device.type = device.type as string;
|
||||
}
|
||||
if (device.version) {
|
||||
//@ts-ignore
|
||||
body.context.device.version = device.version as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (integrations) {
|
||||
if (integrations.all) {
|
||||
body.integrations!.all = integrations.all as boolean;
|
||||
}
|
||||
if (integrations.salesforce) {
|
||||
body.integrations!.salesforce = integrations.salesforce as boolean;
|
||||
}
|
||||
}
|
||||
if (properties) {
|
||||
if (properties.revenue) {
|
||||
body.properties!.revenue = properties.revenue as number;
|
||||
}
|
||||
if (properties.currency) {
|
||||
body.properties!.currency = properties.currency as string;
|
||||
}
|
||||
if (properties.value) {
|
||||
body.properties!.value = properties.value as string;
|
||||
}
|
||||
}
|
||||
responseData = await segmentApiRequest.call(this, 'POST', '/track', body);
|
||||
}
|
||||
//https://segment.com/docs/connections/sources/catalog/libraries/server/http-api/#page
|
||||
if (operation === 'page') {
|
||||
const userId = this.getNodeParameter('userId', i) as string;
|
||||
const event = this.getNodeParameter('event', i) as string;
|
||||
const traits = (this.getNodeParameter('traits', i) as IDataObject).traitsUi as IDataObject;
|
||||
const context = (this.getNodeParameter('context', i) as IDataObject).contextUi as IDataObject;
|
||||
const integrations = (this.getNodeParameter('integrations', i) as IDataObject).integrationsUi as IDataObject;
|
||||
const properties = (this.getNodeParameter('properties', i) as IDataObject).propertiesUi as IDataObject;
|
||||
const body: ITrack = {
|
||||
event,
|
||||
traits: {
|
||||
company: {},
|
||||
address: {},
|
||||
},
|
||||
context: {
|
||||
app: {},
|
||||
campaign: {},
|
||||
device: {},
|
||||
},
|
||||
integrations: {},
|
||||
properties: {},
|
||||
};
|
||||
if (userId) {
|
||||
body.userId = userId as string;
|
||||
} else {
|
||||
body.anonymousId = uuid();
|
||||
}
|
||||
if (traits) {
|
||||
if (traits.email) {
|
||||
body.traits!.email = traits.email as string;
|
||||
}
|
||||
if (traits.firstname) {
|
||||
body.traits!.firstname = traits.firstname as string;
|
||||
}
|
||||
if (traits.lastname) {
|
||||
body.traits!.lastname = traits.lastname as string;
|
||||
}
|
||||
if (traits.gender) {
|
||||
body.traits!.gender = traits.gender as string;
|
||||
}
|
||||
if (traits.phone) {
|
||||
body.traits!.phone = traits.phone as string;
|
||||
}
|
||||
if (traits.username) {
|
||||
body.traits!.username = traits.username as string;
|
||||
}
|
||||
if (traits.website) {
|
||||
body.traits!.website = traits.website as string;
|
||||
}
|
||||
if (traits.age) {
|
||||
body.traits!.age = traits.age as number;
|
||||
}
|
||||
if (traits.avatar) {
|
||||
body.traits!.avatar = traits.avatar as string;
|
||||
}
|
||||
if (traits.birthday) {
|
||||
body.traits!.birthday = traits.birthday as string;
|
||||
}
|
||||
if (traits.createdAt) {
|
||||
body.traits!.createdAt = traits.createdAt as string;
|
||||
}
|
||||
if (traits.description) {
|
||||
body.traits!.description = traits.description as string;
|
||||
}
|
||||
if (traits.id) {
|
||||
body.traits!.id = traits.id as string;
|
||||
}
|
||||
if (traits.company) {
|
||||
const company = (traits.company as IDataObject).companyUi as IDataObject;
|
||||
if (company) {
|
||||
if (company.id) {
|
||||
//@ts-ignore
|
||||
body.traits.company.id = company.id as string;
|
||||
}
|
||||
if (company.name) {
|
||||
//@ts-ignore
|
||||
body.traits.company.name = company.name as string;
|
||||
}
|
||||
if (company.industry) {
|
||||
//@ts-ignore
|
||||
body.traits.company.industry = company.industry as string;
|
||||
}
|
||||
if (company.employeeCount) {
|
||||
//@ts-ignore
|
||||
body.traits.company.employeeCount = company.employeeCount as number;
|
||||
}
|
||||
if (company.plan) {
|
||||
//@ts-ignore
|
||||
body.traits.company.plan = company.plan as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (traits.address) {
|
||||
const address = (traits.address as IDataObject).addressUi as IDataObject;
|
||||
if (address) {
|
||||
if (address.street) {
|
||||
//@ts-ignore
|
||||
body.traits.address.street = address.street as string;
|
||||
}
|
||||
if (address.city) {
|
||||
//@ts-ignore
|
||||
body.traits.address.city = address.city as string;
|
||||
}
|
||||
if (address.state) {
|
||||
//@ts-ignore
|
||||
body.traits.address.state = address.state as string;
|
||||
}
|
||||
if (address.postalCode) {
|
||||
//@ts-ignore
|
||||
body.traits.address.postalCode = address.postalCode as string;
|
||||
}
|
||||
if (address.country) {
|
||||
//@ts-ignore
|
||||
body.traits.address.country = address.country as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (context) {
|
||||
if (context.active) {
|
||||
body.context!.active = context.active as boolean;
|
||||
}
|
||||
if (context.ip) {
|
||||
body.context!.ip = context.ip as string;
|
||||
}
|
||||
if (context.locate) {
|
||||
body.context!.locate = context.locate as string;
|
||||
}
|
||||
if (context.page) {
|
||||
body.context!.page = context.page as string;
|
||||
}
|
||||
if (context.timezone) {
|
||||
body.context!.timezone = context.timezone as string;
|
||||
}
|
||||
if (context.timezone) {
|
||||
body.context!.timezone = context.timezone as string;
|
||||
}
|
||||
if (context.app) {
|
||||
const app = (context.app as IDataObject).appUi as IDataObject;
|
||||
if (app) {
|
||||
if (app.name) {
|
||||
//@ts-ignore
|
||||
body.context.app.name = app.name as string;
|
||||
}
|
||||
if (app.version) {
|
||||
//@ts-ignore
|
||||
body.context.app.version = app.version as string;
|
||||
}
|
||||
if (app.build) {
|
||||
//@ts-ignore
|
||||
body.context.app.build = app.build as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (context.campaign) {
|
||||
const campaign = (context.campaign as IDataObject).campaignUi as IDataObject;
|
||||
if (campaign) {
|
||||
if (campaign.name) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.name = campaign.name as string;
|
||||
}
|
||||
if (campaign.source) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.source = campaign.source as string;
|
||||
}
|
||||
if (campaign.medium) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.medium = campaign.medium as string;
|
||||
}
|
||||
if (campaign.term) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.term = campaign.term as string;
|
||||
}
|
||||
if (campaign.content) {
|
||||
//@ts-ignore
|
||||
body.context.campaign.content = campaign.content as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context.device) {
|
||||
const device = (context.device as IDataObject).deviceUi as IDataObject;
|
||||
if (device) {
|
||||
if (device.id) {
|
||||
//@ts-ignore
|
||||
body.context.device.id = device.id as string;
|
||||
}
|
||||
if (device.manufacturer) {
|
||||
//@ts-ignore
|
||||
body.context.device.manufacturer = device.manufacturer as string;
|
||||
}
|
||||
if (device.model) {
|
||||
//@ts-ignore
|
||||
body.context.device.model = device.model as string;
|
||||
}
|
||||
if (device.type) {
|
||||
//@ts-ignore
|
||||
body.context.device.type = device.type as string;
|
||||
}
|
||||
if (device.version) {
|
||||
//@ts-ignore
|
||||
body.context.device.version = device.version as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (integrations) {
|
||||
if (integrations.all) {
|
||||
body.integrations!.all = integrations.all as boolean;
|
||||
}
|
||||
if (integrations.salesforce) {
|
||||
body.integrations!.salesforce = integrations.salesforce as boolean;
|
||||
}
|
||||
}
|
||||
if (properties) {
|
||||
if (properties.name) {
|
||||
body.properties!.name = properties.name as number;
|
||||
}
|
||||
if (properties.path) {
|
||||
body.properties!.path = properties.path as string;
|
||||
}
|
||||
if (properties.referrer) {
|
||||
body.properties!.referrer = properties.referrer as string;
|
||||
}
|
||||
if (properties.search) {
|
||||
body.properties!.search = properties.search as string;
|
||||
}
|
||||
if (properties.title) {
|
||||
body.properties!.title = properties.title as string;
|
||||
}
|
||||
if (properties.url) {
|
||||
body.properties!.url = properties.url as string;
|
||||
}
|
||||
if (properties.keywords) {
|
||||
body.properties!.keywords = properties.keywords as string;
|
||||
}
|
||||
}
|
||||
responseData = await segmentApiRequest.call(this, 'POST', '/page', body);
|
||||
}
|
||||
}
|
||||
if (Array.isArray(responseData)) {
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
} else {
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
}
|
||||
return [this.helpers.returnJsonArray(returnData)];
|
||||
}
|
||||
}
|
1155
packages/nodes-base/nodes/Segment/TrackDescription.ts
Normal file
1155
packages/nodes-base/nodes/Segment/TrackDescription.ts
Normal file
File diff suppressed because it is too large
Load diff
13
packages/nodes-base/nodes/Segment/TrackInterface.ts
Normal file
13
packages/nodes-base/nodes/Segment/TrackInterface.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { IDataObject } from "n8n-workflow";
|
||||
|
||||
export interface ITrack {
|
||||
event?: string;
|
||||
userId?: string;
|
||||
name?: string;
|
||||
anonymousId?: string;
|
||||
traits?: IDataObject;
|
||||
context?: IDataObject;
|
||||
timestamp?: string;
|
||||
properties?: IDataObject;
|
||||
integrations?: IDataObject;
|
||||
}
|
BIN
packages/nodes-base/nodes/Segment/segment.png
Normal file
BIN
packages/nodes-base/nodes/Segment/segment.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
276
packages/nodes-base/nodes/Trello/AttachmentDescription.ts
Normal file
276
packages/nodes-base/nodes/Trello/AttachmentDescription.ts
Normal file
|
@ -0,0 +1,276 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const attachmentOperations = [
|
||||
// ----------------------------------
|
||||
// attachment
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'attachment',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new attachment for a card',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete an attachment',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get the data of an attachments',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Returns all attachments for the card',
|
||||
}
|
||||
],
|
||||
default: 'getAll',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
|
||||
] as INodeProperties[];
|
||||
|
||||
export const attachmentFields = [
|
||||
|
||||
// ----------------------------------
|
||||
// attachment:create
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'attachment',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card to add attachment to.',
|
||||
},
|
||||
{
|
||||
displayName: 'Source URL',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'attachment',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The URL of the attachment to add.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'attachment',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'MIME Type',
|
||||
name: 'mimeType',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'image/png',
|
||||
description: 'The MIME type of the attachment to add.',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The name of the attachment to add.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// attachment:delete
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
resource: [
|
||||
'attachment',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card that attachment belongs to.',
|
||||
},
|
||||
{
|
||||
displayName: 'Attachment ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
resource: [
|
||||
'attachment',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the attachment to delete.',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// attachment:getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'attachment',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card to get attachments.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'attachment',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list of fields.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// attachment:get
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'attachment',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card to get attachment.',
|
||||
},
|
||||
{
|
||||
displayName: 'Attachment ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'attachment',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the attachment to get.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'attachment',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list of fields.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
] as INodeProperties[];
|
457
packages/nodes-base/nodes/Trello/BoardDescription.ts
Normal file
457
packages/nodes-base/nodes/Trello/BoardDescription.ts
Normal file
|
@ -0,0 +1,457 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const boardOperations = [
|
||||
// ----------------------------------
|
||||
// board
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'board',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new board',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a board',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get the data of a board',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a board',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
}
|
||||
] as INodeProperties[];
|
||||
|
||||
export const boardFields = [
|
||||
|
||||
// ----------------------------------
|
||||
// board:create
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'My board',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'board',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The name of the board',
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'board',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The description of the board',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'board',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Aging',
|
||||
name: 'prefs_cardAging',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Pirate',
|
||||
value: 'pirate',
|
||||
},
|
||||
{
|
||||
name: 'Regular',
|
||||
value: 'regular',
|
||||
},
|
||||
],
|
||||
default: 'regular',
|
||||
description: 'Determines the type of card aging that should take place on the board if card aging is enabled.',
|
||||
},
|
||||
{
|
||||
displayName: 'Background',
|
||||
name: 'prefs_background',
|
||||
type: 'string',
|
||||
default: 'blue',
|
||||
description: 'The id of a custom background or one of: blue, orange, green, red, purple, pink, lime, sky, grey.',
|
||||
},
|
||||
{
|
||||
displayName: 'Comments',
|
||||
name: 'prefs_comments',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Disabled',
|
||||
value: 'disabled',
|
||||
},
|
||||
{
|
||||
name: 'Members',
|
||||
value: 'members',
|
||||
},
|
||||
{
|
||||
name: 'Observers',
|
||||
value: 'observers',
|
||||
},
|
||||
{
|
||||
name: 'Organization',
|
||||
value: 'org',
|
||||
},
|
||||
{
|
||||
name: 'Public',
|
||||
value: 'public',
|
||||
},
|
||||
],
|
||||
default: 'members',
|
||||
description: 'Who can comment on cards on this board.',
|
||||
},
|
||||
{
|
||||
displayName: 'Covers',
|
||||
name: 'prefs_cardCovers',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Determines whether card covers are enabled.',
|
||||
},
|
||||
{
|
||||
displayName: 'Invitations',
|
||||
name: 'prefs_invitations',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Admins',
|
||||
value: 'admins',
|
||||
},
|
||||
{
|
||||
name: 'Members',
|
||||
value: 'members',
|
||||
},
|
||||
],
|
||||
default: 'members',
|
||||
description: 'Determines what types of members can invite users to join.',
|
||||
},
|
||||
{
|
||||
displayName: 'Keep From Source',
|
||||
name: 'keepFromSource',
|
||||
type: 'string',
|
||||
default: 'none',
|
||||
description: 'To keep cards from the original board pass in the value cards.',
|
||||
},
|
||||
{
|
||||
displayName: 'Labels',
|
||||
name: 'defaultLabels',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Determines whether to use the default set of labels.',
|
||||
},
|
||||
{
|
||||
displayName: 'Lists',
|
||||
name: 'defaultLists',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Determines whether to add the default set of lists to a board(To Do, Doing, Done).It is ignored if idBoardSource is provided.',
|
||||
},
|
||||
{
|
||||
displayName: 'Organization ID',
|
||||
name: 'idOrganization',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The id or name of the team the board should belong to.',
|
||||
},
|
||||
{
|
||||
displayName: 'Permission Level',
|
||||
name: 'prefs_permissionLevel',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Organization',
|
||||
value: 'org',
|
||||
},
|
||||
{
|
||||
name: 'Private',
|
||||
value: 'private',
|
||||
},
|
||||
{
|
||||
name: 'Public',
|
||||
value: 'public',
|
||||
},
|
||||
],
|
||||
default: 'private',
|
||||
description: 'The permissions level of the board.',
|
||||
},
|
||||
{
|
||||
displayName: 'Power Ups',
|
||||
name: 'powerUps',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'All',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
name: 'Calendar',
|
||||
value: 'calendar',
|
||||
},
|
||||
{
|
||||
name: 'Card Aging',
|
||||
value: 'cardAging',
|
||||
},
|
||||
{
|
||||
name: 'Recap',
|
||||
value: 'recap',
|
||||
},
|
||||
{
|
||||
name: 'Voting',
|
||||
value: 'voting',
|
||||
},
|
||||
],
|
||||
default: 'all',
|
||||
description: 'The Power-Ups that should be enabled on the new board.',
|
||||
},
|
||||
{
|
||||
displayName: 'Self Join',
|
||||
name: 'prefs_selfJoin',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Determines whether users can join the boards themselves or whether they have to be invited.',
|
||||
},
|
||||
{
|
||||
displayName: 'Source IDs',
|
||||
name: 'idBoardSource',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The id of a board to copy into the new board.',
|
||||
},
|
||||
{
|
||||
displayName: 'Voting',
|
||||
name: 'prefs_voting',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Disabled',
|
||||
value: 'disabled',
|
||||
},
|
||||
{
|
||||
name: 'Members',
|
||||
value: 'members',
|
||||
},
|
||||
{
|
||||
name: 'Observers',
|
||||
value: 'observers',
|
||||
},
|
||||
{
|
||||
name: 'Organization',
|
||||
value: 'org',
|
||||
},
|
||||
{
|
||||
name: 'Public',
|
||||
value: 'public',
|
||||
},
|
||||
],
|
||||
default: 'disabled',
|
||||
description: 'Who can vote on this board.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// board:delete
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
resource: [
|
||||
'board',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the board to delete.',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// board:get
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'board',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the board to get.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'board',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list:<br />closed, dateLastActivity, dateLastView, desc, descData,<br />idOrganization, invitations, invited, labelNames, memberships,<br />name, pinned, powerUps, prefs, shortLink, shortUrl,<br />starred, subscribed, url',
|
||||
},
|
||||
{
|
||||
displayName: 'Plugin Data',
|
||||
name: 'pluginData',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to include pluginData on the card with the response.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// board:update
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
resource: [
|
||||
'board',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the board to update.',
|
||||
},
|
||||
{
|
||||
displayName: 'Update Fields',
|
||||
name: 'updateFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
resource: [
|
||||
'board',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Closed',
|
||||
name: 'closed',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether the board is closed.',
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'desc',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'New description of the board',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'New name of the board',
|
||||
},
|
||||
{
|
||||
displayName: 'Organization ID',
|
||||
name: 'idOrganization',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The id of the team the board should be moved to.',
|
||||
},
|
||||
{
|
||||
displayName: 'Subscribed',
|
||||
name: 'subscribed',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether the acting user is subscribed to the board.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
] as INodeProperties[];
|
429
packages/nodes-base/nodes/Trello/CardDescription.ts
Normal file
429
packages/nodes-base/nodes/Trello/CardDescription.ts
Normal file
|
@ -0,0 +1,429 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const cardOperations = [
|
||||
// ----------------------------------
|
||||
// card
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'card',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new card',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a card',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get the data of a card',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a card',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const cardFields = [
|
||||
// ----------------------------------
|
||||
// card:create
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'List ID',
|
||||
name: 'listId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'card',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The id of the list to create card in',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'My card',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'card',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The name of the card',
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'card',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The description of the card',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'card',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Due Date',
|
||||
name: 'due',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'A due date for the card.',
|
||||
},
|
||||
{
|
||||
displayName: 'Due Complete',
|
||||
name: 'dueComplete',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'If the card is completed.',
|
||||
},
|
||||
{
|
||||
displayName: 'Position',
|
||||
name: 'pos',
|
||||
type: 'string',
|
||||
default: 'bottom',
|
||||
description: 'The position of the new card. top, bottom, or a positive float.',
|
||||
},
|
||||
{
|
||||
displayName: 'Member IDs',
|
||||
name: 'idMembers',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Comma-separated list of member IDs to add to the card.',
|
||||
},
|
||||
{
|
||||
displayName: 'Label IDs',
|
||||
name: 'idLabels',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Comma-separated list of label IDs to add to the card.',
|
||||
},
|
||||
{
|
||||
displayName: 'URL Source',
|
||||
name: 'urlSource',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'A source URL to attach to card.',
|
||||
},
|
||||
{
|
||||
displayName: 'Source ID',
|
||||
name: 'idCardSource',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The ID of a card to copy into the new card.',
|
||||
},
|
||||
{
|
||||
displayName: 'Keep from source',
|
||||
name: 'keepFromSource',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'If using idCardSource you can specify which properties to copy over. all or comma-separated list of: attachments, checklists, comments, due, labels, members, stickers',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// card:delete
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
resource: [
|
||||
'card',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card to delete.',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// card:get
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'card',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card to get.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'card',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list:<br />badges, checkItemStates, closed, dateLastActivity, desc,<br />descData, due, email, idBoard, idChecklists, idLabels, idList,<br />idMembers, idShort, idAttachmentCover, manualCoverAttachment<br />, labels, name, pos, shortUrl, url',
|
||||
},
|
||||
{
|
||||
displayName: 'Board',
|
||||
name: 'board',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to return the board object the card is on.',
|
||||
},
|
||||
{
|
||||
displayName: 'Board Fields',
|
||||
name: 'board_fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list:<br />name, desc, descData, closed, idOrganization, pinned, url, prefs',
|
||||
},
|
||||
{
|
||||
displayName: 'Custom Field Items',
|
||||
name: 'customFieldItems',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to include the customFieldItems.',
|
||||
},
|
||||
{
|
||||
displayName: 'Members',
|
||||
name: 'members',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to return member objects for members on the card.',
|
||||
},
|
||||
{
|
||||
displayName: 'Member Fields',
|
||||
name: 'member_fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list:<br />avatarHash, fullName, initials, username',
|
||||
},
|
||||
{
|
||||
displayName: 'Plugin Data',
|
||||
name: 'pluginData',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to include pluginData on the card with the response.',
|
||||
},
|
||||
{
|
||||
displayName: 'Stickers',
|
||||
name: 'stickers',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to include sticker models with the response.',
|
||||
},
|
||||
{
|
||||
displayName: 'Sticker Fields',
|
||||
name: 'sticker_fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list of sticker fields.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// card:update
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
resource: [
|
||||
'card',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card to update.',
|
||||
},
|
||||
{
|
||||
displayName: 'Update Fields',
|
||||
name: 'updateFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
resource: [
|
||||
'card',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Attachment Cover',
|
||||
name: 'idAttachmentCover',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The ID of the image attachment the card should use as its cover, or null for none.',
|
||||
},
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'idBoard',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The ID of the board the card should be on.',
|
||||
},
|
||||
{
|
||||
displayName: 'Closed',
|
||||
name: 'closed',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether the board is closed.',
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'desc',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'New description of the board.',
|
||||
},
|
||||
{
|
||||
displayName: 'Due Date',
|
||||
name: 'due',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'A due date for the card.',
|
||||
},
|
||||
{
|
||||
displayName: 'Due Complete',
|
||||
name: 'dueComplete',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'If the card is completed.',
|
||||
},
|
||||
{
|
||||
displayName: 'Label IDs',
|
||||
name: 'idLabels',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Comma-separated list of label IDs to set on card.',
|
||||
},
|
||||
{
|
||||
displayName: 'List ID',
|
||||
name: 'idList',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The ID of the list the card should be in.',
|
||||
},
|
||||
{
|
||||
displayName: 'Member IDs',
|
||||
name: 'idMembers',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Comma-separated list of member IDs to set on card.',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'New name of the board',
|
||||
},
|
||||
{
|
||||
displayName: 'Position',
|
||||
name: 'pos',
|
||||
type: 'string',
|
||||
default: 'bottom',
|
||||
description: 'The position of the card. top, bottom, or a positive float.',
|
||||
},
|
||||
{
|
||||
displayName: 'Subscribed',
|
||||
name: 'subscribed',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether the acting user is subscribed to the board.',
|
||||
},
|
||||
],
|
||||
},
|
||||
] as INodeProperties[];
|
528
packages/nodes-base/nodes/Trello/ChecklistDescription.ts
Normal file
528
packages/nodes-base/nodes/Trello/ChecklistDescription.ts
Normal file
|
@ -0,0 +1,528 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const checklistOperations = [
|
||||
// ----------------------------------
|
||||
// checklist
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new checklist',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a checklist',
|
||||
},
|
||||
{
|
||||
name: 'Delete Checklist Item',
|
||||
value: 'deleteCheckItem',
|
||||
description: 'Delete a checklist item',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get the data of a checklist',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Returns all checklists for the card',
|
||||
},
|
||||
{
|
||||
name: 'Get Checklist Items',
|
||||
value: 'getCheckItem',
|
||||
description: 'Get a specific Checklist on a card',
|
||||
},
|
||||
{
|
||||
name: 'Get Completed Checklist Items',
|
||||
value: 'completedCheckItems',
|
||||
description: 'Get the completed Checklist items on a card',
|
||||
},
|
||||
{
|
||||
name: 'Update Checklist Item',
|
||||
value: 'updateCheckItem',
|
||||
description: 'Update an item in a checklist on a card.',
|
||||
},
|
||||
],
|
||||
default: 'getAll',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
|
||||
] as INodeProperties[];
|
||||
|
||||
export const checklistFields = [
|
||||
// ----------------------------------
|
||||
// checklist:create
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card to add checklist to.',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The URL of the checklist to add.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Id Of Checklist Source',
|
||||
name: 'idChecklistSource',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The ID of a source checklist to copy into the new one.',
|
||||
},
|
||||
{
|
||||
displayName: 'Position',
|
||||
name: 'pos',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The position of the checklist on the card. One of: top, bottom, or a positive number.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// checklist:delete
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card that checklist belongs to.',
|
||||
},
|
||||
{
|
||||
displayName: 'Checklist ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the checklist to delete.',
|
||||
},
|
||||
|
||||
|
||||
// ----------------------------------
|
||||
// checklist:getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card to get checklists.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list of fields.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// checklist:get
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Checklist ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the checklist to get.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list of fields.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// checklist:deleteCheckItem
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'deleteCheckItem',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card that checklist belongs to.',
|
||||
},
|
||||
{
|
||||
displayName: 'CheckItem ID',
|
||||
name: 'checkItemId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'deleteCheckItem',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the checklist item to delete.',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// checklist:getCheckItem
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getCheckItem',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card that checklist belongs to.',
|
||||
},
|
||||
{
|
||||
displayName: 'CheckItem ID',
|
||||
name: 'checkItemId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getCheckItem',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the checklist item to get.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getCheckItem',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list of fields.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// checklist:updateCheckItem
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'updateCheckItem',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card that checklist belongs to.',
|
||||
},
|
||||
{
|
||||
displayName: 'CheckItem ID',
|
||||
name: 'checkItemId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'updateCheckItem',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the checklist item to update.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'updateCheckItem',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The new name for the checklist item.',
|
||||
},
|
||||
{
|
||||
displayName: 'State',
|
||||
name: 'state',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'complete',
|
||||
value: 'complete'
|
||||
},
|
||||
{
|
||||
name: 'incomplete',
|
||||
value: 'incomplete',
|
||||
},
|
||||
],
|
||||
default: 'complete',
|
||||
description: 'The resource to operate on.',
|
||||
},
|
||||
{
|
||||
displayName: 'Checklist ID',
|
||||
name: 'checklistId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The ID of the checklist this item is in',
|
||||
},
|
||||
{
|
||||
displayName: 'Position',
|
||||
name: 'pos',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The position of the checklist on the card. One of: top, bottom, or a positive number.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// checklist:completedCheckItems
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'completedCheckItems',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card for checkItems.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'completedCheckItems',
|
||||
],
|
||||
resource: [
|
||||
'checklist',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list of: "idCheckItem", "state".',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
] as INodeProperties[];
|
467
packages/nodes-base/nodes/Trello/LabelDescription.ts
Normal file
467
packages/nodes-base/nodes/Trello/LabelDescription.ts
Normal file
|
@ -0,0 +1,467 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const labelOperations = [
|
||||
// ----------------------------------
|
||||
// label
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Add to Card',
|
||||
value: 'addLabel',
|
||||
description: 'Add a label to a card.',
|
||||
},
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new label',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a label',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get the data of a label',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Returns all label for the board',
|
||||
},
|
||||
{
|
||||
name: 'Remove From Card',
|
||||
value: 'removeLabel',
|
||||
description: 'Remove a label from a card.',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a label.',
|
||||
}
|
||||
|
||||
],
|
||||
default: 'getAll',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
|
||||
] as INodeProperties[];
|
||||
|
||||
export const labelFields = [
|
||||
// ----------------------------------
|
||||
// label:create
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'boardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the board to create the label on.',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'Name for the label.',
|
||||
},
|
||||
{
|
||||
displayName: 'Color',
|
||||
name: 'color',
|
||||
type: 'options',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'black',
|
||||
value: 'black',
|
||||
},
|
||||
{
|
||||
name: 'blue',
|
||||
value: 'blue',
|
||||
},
|
||||
{
|
||||
name: 'green',
|
||||
value: 'green'
|
||||
},
|
||||
{
|
||||
name: 'orange',
|
||||
value: 'orange',
|
||||
},
|
||||
{
|
||||
name: 'lime',
|
||||
value: 'lime',
|
||||
},
|
||||
{
|
||||
name: 'null',
|
||||
value: 'null',
|
||||
},
|
||||
{
|
||||
name: 'pink',
|
||||
value: 'pink',
|
||||
},
|
||||
{
|
||||
name: 'purple',
|
||||
value: 'purple',
|
||||
},
|
||||
{
|
||||
name: 'red',
|
||||
value: 'red',
|
||||
},
|
||||
{
|
||||
name: 'sky',
|
||||
value: 'sky',
|
||||
},
|
||||
{
|
||||
name: 'yellow',
|
||||
value: 'yellow'
|
||||
},
|
||||
],
|
||||
default: 'null',
|
||||
description: 'The color for the label.',
|
||||
},
|
||||
|
||||
|
||||
// ----------------------------------
|
||||
// label:delete
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Label ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the label to delete.',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// label:getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'boardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the board to get label.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list of fields.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// label:get
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Label ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'Get information about a label by ID.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: 'all',
|
||||
description: 'Fields to return. Either "all" or a comma-separated list of fields.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// label:addLabel
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'addLabel',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card to get label.',
|
||||
},
|
||||
{
|
||||
displayName: 'Label ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'addLabel',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the label to add.',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// label:removeLabel
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Card ID',
|
||||
name: 'cardId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'removeLabel',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the card to remove label from.',
|
||||
},
|
||||
{
|
||||
displayName: 'Label ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'removeLabel',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the label to remove.',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// label:update
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Label ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the label to update.',
|
||||
},
|
||||
{
|
||||
displayName: 'Update Fields',
|
||||
name: 'updateFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
resource: [
|
||||
'label',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Name of the label.',
|
||||
},
|
||||
{
|
||||
displayName: 'Color',
|
||||
name: 'color',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'black',
|
||||
value: 'black',
|
||||
},
|
||||
{
|
||||
name: 'blue',
|
||||
value: 'blue',
|
||||
},
|
||||
{
|
||||
name: 'green',
|
||||
value: 'green'
|
||||
},
|
||||
{
|
||||
name: 'orange',
|
||||
value: 'orange',
|
||||
},
|
||||
{
|
||||
name: 'lime',
|
||||
value: 'lime',
|
||||
},
|
||||
{
|
||||
name: 'null',
|
||||
value: 'null',
|
||||
},
|
||||
{
|
||||
name: 'pink',
|
||||
value: 'pink',
|
||||
},
|
||||
{
|
||||
name: 'purple',
|
||||
value: 'purple',
|
||||
},
|
||||
{
|
||||
name: 'red',
|
||||
value: 'red',
|
||||
},
|
||||
{
|
||||
name: 'sky',
|
||||
value: 'sky',
|
||||
},
|
||||
{
|
||||
name: 'yellow',
|
||||
value: 'yellow'
|
||||
},
|
||||
],
|
||||
default: 'null',
|
||||
description: 'The color for the label.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
] as INodeProperties[];
|
247
packages/nodes-base/nodes/Trello/ListDescription.ts
Normal file
247
packages/nodes-base/nodes/Trello/ListDescription.ts
Normal file
|
@ -0,0 +1,247 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const listOperations = [
|
||||
// ----------------------------------
|
||||
// list
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: "Operation",
|
||||
name: "operation",
|
||||
type: "options",
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ["list"]
|
||||
}
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: "Archive",
|
||||
value: "archive",
|
||||
description: "Archive/Unarchive a list"
|
||||
},
|
||||
{
|
||||
name: "Create",
|
||||
value: "create",
|
||||
description: "Create a new list"
|
||||
},
|
||||
{
|
||||
name: "Get",
|
||||
value: "get",
|
||||
description: "Get the data of a list"
|
||||
},
|
||||
{
|
||||
name: "Update",
|
||||
value: "update",
|
||||
description: "Update a list"
|
||||
}
|
||||
],
|
||||
default: "create",
|
||||
description: "The operation to perform."
|
||||
}
|
||||
] as INodeProperties[];
|
||||
|
||||
export const listFields = [
|
||||
// ----------------------------------
|
||||
// list:archive
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: "List ID",
|
||||
name: "id",
|
||||
type: "string",
|
||||
default: "",
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ["archive"],
|
||||
resource: ["list"]
|
||||
}
|
||||
},
|
||||
description: "The ID of the list to archive or unarchive."
|
||||
},
|
||||
{
|
||||
displayName: "Archive",
|
||||
name: "archive",
|
||||
type: "boolean",
|
||||
default: false,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ["archive"],
|
||||
resource: ["list"]
|
||||
}
|
||||
},
|
||||
description: "If the list should be archived or unarchived."
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// list:create
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: "Board ID",
|
||||
name: "idBoard",
|
||||
type: "string",
|
||||
default: "",
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ["create"],
|
||||
resource: ["list"]
|
||||
}
|
||||
},
|
||||
description: "The ID of the board the list should be created in"
|
||||
},
|
||||
{
|
||||
displayName: "Name",
|
||||
name: "name",
|
||||
type: "string",
|
||||
default: "",
|
||||
placeholder: "My list",
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ["create"],
|
||||
resource: ["list"]
|
||||
}
|
||||
},
|
||||
description: "The name of the list"
|
||||
},
|
||||
{
|
||||
displayName: "Additional Fields",
|
||||
name: "additionalFields",
|
||||
type: "collection",
|
||||
placeholder: "Add Field",
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ["create"],
|
||||
resource: ["list"]
|
||||
}
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: "List Source",
|
||||
name: "idListSource",
|
||||
type: "string",
|
||||
default: "",
|
||||
description: "ID of the list to copy into the new list."
|
||||
},
|
||||
{
|
||||
displayName: "Position",
|
||||
name: "pos",
|
||||
type: "string",
|
||||
default: "bottom",
|
||||
description:
|
||||
"The position of the new list. top, bottom, or a positive float."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// list:get
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: "List ID",
|
||||
name: "id",
|
||||
type: "string",
|
||||
default: "",
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ["get"],
|
||||
resource: ["list"]
|
||||
}
|
||||
},
|
||||
description: "The ID of the list to get."
|
||||
},
|
||||
{
|
||||
displayName: "Additional Fields",
|
||||
name: "additionalFields",
|
||||
type: "collection",
|
||||
placeholder: "Add Field",
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ["get"],
|
||||
resource: ["list"]
|
||||
}
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: "Fields",
|
||||
name: "fields",
|
||||
type: "string",
|
||||
default: "all",
|
||||
description:
|
||||
'Fields to return. Either "all" or a comma-separated list of fields.'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// list:update
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: "List ID",
|
||||
name: "id",
|
||||
type: "string",
|
||||
default: "",
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ["update"],
|
||||
resource: ["list"]
|
||||
}
|
||||
},
|
||||
description: "The ID of the list to update."
|
||||
},
|
||||
{
|
||||
displayName: "Update Fields",
|
||||
name: "updateFields",
|
||||
type: "collection",
|
||||
placeholder: "Add Field",
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ["update"],
|
||||
resource: ["list"]
|
||||
}
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: "Board ID",
|
||||
name: "idBoard",
|
||||
type: "string",
|
||||
default: "",
|
||||
description: "ID of a board the list should be moved to."
|
||||
},
|
||||
{
|
||||
displayName: "Closed",
|
||||
name: "closed",
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Whether the list is closed."
|
||||
},
|
||||
{
|
||||
displayName: "Name",
|
||||
name: "name",
|
||||
type: "string",
|
||||
default: "",
|
||||
description: "New name of the list"
|
||||
},
|
||||
{
|
||||
displayName: "Position",
|
||||
name: "pos",
|
||||
type: "string",
|
||||
default: "bottom",
|
||||
description:
|
||||
"The position of the list. top, bottom, or a positive float."
|
||||
},
|
||||
{
|
||||
displayName: "Subscribed",
|
||||
name: "subscribed",
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Whether the acting user is subscribed to the list."
|
||||
}
|
||||
]
|
||||
}
|
||||
] as INodeProperties[];
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "n8n-nodes-base",
|
||||
"version": "0.44.0",
|
||||
"version": "0.45.1",
|
||||
"description": "Base nodes of n8n",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
|
@ -38,6 +38,7 @@
|
|||
"dist/credentials/CodaApi.credentials.js",
|
||||
"dist/credentials/CopperApi.credentials.js",
|
||||
"dist/credentials/ClearbitApi.credentials.js",
|
||||
"dist/credentials/DisqusApi.credentials.js",
|
||||
"dist/credentials/DropboxApi.credentials.js",
|
||||
"dist/credentials/EventbriteApi.credentials.js",
|
||||
"dist/credentials/FreshdeskApi.credentials.js",
|
||||
|
@ -51,6 +52,7 @@
|
|||
"dist/credentials/HttpDigestAuth.credentials.js",
|
||||
"dist/credentials/HttpHeaderAuth.credentials.js",
|
||||
"dist/credentials/HubspotApi.credentials.js",
|
||||
"dist/credentials/HunterApi.credentials.js",
|
||||
"dist/credentials/Imap.credentials.js",
|
||||
"dist/credentials/IntercomApi.credentials.js",
|
||||
"dist/credentials/JiraSoftwareCloudApi.credentials.js",
|
||||
|
@ -75,6 +77,7 @@
|
|||
"dist/credentials/Smtp.credentials.js",
|
||||
"dist/credentials/StripeApi.credentials.js",
|
||||
"dist/credentials/SalesmateApi.credentials.js",
|
||||
"dist/credentials/SegmentApi.credentials.js",
|
||||
"dist/credentials/TelegramApi.credentials.js",
|
||||
"dist/credentials/TodoistApi.credentials.js",
|
||||
"dist/credentials/TrelloApi.credentials.js",
|
||||
|
@ -107,6 +110,7 @@
|
|||
"dist/nodes/Clearbit/Clearbit.node.js",
|
||||
"dist/nodes/Cron.node.js",
|
||||
"dist/nodes/Discord/Discord.node.js",
|
||||
"dist/nodes/Disqus/Disqus.node.js",
|
||||
"dist/nodes/Dropbox/Dropbox.node.js",
|
||||
"dist/nodes/EditImage.node.js",
|
||||
"dist/nodes/EmailReadImap.node.js",
|
||||
|
@ -132,6 +136,7 @@
|
|||
"dist/nodes/HtmlExtract/HtmlExtract.node.js",
|
||||
"dist/nodes/HttpRequest.node.js",
|
||||
"dist/nodes/Hubspot/Hubspot.node.js",
|
||||
"dist/nodes/Hunter/Hunter.node.js",
|
||||
"dist/nodes/If.node.js",
|
||||
"dist/nodes/Intercom/Intercom.node.js",
|
||||
"dist/nodes/Interval.node.js",
|
||||
|
@ -174,6 +179,7 @@
|
|||
"dist/nodes/Stripe/StripeTrigger.node.js",
|
||||
"dist/nodes/Switch.node.js",
|
||||
"dist/nodes/Salesmate/Salesmate.node.js",
|
||||
"dist/nodes/Segment/Segment.node.js",
|
||||
"dist/nodes/Telegram/Telegram.node.js",
|
||||
"dist/nodes/Telegram/TelegramTrigger.node.js",
|
||||
"dist/nodes/Todoist/Todoist.node.js",
|
||||
|
@ -208,10 +214,11 @@
|
|||
"@types/nodemailer": "^4.6.5",
|
||||
"@types/redis": "^2.8.11",
|
||||
"@types/request-promise-native": "~1.0.15",
|
||||
"@types/uuid": "^3.4.6",
|
||||
"@types/xml2js": "^0.4.3",
|
||||
"gulp": "^4.0.0",
|
||||
"jest": "^24.9.0",
|
||||
"n8n-workflow": "~0.20.0",
|
||||
"n8n-workflow": "~0.21.0",
|
||||
"ts-jest": "^24.0.2",
|
||||
"tslint": "^5.17.0",
|
||||
"typescript": "~3.7.4"
|
||||
|
@ -232,13 +239,14 @@
|
|||
"lodash.unset": "^4.5.2",
|
||||
"mongodb": "^3.3.2",
|
||||
"mysql2": "^2.0.1",
|
||||
"n8n-core": "~0.22.0",
|
||||
"n8n-core": "~0.23.0",
|
||||
"nodemailer": "^5.1.1",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"pg-promise": "^9.0.3",
|
||||
"redis": "^2.8.0",
|
||||
"rhea": "^1.0.11",
|
||||
"rss-parser": "^3.7.0",
|
||||
"uuid": "^3.4.0",
|
||||
"vm2": "^3.6.10",
|
||||
"xlsx": "^0.14.3",
|
||||
"xml2js": "^0.4.22"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "n8n-workflow",
|
||||
"version": "0.20.0",
|
||||
"version": "0.21.0",
|
||||
"description": "Workflow base code of n8n",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
|
|
|
@ -495,7 +495,7 @@ export interface IWebhookData {
|
|||
node: string;
|
||||
path: string;
|
||||
webhookDescription: IWebhookDescription;
|
||||
workflow: Workflow;
|
||||
workflowId: string;
|
||||
workflowExecuteAdditionalData: IWorkflowExecuteAdditionalData;
|
||||
}
|
||||
|
||||
|
|
|
@ -771,7 +771,7 @@ export function getNodeWebhooks(workflow: Workflow, node: INode, additionalData:
|
|||
node: node.name,
|
||||
path,
|
||||
webhookDescription,
|
||||
workflow,
|
||||
workflowId: workflow.id,
|
||||
workflowExecuteAdditionalData: additionalData,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -907,41 +907,6 @@ export class Workflow {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the hooks of the node
|
||||
*
|
||||
* @param {string} hookName The name of the hook to execute
|
||||
* @param {IWebhookData} webhookData
|
||||
* @param {INodeExecuteFunctions} nodeExecuteFunctions
|
||||
* @param {WorkflowExecuteMode} mode
|
||||
* @returns {Promise<void>}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
async runNodeHooks(hookName: string, webhookData: IWebhookData, nodeExecuteFunctions: INodeExecuteFunctions, mode: WorkflowExecuteMode): Promise<void> {
|
||||
const node = this.getNode(webhookData.node) as INode;
|
||||
const nodeType = this.nodeTypes.getByName(node.type) as INodeType;
|
||||
|
||||
if (nodeType.description.hooks === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (nodeType.description.hooks[hookName] === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (nodeType.hooks === undefined && nodeType.description.hooks[hookName]!.length !== 0) {
|
||||
// There should be hook functions but they do not exist
|
||||
throw new Error('There are hooks defined to run but are not implemented.');
|
||||
}
|
||||
|
||||
for (const hookDescription of nodeType.description.hooks[hookName]!) {
|
||||
const thisArgs = nodeExecuteFunctions.getExecuteHookFunctions(this, node, webhookData.workflowExecuteAdditionalData, mode);
|
||||
await nodeType.hooks![hookDescription.method].call(thisArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the Webhooks method of the node
|
||||
|
|
Loading…
Reference in a new issue