mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-10 06:34:05 -08:00
Merge 'Master' into 'PagerDuty-OAuth2-support'
This commit is contained in:
commit
5f012906f3
|
@ -11,6 +11,7 @@ import {
|
|||
ActiveExecutions,
|
||||
CredentialsOverwrites,
|
||||
Db,
|
||||
ExternalHooks,
|
||||
GenericHelpers,
|
||||
IWorkflowBase,
|
||||
IWorkflowExecutionDataProcess,
|
||||
|
@ -108,6 +109,10 @@ export class Execute extends Command {
|
|||
const credentialsOverwrites = CredentialsOverwrites();
|
||||
await credentialsOverwrites.init();
|
||||
|
||||
// Load all external hooks
|
||||
const externalHooks = ExternalHooks();
|
||||
await externalHooks.init();
|
||||
|
||||
// Add the found types to an instance other parts of the application can use
|
||||
const nodeTypes = NodeTypes();
|
||||
await nodeTypes.init(loadNodesAndCredentials.nodeTypes);
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
} from 'n8n-core';
|
||||
import { Command, flags } from '@oclif/command';
|
||||
const open = require('open');
|
||||
// import { dirname } from 'path';
|
||||
|
||||
import * as config from '../config';
|
||||
import {
|
||||
|
@ -13,6 +12,7 @@ import {
|
|||
CredentialTypes,
|
||||
CredentialsOverwrites,
|
||||
Db,
|
||||
ExternalHooks,
|
||||
GenericHelpers,
|
||||
LoadNodesAndCredentials,
|
||||
NodeTypes,
|
||||
|
@ -113,6 +113,10 @@ export class Start extends Command {
|
|||
const credentialsOverwrites = CredentialsOverwrites();
|
||||
await credentialsOverwrites.init();
|
||||
|
||||
// Load all external hooks
|
||||
const externalHooks = ExternalHooks();
|
||||
await externalHooks.init();
|
||||
|
||||
// Add the found types to an instance other parts of the application can use
|
||||
const nodeTypes = NodeTypes();
|
||||
await nodeTypes.init(loadNodesAndCredentials.nodeTypes);
|
||||
|
|
|
@ -271,6 +271,13 @@ const config = convict({
|
|||
},
|
||||
},
|
||||
|
||||
externalHookFiles: {
|
||||
doc: 'Files containing external hooks. Multiple files can be separated by colon (":")',
|
||||
format: String,
|
||||
default: '',
|
||||
env: 'EXTERNAL_HOOK_FILES'
|
||||
},
|
||||
|
||||
nodes: {
|
||||
exclude: {
|
||||
doc: 'Nodes not to load',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "n8n",
|
||||
"version": "0.68.2",
|
||||
"version": "0.70.0",
|
||||
"description": "n8n Workflow Automation Tool",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
|
@ -100,10 +100,10 @@
|
|||
"lodash.get": "^4.4.2",
|
||||
"mongodb": "^3.5.5",
|
||||
"mysql2": "^2.0.1",
|
||||
"n8n-core": "~0.35.0",
|
||||
"n8n-editor-ui": "~0.46.0",
|
||||
"n8n-nodes-base": "~0.63.1",
|
||||
"n8n-workflow": "~0.32.0",
|
||||
"n8n-core": "~0.36.0",
|
||||
"n8n-editor-ui": "~0.47.0",
|
||||
"n8n-nodes-base": "~0.65.0",
|
||||
"n8n-workflow": "~0.33.0",
|
||||
"oauth-1.0a": "^2.2.6",
|
||||
"open": "^7.0.0",
|
||||
"pg": "^7.11.0",
|
||||
|
|
79
packages/cli/src/ExternalHooks.ts
Normal file
79
packages/cli/src/ExternalHooks.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
import {
|
||||
Db,
|
||||
IExternalHooksFunctions,
|
||||
IExternalHooksClass,
|
||||
} from './';
|
||||
|
||||
import * as config from '../config';
|
||||
|
||||
|
||||
class ExternalHooksClass implements IExternalHooksClass {
|
||||
|
||||
externalHooks: {
|
||||
[key: string]: Array<() => {}>
|
||||
} = {};
|
||||
initDidRun = false;
|
||||
|
||||
|
||||
async init(): Promise<void> {
|
||||
if (this.initDidRun === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
const externalHookFiles = config.get('externalHookFiles').split(':');
|
||||
|
||||
// Load all the provided hook-files
|
||||
for (let hookFilePath of externalHookFiles) {
|
||||
hookFilePath = hookFilePath.trim();
|
||||
if (hookFilePath !== '') {
|
||||
try {
|
||||
const hookFile = require(hookFilePath);
|
||||
|
||||
for (const resource of Object.keys(hookFile)) {
|
||||
for (const operation of Object.keys(hookFile[resource])) {
|
||||
// Save all the hook functions directly under their string
|
||||
// format in an array
|
||||
const hookString = `${resource}.${operation}`;
|
||||
if (this.externalHooks[hookString] === undefined) {
|
||||
this.externalHooks[hookString] = [];
|
||||
}
|
||||
|
||||
this.externalHooks[hookString].push.apply(this.externalHooks[hookString], hookFile[resource][operation]);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`Problem loading external hook file "${hookFilePath}": ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.initDidRun = true;
|
||||
}
|
||||
|
||||
async run(hookName: string, hookParameters?: any[]): Promise<void> { // tslint:disable-line:no-any
|
||||
const externalHookFunctions: IExternalHooksFunctions = {
|
||||
dbCollections: Db.collections,
|
||||
};
|
||||
|
||||
if (this.externalHooks[hookName] === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(const externalHookFunction of this.externalHooks[hookName]) {
|
||||
await externalHookFunction.apply(externalHookFunctions, hookParameters);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
let externalHooksInstance: ExternalHooksClass | undefined;
|
||||
|
||||
export function ExternalHooks(): ExternalHooksClass {
|
||||
if (externalHooksInstance === undefined) {
|
||||
externalHooksInstance = new ExternalHooksClass();
|
||||
}
|
||||
|
||||
return externalHooksInstance;
|
||||
}
|
|
@ -197,6 +197,30 @@ export interface IExecutingWorkflowData {
|
|||
workflowExecution?: PCancelable<IRun>;
|
||||
}
|
||||
|
||||
export interface IExternalHooks {
|
||||
credentials?: {
|
||||
create?: Array<{ (this: IExternalHooksFunctions, credentialsData: ICredentialsEncrypted): Promise<void>; }>
|
||||
delete?: Array<{ (this: IExternalHooksFunctions, credentialId: string): Promise<void>; }>
|
||||
update?: Array<{ (this: IExternalHooksFunctions, credentialsData: ICredentialsDb): Promise<void>; }>
|
||||
};
|
||||
workflow?: {
|
||||
activate?: Array<{ (this: IExternalHooksFunctions, workflowData: IWorkflowDb): Promise<void>; }>
|
||||
create?: Array<{ (this: IExternalHooksFunctions, workflowData: IWorkflowBase): Promise<void>; }>
|
||||
delete?: Array<{ (this: IExternalHooksFunctions, workflowId: string): Promise<void>; }>
|
||||
execute?: Array<{ (this: IExternalHooksFunctions, workflowData: IWorkflowDb, mode: WorkflowExecuteMode): Promise<void>; }>
|
||||
update?: Array<{ (this: IExternalHooksFunctions, workflowData: IWorkflowDb): Promise<void>; }>
|
||||
};
|
||||
}
|
||||
|
||||
export interface IExternalHooksFunctions {
|
||||
dbCollections: IDatabaseCollections;
|
||||
}
|
||||
|
||||
export interface IExternalHooksClass {
|
||||
init(): Promise<void>;
|
||||
run(hookName: string, hookParameters?: any[]): Promise<void>; // tslint:disable-line:no-any
|
||||
}
|
||||
|
||||
export interface IN8nConfig {
|
||||
database: IN8nConfigDatabase;
|
||||
endpoints: IN8nConfigEndpoints;
|
||||
|
|
|
@ -27,6 +27,7 @@ import {
|
|||
CredentialsHelper,
|
||||
CredentialTypes,
|
||||
Db,
|
||||
ExternalHooks,
|
||||
IActivationError,
|
||||
ICustomRequest,
|
||||
ICredentialsDb,
|
||||
|
@ -41,6 +42,7 @@ import {
|
|||
IExecutionsListResponse,
|
||||
IExecutionsStopData,
|
||||
IExecutionsSummary,
|
||||
IExternalHooksClass,
|
||||
IN8nUISettings,
|
||||
IPackageVersions,
|
||||
IWorkflowBase,
|
||||
|
@ -103,6 +105,7 @@ class App {
|
|||
testWebhooks: TestWebhooks.TestWebhooks;
|
||||
endpointWebhook: string;
|
||||
endpointWebhookTest: string;
|
||||
externalHooks: IExternalHooksClass;
|
||||
saveDataErrorExecution: string;
|
||||
saveDataSuccessExecution: string;
|
||||
saveManualExecutions: boolean;
|
||||
|
@ -134,6 +137,8 @@ class App {
|
|||
this.protocol = config.get('protocol');
|
||||
this.sslKey = config.get('ssl_key');
|
||||
this.sslCert = config.get('ssl_cert');
|
||||
|
||||
this.externalHooks = ExternalHooks();
|
||||
}
|
||||
|
||||
|
||||
|
@ -351,7 +356,7 @@ class App {
|
|||
// Creates a new workflow
|
||||
this.app.post('/rest/workflows', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowResponse> => {
|
||||
|
||||
const newWorkflowData = req.body;
|
||||
const newWorkflowData = req.body as IWorkflowBase;
|
||||
|
||||
newWorkflowData.name = newWorkflowData.name.trim();
|
||||
newWorkflowData.createdAt = this.getCurrentDate();
|
||||
|
@ -359,6 +364,8 @@ class App {
|
|||
|
||||
newWorkflowData.id = undefined;
|
||||
|
||||
await this.externalHooks.run('workflow.create', [newWorkflowData]);
|
||||
|
||||
// Save the workflow in DB
|
||||
const result = await Db.collections.Workflow!.save(newWorkflowData);
|
||||
|
||||
|
@ -434,9 +441,11 @@ class App {
|
|||
// Updates an existing workflow
|
||||
this.app.patch('/rest/workflows/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowResponse> => {
|
||||
|
||||
const newWorkflowData = req.body;
|
||||
const newWorkflowData = req.body as IWorkflowBase;
|
||||
const id = req.params.id;
|
||||
|
||||
await this.externalHooks.run('workflow.update', [newWorkflowData]);
|
||||
|
||||
if (this.activeWorkflowRunner.isActive(id)) {
|
||||
// When workflow gets saved always remove it as the triggers could have been
|
||||
// changed and so the changes would not take effect
|
||||
|
@ -478,6 +487,8 @@ class App {
|
|||
if (responseData.active === true) {
|
||||
// When the workflow is supposed to be active add it again
|
||||
try {
|
||||
await this.externalHooks.run('workflow.activate', [responseData]);
|
||||
|
||||
await this.activeWorkflowRunner.add(id);
|
||||
} catch (error) {
|
||||
// If workflow could not be activated set it again to inactive
|
||||
|
@ -502,6 +513,8 @@ class App {
|
|||
this.app.delete('/rest/workflows/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => {
|
||||
const id = req.params.id;
|
||||
|
||||
await this.externalHooks.run('workflow.delete', [id]);
|
||||
|
||||
if (this.activeWorkflowRunner.isActive(id)) {
|
||||
// Before deleting a workflow deactivate it
|
||||
await this.activeWorkflowRunner.remove(id);
|
||||
|
@ -663,6 +676,8 @@ class App {
|
|||
this.app.delete('/rest/credentials/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => {
|
||||
const id = req.params.id;
|
||||
|
||||
await this.externalHooks.run('credentials.delete', [id]);
|
||||
|
||||
await Db.collections.Credentials!.delete({ id });
|
||||
|
||||
return true;
|
||||
|
@ -708,6 +723,8 @@ class App {
|
|||
credentials.setData(incomingData.data, encryptionKey);
|
||||
const newCredentialsData = credentials.getDataToSave() as ICredentialsDb;
|
||||
|
||||
await this.externalHooks.run('credentials.create', [newCredentialsData]);
|
||||
|
||||
// Add special database related data
|
||||
newCredentialsData.createdAt = this.getCurrentDate();
|
||||
newCredentialsData.updatedAt = this.getCurrentDate();
|
||||
|
@ -783,6 +800,8 @@ class App {
|
|||
// Add special database related data
|
||||
newCredentialsData.updatedAt = this.getCurrentDate();
|
||||
|
||||
await this.externalHooks.run('credentials.update', [newCredentialsData]);
|
||||
|
||||
// Update the credentials in DB
|
||||
await Db.collections.Credentials!.update(id, newCredentialsData);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
CredentialsHelper,
|
||||
Db,
|
||||
ExternalHooks,
|
||||
IExecutionDb,
|
||||
IExecutionFlattedDb,
|
||||
IPushDataExecutionFinished,
|
||||
|
@ -303,6 +304,10 @@ export async function executeWorkflow(workflowInfo: IExecuteWorkflowInfo, additi
|
|||
workflowData = workflowInfo.code;
|
||||
}
|
||||
|
||||
const externalHooks = ExternalHooks();
|
||||
await externalHooks.init();
|
||||
await externalHooks.run('workflow.execute', [workflowData, mode]);
|
||||
|
||||
const nodeTypes = NodeTypes();
|
||||
|
||||
const workflowName = workflowData ? workflowData.name : undefined;
|
||||
|
|
|
@ -2,6 +2,7 @@ import {
|
|||
ActiveExecutions,
|
||||
CredentialsOverwrites,
|
||||
CredentialTypes,
|
||||
ExternalHooks,
|
||||
ICredentialsOverwrite,
|
||||
ICredentialsTypeData,
|
||||
IProcessMessageDataHook,
|
||||
|
@ -100,6 +101,9 @@ export class WorkflowRunner {
|
|||
* @memberof WorkflowRunner
|
||||
*/
|
||||
async run(data: IWorkflowExecutionDataProcess, loadStaticData?: boolean): Promise<string> {
|
||||
const externalHooks = ExternalHooks();
|
||||
await externalHooks.run('workflow.execute', [data.workflowData, data.executionMode]);
|
||||
|
||||
const executionsProcess = config.get('executions.process') as string;
|
||||
if (executionsProcess === 'main') {
|
||||
return this.runMainProcess(data, loadStaticData);
|
||||
|
|
|
@ -8,8 +8,8 @@ export class InitialMigration1588157391238 implements MigrationInterface {
|
|||
async up(queryRunner: QueryRunner): Promise<void> {
|
||||
const tablePrefix = config.get('database.tablePrefix');
|
||||
|
||||
await queryRunner.query('CREATE TABLE IF NOT EXISTS `' + tablePrefix + 'credentials_entity` (`id` int NOT NULL AUTO_INCREMENT, `name` varchar(128) NOT NULL, `data` text NOT NULL, `type` varchar(32) NOT NULL, `nodesAccess` json NOT NULL, `createdAt` datetime NOT NULL, `updatedAt` datetime NOT NULL, INDEX `IDX_07fde106c0b471d8cc80a64fc8` (`type`), PRIMARY KEY (`id`)) ENGINE=InnoDB', undefined);
|
||||
await queryRunner.query('CREATE TABLE IF NOT EXISTS `' + tablePrefix + 'execution_entity` (`id` int NOT NULL AUTO_INCREMENT, `data` text NOT NULL, `finished` tinyint NOT NULL, `mode` varchar(255) NOT NULL, `retryOf` varchar(255) NULL, `retrySuccessId` varchar(255) NULL, `startedAt` datetime NOT NULL, `stoppedAt` datetime NOT NULL, `workflowData` json NOT NULL, `workflowId` varchar(255) NULL, INDEX `IDX_c4d999a5e90784e8caccf5589d` (`workflowId`), PRIMARY KEY (`id`)) ENGINE=InnoDB', undefined);
|
||||
await queryRunner.query('CREATE TABLE IF NOT EXISTS `' + tablePrefix + 'credentials_entity` (`id` int NOT NULL AUTO_INCREMENT, `name` varchar(128) NOT NULL, `data` text NOT NULL, `type` varchar(32) NOT NULL, `nodesAccess` json NOT NULL, `createdAt` datetime NOT NULL, `updatedAt` datetime NOT NULL, INDEX `IDX_' + tablePrefix + '07fde106c0b471d8cc80a64fc8` (`type`), PRIMARY KEY (`id`)) ENGINE=InnoDB', undefined);
|
||||
await queryRunner.query('CREATE TABLE IF NOT EXISTS `' + tablePrefix + 'execution_entity` (`id` int NOT NULL AUTO_INCREMENT, `data` text NOT NULL, `finished` tinyint NOT NULL, `mode` varchar(255) NOT NULL, `retryOf` varchar(255) NULL, `retrySuccessId` varchar(255) NULL, `startedAt` datetime NOT NULL, `stoppedAt` datetime NOT NULL, `workflowData` json NOT NULL, `workflowId` varchar(255) NULL, INDEX `IDX_' + tablePrefix + 'c4d999a5e90784e8caccf5589d` (`workflowId`), PRIMARY KEY (`id`)) ENGINE=InnoDB', undefined);
|
||||
await queryRunner.query('CREATE TABLE IF NOT EXISTS`' + tablePrefix + 'workflow_entity` (`id` int NOT NULL AUTO_INCREMENT, `name` varchar(128) NOT NULL, `active` tinyint NOT NULL, `nodes` json NOT NULL, `connections` json NOT NULL, `createdAt` datetime NOT NULL, `updatedAt` datetime NOT NULL, `settings` json NULL, `staticData` json NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB', undefined);
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,9 @@ export class InitialMigration1588157391238 implements MigrationInterface {
|
|||
const tablePrefix = config.get('database.tablePrefix');
|
||||
|
||||
await queryRunner.query('DROP TABLE `' + tablePrefix + 'workflow_entity`', undefined);
|
||||
await queryRunner.query('DROP INDEX `IDX_c4d999a5e90784e8caccf5589d` ON `' + tablePrefix + 'execution_entity`', undefined);
|
||||
await queryRunner.query('DROP INDEX `IDX_' + tablePrefix + 'c4d999a5e90784e8caccf5589d` ON `' + tablePrefix + 'execution_entity`', undefined);
|
||||
await queryRunner.query('DROP TABLE `' + tablePrefix + 'execution_entity`', undefined);
|
||||
await queryRunner.query('DROP INDEX `IDX_07fde106c0b471d8cc80a64fc8` ON `' + tablePrefix + 'credentials_entity`', undefined);
|
||||
await queryRunner.query('DROP INDEX `IDX_' + tablePrefix + '07fde106c0b471d8cc80a64fc8` ON `' + tablePrefix + 'credentials_entity`', undefined);
|
||||
await queryRunner.query('DROP TABLE `' + tablePrefix + 'credentials_entity`', undefined);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,29 +7,31 @@ export class InitialMigration1587669153312 implements MigrationInterface {
|
|||
|
||||
async up(queryRunner: QueryRunner): Promise<void> {
|
||||
let tablePrefix = config.get('database.tablePrefix');
|
||||
const tablePrefixIndex = tablePrefix;
|
||||
const schema = config.get('database.postgresdb.schema');
|
||||
if (schema) {
|
||||
tablePrefix = schema + '.' + tablePrefix;
|
||||
}
|
||||
|
||||
await queryRunner.query(`CREATE TABLE IF NOT EXISTS ${tablePrefix}credentials_entity ("id" SERIAL NOT NULL, "name" character varying(128) NOT NULL, "data" text NOT NULL, "type" character varying(32) NOT NULL, "nodesAccess" json NOT NULL, "createdAt" TIMESTAMP NOT NULL, "updatedAt" TIMESTAMP NOT NULL, CONSTRAINT PK_814c3d3c36e8a27fa8edb761b0e PRIMARY KEY ("id"))`, undefined);
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS IDX_07fde106c0b471d8cc80a64fc8 ON ${tablePrefix}credentials_entity (type) `, undefined);
|
||||
await queryRunner.query(`CREATE TABLE IF NOT EXISTS ${tablePrefix}execution_entity ("id" SERIAL NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" character varying NOT NULL, "retryOf" character varying, "retrySuccessId" character varying, "startedAt" TIMESTAMP NOT NULL, "stoppedAt" TIMESTAMP NOT NULL, "workflowData" json NOT NULL, "workflowId" character varying, CONSTRAINT PK_e3e63bbf986767844bbe1166d4e PRIMARY KEY ("id"))`, undefined);
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS IDX_c4d999a5e90784e8caccf5589d ON ${tablePrefix}execution_entity ("workflowId") `, undefined);
|
||||
await queryRunner.query(`CREATE TABLE IF NOT EXISTS ${tablePrefix}workflow_entity ("id" SERIAL NOT NULL, "name" character varying(128) NOT NULL, "active" boolean NOT NULL, "nodes" json NOT NULL, "connections" json NOT NULL, "createdAt" TIMESTAMP NOT NULL, "updatedAt" TIMESTAMP NOT NULL, "settings" json, "staticData" json, CONSTRAINT PK_eded7d72664448da7745d551207 PRIMARY KEY ("id"))`, undefined);
|
||||
await queryRunner.query(`CREATE TABLE IF NOT EXISTS ${tablePrefix}credentials_entity ("id" SERIAL NOT NULL, "name" character varying(128) NOT NULL, "data" text NOT NULL, "type" character varying(32) NOT NULL, "nodesAccess" json NOT NULL, "createdAt" TIMESTAMP NOT NULL, "updatedAt" TIMESTAMP NOT NULL, CONSTRAINT PK_${tablePrefixIndex}814c3d3c36e8a27fa8edb761b0e PRIMARY KEY ("id"))`, undefined);
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS IDX_${tablePrefixIndex}07fde106c0b471d8cc80a64fc8 ON ${tablePrefix}credentials_entity (type) `, undefined);
|
||||
await queryRunner.query(`CREATE TABLE IF NOT EXISTS ${tablePrefix}execution_entity ("id" SERIAL NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" character varying NOT NULL, "retryOf" character varying, "retrySuccessId" character varying, "startedAt" TIMESTAMP NOT NULL, "stoppedAt" TIMESTAMP NOT NULL, "workflowData" json NOT NULL, "workflowId" character varying, CONSTRAINT PK_${tablePrefixIndex}e3e63bbf986767844bbe1166d4e PRIMARY KEY ("id"))`, undefined);
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS IDX_${tablePrefixIndex}c4d999a5e90784e8caccf5589d ON ${tablePrefix}execution_entity ("workflowId") `, undefined);
|
||||
await queryRunner.query(`CREATE TABLE IF NOT EXISTS ${tablePrefix}workflow_entity ("id" SERIAL NOT NULL, "name" character varying(128) NOT NULL, "active" boolean NOT NULL, "nodes" json NOT NULL, "connections" json NOT NULL, "createdAt" TIMESTAMP NOT NULL, "updatedAt" TIMESTAMP NOT NULL, "settings" json, "staticData" json, CONSTRAINT PK_${tablePrefixIndex}eded7d72664448da7745d551207 PRIMARY KEY ("id"))`, undefined);
|
||||
}
|
||||
|
||||
async down(queryRunner: QueryRunner): Promise<void> {
|
||||
let tablePrefix = config.get('database.tablePrefix');
|
||||
const tablePrefixIndex = tablePrefix;
|
||||
const schema = config.get('database.postgresdb.schema');
|
||||
if (schema) {
|
||||
tablePrefix = schema + '.' + tablePrefix;
|
||||
}
|
||||
|
||||
await queryRunner.query(`DROP TABLE ${tablePrefix}workflow_entity`, undefined);
|
||||
await queryRunner.query(`DROP INDEX IDX_c4d999a5e90784e8caccf5589d`, undefined);
|
||||
await queryRunner.query(`DROP INDEX IDX_${tablePrefixIndex}c4d999a5e90784e8caccf5589d`, undefined);
|
||||
await queryRunner.query(`DROP TABLE ${tablePrefix}execution_entity`, undefined);
|
||||
await queryRunner.query(`DROP INDEX IDX_07fde106c0b471d8cc80a64fc8`, undefined);
|
||||
await queryRunner.query(`DROP INDEX IDX_${tablePrefixIndex}07fde106c0b471d8cc80a64fc8`, undefined);
|
||||
await queryRunner.query(`DROP TABLE ${tablePrefix}credentials_entity`, undefined);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ export class InitialMigration1588102412422 implements MigrationInterface {
|
|||
const tablePrefix = config.get('database.tablePrefix');
|
||||
|
||||
await queryRunner.query(`CREATE TABLE IF NOT EXISTS "${tablePrefix}credentials_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(128) NOT NULL, "data" text NOT NULL, "type" varchar(32) NOT NULL, "nodesAccess" text NOT NULL, "createdAt" datetime NOT NULL, "updatedAt" datetime NOT NULL)`, undefined);
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_07fde106c0b471d8cc80a64fc8" ON "${tablePrefix}credentials_entity" ("type") `, undefined);
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8" ON "${tablePrefix}credentials_entity" ("type") `, undefined);
|
||||
await queryRunner.query(`CREATE TABLE IF NOT EXISTS "${tablePrefix}execution_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" varchar NOT NULL, "retryOf" varchar, "retrySuccessId" varchar, "startedAt" datetime NOT NULL, "stoppedAt" datetime NOT NULL, "workflowData" text NOT NULL, "workflowId" varchar)`, undefined);
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_c4d999a5e90784e8caccf5589d" ON "${tablePrefix}execution_entity" ("workflowId") `, undefined);
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_${tablePrefix}c4d999a5e90784e8caccf5589d" ON "${tablePrefix}execution_entity" ("workflowId") `, undefined);
|
||||
await queryRunner.query(`CREATE TABLE IF NOT EXISTS "${tablePrefix}workflow_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(128) NOT NULL, "active" boolean NOT NULL, "nodes" text NOT NULL, "connections" text NOT NULL, "createdAt" datetime NOT NULL, "updatedAt" datetime NOT NULL, "settings" text, "staticData" text)`, undefined);
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,9 @@ export class InitialMigration1588102412422 implements MigrationInterface {
|
|||
const tablePrefix = config.get('database.tablePrefix');
|
||||
|
||||
await queryRunner.query(`DROP TABLE "${tablePrefix}workflow_entity"`, undefined);
|
||||
await queryRunner.query(`DROP INDEX "IDX_c4d999a5e90784e8caccf5589d"`, undefined);
|
||||
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}c4d999a5e90784e8caccf5589d"`, undefined);
|
||||
await queryRunner.query(`DROP TABLE "${tablePrefix}execution_entity"`, undefined);
|
||||
await queryRunner.query(`DROP INDEX "IDX_07fde106c0b471d8cc80a64fc8"`, undefined);
|
||||
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8"`, undefined);
|
||||
await queryRunner.query(`DROP TABLE "${tablePrefix}credentials_entity"`, undefined);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export * from './CredentialsHelper';
|
||||
export * from './CredentialTypes';
|
||||
export * from './CredentialsOverwrites';
|
||||
export * from './ExternalHooks';
|
||||
export * from './Interfaces';
|
||||
export * from './LoadNodesAndCredentials';
|
||||
export * from './NodeTypes';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "n8n-core",
|
||||
"version": "0.35.0",
|
||||
"version": "0.36.0",
|
||||
"description": "Core functionality of n8n",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "n8n-editor-ui",
|
||||
"version": "0.46.0",
|
||||
"version": "0.47.0",
|
||||
"description": "Workflow Editor UI for n8n",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
|
@ -64,7 +64,7 @@
|
|||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.set": "^4.3.2",
|
||||
"n8n-workflow": "~0.32.0",
|
||||
"n8n-workflow": "~0.33.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"prismjs": "^1.17.1",
|
||||
"quill": "^2.0.0-dev.3",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "n8n-node-dev",
|
||||
"version": "0.7.0",
|
||||
"version": "0.9.0",
|
||||
"description": "CLI to simplify n8n credentials/node development",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
|
|
|
@ -105,10 +105,10 @@ export async function buildFiles (options?: IBuildOptions): Promise<string> {
|
|||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
copyfiles([join(process.cwd(), './*.png'), outputDirectory], { up: true }, () => resolve(outputDirectory));
|
||||
buildProcess.on('exit', code => {
|
||||
// Remove the tmp tsconfig file
|
||||
tsconfigData.cleanup();
|
||||
copyfiles([join(process.cwd(), './*.png'), outputDirectory], { up: true }, () => resolve(outputDirectory));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
const scopes = [
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
'https://www.googleapis.com/auth/drive.appdata',
|
||||
'https://www.googleapis.com/auth/drive.photos.readonly',
|
||||
];
|
||||
|
||||
export class GoogleDriveOAuth2Api implements ICredentialType {
|
||||
name = 'googleDriveOAuth2Api';
|
||||
extends = [
|
||||
'googleOAuth2Api',
|
||||
];
|
||||
displayName = 'Google Drive OAuth2 API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: scopes.join(' '),
|
||||
},
|
||||
];
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
const scopes = [
|
||||
'contacts',
|
||||
'forms',
|
||||
'tickets',
|
||||
];
|
||||
|
||||
export class HubspotOAuth2Api implements ICredentialType {
|
||||
name = 'hubspotOAuth2Api';
|
||||
extends = [
|
||||
'oAuth2Api',
|
||||
];
|
||||
displayName = 'Hubspot OAuth2 API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'https://app.hubspot.com/oauth/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'https://api.hubapi.com/oauth/v1/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: scopes.join(' '),
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'grant_type=authorization_code',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'body',
|
||||
description: 'Resource to consume.',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
|
||||
export class MailchimpOAuth2Api implements ICredentialType {
|
||||
name = 'mailchimpOAuth2Api';
|
||||
extends = [
|
||||
'oAuth2Api',
|
||||
];
|
||||
displayName = 'Mailchimp OAuth2 API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'https://login.mailchimp.com/oauth2/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'https://login.mailchimp.com/oauth2/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Metadata',
|
||||
name: 'metadataUrl',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'https://login.mailchimp.com/oauth2/metadata',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'header',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class MauticOAuth2Api implements ICredentialType {
|
||||
name = 'mauticOAuth2Api';
|
||||
extends = [
|
||||
'oAuth2Api',
|
||||
];
|
||||
displayName = 'Mautic OAuth2 API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'URL',
|
||||
name: 'url',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
placeholder: 'https://name.mautic.net',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
placeholder: 'https://name.mautic.net/oauth/v2/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
placeholder: 'https://name.mautic.net/oauth/v2/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'header',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import { ICredentialType, NodePropertyTypes } from 'n8n-workflow';
|
||||
|
||||
export class MessageBirdApi implements ICredentialType {
|
||||
name = 'messageBirdApi';
|
||||
displayName = 'MessageBird API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'accessKey',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: ''
|
||||
}
|
||||
];
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
const scopes = [
|
||||
'surveys_read',
|
||||
'collectors_read',
|
||||
'responses_read',
|
||||
'responses_read_detail',
|
||||
'webhooks_write',
|
||||
'webhooks_read',
|
||||
];
|
||||
|
||||
export class SurveyMonkeyOAuth2Api implements ICredentialType {
|
||||
name = 'surveyMonkeyOAuth2Api';
|
||||
extends = [
|
||||
'oAuth2Api',
|
||||
];
|
||||
displayName = 'SurveyMonkey OAuth2 API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'https://api.surveymonkey.com/oauth/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'https://api.surveymonkey.com/oauth/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: scopes.join(','),
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'body'
|
||||
},
|
||||
];
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
const scopes = [
|
||||
'webhooks:write',
|
||||
'webhooks:read',
|
||||
'forms:read',
|
||||
];
|
||||
|
||||
|
||||
export class TypeformOAuth2Api implements ICredentialType {
|
||||
name = 'typeformOAuth2Api';
|
||||
extends = [
|
||||
'oAuth2Api',
|
||||
];
|
||||
displayName = 'Typeform OAuth2 API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'https://api.typeform.com/oauth/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'https://api.typeform.com/oauth/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: scopes.join(','),
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'header',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -8,10 +8,11 @@ export class ZendeskApi implements ICredentialType {
|
|||
displayName = 'Zendesk API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'URL',
|
||||
name: 'url',
|
||||
displayName: 'Subdomain',
|
||||
name: 'subdomain',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
description: 'The subdomain of your Zendesk work environment.',
|
||||
default: 'n8n',
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
const scopes = [
|
||||
'read',
|
||||
'write',
|
||||
];
|
||||
|
||||
export class ZendeskOAuth2Api implements ICredentialType {
|
||||
name = 'zendeskOAuth2Api';
|
||||
extends = [
|
||||
'oAuth2Api',
|
||||
];
|
||||
displayName = 'Zendesk OAuth2 API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Subdomain',
|
||||
name: 'subdomain',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
placeholder: 'n8n',
|
||||
description: 'The subdomain of your Zendesk work environment.',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: 'https://{SUBDOMAIN_HERE}.zendesk.com/oauth/authorizations/new',
|
||||
description: 'URL to get authorization code. Replace {SUBDOMAIN_HERE} with your subdomain.',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: 'https://{SUBDOMAIN_HERE}.zendesk.com/oauth/tokens',
|
||||
description: 'URL to get access token. Replace {SUBDOMAIN_HERE} with your subdomain.',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Client ID',
|
||||
name: 'clientId',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Client Secret',
|
||||
name: 'clientSecret',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: scopes.join(' '),
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: '',
|
||||
description: 'For some services additional query parameters have to be set which can be defined here.',
|
||||
placeholder: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'body',
|
||||
description: 'Resource to consume.',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -244,11 +244,6 @@ export class Github implements INodeType {
|
|||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get Emails',
|
||||
value: 'getEmails',
|
||||
description: 'Returns the email addresses of a user',
|
||||
},
|
||||
{
|
||||
name: 'Get Repositories',
|
||||
value: 'getRepositories',
|
||||
|
|
|
@ -34,7 +34,25 @@ export class GithubTrigger implements INodeType {
|
|||
{
|
||||
name: 'githubApi',
|
||||
required: true,
|
||||
}
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'accessToken',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'githubOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
{
|
||||
|
@ -45,6 +63,23 @@ export class GithubTrigger implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Access Token',
|
||||
value: 'accessToken',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'accessToken',
|
||||
description: 'The resource to operate on.',
|
||||
},
|
||||
{
|
||||
displayName: 'Repository Owner',
|
||||
name: 'owner',
|
||||
|
|
142
packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts
Normal file
142
packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts
Normal file
|
@ -0,0 +1,142 @@
|
|||
import {
|
||||
OptionsWithUri,
|
||||
} from 'request';
|
||||
|
||||
import {
|
||||
IExecuteFunctions,
|
||||
IExecuteSingleFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IDataObject,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import * as moment from 'moment-timezone';
|
||||
|
||||
import * as jwt from 'jsonwebtoken';
|
||||
|
||||
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
const authenticationMethod = this.getNodeParameter('authentication', 0, 'serviceAccount') as string;
|
||||
|
||||
let options: OptionsWithUri = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method,
|
||||
body,
|
||||
qs,
|
||||
uri: uri || `https://www.googleapis.com${resource}`,
|
||||
json: true,
|
||||
};
|
||||
options = Object.assign({}, options, option);
|
||||
try {
|
||||
if (Object.keys(body).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
|
||||
if (authenticationMethod === 'serviceAccount') {
|
||||
const credentials = this.getCredentials('googleApi');
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
|
||||
const { access_token } = await getAccessToken.call(this, credentials as IDataObject);
|
||||
|
||||
options.headers!.Authorization = `Bearer ${access_token}`;
|
||||
//@ts-ignore
|
||||
return await this.helpers.request(options);
|
||||
} else {
|
||||
//@ts-ignore
|
||||
return await this.helpers.requestOAuth2.call(this, 'googleDriveOAuth2Api', options);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.response && error.response.body && error.response.body.error) {
|
||||
|
||||
let errorMessages;
|
||||
|
||||
if (error.response.body.error.errors) {
|
||||
// Try to return the error prettier
|
||||
errorMessages = error.response.body.error.errors;
|
||||
|
||||
errorMessages = errorMessages.map((errorItem: IDataObject) => errorItem.message);
|
||||
|
||||
errorMessages = errorMessages.join('|');
|
||||
|
||||
} else if (error.response.body.error.message) {
|
||||
errorMessages = error.response.body.error.message;
|
||||
}
|
||||
|
||||
throw new Error(`Google Drive error response [${error.statusCode}]: ${errorMessages}`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
query.maxResults = 100;
|
||||
|
||||
do {
|
||||
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
|
||||
query.pageToken = responseData['nextPageToken'];
|
||||
returnData.push.apply(returnData, responseData[propertyName]);
|
||||
} while (
|
||||
responseData['nextPageToken'] !== undefined &&
|
||||
responseData['nextPageToken'] !== ''
|
||||
);
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, credentials: IDataObject): Promise<IDataObject> {
|
||||
//https://developers.google.com/identity/protocols/oauth2/service-account#httprest
|
||||
|
||||
const scopes = [
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
'https://www.googleapis.com/auth/drive.appdata',
|
||||
'https://www.googleapis.com/auth/drive.photos.readonly',
|
||||
];
|
||||
|
||||
const now = moment().unix();
|
||||
|
||||
const signature = jwt.sign(
|
||||
{
|
||||
'iss': credentials.email as string,
|
||||
'sub': credentials.email as string,
|
||||
'scope': scopes.join(' '),
|
||||
'aud': `https://oauth2.googleapis.com/token`,
|
||||
'iat': now,
|
||||
'exp': now + 3600,
|
||||
},
|
||||
credentials.privateKey as string,
|
||||
{
|
||||
algorithm: 'RS256',
|
||||
header: {
|
||||
'kid': credentials.privateKey as string,
|
||||
'typ': 'JWT',
|
||||
'alg': 'RS256',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
method: 'POST',
|
||||
form: {
|
||||
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
||||
assertion: signature,
|
||||
},
|
||||
uri: 'https://oauth2.googleapis.com/token',
|
||||
json: true
|
||||
};
|
||||
|
||||
//@ts-ignore
|
||||
return this.helpers.request(options);
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
import { google } from 'googleapis';
|
||||
const { Readable } = require('stream');
|
||||
|
||||
import {
|
||||
BINARY_ENCODING,
|
||||
IExecuteFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IDataObject,
|
||||
INodeTypeDescription,
|
||||
|
@ -12,8 +10,9 @@ import {
|
|||
INodeType,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { getAuthenticationClient } from '../GoogleApi';
|
||||
|
||||
import {
|
||||
googleApiRequest,
|
||||
} from './GenericFunctions';
|
||||
|
||||
export class GoogleDrive implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
|
@ -34,9 +33,43 @@ export class GoogleDrive implements INodeType {
|
|||
{
|
||||
name: 'googleApi',
|
||||
required: true,
|
||||
}
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'serviceAccount',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'googleDriveOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Service Account',
|
||||
value: 'serviceAccount',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'serviceAccount',
|
||||
},
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
|
@ -764,7 +797,7 @@ export class GoogleDrive implements INodeType {
|
|||
{
|
||||
name: 'domain',
|
||||
value: 'domain',
|
||||
description:"All files shared to the user's domain that are searchable",
|
||||
description: 'All files shared to the user\'s domain that are searchable',
|
||||
},
|
||||
{
|
||||
name: 'drive',
|
||||
|
@ -813,26 +846,6 @@ export class GoogleDrive implements INodeType {
|
|||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
const credentials = this.getCredentials('googleApi');
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
|
||||
const scopes = [
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
'https://www.googleapis.com/auth/drive.appdata',
|
||||
'https://www.googleapis.com/auth/drive.photos.readonly',
|
||||
];
|
||||
|
||||
const client = await getAuthenticationClient(credentials.email as string, credentials.privateKey as string, scopes);
|
||||
|
||||
const drive = google.drive({
|
||||
version: 'v3',
|
||||
// @ts-ignore
|
||||
auth: client,
|
||||
});
|
||||
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
|
||||
|
@ -857,22 +870,20 @@ export class GoogleDrive implements INodeType {
|
|||
|
||||
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||
|
||||
const copyOptions = {
|
||||
fileId,
|
||||
const body: IDataObject = {
|
||||
fields: queryFields,
|
||||
requestBody: {} as IDataObject,
|
||||
};
|
||||
|
||||
const optionProperties = ['name', 'parents'];
|
||||
for (const propertyName of optionProperties) {
|
||||
if (options[propertyName] !== undefined) {
|
||||
copyOptions.requestBody[propertyName] = options[propertyName];
|
||||
body[propertyName] = options[propertyName];
|
||||
}
|
||||
}
|
||||
|
||||
const response = await drive.files.copy(copyOptions);
|
||||
const response = await googleApiRequest.call(this, 'POST', `/drive/v3/files/${fileId}/copy`, body);
|
||||
|
||||
returnData.push(response.data as IDataObject);
|
||||
returnData.push(response as IDataObject);
|
||||
|
||||
} else if (operation === 'download') {
|
||||
// ----------------------------------
|
||||
|
@ -881,15 +892,13 @@ export class GoogleDrive implements INodeType {
|
|||
|
||||
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||
|
||||
const response = await drive.files.get(
|
||||
{
|
||||
fileId,
|
||||
alt: 'media',
|
||||
},
|
||||
{
|
||||
responseType: 'arraybuffer',
|
||||
},
|
||||
);
|
||||
const requestOptions = {
|
||||
resolveWithFullResponse: true,
|
||||
encoding: null,
|
||||
json: false,
|
||||
};
|
||||
|
||||
const response = await googleApiRequest.call(this, 'GET', `/drive/v3/files/${fileId}`, {}, { alt: 'media' }, undefined, requestOptions);
|
||||
|
||||
let mimeType: string | undefined;
|
||||
if (response.headers['content-type']) {
|
||||
|
@ -912,7 +921,7 @@ export class GoogleDrive implements INodeType {
|
|||
|
||||
const dataPropertyNameDownload = this.getNodeParameter('binaryPropertyName', i) as string;
|
||||
|
||||
const data = Buffer.from(response.data as string);
|
||||
const data = Buffer.from(response.body as string);
|
||||
|
||||
items[i].binary![dataPropertyNameDownload] = await this.helpers.prepareBinaryData(data as unknown as Buffer, undefined, mimeType);
|
||||
|
||||
|
@ -936,7 +945,7 @@ export class GoogleDrive implements INodeType {
|
|||
queryCorpora = options.corpora as string;
|
||||
}
|
||||
|
||||
let driveId : string | undefined;
|
||||
let driveId: string | undefined;
|
||||
driveId = options.driveId as string;
|
||||
if (driveId === '') {
|
||||
driveId = undefined;
|
||||
|
@ -988,20 +997,19 @@ export class GoogleDrive implements INodeType {
|
|||
|
||||
const pageSize = this.getNodeParameter('limit', i) as number;
|
||||
|
||||
const res = await drive.files.list({
|
||||
const qs = {
|
||||
pageSize,
|
||||
orderBy: 'modifiedTime',
|
||||
fields: `nextPageToken, files(${queryFields})`,
|
||||
spaces: querySpaces,
|
||||
corpora: queryCorpora,
|
||||
driveId,
|
||||
q: queryString,
|
||||
includeItemsFromAllDrives: (queryCorpora !== '' || driveId !== ''), // Actually depracated,
|
||||
supportsAllDrives: (queryCorpora !== '' || driveId !== ''), // see https://developers.google.com/drive/api/v3/reference/files/list
|
||||
// However until June 2020 still needs to be set, to avoid API errors.
|
||||
});
|
||||
includeItemsFromAllDrives: (queryCorpora !== '' || driveId !== ''),
|
||||
supportsAllDrives: (queryCorpora !== '' || driveId !== ''),
|
||||
};
|
||||
|
||||
const files = res!.data.files;
|
||||
const response = await googleApiRequest.call(this, 'GET', `/drive/v3/files`, {}, qs);
|
||||
|
||||
const files = response!.files;
|
||||
|
||||
return [this.helpers.returnJsonArray(files as IDataObject[])];
|
||||
|
||||
|
@ -1044,29 +1052,35 @@ export class GoogleDrive implements INodeType {
|
|||
const name = this.getNodeParameter('name', i) as string;
|
||||
const parents = this.getNodeParameter('parents', i) as string[];
|
||||
|
||||
const response = await drive.files.create({
|
||||
requestBody: {
|
||||
name,
|
||||
originalFilename,
|
||||
parents,
|
||||
},
|
||||
let qs: IDataObject = {
|
||||
fields: queryFields,
|
||||
media: {
|
||||
mimeType,
|
||||
body: ((buffer: Buffer) => {
|
||||
const readableInstanceStream = new Readable({
|
||||
read() {
|
||||
this.push(buffer);
|
||||
this.push(null);
|
||||
}
|
||||
});
|
||||
uploadType: 'media',
|
||||
};
|
||||
|
||||
return readableInstanceStream;
|
||||
})(body),
|
||||
const requestOptions = {
|
||||
headers: {
|
||||
'Content-Type': mimeType,
|
||||
'Content-Length': body.byteLength,
|
||||
},
|
||||
});
|
||||
encoding: null,
|
||||
json: false,
|
||||
};
|
||||
|
||||
returnData.push(response.data as IDataObject);
|
||||
let response = await googleApiRequest.call(this, 'POST', `/upload/drive/v3/files`, body, qs, undefined, requestOptions);
|
||||
|
||||
body = {
|
||||
mimeType,
|
||||
name,
|
||||
originalFilename,
|
||||
};
|
||||
|
||||
qs = {
|
||||
addParents: parents.join(','),
|
||||
};
|
||||
|
||||
response = await googleApiRequest.call(this, 'PATCH', `/drive/v3/files/${JSON.parse(response).id}`, body, qs);
|
||||
|
||||
returnData.push(response as IDataObject);
|
||||
}
|
||||
|
||||
} else if (resource === 'folder') {
|
||||
|
@ -1077,19 +1091,19 @@ export class GoogleDrive implements INodeType {
|
|||
|
||||
const name = this.getNodeParameter('name', i) as string;
|
||||
|
||||
const fileMetadata = {
|
||||
const body = {
|
||||
name,
|
||||
mimeType: 'application/vnd.google-apps.folder',
|
||||
parents: options.parents || [],
|
||||
};
|
||||
|
||||
const response = await drive.files.create({
|
||||
// @ts-ignore
|
||||
resource: fileMetadata,
|
||||
const qs = {
|
||||
fields: queryFields,
|
||||
});
|
||||
};
|
||||
|
||||
returnData.push(response.data as IDataObject);
|
||||
const response = await googleApiRequest.call(this, 'POST', '/drive/v3/files', body, qs);
|
||||
|
||||
returnData.push(response as IDataObject);
|
||||
}
|
||||
}
|
||||
if (['file', 'folder'].includes(resource)) {
|
||||
|
@ -1100,9 +1114,7 @@ export class GoogleDrive implements INodeType {
|
|||
|
||||
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||
|
||||
await drive.files.delete({
|
||||
fileId,
|
||||
});
|
||||
const response = await googleApiRequest.call(this, 'DELETE', `/drive/v3/files/${fileId}`);
|
||||
|
||||
// If we are still here it did succeed
|
||||
returnData.push({
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
import { JWT } from 'google-auth-library';
|
||||
import { google } from 'googleapis';
|
||||
|
||||
|
||||
/**
|
||||
* Returns the authentication client needed to access spreadsheet
|
||||
*/
|
||||
export async function getAuthenticationClient(email: string, privateKey: string, scopes: string[]): Promise <JWT> {
|
||||
const client = new google.auth.JWT(
|
||||
email,
|
||||
undefined,
|
||||
privateKey,
|
||||
scopes,
|
||||
undefined
|
||||
);
|
||||
|
||||
// TODO: Check later if this or the above should be cached
|
||||
await client.authorize();
|
||||
|
||||
// @ts-ignore
|
||||
return client;
|
||||
}
|
|
@ -622,7 +622,7 @@ export class GoogleSheets implements INodeType {
|
|||
// ----------------------------------
|
||||
// append
|
||||
// ----------------------------------
|
||||
const keyRow = this.getNodeParameter('keyRow', 0) as number;
|
||||
const keyRow = parseInt(this.getNodeParameter('keyRow', 0) as string, 10);
|
||||
|
||||
const items = this.getInputData();
|
||||
|
||||
|
@ -670,7 +670,7 @@ export class GoogleSheets implements INodeType {
|
|||
sheetId: range.sheetId,
|
||||
dimension: deletePropertyToDimensions[propertyName] as string,
|
||||
startIndex: range.startIndex,
|
||||
endIndex: range.startIndex + range.amount,
|
||||
endIndex: parseInt(range.startIndex.toString(), 10) + parseInt(range.amount.toString(), 10),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -693,8 +693,8 @@ export class GoogleSheets implements INodeType {
|
|||
return [];
|
||||
}
|
||||
|
||||
const dataStartRow = this.getNodeParameter('dataStartRow', 0) as number;
|
||||
const keyRow = this.getNodeParameter('keyRow', 0) as number;
|
||||
const dataStartRow = parseInt(this.getNodeParameter('dataStartRow', 0) as string, 10);
|
||||
const keyRow = parseInt(this.getNodeParameter('keyRow', 0) as string, 10);
|
||||
|
||||
const items = this.getInputData();
|
||||
|
||||
|
@ -735,8 +735,8 @@ export class GoogleSheets implements INodeType {
|
|||
}
|
||||
];
|
||||
} else {
|
||||
const dataStartRow = this.getNodeParameter('dataStartRow', 0) as number;
|
||||
const keyRow = this.getNodeParameter('keyRow', 0) as number;
|
||||
const dataStartRow = parseInt(this.getNodeParameter('dataStartRow', 0) as string, 10);
|
||||
const keyRow = parseInt(this.getNodeParameter('keyRow', 0) as string, 10);
|
||||
|
||||
returnData = sheet.structureArrayDataByColumn(sheetData, keyRow, dataStartRow);
|
||||
}
|
||||
|
@ -769,8 +769,8 @@ export class GoogleSheets implements INodeType {
|
|||
const data = await sheet.batchUpdate(updateData, valueInputMode);
|
||||
} else {
|
||||
const keyName = this.getNodeParameter('key', 0) as string;
|
||||
const keyRow = this.getNodeParameter('keyRow', 0) as number;
|
||||
const dataStartRow = this.getNodeParameter('dataStartRow', 0) as number;
|
||||
const keyRow = parseInt(this.getNodeParameter('keyRow', 0) as string, 10);
|
||||
const dataStartRow = parseInt(this.getNodeParameter('dataStartRow', 0) as string, 10);
|
||||
|
||||
const setData: IDataObject[] = [];
|
||||
items.forEach((item) => {
|
||||
|
|
|
@ -15,11 +15,12 @@ import {
|
|||
|
||||
export async function hubspotApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const node = this.getNode();
|
||||
const credentialName = Object.keys(node.credentials!)[0];
|
||||
const credentials = this.getCredentials(credentialName);
|
||||
let authenticationMethod = this.getNodeParameter('authentication', 0);
|
||||
|
||||
if (this.getNode().type.includes('Trigger')) {
|
||||
authenticationMethod = 'developerApi';
|
||||
}
|
||||
|
||||
query!.hapikey = credentials!.apiKey as string;
|
||||
const options: OptionsWithUri = {
|
||||
method,
|
||||
qs: query,
|
||||
|
@ -28,18 +29,42 @@ export async function hubspotApiRequest(this: IHookFunctions | IExecuteFunctions
|
|||
json: true,
|
||||
useQuerystring: true,
|
||||
};
|
||||
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
if (authenticationMethod === 'apiKey') {
|
||||
const credentials = this.getCredentials('hubspotApi');
|
||||
|
||||
options.qs.hapikey = credentials!.apiKey as string;
|
||||
|
||||
return await this.helpers.request!(options);
|
||||
} else if (authenticationMethod === 'developerApi') {
|
||||
const credentials = this.getCredentials('hubspotDeveloperApi');
|
||||
|
||||
options.qs.hapikey = credentials!.apiKey as string;
|
||||
|
||||
return await this.helpers.request!(options);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
return await this.helpers.requestOAuth2!.call(this, 'hubspotOAuth2Api', options, 'Bearer');
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.response && error.response.body && error.response.body.errors) {
|
||||
// Try to return the error prettier
|
||||
let errorMessages = error.response.body.errors;
|
||||
let errorMessages;
|
||||
|
||||
if (errorMessages[0].message) {
|
||||
// @ts-ignore
|
||||
errorMessages = errorMessages.map(errorItem => errorItem.message);
|
||||
if (error.response && error.response.body) {
|
||||
|
||||
if (error.response.body.message) {
|
||||
|
||||
errorMessages = [error.response.body.message];
|
||||
|
||||
} else if (error.response.body.errors) {
|
||||
// Try to return the error prettier
|
||||
errorMessages = error.response.body.errors;
|
||||
|
||||
if (errorMessages[0].message) {
|
||||
// @ts-ignore
|
||||
errorMessages = errorMessages.map(errorItem => errorItem.message);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Hubspot error response [${error.statusCode}]: ${errorMessages.join('|')}`);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,9 +73,44 @@ export class Hubspot implements INodeType {
|
|||
{
|
||||
name: 'hubspotApi',
|
||||
required: true,
|
||||
}
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'apiKey',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'hubspotOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'API Key',
|
||||
value: 'apiKey',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'apiKey',
|
||||
description: 'The method of authentication.',
|
||||
},
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
|
|
|
@ -246,7 +246,13 @@ export class HubspotTrigger implements INodeType {
|
|||
};
|
||||
|
||||
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||
const credentials = this.getCredentials('hubspotDeveloperApi');
|
||||
|
||||
const credentials = this.getCredentials('hubspotDeveloperApi') as IDataObject;
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials found!');
|
||||
}
|
||||
|
||||
const req = this.getRequestObject();
|
||||
const bodyData = req.body;
|
||||
const headerData = this.getHeaderData();
|
||||
|
@ -254,12 +260,18 @@ export class HubspotTrigger implements INodeType {
|
|||
if (headerData['x-hubspot-signature'] === undefined) {
|
||||
return {};
|
||||
}
|
||||
const hash = `${credentials!.clientSecret}${JSON.stringify(bodyData)}`;
|
||||
const signature = createHash('sha256').update(hash).digest('hex');
|
||||
//@ts-ignore
|
||||
if (signature !== headerData['x-hubspot-signature']) {
|
||||
return {};
|
||||
|
||||
// check signare if client secret is defined
|
||||
|
||||
if (credentials.clientSecret !== '') {
|
||||
const hash = `${credentials!.clientSecret}${JSON.stringify(bodyData)}`;
|
||||
const signature = createHash('sha256').update(hash).digest('hex');
|
||||
//@ts-ignore
|
||||
if (signature !== headerData['x-hubspot-signature']) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < bodyData.length; i++) {
|
||||
const subscriptionType = bodyData[i].subscriptionType as string;
|
||||
if (subscriptionType.includes('contact')) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {
|
||||
OptionsWithUri,
|
||||
OptionsWithUrl,
|
||||
} from 'request';
|
||||
|
||||
import {
|
||||
|
@ -14,37 +14,54 @@ import {
|
|||
} from 'n8n-workflow';
|
||||
|
||||
export async function mailchimpApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, endpoint: string, method: string, body: any = {}, qs: IDataObject = {} ,headers?: object): Promise<any> { // tslint:disable-line:no-any
|
||||
const credentials = this.getCredentials('mailchimpApi');
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
|
||||
const headerWithAuthentication = Object.assign({}, headers, { Authorization: `apikey ${credentials.apiKey}` });
|
||||
|
||||
if (!(credentials.apiKey as string).includes('-')) {
|
||||
throw new Error('The API key is not valid!');
|
||||
}
|
||||
|
||||
const datacenter = (credentials.apiKey as string).split('-').pop();
|
||||
const authenticationMethod = this.getNodeParameter('authentication', 0) as string;
|
||||
|
||||
const host = 'api.mailchimp.com/3.0';
|
||||
|
||||
const options: OptionsWithUri = {
|
||||
headers: headerWithAuthentication,
|
||||
const options: OptionsWithUrl = {
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
method,
|
||||
qs,
|
||||
uri: `https://${datacenter}.${host}${endpoint}`,
|
||||
body,
|
||||
url: ``,
|
||||
json: true,
|
||||
};
|
||||
|
||||
if (Object.keys(body).length !== 0) {
|
||||
options.body = body;
|
||||
if (Object.keys(body).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
if (authenticationMethod === 'apiKey') {
|
||||
const credentials = this.getCredentials('mailchimpApi');
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
|
||||
options.headers = Object.assign({}, headers, { Authorization: `apikey ${credentials.apiKey}` });
|
||||
|
||||
if (!(credentials.apiKey as string).includes('-')) {
|
||||
throw new Error('The API key is not valid!');
|
||||
}
|
||||
|
||||
const datacenter = (credentials.apiKey as string).split('-').pop();
|
||||
options.url = `https://${datacenter}.${host}${endpoint}`;
|
||||
|
||||
return await this.helpers.request!(options);
|
||||
} else {
|
||||
const credentials = this.getCredentials('mailchimpOAuth2Api') as IDataObject;
|
||||
|
||||
const { api_endpoint } = await getMetadata.call(this, credentials.oauthTokenData as IDataObject);
|
||||
|
||||
options.url = `${api_endpoint}/3.0${endpoint}`;
|
||||
//@ts-ignore
|
||||
return await this.helpers.requestOAuth2!.call(this, 'mailchimpOAuth2Api', options, 'Bearer');
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.response.body && error.response.body.detail) {
|
||||
if (error.respose && error.response.body && error.response.body.detail) {
|
||||
throw new Error(`Mailchimp Error response [${error.statusCode}]: ${error.response.body.detail}`);
|
||||
}
|
||||
throw error;
|
||||
|
@ -80,3 +97,17 @@ export function validateJSON(json: string | undefined): any { // tslint:disable-
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getMetadata(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, oauthTokenData: IDataObject) {
|
||||
const credentials = this.getCredentials('mailchimpOAuth2Api') as IDataObject;
|
||||
const options: OptionsWithUrl = {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': `OAuth ${oauthTokenData.access_token}`,
|
||||
},
|
||||
method: 'GET',
|
||||
url: credentials.metadataUrl as string,
|
||||
json: true,
|
||||
};
|
||||
return this.helpers.request!(options);
|
||||
}
|
||||
|
|
|
@ -69,9 +69,44 @@ export class Mailchimp implements INodeType {
|
|||
{
|
||||
name: 'mailchimpApi',
|
||||
required: true,
|
||||
}
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'apiKey',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'mailchimpOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'API Key',
|
||||
value: 'apiKey',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'apiKey',
|
||||
description: 'Method of authentication.',
|
||||
},
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
|
@ -1536,6 +1571,7 @@ export class Mailchimp implements INodeType {
|
|||
responseData = { success: true };
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(responseData)) {
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
} else {
|
||||
|
|
|
@ -33,7 +33,25 @@ export class MailchimpTrigger implements INodeType {
|
|||
{
|
||||
name: 'mailchimpApi',
|
||||
required: true,
|
||||
}
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'apiKey',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'mailchimpOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
{
|
||||
|
@ -50,6 +68,23 @@ export class MailchimpTrigger implements INodeType {
|
|||
}
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'API Key',
|
||||
value: 'apiKey',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'apiKey',
|
||||
description: 'Method of authentication.',
|
||||
},
|
||||
{
|
||||
displayName: 'List',
|
||||
name: 'list',
|
||||
|
|
|
@ -226,6 +226,94 @@ export const contactFields = [
|
|||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Address',
|
||||
name: 'addressUi',
|
||||
placeholder: 'Address',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'addressValues',
|
||||
displayName: 'Address',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Address Line 1',
|
||||
name: 'address1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Address Line 2',
|
||||
name: 'address2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'City',
|
||||
name: 'city',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'State',
|
||||
name: 'state',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Country',
|
||||
name: 'country',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Zip Code',
|
||||
name: 'zipCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'B2B or B2C',
|
||||
name: 'b2bOrb2c',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'B2B',
|
||||
value: 'B2B',
|
||||
},
|
||||
{
|
||||
name: 'B2C',
|
||||
value: 'B2C',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'CRM ID',
|
||||
name: 'crmId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Fax',
|
||||
name: 'fax',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Has Purchased',
|
||||
name: 'hasPurchased',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'IP Address',
|
||||
name: 'ipAddress',
|
||||
|
@ -240,6 +328,12 @@ export const contactFields = [
|
|||
default: '',
|
||||
description: 'Date/time in UTC;',
|
||||
},
|
||||
{
|
||||
displayName: 'Mobile',
|
||||
name: 'mobile',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Owner ID',
|
||||
name: 'ownerId',
|
||||
|
@ -247,6 +341,112 @@ export const contactFields = [
|
|||
default: '',
|
||||
description: 'ID of a Mautic user to assign this contact to',
|
||||
},
|
||||
{
|
||||
displayName: 'Phone',
|
||||
name: 'phone',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Prospect or Customer',
|
||||
name: 'prospectOrCustomer',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Prospect',
|
||||
value: 'Prospect',
|
||||
},
|
||||
{
|
||||
name: 'Customer',
|
||||
value: 'Customer',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Sandbox',
|
||||
name: 'sandbox',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Stage',
|
||||
name: 'stage',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getStages',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tags',
|
||||
name: 'tags',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getTags',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Social Media',
|
||||
name: 'socialMediaUi',
|
||||
placeholder: 'Social Media',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'socialMediaValues',
|
||||
displayName: 'Social Media',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Facebook',
|
||||
name: 'facebook',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Foursquare',
|
||||
name: 'foursquare',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Instagram',
|
||||
name: 'instagram',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'LinkedIn',
|
||||
name: 'linkedIn',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Skype',
|
||||
name: 'skype',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Twitter',
|
||||
name: 'twitter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Website',
|
||||
name: 'website',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
|
@ -318,6 +518,103 @@ export const contactFields = [
|
|||
default: '',
|
||||
description: 'Contact parameters',
|
||||
},
|
||||
{
|
||||
displayName: 'Address',
|
||||
name: 'addressUi',
|
||||
placeholder: 'Address',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'addressValues',
|
||||
displayName: 'Address',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Address Line 1',
|
||||
name: 'address1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Address Line 2',
|
||||
name: 'address2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'City',
|
||||
name: 'city',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'State',
|
||||
name: 'state',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Country',
|
||||
name: 'country',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Zip Code',
|
||||
name: 'zipCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'B2B or B2C',
|
||||
name: 'b2bOrb2c',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'B2B',
|
||||
value: 'B2B',
|
||||
},
|
||||
{
|
||||
name: 'B2C',
|
||||
value: 'B2C',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'CRM ID',
|
||||
name: 'crmId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
|
@ -332,6 +629,19 @@ export const contactFields = [
|
|||
default: '',
|
||||
description: 'Email address of the contact.',
|
||||
},
|
||||
{
|
||||
displayName: 'Fax',
|
||||
name: 'fax',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'First Name',
|
||||
name: 'firstName',
|
||||
|
@ -346,6 +656,47 @@ export const contactFields = [
|
|||
default: '',
|
||||
description: 'First Name',
|
||||
},
|
||||
{
|
||||
displayName: 'Has Purchased',
|
||||
name: 'hasPurchased',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'IP Address',
|
||||
name: 'ipAddress',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'IP address to associate with the contact',
|
||||
},
|
||||
{
|
||||
displayName: 'Last Active',
|
||||
name: 'lastActive',
|
||||
type: 'dateTime',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Date/time in UTC;',
|
||||
},
|
||||
{
|
||||
displayName: 'Last Name',
|
||||
name: 'lastName',
|
||||
|
@ -360,6 +711,60 @@ export const contactFields = [
|
|||
default: '',
|
||||
description: 'LastName',
|
||||
},
|
||||
{
|
||||
displayName: 'Mobile',
|
||||
name: 'mobile',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Owner ID',
|
||||
name: 'ownerId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'ID of a Mautic user to assign this contact to',
|
||||
},
|
||||
{
|
||||
displayName: 'Phone',
|
||||
name: 'phone',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Position',
|
||||
name: 'position',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Position',
|
||||
},
|
||||
{
|
||||
displayName: 'Primary Company',
|
||||
name: 'company',
|
||||
|
@ -378,9 +783,9 @@ export const contactFields = [
|
|||
description: 'Primary company',
|
||||
},
|
||||
{
|
||||
displayName: 'Position',
|
||||
name: 'position',
|
||||
type: 'string',
|
||||
displayName: 'Prospect or Customer',
|
||||
name: 'prospectOrCustomer',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
|
@ -388,8 +793,62 @@ export const contactFields = [
|
|||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Prospect',
|
||||
value: 'Prospect',
|
||||
},
|
||||
{
|
||||
name: 'Customer',
|
||||
value: 'Customer',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Sandbox',
|
||||
name: 'sandbox',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Stage',
|
||||
name: 'stage',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getStages',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tags',
|
||||
name: 'tags',
|
||||
type: 'multiOptions',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getTags',
|
||||
},
|
||||
default: '',
|
||||
description: 'Position',
|
||||
},
|
||||
{
|
||||
displayName: 'Title',
|
||||
|
@ -405,27 +864,94 @@ export const contactFields = [
|
|||
default: '',
|
||||
description: 'Title',
|
||||
},
|
||||
{
|
||||
displayName: 'Social Media',
|
||||
name: 'socialMediaUi',
|
||||
placeholder: 'Social Media',
|
||||
type: 'fixedCollection',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'socialMediaValues',
|
||||
displayName: 'Social Media',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Facebook',
|
||||
name: 'facebook',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Foursquare',
|
||||
name: 'foursquare',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Instagram',
|
||||
name: 'instagram',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'LinkedIn',
|
||||
name: 'linkedIn',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Skype',
|
||||
name: 'skype',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Twitter',
|
||||
name: 'twitter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Website',
|
||||
name: 'website',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'IP Address',
|
||||
name: 'ipAddress',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/jsonParameters': [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'IP address to associate with the contact',
|
||||
},
|
||||
{
|
||||
displayName: 'Last Active',
|
||||
name: 'lastActive',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Date/time in UTC;',
|
||||
},
|
||||
{
|
||||
displayName: 'Owner ID',
|
||||
name: 'ownerId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'ID of a Mautic user to assign this contact to',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import {
|
|||
import {
|
||||
IDataObject,
|
||||
} from 'n8n-workflow';
|
||||
import { errors } from 'imap-simple';
|
||||
|
||||
interface OMauticErrorResponse {
|
||||
errors: Array<{
|
||||
|
@ -19,7 +18,7 @@ interface OMauticErrorResponse {
|
|||
}>;
|
||||
}
|
||||
|
||||
function getErrors(error: OMauticErrorResponse): string {
|
||||
export function getErrors(error: OMauticErrorResponse): string {
|
||||
const returnErrors: string[] = [];
|
||||
|
||||
for (const errorItem of error.errors) {
|
||||
|
@ -31,23 +30,40 @@ function getErrors(error: OMauticErrorResponse): string {
|
|||
|
||||
|
||||
export async function mauticApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query?: IDataObject, uri?: string): Promise<any> { // tslint:disable-line:no-any
|
||||
const credentials = this.getCredentials('mauticApi');
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
const base64Key = Buffer.from(`${credentials.username}:${credentials.password}`).toString('base64');
|
||||
const authenticationMethod = this.getNodeParameter('authentication', 0, 'credentials') as string;
|
||||
|
||||
const options: OptionsWithUri = {
|
||||
headers: { Authorization: `Basic ${base64Key}` },
|
||||
headers: {},
|
||||
method,
|
||||
qs: query,
|
||||
uri: uri || `${credentials.url}/api${endpoint}`,
|
||||
uri: uri || `/api${endpoint}`,
|
||||
body,
|
||||
json: true
|
||||
};
|
||||
try {
|
||||
const returnData = await this.helpers.request!(options);
|
||||
|
||||
if (returnData.error) {
|
||||
try {
|
||||
|
||||
let returnData;
|
||||
|
||||
if (authenticationMethod === 'credentials') {
|
||||
const credentials = this.getCredentials('mauticApi') as IDataObject;
|
||||
|
||||
const base64Key = Buffer.from(`${credentials.username}:${credentials.password}`).toString('base64');
|
||||
|
||||
options.headers!.Authorization = `Basic ${base64Key}`;
|
||||
|
||||
options.uri = `${credentials.url}${options.uri}`;
|
||||
//@ts-ignore
|
||||
returnData = await this.helpers.request(options);
|
||||
} else {
|
||||
const credentials = this.getCredentials('mauticOAuth2Api') as IDataObject;
|
||||
|
||||
options.uri = `${credentials.url}${options.uri}`;
|
||||
//@ts-ignore
|
||||
returnData = await this.helpers.requestOAuth2.call(this, 'mauticOAuth2Api', options);
|
||||
}
|
||||
|
||||
if (returnData.errors) {
|
||||
// They seem to to sometimes return 200 status but still error.
|
||||
throw new Error(getErrors(returnData));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { snakeCase } from 'change-case';
|
||||
|
||||
import {
|
||||
IExecuteFunctions,
|
||||
} from 'n8n-core';
|
||||
|
@ -15,12 +13,18 @@ import {
|
|||
mauticApiRequest,
|
||||
mauticApiRequestAllItems,
|
||||
validateJSON,
|
||||
getErrors,
|
||||
} from './GenericFunctions';
|
||||
|
||||
import {
|
||||
contactFields,
|
||||
contactOperations,
|
||||
} from './ContactDescription';
|
||||
|
||||
import {
|
||||
snakeCase,
|
||||
} from 'change-case';
|
||||
|
||||
export class Mautic implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Mautic',
|
||||
|
@ -40,9 +44,43 @@ export class Mautic implements INodeType {
|
|||
{
|
||||
name: 'mauticApi',
|
||||
required: true,
|
||||
}
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'credentials',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'mauticOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Credentials',
|
||||
value: 'credentials',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'credentials',
|
||||
},
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
|
@ -77,6 +115,32 @@ export class Mautic implements INodeType {
|
|||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available tags to display them to user so that he can
|
||||
// select them easily
|
||||
async getTags(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const tags = await mauticApiRequestAllItems.call(this, 'tags', 'GET', '/tags');
|
||||
for (const tag of tags) {
|
||||
returnData.push({
|
||||
name: tag.tag,
|
||||
value: tag.tag,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available stages to display them to user so that he can
|
||||
// select them easily
|
||||
async getStages(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const stages = await mauticApiRequestAllItems.call(this, 'stages', 'GET', '/stages');
|
||||
for (const stage of stages) {
|
||||
returnData.push({
|
||||
name: stage.name,
|
||||
value: stage.id,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -124,6 +188,62 @@ export class Mautic implements INodeType {
|
|||
if (additionalFields.ownerId) {
|
||||
body.ownerId = additionalFields.ownerId as string;
|
||||
}
|
||||
if (additionalFields.addressUi) {
|
||||
const addressValues = (additionalFields.addressUi as IDataObject).addressValues as IDataObject;
|
||||
if (addressValues) {
|
||||
body.address1 = addressValues.address1 as string;
|
||||
body.address2 = addressValues.address2 as string;
|
||||
body.city = addressValues.city as string;
|
||||
body.state = addressValues.state as string;
|
||||
body.country = addressValues.country as string;
|
||||
body.zipcode = addressValues.zipCode as string;
|
||||
}
|
||||
}
|
||||
if (additionalFields.socialMediaUi) {
|
||||
const socialMediaValues = (additionalFields.socialMediaUi as IDataObject).socialMediaValues as IDataObject;
|
||||
if (socialMediaValues) {
|
||||
body.facebook = socialMediaValues.facebook as string;
|
||||
body.foursquare = socialMediaValues.foursquare as string;
|
||||
body.instagram = socialMediaValues.instagram as string;
|
||||
body.linkedin = socialMediaValues.linkedIn as string;
|
||||
body.skype = socialMediaValues.skype as string;
|
||||
body.twitter = socialMediaValues.twitter as string;
|
||||
}
|
||||
}
|
||||
if (additionalFields.b2bOrb2c) {
|
||||
body.b2b_or_b2c = additionalFields.b2bOrb2c as string;
|
||||
}
|
||||
if (additionalFields.crmId) {
|
||||
body.crm_id = additionalFields.crmId as string;
|
||||
}
|
||||
if (additionalFields.fax) {
|
||||
body.fax = additionalFields.fax as string;
|
||||
}
|
||||
if (additionalFields.hasPurchased) {
|
||||
body.haspurchased = additionalFields.hasPurchased as boolean;
|
||||
}
|
||||
if (additionalFields.mobile) {
|
||||
body.mobile = additionalFields.mobile as string;
|
||||
}
|
||||
if (additionalFields.phone) {
|
||||
body.phone = additionalFields.phone as string;
|
||||
}
|
||||
if (additionalFields.prospectOrCustomer) {
|
||||
body.prospect_or_customer = additionalFields.prospectOrCustomer as string;
|
||||
}
|
||||
if (additionalFields.sandbox) {
|
||||
body.sandbox = additionalFields.sandbox as boolean;
|
||||
}
|
||||
if (additionalFields.stage) {
|
||||
body.stage = additionalFields.stage as string;
|
||||
}
|
||||
if (additionalFields.tags) {
|
||||
body.tags = additionalFields.tags as string;
|
||||
}
|
||||
if (additionalFields.website) {
|
||||
body.website = additionalFields.website as string;
|
||||
}
|
||||
|
||||
responseData = await mauticApiRequest.call(this, 'POST', '/contacts/new', body);
|
||||
responseData = responseData.contact;
|
||||
}
|
||||
|
@ -167,6 +287,61 @@ export class Mautic implements INodeType {
|
|||
if (updateFields.ownerId) {
|
||||
body.ownerId = updateFields.ownerId as string;
|
||||
}
|
||||
if (updateFields.addressUi) {
|
||||
const addressValues = (updateFields.addressUi as IDataObject).addressValues as IDataObject;
|
||||
if (addressValues) {
|
||||
body.address1 = addressValues.address1 as string;
|
||||
body.address2 = addressValues.address2 as string;
|
||||
body.city = addressValues.city as string;
|
||||
body.state = addressValues.state as string;
|
||||
body.country = addressValues.country as string;
|
||||
body.zipcode = addressValues.zipCode as string;
|
||||
}
|
||||
}
|
||||
if (updateFields.socialMediaUi) {
|
||||
const socialMediaValues = (updateFields.socialMediaUi as IDataObject).socialMediaValues as IDataObject;
|
||||
if (socialMediaValues) {
|
||||
body.facebook = socialMediaValues.facebook as string;
|
||||
body.foursquare = socialMediaValues.foursquare as string;
|
||||
body.instagram = socialMediaValues.instagram as string;
|
||||
body.linkedin = socialMediaValues.linkedIn as string;
|
||||
body.skype = socialMediaValues.skype as string;
|
||||
body.twitter = socialMediaValues.twitter as string;
|
||||
}
|
||||
}
|
||||
if (updateFields.b2bOrb2c) {
|
||||
body.b2b_or_b2c = updateFields.b2bOrb2c as string;
|
||||
}
|
||||
if (updateFields.crmId) {
|
||||
body.crm_id = updateFields.crmId as string;
|
||||
}
|
||||
if (updateFields.fax) {
|
||||
body.fax = updateFields.fax as string;
|
||||
}
|
||||
if (updateFields.hasPurchased) {
|
||||
body.haspurchased = updateFields.hasPurchased as boolean;
|
||||
}
|
||||
if (updateFields.mobile) {
|
||||
body.mobile = updateFields.mobile as string;
|
||||
}
|
||||
if (updateFields.phone) {
|
||||
body.phone = updateFields.phone as string;
|
||||
}
|
||||
if (updateFields.prospectOrCustomer) {
|
||||
body.prospect_or_customer = updateFields.prospectOrCustomer as string;
|
||||
}
|
||||
if (updateFields.sandbox) {
|
||||
body.sandbox = updateFields.sandbox as boolean;
|
||||
}
|
||||
if (updateFields.stage) {
|
||||
body.stage = updateFields.stage as string;
|
||||
}
|
||||
if (updateFields.tags) {
|
||||
body.tags = updateFields.tags as string;
|
||||
}
|
||||
if (updateFields.website) {
|
||||
body.website = updateFields.website as string;
|
||||
}
|
||||
responseData = await mauticApiRequest.call(this, 'PATCH', `/contacts/${contactId}/edit`, body);
|
||||
responseData = responseData.contact;
|
||||
}
|
||||
|
@ -193,6 +368,9 @@ export class Mautic implements INodeType {
|
|||
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||
qs.start = 0;
|
||||
responseData = await mauticApiRequest.call(this, 'GET', '/contacts', {}, qs);
|
||||
if (responseData.errors) {
|
||||
throw new Error(getErrors(responseData));
|
||||
}
|
||||
responseData = responseData.contacts;
|
||||
responseData = Object.values(responseData);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,25 @@ export class MauticTrigger implements INodeType {
|
|||
{
|
||||
name: 'mauticApi',
|
||||
required: true,
|
||||
}
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'credentials',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'mauticOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
{
|
||||
|
@ -49,6 +67,22 @@ export class MauticTrigger implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Credentials',
|
||||
value: 'credentials',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'credentials',
|
||||
},
|
||||
{
|
||||
displayName: 'Events',
|
||||
name: 'events',
|
||||
|
|
64
packages/nodes-base/nodes/MessageBird/GenericFunctions.ts
Normal file
64
packages/nodes-base/nodes/MessageBird/GenericFunctions.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
import {
|
||||
OptionsWithUri,
|
||||
} from 'request';
|
||||
|
||||
import {
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IDataObject,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
/**
|
||||
* Make an API request to Message Bird
|
||||
*
|
||||
* @param {IHookFunctions} this
|
||||
* @param {string} method
|
||||
* @param {string} url
|
||||
* @param {object} body
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export async function messageBirdApiRequest(
|
||||
this: IHookFunctions | IExecuteFunctions,
|
||||
method: string,
|
||||
resource: string,
|
||||
body: IDataObject,
|
||||
query: IDataObject = {},
|
||||
): Promise<any> { // tslint:disable-line:no-any
|
||||
const credentials = this.getCredentials('messageBirdApi');
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials returned!');
|
||||
}
|
||||
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `AccessKey ${credentials.accessKey}`,
|
||||
},
|
||||
method,
|
||||
qs: query,
|
||||
body,
|
||||
uri: `https://rest.messagebird.com${resource}`,
|
||||
json: true,
|
||||
};
|
||||
|
||||
try {
|
||||
return await this.helpers.request(options);
|
||||
} catch (error) {
|
||||
if (error.statusCode === 401) {
|
||||
throw new Error('The Message Bird credentials are not valid!');
|
||||
}
|
||||
|
||||
if (error.response && error.response.body && error.response.body.errors) {
|
||||
// Try to return the error prettier
|
||||
const errorMessage = error.response.body.errors.map((e: IDataObject) => e.description);
|
||||
|
||||
throw new Error(`MessageBird Error response [${error.statusCode}]: ${errorMessage.join('|')}`);
|
||||
}
|
||||
|
||||
// If that data does not exist for some reason return the actual error
|
||||
throw error;
|
||||
}
|
||||
}
|
362
packages/nodes-base/nodes/MessageBird/MessageBird.node.ts
Normal file
362
packages/nodes-base/nodes/MessageBird/MessageBird.node.ts
Normal file
|
@ -0,0 +1,362 @@
|
|||
import {
|
||||
IExecuteFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IDataObject,
|
||||
INodeTypeDescription,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
messageBirdApiRequest,
|
||||
} from './GenericFunctions';
|
||||
|
||||
export class MessageBird implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'MessageBird',
|
||||
name: 'messageBird',
|
||||
icon: 'file:messagebird.png',
|
||||
group: ['output'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Sending SMS',
|
||||
defaults: {
|
||||
name: 'MessageBird',
|
||||
color: '#2481d7'
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'messageBirdApi',
|
||||
required: true
|
||||
}
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'SMS',
|
||||
value: 'sms'
|
||||
}
|
||||
],
|
||||
default: 'sms',
|
||||
description: 'The resource to operate on.'
|
||||
},
|
||||
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'sms',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Send',
|
||||
value: 'send',
|
||||
description: 'Send text messages (SMS)',
|
||||
},
|
||||
],
|
||||
default: 'send',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// sms:send
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'From',
|
||||
name: 'originator',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: '14155238886',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'send',
|
||||
],
|
||||
resource: [
|
||||
'sms',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The number from which to send the message.',
|
||||
},
|
||||
{
|
||||
displayName: 'To',
|
||||
name: 'recipients',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: '14155238886/+14155238886',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['send'],
|
||||
resource: ['sms'],
|
||||
},
|
||||
},
|
||||
description: 'All recipients separated by commas.',
|
||||
},
|
||||
|
||||
{
|
||||
displayName: 'Message',
|
||||
name: 'message',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'send',
|
||||
],
|
||||
resource: [
|
||||
'sms',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The message to be send.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Fields',
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Created Date-time',
|
||||
name: 'createdDatetime',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'The date and time of the creation of the message in RFC3339 format (Y-m-dTH:i:sP).',
|
||||
},
|
||||
{
|
||||
displayName: 'Datacoding',
|
||||
name: 'datacoding',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Auto',
|
||||
value: 'auto',
|
||||
},
|
||||
{
|
||||
name: 'Plain',
|
||||
value: 'plain',
|
||||
},
|
||||
{
|
||||
name: 'Unicode',
|
||||
value: 'unicode',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
description: 'Using unicode will limit the maximum number of characters to 70 instead of 160.',
|
||||
},
|
||||
{
|
||||
displayName: 'Gateway',
|
||||
name: 'gateway',
|
||||
type: 'number',
|
||||
default: '',
|
||||
description: 'The SMS route that is used to send the message.',
|
||||
},
|
||||
{
|
||||
displayName: 'Group IDs',
|
||||
name: 'groupIds',
|
||||
placeholder: '1,2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Group IDs separated by commas, If provided recipients can be omitted.',
|
||||
},
|
||||
{
|
||||
displayName: 'Message Type',
|
||||
name: 'mclass',
|
||||
type: 'options',
|
||||
placeholder: 'Permissible values from 0-3',
|
||||
options: [
|
||||
{
|
||||
name: 'Flash',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
name: 'Normal',
|
||||
value: 0,
|
||||
},
|
||||
],
|
||||
default: 1,
|
||||
description: 'Indicated the message type. 1 is a normal message, 0 is a flash message.',
|
||||
},
|
||||
{
|
||||
displayName: 'Reference',
|
||||
name: 'reference',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'A client reference.',
|
||||
},
|
||||
{
|
||||
displayName: 'Report Url',
|
||||
name: 'reportUrl',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The status report URL to be used on a per-message basis.<br /> Reference is required for a status report webhook to be sent.',
|
||||
},
|
||||
{
|
||||
displayName: 'Scheduled Date-time',
|
||||
name: 'scheduledDatetime',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'The scheduled date and time of the message in RFC3339 format (Y-m-dTH:i:sP).',
|
||||
},
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Binary',
|
||||
value: 'binary'
|
||||
},
|
||||
{
|
||||
name: 'Flash',
|
||||
value: 'flash'
|
||||
},
|
||||
{
|
||||
name: 'SMS',
|
||||
value: 'sms'
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
description: 'The type of message.<br /> Values can be: sms, binary, or flash.',
|
||||
},
|
||||
{
|
||||
displayName: 'Type Details',
|
||||
name: 'typeDetails',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'A hash with extra information.<br /> Is only used when a binary message is sent.',
|
||||
},
|
||||
{
|
||||
displayName: 'Validity',
|
||||
name: 'validity',
|
||||
type: 'number',
|
||||
default: 1,
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
description: 'The amount of seconds that the message is valid.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let operation: string;
|
||||
let resource: string;
|
||||
|
||||
// For POST
|
||||
let bodyRequest: IDataObject;
|
||||
// For Query string
|
||||
let qs: IDataObject;
|
||||
|
||||
let requestMethod;
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
qs = {};
|
||||
|
||||
resource = this.getNodeParameter('resource', i) as string;
|
||||
operation = this.getNodeParameter('operation', i) as string;
|
||||
|
||||
if (resource === 'sms') {
|
||||
//https://developers.messagebird.com/api/sms-messaging/#sms-api
|
||||
if (operation === 'send') {
|
||||
// ----------------------------------
|
||||
// sms:send
|
||||
// ----------------------------------
|
||||
|
||||
requestMethod = 'POST';
|
||||
const originator = this.getNodeParameter('originator', i) as string;
|
||||
const body = this.getNodeParameter('message', i) as string;
|
||||
|
||||
bodyRequest = {
|
||||
recipients: [],
|
||||
originator,
|
||||
body
|
||||
};
|
||||
const additionalFields = this.getNodeParameter(
|
||||
'additionalFields',
|
||||
i
|
||||
) as IDataObject;
|
||||
|
||||
if (additionalFields.groupIds) {
|
||||
bodyRequest.groupIds = additionalFields.groupIds as string;
|
||||
}
|
||||
if (additionalFields.type) {
|
||||
bodyRequest.type = additionalFields.type as string;
|
||||
}
|
||||
if (additionalFields.reference) {
|
||||
bodyRequest.reference = additionalFields.reference as string;
|
||||
}
|
||||
if (additionalFields.reportUrl) {
|
||||
bodyRequest.reportUrl = additionalFields.reportUrl as string;
|
||||
}
|
||||
if (additionalFields.validity) {
|
||||
bodyRequest.validity = additionalFields.reportUrl as number;
|
||||
}
|
||||
if (additionalFields.gateway) {
|
||||
bodyRequest.gateway = additionalFields.gateway as string;
|
||||
}
|
||||
if (additionalFields.typeDetails) {
|
||||
bodyRequest.typeDetails = additionalFields.typeDetails as string;
|
||||
}
|
||||
if (additionalFields.datacoding) {
|
||||
bodyRequest.datacoding = additionalFields.datacoding as string;
|
||||
}
|
||||
if (additionalFields.mclass) {
|
||||
bodyRequest.mclass = additionalFields.mclass as number;
|
||||
}
|
||||
if (additionalFields.scheduledDatetime) {
|
||||
bodyRequest.scheduledDatetime = additionalFields.scheduledDatetime as string;
|
||||
}
|
||||
if (additionalFields.createdDatetime) {
|
||||
bodyRequest.createdDatetime = additionalFields.createdDatetime as string;
|
||||
}
|
||||
|
||||
const receivers = this.getNodeParameter('recipients', i) as string;
|
||||
|
||||
bodyRequest.recipients = receivers.split(',').map(item => {
|
||||
return parseInt(item, 10);
|
||||
});
|
||||
} else {
|
||||
throw new Error(`The operation "${operation}" is not known!`);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`The resource "${resource}" is not known!`);
|
||||
}
|
||||
|
||||
const responseData = await messageBirdApiRequest.call(
|
||||
this,
|
||||
requestMethod,
|
||||
'/messages',
|
||||
bodyRequest,
|
||||
qs
|
||||
);
|
||||
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
|
||||
return [this.helpers.returnJsonArray(returnData)];
|
||||
}
|
||||
}
|
BIN
packages/nodes-base/nodes/MessageBird/messagebird.png
Normal file
BIN
packages/nodes-base/nodes/MessageBird/messagebird.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -15,6 +15,21 @@ export const boardItemOperations = [
|
|||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Add Update',
|
||||
value: 'addUpdate',
|
||||
description: `Add an update to an item.`,
|
||||
},
|
||||
{
|
||||
name: 'Change Column Value',
|
||||
value: 'changeColumnValue',
|
||||
description: 'Change a column value for a board item',
|
||||
},
|
||||
{
|
||||
name: 'Change Multiple Column Values',
|
||||
value: 'changeMultipleColumnValues',
|
||||
description: 'Change multiple column values for a board item',
|
||||
},
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
|
@ -48,6 +63,192 @@ export const boardItemOperations = [
|
|||
|
||||
export const boardItemFields = [
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* boardItem:addUpdate */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Item ID',
|
||||
name: 'itemId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'boardItem',
|
||||
],
|
||||
operation: [
|
||||
'addUpdate',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The unique identifier of the item to add update to.',
|
||||
},
|
||||
{
|
||||
displayName: 'Update Text',
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'boardItem',
|
||||
],
|
||||
operation: [
|
||||
'addUpdate',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The update text to add.',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* boardItem:changeColumnValue */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'boardId',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getBoards',
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'boardItem',
|
||||
],
|
||||
operation: [
|
||||
'changeColumnValue',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The unique identifier of the board.',
|
||||
},
|
||||
{
|
||||
displayName: 'Item ID',
|
||||
name: 'itemId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'boardItem',
|
||||
],
|
||||
operation: [
|
||||
'changeColumnValue',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The unique identifier of the item to to change column of.',
|
||||
},
|
||||
{
|
||||
displayName: 'Column ID',
|
||||
name: 'columnId',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getColumns',
|
||||
loadOptionsDependsOn: [
|
||||
'boardId'
|
||||
],
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'boardItem',
|
||||
],
|
||||
operation: [
|
||||
'changeColumnValue',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: `The column's unique identifier.`,
|
||||
},
|
||||
{
|
||||
displayName: 'Value',
|
||||
name: 'value',
|
||||
type: 'json',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'boardItem',
|
||||
],
|
||||
operation: [
|
||||
'changeColumnValue',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The column value in JSON format. Documentation can be found <a href="https://monday.com/developers/v2#mutations-section-columns-change-column-value" target="_blank">here</a>.',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* boardItem:changeMultipleColumnValues */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'boardId',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getBoards',
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'boardItem',
|
||||
],
|
||||
operation: [
|
||||
'changeMultipleColumnValues',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The unique identifier of the board.',
|
||||
},
|
||||
{
|
||||
displayName: 'Item ID',
|
||||
name: 'itemId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'boardItem',
|
||||
],
|
||||
operation: [
|
||||
'changeMultipleColumnValues',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: `Item's ID`
|
||||
},
|
||||
{
|
||||
displayName: 'Column Values',
|
||||
name: 'columnValues',
|
||||
type: 'json',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'boardItem',
|
||||
],
|
||||
operation: [
|
||||
'changeMultipleColumnValues',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The column fields and values in JSON format. Documentation can be found <a href="https://monday.com/developers/v2#mutations-section-columns-change-multiple-column-values" target="_blank">here</a>.',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* boardItem:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
|
|
@ -455,6 +455,84 @@ export class MondayCom implements INodeType {
|
|||
}
|
||||
}
|
||||
if (resource === 'boardItem') {
|
||||
if (operation === 'addUpdate') {
|
||||
const itemId = parseInt((this.getNodeParameter('itemId', i) as string), 10);
|
||||
const value = this.getNodeParameter('value', i) as string;
|
||||
|
||||
const body: IGraphqlBody = {
|
||||
query:
|
||||
`mutation ($itemId: Int!, $value: String!) {
|
||||
create_update (item_id: $itemId, body: $value) {
|
||||
id
|
||||
}
|
||||
}`,
|
||||
variables: {
|
||||
itemId,
|
||||
value,
|
||||
},
|
||||
};
|
||||
|
||||
responseData = await mondayComApiRequest.call(this, body);
|
||||
responseData = responseData.data.create_update;
|
||||
}
|
||||
if (operation === 'changeColumnValue') {
|
||||
const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10);
|
||||
const itemId = parseInt((this.getNodeParameter('itemId', i) as string), 10);
|
||||
const columnId = this.getNodeParameter('columnId', i) as string;
|
||||
const value = this.getNodeParameter('value', i) as string;
|
||||
|
||||
const body: IGraphqlBody = {
|
||||
query:
|
||||
`mutation ($boardId: Int!, $itemId: Int!, $columnId: String!, $value: JSON!) {
|
||||
change_column_value (board_id: $boardId, item_id: $itemId, column_id: $columnId, value: $value) {
|
||||
id
|
||||
}
|
||||
}`,
|
||||
variables: {
|
||||
boardId,
|
||||
itemId,
|
||||
columnId,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
JSON.parse(value);
|
||||
} catch (e) {
|
||||
throw new Error('Custom Values must be a valid JSON');
|
||||
}
|
||||
body.variables.value = JSON.stringify(JSON.parse(value));
|
||||
|
||||
responseData = await mondayComApiRequest.call(this, body);
|
||||
responseData = responseData.data.change_column_value;
|
||||
}
|
||||
if (operation === 'changeMultipleColumnValues') {
|
||||
const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10);
|
||||
const itemId = parseInt((this.getNodeParameter('itemId', i) as string), 10);
|
||||
const columnValues = this.getNodeParameter('columnValues', i) as string;
|
||||
|
||||
const body: IGraphqlBody = {
|
||||
query:
|
||||
`mutation ($boardId: Int!, $itemId: Int!, $columnValues: JSON!) {
|
||||
change_multiple_column_values (board_id: $boardId, item_id: $itemId, column_values: $columnValues) {
|
||||
id
|
||||
}
|
||||
}`,
|
||||
variables: {
|
||||
boardId,
|
||||
itemId,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
JSON.parse(columnValues);
|
||||
} catch (e) {
|
||||
throw new Error('Custom Values must be a valid JSON');
|
||||
}
|
||||
body.variables.columnValues = JSON.stringify(JSON.parse(columnValues));
|
||||
|
||||
responseData = await mondayComApiRequest.call(this, body);
|
||||
responseData = responseData.data.change_multiple_column_values;
|
||||
}
|
||||
if (operation === 'create') {
|
||||
const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10);
|
||||
const groupId = this.getNodeParameter('groupId', i) as string;
|
||||
|
|
|
@ -32,7 +32,18 @@ export class MongoDb implements INodeType {
|
|||
const items = this.getInputData();
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
|
||||
if (operation === 'find') {
|
||||
if (operation === 'delete') {
|
||||
// ----------------------------------
|
||||
// delete
|
||||
// ----------------------------------
|
||||
|
||||
const { deletedCount } = await mdb
|
||||
.collection(this.getNodeParameter('collection', 0) as string)
|
||||
.deleteMany(JSON.parse(this.getNodeParameter('query', 0) as string));
|
||||
|
||||
returnItems = this.helpers.returnJsonArray([{ deletedCount }]);
|
||||
|
||||
} else if (operation === 'find') {
|
||||
// ----------------------------------
|
||||
// find
|
||||
// ----------------------------------
|
||||
|
|
|
@ -28,6 +28,11 @@ export const nodeDescription: INodeTypeDescription = {
|
|||
name: 'operation',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete documents.'
|
||||
},
|
||||
{
|
||||
name: 'Find',
|
||||
value: 'find',
|
||||
|
@ -57,13 +62,36 @@ export const nodeDescription: INodeTypeDescription = {
|
|||
description: 'MongoDB Collection'
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// delete
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Delete Query (JSON format)',
|
||||
name: 'query',
|
||||
type: 'json',
|
||||
typeOptions: {
|
||||
rows: 5
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'delete'
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '{}',
|
||||
placeholder: `{ "birth": { "$gt": "1950-01-01" } }`,
|
||||
required: true,
|
||||
description: 'MongoDB Delete query.'
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// find
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Query (JSON format)',
|
||||
name: 'query',
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
typeOptions: {
|
||||
rows: 5
|
||||
},
|
||||
|
|
|
@ -213,20 +213,20 @@ export class OpenWeatherMap implements INodeType {
|
|||
// Set base data
|
||||
qs = {
|
||||
APPID: credentials.accessToken,
|
||||
units: this.getNodeParameter('format', 0) as string
|
||||
units: this.getNodeParameter('format', i) as string
|
||||
};
|
||||
|
||||
// Get the location
|
||||
locationSelection = this.getNodeParameter('locationSelection', 0) as string;
|
||||
locationSelection = this.getNodeParameter('locationSelection', i) as string;
|
||||
if (locationSelection === 'cityName') {
|
||||
qs.q = this.getNodeParameter('cityName', 0) as string;
|
||||
qs.q = this.getNodeParameter('cityName', i) as string;
|
||||
} else if (locationSelection === 'cityId') {
|
||||
qs.id = this.getNodeParameter('cityId', 0) as number;
|
||||
qs.id = this.getNodeParameter('cityId', i) as number;
|
||||
} else if (locationSelection === 'coordinates') {
|
||||
qs.lat = this.getNodeParameter('latitude', 0) as string;
|
||||
qs.lon = this.getNodeParameter('longitude', 0) as string;
|
||||
qs.lat = this.getNodeParameter('latitude', i) as string;
|
||||
qs.lon = this.getNodeParameter('longitude', i) as string;
|
||||
} else if (locationSelection === 'zipCode') {
|
||||
qs.zip = this.getNodeParameter('zipCode', 0) as string;
|
||||
qs.zip = this.getNodeParameter('zipCode', i) as string;
|
||||
} else {
|
||||
throw new Error(`The locationSelection "${locationSelection}" is not known!`);
|
||||
}
|
||||
|
|
|
@ -14,19 +14,13 @@ import {
|
|||
} from 'n8n-workflow';
|
||||
|
||||
export async function surveyMonkeyApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const credentials = this.getCredentials('surveyMonkeyApi');
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
const authenticationMethod = this.getNodeParameter('authentication', 0);
|
||||
|
||||
const endpoint = 'https://api.surveymonkey.com/v3';
|
||||
|
||||
let options: OptionsWithUri = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `bearer ${credentials.accessToken}`,
|
||||
},
|
||||
method,
|
||||
body,
|
||||
|
@ -34,6 +28,7 @@ export async function surveyMonkeyApiRequest(this: IExecuteFunctions | IWebhookF
|
|||
uri: uri || `${endpoint}${resource}`,
|
||||
json: true
|
||||
};
|
||||
|
||||
if (!Object.keys(body).length) {
|
||||
delete options.body;
|
||||
}
|
||||
|
@ -41,8 +36,22 @@ export async function surveyMonkeyApiRequest(this: IExecuteFunctions | IWebhookF
|
|||
delete options.qs;
|
||||
}
|
||||
options = Object.assign({}, options, option);
|
||||
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
if ( authenticationMethod === 'accessToken') {
|
||||
const credentials = this.getCredentials('surveyMonkeyApi');
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
// @ts-ignore
|
||||
options.headers['Authorization'] = `bearer ${credentials.accessToken}`;
|
||||
|
||||
return await this.helpers.request!(options);
|
||||
|
||||
} else {
|
||||
return await this.helpers.requestOAuth2?.call(this, 'surveyMonkeyOAuth2Api', options);
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error.response.body.error.message;
|
||||
if (errorMessage !== undefined) {
|
||||
|
|
|
@ -49,6 +49,24 @@ export class SurveyMonkeyTrigger implements INodeType {
|
|||
{
|
||||
name: 'surveyMonkeyApi',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'accessToken',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'surveyMonkeyOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
|
@ -66,6 +84,23 @@ export class SurveyMonkeyTrigger implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Access Token',
|
||||
value: 'accessToken',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'accessToken',
|
||||
description: 'Method of authentication.',
|
||||
},
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'objectType',
|
||||
|
@ -453,11 +488,18 @@ export class SurveyMonkeyTrigger implements INodeType {
|
|||
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||
const event = this.getNodeParameter('event') as string;
|
||||
const objectType = this.getNodeParameter('objectType') as string;
|
||||
const credentials = this.getCredentials('surveyMonkeyApi') as IDataObject;
|
||||
const authenticationMethod = this.getNodeParameter('authentication') as string;
|
||||
let credentials : IDataObject;
|
||||
const headerData = this.getHeaderData() as IDataObject;
|
||||
const req = this.getRequestObject();
|
||||
const webhookName = this.getWebhookName();
|
||||
|
||||
if (authenticationMethod === 'accessToken') {
|
||||
credentials = this.getCredentials('surveyMonkeyApi') as IDataObject;
|
||||
} else {
|
||||
credentials = this.getCredentials('surveyMonkeyOAuth2Api') as IDataObject;
|
||||
}
|
||||
|
||||
if (webhookName === 'setup') {
|
||||
// It is a create webhook confirmation request
|
||||
return {};
|
||||
|
|
|
@ -133,7 +133,15 @@ export class Twitter implements INodeType {
|
|||
let attachmentBody = {};
|
||||
let response: IDataObject = {};
|
||||
|
||||
if (binaryData[binaryPropertyName].mimeType.includes('image')) {
|
||||
const isAnimatedWebp = (Buffer.from(binaryData[binaryPropertyName].data, 'base64').toString().indexOf('ANMF') !== -1);
|
||||
|
||||
const isImage = binaryData[binaryPropertyName].mimeType.includes('image');
|
||||
|
||||
if (isImage && isAnimatedWebp) {
|
||||
throw new Error('Animated .webp images are not supported use .gif instead');
|
||||
}
|
||||
|
||||
if (isImage) {
|
||||
|
||||
const attachmentBody = {
|
||||
media_data: binaryData[binaryPropertyName].data,
|
||||
|
|
|
@ -45,18 +45,10 @@ export interface ITypeformAnswerField {
|
|||
* @returns {Promise<any>}
|
||||
*/
|
||||
export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise<any> { // tslint:disable-line:no-any
|
||||
const credentials = this.getCredentials('typeformApi');
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
|
||||
query = query || {};
|
||||
const authenticationMethod = this.getNodeParameter('authentication', 0);
|
||||
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
'Authorization': `bearer ${credentials.accessToken}`,
|
||||
},
|
||||
headers: {},
|
||||
method,
|
||||
body,
|
||||
qs: query,
|
||||
|
@ -64,8 +56,23 @@ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoa
|
|||
json: true,
|
||||
};
|
||||
|
||||
query = query || {};
|
||||
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
if (authenticationMethod === 'accessToken') {
|
||||
|
||||
const credentials = this.getCredentials('typeformApi');
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
|
||||
options.headers!['Authorization'] = `bearer ${credentials.accessToken}`;
|
||||
|
||||
return await this.helpers.request!(options);
|
||||
} else {
|
||||
return await this.helpers.requestOAuth2!.call(this, 'typeformOAuth2Api', options);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.statusCode === 401) {
|
||||
// Return a clear error
|
||||
|
|
|
@ -37,7 +37,25 @@ export class TypeformTrigger implements INodeType {
|
|||
{
|
||||
name: 'typeformApi',
|
||||
required: true,
|
||||
}
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'accessToken',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'typeformOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
{
|
||||
|
@ -48,6 +66,23 @@ export class TypeformTrigger implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Access Token',
|
||||
value: 'accessToken',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'accessToken',
|
||||
description: 'The resource to operate on.',
|
||||
},
|
||||
{
|
||||
displayName: 'Form',
|
||||
name: 'formId',
|
||||
|
|
|
@ -14,26 +14,48 @@ import {
|
|||
} from 'n8n-workflow';
|
||||
|
||||
export async function zendeskApiRequest(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('zendeskApi');
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
const base64Key = Buffer.from(`${credentials.email}/token:${credentials.apiToken}`).toString('base64');
|
||||
const authenticationMethod = this.getNodeParameter('authentication', 0);
|
||||
|
||||
let options: OptionsWithUri = {
|
||||
headers: { 'Authorization': `Basic ${base64Key}`},
|
||||
headers: {},
|
||||
method,
|
||||
qs,
|
||||
body,
|
||||
uri: uri ||`${credentials.url}/api/v2${resource}.json`,
|
||||
//@ts-ignore
|
||||
uri,
|
||||
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) {
|
||||
if (authenticationMethod === 'apiToken') {
|
||||
const credentials = this.getCredentials('zendeskApi');
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
|
||||
const base64Key = Buffer.from(`${credentials.email}/token:${credentials.apiToken}`).toString('base64');
|
||||
options.uri = `https://${credentials.subdomain}.zendesk.com/api/v2${resource}.json`;
|
||||
options.headers!['Authorization'] = `Basic ${base64Key}`;
|
||||
|
||||
return await this.helpers.request!(options);
|
||||
} else {
|
||||
const credentials = this.getCredentials('zendeskOAuth2Api');
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
|
||||
options.uri = `https://${credentials.subdomain}.zendesk.com/api/v2${resource}.json`;
|
||||
|
||||
return await this.helpers.requestOAuth2!.call(this, 'zendeskOAuth2Api', options);
|
||||
}
|
||||
} catch(err) {
|
||||
let errorMessage = err.message;
|
||||
if (err.response && err.response.body && err.response.body.error) {
|
||||
errorMessage = err.response.body.error;
|
||||
|
|
|
@ -52,9 +52,44 @@ export class Zendesk implements INodeType {
|
|||
{
|
||||
name: 'zendeskApi',
|
||||
required: true,
|
||||
}
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'apiToken',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'zendeskOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'API Token',
|
||||
value: 'apiToken',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'apiToken',
|
||||
description: 'The resource to operate on.',
|
||||
},
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
|
|
|
@ -42,7 +42,25 @@ export class ZendeskTrigger implements INodeType {
|
|||
{
|
||||
name: 'zendeskApi',
|
||||
required: true,
|
||||
}
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'apiToken',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'zendeskOAuth2Api',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: [
|
||||
'oAuth2',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
{
|
||||
|
@ -53,6 +71,23 @@ export class ZendeskTrigger implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'API Token',
|
||||
value: 'apiToken',
|
||||
},
|
||||
{
|
||||
name: 'OAuth2',
|
||||
value: 'oAuth2',
|
||||
},
|
||||
],
|
||||
default: 'apiToken',
|
||||
description: 'The resource to operate on.',
|
||||
},
|
||||
{
|
||||
displayName: 'Service',
|
||||
name: 'service',
|
||||
|
|
|
@ -1,364 +1,371 @@
|
|||
{
|
||||
"name": "n8n-nodes-base",
|
||||
"version": "0.63.1",
|
||||
"description": "Base nodes of n8n",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
"author": {
|
||||
"name": "Jan Oberhauser",
|
||||
"email": "jan@n8n.io"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/n8n-io/n8n.git"
|
||||
},
|
||||
"main": "dist/src/index",
|
||||
"types": "dist/src/index.d.ts",
|
||||
"scripts": {
|
||||
"dev": "npm run watch",
|
||||
"build": "tsc && gulp",
|
||||
"tslint": "tslint -p tsconfig.json -c tslint.json",
|
||||
"watch": "tsc --watch",
|
||||
"test": "jest"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
"name": "n8n-nodes-base",
|
||||
"version": "0.65.0",
|
||||
"description": "Base nodes of n8n",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
"author": {
|
||||
"name": "Jan Oberhauser",
|
||||
"email": "jan@n8n.io"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/n8n-io/n8n.git"
|
||||
},
|
||||
"main": "dist/src/index",
|
||||
"types": "dist/src/index.d.ts",
|
||||
"scripts": {
|
||||
"dev": "npm run watch",
|
||||
"build": "tsc && gulp",
|
||||
"tslint": "tslint -p tsconfig.json -c tslint.json",
|
||||
"watch": "tsc --watch",
|
||||
"test": "jest"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"n8n": {
|
||||
"credentials": [
|
||||
"dist/credentials/ActiveCampaignApi.credentials.js",
|
||||
"dist/credentials/AgileCrmApi.credentials.js",
|
||||
"dist/credentials/AcuitySchedulingApi.credentials.js",
|
||||
"dist/credentials/AirtableApi.credentials.js",
|
||||
"dist/credentials/Amqp.credentials.js",
|
||||
"dist/credentials/AsanaApi.credentials.js",
|
||||
"dist/credentials/Aws.credentials.js",
|
||||
"dist/credentials/AffinityApi.credentials.js",
|
||||
"dist/credentials/BannerbearApi.credentials.js",
|
||||
"dist/credentials/BitbucketApi.credentials.js",
|
||||
"dist/credentials/BitlyApi.credentials.js",
|
||||
"dist/credentials/ChargebeeApi.credentials.js",
|
||||
"dist/credentials/ClearbitApi.credentials.js",
|
||||
"dist/credentials/ClickUpApi.credentials.js",
|
||||
"dist/credentials/ClockifyApi.credentials.js",
|
||||
"dist/credentials/CockpitApi.credentials.js",
|
||||
"dist/credentials/CodaApi.credentials.js",
|
||||
"dist/credentials/CopperApi.credentials.js",
|
||||
"dist/credentials/CalendlyApi.credentials.js",
|
||||
"dist/credentials/DisqusApi.credentials.js",
|
||||
"dist/credentials/DriftApi.credentials.js",
|
||||
"dist/credentials/DropboxApi.credentials.js",
|
||||
"dist/credentials/EventbriteApi.credentials.js",
|
||||
"dist/credentials/FacebookGraphApi.credentials.js",
|
||||
"dist/credentials/FreshdeskApi.credentials.js",
|
||||
"dist/credentials/FileMaker.credentials.js",
|
||||
"dist/credentials/FlowApi.credentials.js",
|
||||
"dist/credentials/GithubApi.credentials.js",
|
||||
"dist/credentials/GithubOAuth2Api.credentials.js",
|
||||
"dist/credentials/GitlabApi.credentials.js",
|
||||
"dist/credentials/GoogleApi.credentials.js",
|
||||
"dist/credentials/GoogleCalendarOAuth2Api.credentials.js",
|
||||
"dist/credentials/GoogleDriveOAuth2Api.credentials.js",
|
||||
"dist/credentials/GoogleOAuth2Api.credentials.js",
|
||||
"dist/credentials/GoogleSheetsOAuth2Api.credentials.js",
|
||||
"dist/credentials/GumroadApi.credentials.js",
|
||||
"dist/credentials/HarvestApi.credentials.js",
|
||||
"dist/credentials/HelpScoutOAuth2Api.credentials.js",
|
||||
"dist/credentials/HttpBasicAuth.credentials.js",
|
||||
"dist/credentials/HttpDigestAuth.credentials.js",
|
||||
"dist/credentials/HttpHeaderAuth.credentials.js",
|
||||
"dist/credentials/HubspotApi.credentials.js",
|
||||
"dist/credentials/HubspotDeveloperApi.credentials.js",
|
||||
"dist/credentials/HubspotOAuth2Api.credentials.js",
|
||||
"dist/credentials/HunterApi.credentials.js",
|
||||
"dist/credentials/Imap.credentials.js",
|
||||
"dist/credentials/IntercomApi.credentials.js",
|
||||
"dist/credentials/InvoiceNinjaApi.credentials.js",
|
||||
"dist/credentials/JiraSoftwareCloudApi.credentials.js",
|
||||
"dist/credentials/JiraSoftwareServerApi.credentials.js",
|
||||
"dist/credentials/JotFormApi.credentials.js",
|
||||
"dist/credentials/KeapOAuth2Api.credentials.js",
|
||||
"dist/credentials/LinkFishApi.credentials.js",
|
||||
"dist/credentials/MailchimpApi.credentials.js",
|
||||
"dist/credentials/MailchimpOAuth2Api.credentials.js",
|
||||
"dist/credentials/MailgunApi.credentials.js",
|
||||
"dist/credentials/MailjetEmailApi.credentials.js",
|
||||
"dist/credentials/MailjetSmsApi.credentials.js",
|
||||
"dist/credentials/MandrillApi.credentials.js",
|
||||
"dist/credentials/MattermostApi.credentials.js",
|
||||
"dist/credentials/MauticApi.credentials.js",
|
||||
"dist/credentials/MauticOAuth2Api.credentials.js",
|
||||
"dist/credentials/MessageBirdApi.credentials.js",
|
||||
"dist/credentials/MicrosoftExcelOAuth2Api.credentials.js",
|
||||
"dist/credentials/MicrosoftOAuth2Api.credentials.js",
|
||||
"dist/credentials/MicrosoftOneDriveOAuth2Api.credentials.js",
|
||||
"dist/credentials/MoceanApi.credentials.js",
|
||||
"dist/credentials/MondayComApi.credentials.js",
|
||||
"dist/credentials/MongoDb.credentials.js",
|
||||
"dist/credentials/Msg91Api.credentials.js",
|
||||
"dist/credentials/MySql.credentials.js",
|
||||
"dist/credentials/NextCloudApi.credentials.js",
|
||||
"dist/credentials/OAuth1Api.credentials.js",
|
||||
"dist/credentials/OAuth2Api.credentials.js",
|
||||
"dist/credentials/OpenWeatherMapApi.credentials.js",
|
||||
"dist/credentials/PagerDutyApi.credentials.js",
|
||||
"dist/credentials/PayPalApi.credentials.js",
|
||||
"dist/credentials/PipedriveApi.credentials.js",
|
||||
"dist/credentials/Postgres.credentials.js",
|
||||
"dist/credentials/Redis.credentials.js",
|
||||
"dist/credentials/RocketchatApi.credentials.js",
|
||||
"dist/credentials/RundeckApi.credentials.js",
|
||||
"dist/credentials/ShopifyApi.credentials.js",
|
||||
"dist/credentials/SalesforceOAuth2Api.credentials.js",
|
||||
"dist/credentials/SlackApi.credentials.js",
|
||||
"dist/credentials/SlackOAuth2Api.credentials.js",
|
||||
"dist/credentials/Sms77Api.credentials.js",
|
||||
"dist/credentials/Smtp.credentials.js",
|
||||
"dist/credentials/StripeApi.credentials.js",
|
||||
"dist/credentials/SalesmateApi.credentials.js",
|
||||
"dist/credentials/SegmentApi.credentials.js",
|
||||
"dist/credentials/SurveyMonkeyApi.credentials.js",
|
||||
"dist/credentials/SurveyMonkeyOAuth2Api.credentials.js",
|
||||
"dist/credentials/TelegramApi.credentials.js",
|
||||
"dist/credentials/TodoistApi.credentials.js",
|
||||
"dist/credentials/TrelloApi.credentials.js",
|
||||
"dist/credentials/TwilioApi.credentials.js",
|
||||
"dist/credentials/TwitterOAuth1Api.credentials.js",
|
||||
"dist/credentials/TypeformApi.credentials.js",
|
||||
"dist/credentials/TypeformOAuth2Api.credentials.js",
|
||||
"dist/credentials/TogglApi.credentials.js",
|
||||
"dist/credentials/UpleadApi.credentials.js",
|
||||
"dist/credentials/VeroApi.credentials.js",
|
||||
"dist/credentials/WebflowApi.credentials.js",
|
||||
"dist/credentials/WooCommerceApi.credentials.js",
|
||||
"dist/credentials/WordpressApi.credentials.js",
|
||||
"dist/credentials/ZendeskApi.credentials.js",
|
||||
"dist/credentials/ZendeskOAuth2Api.credentials.js",
|
||||
"dist/credentials/ZohoOAuth2Api.credentials.js",
|
||||
"dist/credentials/ZulipApi.credentials.js"
|
||||
],
|
||||
"n8n": {
|
||||
"credentials": [
|
||||
"dist/credentials/ActiveCampaignApi.credentials.js",
|
||||
"dist/credentials/AgileCrmApi.credentials.js",
|
||||
"dist/credentials/AcuitySchedulingApi.credentials.js",
|
||||
"dist/credentials/AirtableApi.credentials.js",
|
||||
"dist/credentials/Amqp.credentials.js",
|
||||
"dist/credentials/AsanaApi.credentials.js",
|
||||
"dist/credentials/Aws.credentials.js",
|
||||
"dist/credentials/AffinityApi.credentials.js",
|
||||
"dist/credentials/BannerbearApi.credentials.js",
|
||||
"dist/credentials/BitbucketApi.credentials.js",
|
||||
"dist/credentials/BitlyApi.credentials.js",
|
||||
"dist/credentials/ChargebeeApi.credentials.js",
|
||||
"dist/credentials/ClearbitApi.credentials.js",
|
||||
"dist/credentials/ClickUpApi.credentials.js",
|
||||
"dist/credentials/ClockifyApi.credentials.js",
|
||||
"dist/credentials/CockpitApi.credentials.js",
|
||||
"dist/credentials/CodaApi.credentials.js",
|
||||
"dist/credentials/CopperApi.credentials.js",
|
||||
"dist/credentials/CalendlyApi.credentials.js",
|
||||
"dist/credentials/DisqusApi.credentials.js",
|
||||
"dist/credentials/DriftApi.credentials.js",
|
||||
"dist/credentials/DropboxApi.credentials.js",
|
||||
"dist/credentials/EventbriteApi.credentials.js",
|
||||
"dist/credentials/FacebookGraphApi.credentials.js",
|
||||
"dist/credentials/FreshdeskApi.credentials.js",
|
||||
"dist/credentials/FileMaker.credentials.js",
|
||||
"dist/credentials/FlowApi.credentials.js",
|
||||
"dist/credentials/GithubApi.credentials.js",
|
||||
"dist/credentials/GithubOAuth2Api.credentials.js",
|
||||
"dist/credentials/GitlabApi.credentials.js",
|
||||
"dist/credentials/GoogleApi.credentials.js",
|
||||
"dist/credentials/GoogleCalendarOAuth2Api.credentials.js",
|
||||
"dist/credentials/GoogleOAuth2Api.credentials.js",
|
||||
"dist/credentials/GoogleSheetsOAuth2Api.credentials.js",
|
||||
"dist/credentials/GumroadApi.credentials.js",
|
||||
"dist/credentials/HarvestApi.credentials.js",
|
||||
"dist/credentials/HelpScoutOAuth2Api.credentials.js",
|
||||
"dist/credentials/HttpBasicAuth.credentials.js",
|
||||
"dist/credentials/HttpDigestAuth.credentials.js",
|
||||
"dist/credentials/HttpHeaderAuth.credentials.js",
|
||||
"dist/credentials/HubspotApi.credentials.js",
|
||||
"dist/credentials/HubspotDeveloperApi.credentials.js",
|
||||
"dist/credentials/HunterApi.credentials.js",
|
||||
"dist/credentials/Imap.credentials.js",
|
||||
"dist/credentials/IntercomApi.credentials.js",
|
||||
"dist/credentials/InvoiceNinjaApi.credentials.js",
|
||||
"dist/credentials/JiraSoftwareCloudApi.credentials.js",
|
||||
"dist/credentials/JiraSoftwareServerApi.credentials.js",
|
||||
"dist/credentials/JotFormApi.credentials.js",
|
||||
"dist/credentials/KeapOAuth2Api.credentials.js",
|
||||
"dist/credentials/LinkFishApi.credentials.js",
|
||||
"dist/credentials/MailchimpApi.credentials.js",
|
||||
"dist/credentials/MailgunApi.credentials.js",
|
||||
"dist/credentials/MailjetEmailApi.credentials.js",
|
||||
"dist/credentials/MailjetSmsApi.credentials.js",
|
||||
"dist/credentials/MandrillApi.credentials.js",
|
||||
"dist/credentials/MattermostApi.credentials.js",
|
||||
"dist/credentials/MauticApi.credentials.js",
|
||||
"dist/credentials/MicrosoftExcelOAuth2Api.credentials.js",
|
||||
"dist/credentials/MicrosoftOAuth2Api.credentials.js",
|
||||
"dist/credentials/MicrosoftOneDriveOAuth2Api.credentials.js",
|
||||
"dist/credentials/MoceanApi.credentials.js",
|
||||
"dist/credentials/MondayComApi.credentials.js",
|
||||
"dist/credentials/MongoDb.credentials.js",
|
||||
"dist/credentials/Msg91Api.credentials.js",
|
||||
"dist/credentials/MySql.credentials.js",
|
||||
"dist/credentials/NextCloudApi.credentials.js",
|
||||
"dist/credentials/OAuth1Api.credentials.js",
|
||||
"dist/credentials/OAuth2Api.credentials.js",
|
||||
"dist/credentials/OpenWeatherMapApi.credentials.js",
|
||||
"dist/credentials/PagerDutyApi.credentials.js",
|
||||
"dist/credentials/PagerDutyOAuth2Api.credentials.js",
|
||||
"dist/credentials/PayPalApi.credentials.js",
|
||||
"dist/credentials/PipedriveApi.credentials.js",
|
||||
"dist/credentials/Postgres.credentials.js",
|
||||
"dist/credentials/Redis.credentials.js",
|
||||
"dist/credentials/RocketchatApi.credentials.js",
|
||||
"dist/credentials/RundeckApi.credentials.js",
|
||||
"dist/credentials/ShopifyApi.credentials.js",
|
||||
"dist/credentials/SalesforceOAuth2Api.credentials.js",
|
||||
"dist/credentials/SlackApi.credentials.js",
|
||||
"dist/credentials/SlackOAuth2Api.credentials.js",
|
||||
"dist/credentials/Sms77Api.credentials.js",
|
||||
"dist/credentials/Smtp.credentials.js",
|
||||
"dist/credentials/StripeApi.credentials.js",
|
||||
"dist/credentials/SalesmateApi.credentials.js",
|
||||
"dist/credentials/SegmentApi.credentials.js",
|
||||
"dist/credentials/SurveyMonkeyApi.credentials.js",
|
||||
"dist/credentials/TelegramApi.credentials.js",
|
||||
"dist/credentials/TodoistApi.credentials.js",
|
||||
"dist/credentials/TrelloApi.credentials.js",
|
||||
"dist/credentials/TwilioApi.credentials.js",
|
||||
"dist/credentials/TwitterOAuth1Api.credentials.js",
|
||||
"dist/credentials/TypeformApi.credentials.js",
|
||||
"dist/credentials/TogglApi.credentials.js",
|
||||
"dist/credentials/UpleadApi.credentials.js",
|
||||
"dist/credentials/VeroApi.credentials.js",
|
||||
"dist/credentials/WebflowApi.credentials.js",
|
||||
"dist/credentials/WooCommerceApi.credentials.js",
|
||||
"dist/credentials/WordpressApi.credentials.js",
|
||||
"dist/credentials/ZendeskApi.credentials.js",
|
||||
"dist/credentials/ZohoOAuth2Api.credentials.js",
|
||||
"dist/credentials/ZulipApi.credentials.js"
|
||||
],
|
||||
"nodes": [
|
||||
"dist/nodes/ActiveCampaign/ActiveCampaign.node.js",
|
||||
"dist/nodes/ActiveCampaign/ActiveCampaignTrigger.node.js",
|
||||
"dist/nodes/AgileCrm/AgileCrm.node.js",
|
||||
"dist/nodes/Airtable/Airtable.node.js",
|
||||
"dist/nodes/AcuityScheduling/AcuitySchedulingTrigger.node.js",
|
||||
"dist/nodes/Amqp/Amqp.node.js",
|
||||
"dist/nodes/Amqp/AmqpTrigger.node.js",
|
||||
"dist/nodes/Asana/Asana.node.js",
|
||||
"dist/nodes/Asana/AsanaTrigger.node.js",
|
||||
"dist/nodes/Affinity/Affinity.node.js",
|
||||
"dist/nodes/Affinity/AffinityTrigger.node.js",
|
||||
"dist/nodes/Aws/AwsLambda.node.js",
|
||||
"dist/nodes/Aws/S3/AwsS3.node.js",
|
||||
"dist/nodes/Aws/AwsSes.node.js",
|
||||
"dist/nodes/Aws/AwsSns.node.js",
|
||||
"dist/nodes/Aws/AwsSnsTrigger.node.js",
|
||||
"dist/nodes/Bannerbear/Bannerbear.node.js",
|
||||
"dist/nodes/Bitbucket/BitbucketTrigger.node.js",
|
||||
"dist/nodes/Bitly/Bitly.node.js",
|
||||
"dist/nodes/Calendly/CalendlyTrigger.node.js",
|
||||
"dist/nodes/Chargebee/Chargebee.node.js",
|
||||
"dist/nodes/Chargebee/ChargebeeTrigger.node.js",
|
||||
"dist/nodes/Clearbit/Clearbit.node.js",
|
||||
"dist/nodes/ClickUp/ClickUp.node.js",
|
||||
"dist/nodes/ClickUp/ClickUpTrigger.node.js",
|
||||
"dist/nodes/Clockify/ClockifyTrigger.node.js",
|
||||
"dist/nodes/Cockpit/Cockpit.node.js",
|
||||
"dist/nodes/Coda/Coda.node.js",
|
||||
"dist/nodes/Copper/CopperTrigger.node.js",
|
||||
"dist/nodes/Cron.node.js",
|
||||
"dist/nodes/Crypto.node.js",
|
||||
"dist/nodes/DateTime.node.js",
|
||||
"dist/nodes/Discord/Discord.node.js",
|
||||
"dist/nodes/Disqus/Disqus.node.js",
|
||||
"dist/nodes/Drift/Drift.node.js",
|
||||
"dist/nodes/Dropbox/Dropbox.node.js",
|
||||
"dist/nodes/EditImage.node.js",
|
||||
"dist/nodes/EmailReadImap.node.js",
|
||||
"dist/nodes/EmailSend.node.js",
|
||||
"dist/nodes/ErrorTrigger.node.js",
|
||||
"dist/nodes/Eventbrite/EventbriteTrigger.node.js",
|
||||
"dist/nodes/ExecuteCommand.node.js",
|
||||
"dist/nodes/ExecuteWorkflow.node.js",
|
||||
"dist/nodes/Facebook/FacebookGraphApi.node.js",
|
||||
"dist/nodes/FileMaker/FileMaker.node.js",
|
||||
"dist/nodes/Freshdesk/Freshdesk.node.js",
|
||||
"dist/nodes/Flow/Flow.node.js",
|
||||
"dist/nodes/Flow/FlowTrigger.node.js",
|
||||
"dist/nodes/Function.node.js",
|
||||
"dist/nodes/FunctionItem.node.js",
|
||||
"dist/nodes/Github/Github.node.js",
|
||||
"dist/nodes/Github/GithubTrigger.node.js",
|
||||
"dist/nodes/Gitlab/Gitlab.node.js",
|
||||
"dist/nodes/Gitlab/GitlabTrigger.node.js",
|
||||
"dist/nodes/Google/Calendar/GoogleCalendar.node.js",
|
||||
"dist/nodes/Google/Drive/GoogleDrive.node.js",
|
||||
"dist/nodes/Google/Sheet/GoogleSheets.node.js",
|
||||
"dist/nodes/GraphQL/GraphQL.node.js",
|
||||
"dist/nodes/Gumroad/GumroadTrigger.node.js",
|
||||
"dist/nodes/Harvest/Harvest.node.js",
|
||||
"dist/nodes/HelpScout/HelpScout.node.js",
|
||||
"dist/nodes/HelpScout/HelpScoutTrigger.node.js",
|
||||
"dist/nodes/HtmlExtract/HtmlExtract.node.js",
|
||||
"dist/nodes/HttpRequest.node.js",
|
||||
"dist/nodes/Hubspot/Hubspot.node.js",
|
||||
"dist/nodes/Hubspot/HubspotTrigger.node.js",
|
||||
"dist/nodes/Hunter/Hunter.node.js",
|
||||
"dist/nodes/If.node.js",
|
||||
"dist/nodes/Intercom/Intercom.node.js",
|
||||
"dist/nodes/Interval.node.js",
|
||||
"dist/nodes/InvoiceNinja/InvoiceNinja.node.js",
|
||||
"dist/nodes/InvoiceNinja/InvoiceNinjaTrigger.node.js",
|
||||
"dist/nodes/Jira/Jira.node.js",
|
||||
"dist/nodes/JotForm/JotFormTrigger.node.js",
|
||||
"dist/nodes/Keap/Keap.node.js",
|
||||
"dist/nodes/Keap/KeapTrigger.node.js",
|
||||
"dist/nodes/LinkFish/LinkFish.node.js",
|
||||
"dist/nodes/Mailchimp/Mailchimp.node.js",
|
||||
"dist/nodes/Mailchimp/MailchimpTrigger.node.js",
|
||||
"dist/nodes/Mailgun/Mailgun.node.js",
|
||||
"dist/nodes/Mailjet/Mailjet.node.js",
|
||||
"dist/nodes/Mailjet/MailjetTrigger.node.js",
|
||||
"dist/nodes/Mandrill/Mandrill.node.js",
|
||||
"dist/nodes/Mattermost/Mattermost.node.js",
|
||||
"dist/nodes/Mautic/Mautic.node.js",
|
||||
"dist/nodes/Mautic/MauticTrigger.node.js",
|
||||
"dist/nodes/Merge.node.js",
|
||||
"dist/nodes/Microsoft/Excel/MicrosoftExcel.node.js",
|
||||
"dist/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.js",
|
||||
"dist/nodes/MoveBinaryData.node.js",
|
||||
"dist/nodes/Mocean/Mocean.node.js",
|
||||
"dist/nodes/MondayCom/MondayCom.node.js",
|
||||
"dist/nodes/MongoDb/MongoDb.node.js",
|
||||
"dist/nodes/MoveBinaryData.node.js",
|
||||
"dist/nodes/Msg91/Msg91.node.js",
|
||||
"dist/nodes/MySql/MySql.node.js",
|
||||
"dist/nodes/NextCloud/NextCloud.node.js",
|
||||
"dist/nodes/NoOp.node.js",
|
||||
"dist/nodes/OpenWeatherMap.node.js",
|
||||
"dist/nodes/PagerDuty/PagerDuty.node.js",
|
||||
"dist/nodes/PayPal/PayPal.node.js",
|
||||
"dist/nodes/PayPal/PayPalTrigger.node.js",
|
||||
"dist/nodes/Pipedrive/Pipedrive.node.js",
|
||||
"dist/nodes/Pipedrive/PipedriveTrigger.node.js",
|
||||
"dist/nodes/Postgres/Postgres.node.js",
|
||||
"dist/nodes/ReadBinaryFile.node.js",
|
||||
"dist/nodes/ReadBinaryFiles.node.js",
|
||||
"dist/nodes/ReadPdf.node.js",
|
||||
"dist/nodes/Redis/Redis.node.js",
|
||||
"dist/nodes/RenameKeys.node.js",
|
||||
"dist/nodes/Rocketchat/Rocketchat.node.js",
|
||||
"dist/nodes/RssFeedRead.node.js",
|
||||
"dist/nodes/Rundeck/Rundeck.node.js",
|
||||
"dist/nodes/Salesforce/Salesforce.node.js",
|
||||
"dist/nodes/Set.node.js",
|
||||
"dist/nodes/Shopify/Shopify.node.js",
|
||||
"dist/nodes/Shopify/ShopifyTrigger.node.js",
|
||||
"dist/nodes/Slack/Slack.node.js",
|
||||
"dist/nodes/Sms77/Sms77.node.js",
|
||||
"dist/nodes/SplitInBatches.node.js",
|
||||
"dist/nodes/SpreadsheetFile.node.js",
|
||||
"dist/nodes/SseTrigger.node.js",
|
||||
"dist/nodes/Start.node.js",
|
||||
"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/SurveyMonkey/SurveyMonkeyTrigger.node.js",
|
||||
"dist/nodes/Telegram/Telegram.node.js",
|
||||
"dist/nodes/Telegram/TelegramTrigger.node.js",
|
||||
"dist/nodes/Todoist/Todoist.node.js",
|
||||
"dist/nodes/Toggl/TogglTrigger.node.js",
|
||||
"dist/nodes/Trello/Trello.node.js",
|
||||
"dist/nodes/Trello/TrelloTrigger.node.js",
|
||||
"dist/nodes/Twilio/Twilio.node.js",
|
||||
"dist/nodes/Twitter/Twitter.node.js",
|
||||
"dist/nodes/Typeform/TypeformTrigger.node.js",
|
||||
"dist/nodes/Uplead/Uplead.node.js",
|
||||
"dist/nodes/Vero/Vero.node.js",
|
||||
"dist/nodes/Webflow/WebflowTrigger.node.js",
|
||||
"dist/nodes/Webhook.node.js",
|
||||
"dist/nodes/Wordpress/Wordpress.node.js",
|
||||
"dist/nodes/WooCommerce/WooCommerce.node.js",
|
||||
"dist/nodes/WooCommerce/WooCommerceTrigger.node.js",
|
||||
"dist/nodes/WriteBinaryFile.node.js",
|
||||
"dist/nodes/Xml.node.js",
|
||||
"dist/nodes/Zendesk/Zendesk.node.js",
|
||||
"dist/nodes/Zendesk/ZendeskTrigger.node.js",
|
||||
"dist/nodes/Zoho/ZohoCrm.node.js",
|
||||
"dist/nodes/Zulip/Zulip.node.js"
|
||||
]
|
||||
"nodes": [
|
||||
"dist/nodes/ActiveCampaign/ActiveCampaign.node.js",
|
||||
"dist/nodes/ActiveCampaign/ActiveCampaignTrigger.node.js",
|
||||
"dist/nodes/AgileCrm/AgileCrm.node.js",
|
||||
"dist/nodes/Airtable/Airtable.node.js",
|
||||
"dist/nodes/AcuityScheduling/AcuitySchedulingTrigger.node.js",
|
||||
"dist/nodes/Amqp/Amqp.node.js",
|
||||
"dist/nodes/Amqp/AmqpTrigger.node.js",
|
||||
"dist/nodes/Asana/Asana.node.js",
|
||||
"dist/nodes/Asana/AsanaTrigger.node.js",
|
||||
"dist/nodes/Affinity/Affinity.node.js",
|
||||
"dist/nodes/Affinity/AffinityTrigger.node.js",
|
||||
"dist/nodes/Aws/AwsLambda.node.js",
|
||||
"dist/nodes/Aws/S3/AwsS3.node.js",
|
||||
"dist/nodes/Aws/AwsSes.node.js",
|
||||
"dist/nodes/Aws/AwsSns.node.js",
|
||||
"dist/nodes/Aws/AwsSnsTrigger.node.js",
|
||||
"dist/nodes/Bannerbear/Bannerbear.node.js",
|
||||
"dist/nodes/Bitbucket/BitbucketTrigger.node.js",
|
||||
"dist/nodes/Bitly/Bitly.node.js",
|
||||
"dist/nodes/Calendly/CalendlyTrigger.node.js",
|
||||
"dist/nodes/Chargebee/Chargebee.node.js",
|
||||
"dist/nodes/Chargebee/ChargebeeTrigger.node.js",
|
||||
"dist/nodes/Clearbit/Clearbit.node.js",
|
||||
"dist/nodes/ClickUp/ClickUp.node.js",
|
||||
"dist/nodes/ClickUp/ClickUpTrigger.node.js",
|
||||
"dist/nodes/Clockify/ClockifyTrigger.node.js",
|
||||
"dist/nodes/Cockpit/Cockpit.node.js",
|
||||
"dist/nodes/Coda/Coda.node.js",
|
||||
"dist/nodes/Copper/CopperTrigger.node.js",
|
||||
"dist/nodes/Cron.node.js",
|
||||
"dist/nodes/Crypto.node.js",
|
||||
"dist/nodes/DateTime.node.js",
|
||||
"dist/nodes/Discord/Discord.node.js",
|
||||
"dist/nodes/Disqus/Disqus.node.js",
|
||||
"dist/nodes/Drift/Drift.node.js",
|
||||
"dist/nodes/Dropbox/Dropbox.node.js",
|
||||
"dist/nodes/EditImage.node.js",
|
||||
"dist/nodes/EmailReadImap.node.js",
|
||||
"dist/nodes/EmailSend.node.js",
|
||||
"dist/nodes/ErrorTrigger.node.js",
|
||||
"dist/nodes/Eventbrite/EventbriteTrigger.node.js",
|
||||
"dist/nodes/ExecuteCommand.node.js",
|
||||
"dist/nodes/ExecuteWorkflow.node.js",
|
||||
"dist/nodes/Facebook/FacebookGraphApi.node.js",
|
||||
"dist/nodes/FileMaker/FileMaker.node.js",
|
||||
"dist/nodes/Freshdesk/Freshdesk.node.js",
|
||||
"dist/nodes/Flow/Flow.node.js",
|
||||
"dist/nodes/Flow/FlowTrigger.node.js",
|
||||
"dist/nodes/Function.node.js",
|
||||
"dist/nodes/FunctionItem.node.js",
|
||||
"dist/nodes/Github/Github.node.js",
|
||||
"dist/nodes/Github/GithubTrigger.node.js",
|
||||
"dist/nodes/Gitlab/Gitlab.node.js",
|
||||
"dist/nodes/Gitlab/GitlabTrigger.node.js",
|
||||
"dist/nodes/Google/Calendar/GoogleCalendar.node.js",
|
||||
"dist/nodes/Google/Drive/GoogleDrive.node.js",
|
||||
"dist/nodes/Google/Sheet/GoogleSheets.node.js",
|
||||
"dist/nodes/GraphQL/GraphQL.node.js",
|
||||
"dist/nodes/Gumroad/GumroadTrigger.node.js",
|
||||
"dist/nodes/Harvest/Harvest.node.js",
|
||||
"dist/nodes/HelpScout/HelpScout.node.js",
|
||||
"dist/nodes/HelpScout/HelpScoutTrigger.node.js",
|
||||
"dist/nodes/HtmlExtract/HtmlExtract.node.js",
|
||||
"dist/nodes/HttpRequest.node.js",
|
||||
"dist/nodes/Hubspot/Hubspot.node.js",
|
||||
"dist/nodes/Hubspot/HubspotTrigger.node.js",
|
||||
"dist/nodes/Hunter/Hunter.node.js",
|
||||
"dist/nodes/If.node.js",
|
||||
"dist/nodes/Intercom/Intercom.node.js",
|
||||
"dist/nodes/Interval.node.js",
|
||||
"dist/nodes/InvoiceNinja/InvoiceNinja.node.js",
|
||||
"dist/nodes/InvoiceNinja/InvoiceNinjaTrigger.node.js",
|
||||
"dist/nodes/Jira/Jira.node.js",
|
||||
"dist/nodes/JotForm/JotFormTrigger.node.js",
|
||||
"dist/nodes/Keap/Keap.node.js",
|
||||
"dist/nodes/Keap/KeapTrigger.node.js",
|
||||
"dist/nodes/LinkFish/LinkFish.node.js",
|
||||
"dist/nodes/Mailchimp/Mailchimp.node.js",
|
||||
"dist/nodes/Mailchimp/MailchimpTrigger.node.js",
|
||||
"dist/nodes/Mailgun/Mailgun.node.js",
|
||||
"dist/nodes/Mailjet/Mailjet.node.js",
|
||||
"dist/nodes/Mailjet/MailjetTrigger.node.js",
|
||||
"dist/nodes/Mandrill/Mandrill.node.js",
|
||||
"dist/nodes/Mattermost/Mattermost.node.js",
|
||||
"dist/nodes/Mautic/Mautic.node.js",
|
||||
"dist/nodes/Mautic/MauticTrigger.node.js",
|
||||
"dist/nodes/Merge.node.js",
|
||||
"dist/nodes/MessageBird/MessageBird.node.js",
|
||||
"dist/nodes/Microsoft/Excel/MicrosoftExcel.node.js",
|
||||
"dist/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.js",
|
||||
"dist/nodes/MoveBinaryData.node.js",
|
||||
"dist/nodes/Mocean/Mocean.node.js",
|
||||
"dist/nodes/MondayCom/MondayCom.node.js",
|
||||
"dist/nodes/MongoDb/MongoDb.node.js",
|
||||
"dist/nodes/MoveBinaryData.node.js",
|
||||
"dist/nodes/Msg91/Msg91.node.js",
|
||||
"dist/nodes/MySql/MySql.node.js",
|
||||
"dist/nodes/NextCloud/NextCloud.node.js",
|
||||
"dist/nodes/NoOp.node.js",
|
||||
"dist/nodes/OpenWeatherMap.node.js",
|
||||
"dist/nodes/PagerDuty/PagerDuty.node.js",
|
||||
"dist/nodes/PayPal/PayPal.node.js",
|
||||
"dist/nodes/PayPal/PayPalTrigger.node.js",
|
||||
"dist/nodes/Pipedrive/Pipedrive.node.js",
|
||||
"dist/nodes/Pipedrive/PipedriveTrigger.node.js",
|
||||
"dist/nodes/Postgres/Postgres.node.js",
|
||||
"dist/nodes/ReadBinaryFile.node.js",
|
||||
"dist/nodes/ReadBinaryFiles.node.js",
|
||||
"dist/nodes/ReadPdf.node.js",
|
||||
"dist/nodes/Redis/Redis.node.js",
|
||||
"dist/nodes/RenameKeys.node.js",
|
||||
"dist/nodes/Rocketchat/Rocketchat.node.js",
|
||||
"dist/nodes/RssFeedRead.node.js",
|
||||
"dist/nodes/Rundeck/Rundeck.node.js",
|
||||
"dist/nodes/Salesforce/Salesforce.node.js",
|
||||
"dist/nodes/Set.node.js",
|
||||
"dist/nodes/Shopify/Shopify.node.js",
|
||||
"dist/nodes/Shopify/ShopifyTrigger.node.js",
|
||||
"dist/nodes/Slack/Slack.node.js",
|
||||
"dist/nodes/Sms77/Sms77.node.js",
|
||||
"dist/nodes/SplitInBatches.node.js",
|
||||
"dist/nodes/SpreadsheetFile.node.js",
|
||||
"dist/nodes/SseTrigger.node.js",
|
||||
"dist/nodes/Start.node.js",
|
||||
"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/SurveyMonkey/SurveyMonkeyTrigger.node.js",
|
||||
"dist/nodes/Telegram/Telegram.node.js",
|
||||
"dist/nodes/Telegram/TelegramTrigger.node.js",
|
||||
"dist/nodes/Todoist/Todoist.node.js",
|
||||
"dist/nodes/Toggl/TogglTrigger.node.js",
|
||||
"dist/nodes/Trello/Trello.node.js",
|
||||
"dist/nodes/Trello/TrelloTrigger.node.js",
|
||||
"dist/nodes/Twilio/Twilio.node.js",
|
||||
"dist/nodes/Twitter/Twitter.node.js",
|
||||
"dist/nodes/Typeform/TypeformTrigger.node.js",
|
||||
"dist/nodes/Uplead/Uplead.node.js",
|
||||
"dist/nodes/Vero/Vero.node.js",
|
||||
"dist/nodes/Webflow/WebflowTrigger.node.js",
|
||||
"dist/nodes/Webhook.node.js",
|
||||
"dist/nodes/Wordpress/Wordpress.node.js",
|
||||
"dist/nodes/WooCommerce/WooCommerce.node.js",
|
||||
"dist/nodes/WooCommerce/WooCommerceTrigger.node.js",
|
||||
"dist/nodes/WriteBinaryFile.node.js",
|
||||
"dist/nodes/Xml.node.js",
|
||||
"dist/nodes/Zendesk/Zendesk.node.js",
|
||||
"dist/nodes/Zendesk/ZendeskTrigger.node.js",
|
||||
"dist/nodes/Zoho/ZohoCrm.node.js",
|
||||
"dist/nodes/Zulip/Zulip.node.js"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/aws4": "^1.5.1",
|
||||
"@types/basic-auth": "^1.1.2",
|
||||
"@types/cheerio": "^0.22.15",
|
||||
"@types/cron": "^1.6.1",
|
||||
"@types/eventsource": "^1.1.2",
|
||||
"@types/express": "^4.16.1",
|
||||
"@types/formidable": "^1.0.31",
|
||||
"@types/gm": "^1.18.2",
|
||||
"@types/imap-simple": "^4.2.0",
|
||||
"@types/jest": "^24.0.18",
|
||||
"@types/lodash.set": "^4.3.6",
|
||||
"@types/moment-timezone": "^0.5.12",
|
||||
"@types/mongodb": "^3.5.4",
|
||||
"@types/node": "^10.10.1",
|
||||
"@types/nodemailer": "^6.4.0",
|
||||
"@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.32.0",
|
||||
"ts-jest": "^24.0.2",
|
||||
"tslint": "^5.17.0",
|
||||
"typescript": "~3.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"aws4": "^1.8.0",
|
||||
"basic-auth": "^2.0.1",
|
||||
"change-case": "^4.1.1",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"cron": "^1.7.2",
|
||||
"eventsource": "^1.0.7",
|
||||
"formidable": "^1.2.1",
|
||||
"glob-promise": "^3.4.0",
|
||||
"gm": "^1.23.1",
|
||||
"imap-simple": "^4.3.0",
|
||||
"iso-639-1": "^2.1.3",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.set": "^4.3.2",
|
||||
"lodash.unset": "^4.5.2",
|
||||
"moment": "2.24.0",
|
||||
"moment-timezone": "^0.5.28",
|
||||
"mongodb": "^3.5.5",
|
||||
"mysql2": "^2.0.1",
|
||||
"n8n-core": "~0.36.0",
|
||||
"nodemailer": "^6.4.6",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"pg-promise": "^9.0.3",
|
||||
"redis": "^2.8.0",
|
||||
"request": "^2.88.2",
|
||||
"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"
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
"^.+\\.tsx?$": "ts-jest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/aws4": "^1.5.1",
|
||||
"@types/basic-auth": "^1.1.2",
|
||||
"@types/cheerio": "^0.22.15",
|
||||
"@types/cron": "^1.6.1",
|
||||
"@types/eventsource": "^1.1.2",
|
||||
"@types/express": "^4.16.1",
|
||||
"@types/formidable": "^1.0.31",
|
||||
"@types/gm": "^1.18.2",
|
||||
"@types/imap-simple": "^4.2.0",
|
||||
"@types/jest": "^24.0.18",
|
||||
"@types/lodash.set": "^4.3.6",
|
||||
"@types/moment-timezone": "^0.5.12",
|
||||
"@types/mongodb": "^3.5.4",
|
||||
"@types/node": "^10.10.1",
|
||||
"@types/nodemailer": "^6.4.0",
|
||||
"@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.32.0",
|
||||
"ts-jest": "^24.0.2",
|
||||
"tslint": "^5.17.0",
|
||||
"typescript": "~3.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"aws4": "^1.8.0",
|
||||
"basic-auth": "^2.0.1",
|
||||
"change-case": "^4.1.1",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"cron": "^1.7.2",
|
||||
"eventsource": "^1.0.7",
|
||||
"formidable": "^1.2.1",
|
||||
"glob-promise": "^3.4.0",
|
||||
"gm": "^1.23.1",
|
||||
"googleapis": "~50.0.0",
|
||||
"imap-simple": "^4.3.0",
|
||||
"iso-639-1": "^2.1.3",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.set": "^4.3.2",
|
||||
"lodash.unset": "^4.5.2",
|
||||
"moment": "2.24.0",
|
||||
"moment-timezone": "^0.5.28",
|
||||
"mongodb": "^3.5.5",
|
||||
"mysql2": "^2.0.1",
|
||||
"n8n-core": "~0.35.0",
|
||||
"nodemailer": "^6.4.6",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"pg-promise": "^9.0.3",
|
||||
"redis": "^2.8.0",
|
||||
"request": "^2.88.2",
|
||||
"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"
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
"^.+\\.tsx?$": "ts-jest"
|
||||
},
|
||||
"testURL": "http://localhost/",
|
||||
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
|
||||
"testPathIgnorePatterns": [
|
||||
"/dist/",
|
||||
"/node_modules/"
|
||||
],
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js",
|
||||
"json"
|
||||
]
|
||||
}
|
||||
"testURL": "http://localhost/",
|
||||
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
|
||||
"testPathIgnorePatterns": [
|
||||
"/dist/",
|
||||
"/node_modules/"
|
||||
],
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js",
|
||||
"json"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "n8n-workflow",
|
||||
"version": "0.32.0",
|
||||
"version": "0.33.0",
|
||||
"description": "Workflow base code of n8n",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
|
|
Loading…
Reference in a new issue