Add additional external workflow hooks

This commit is contained in:
Jan Oberhauser 2020-05-06 00:59:58 +02:00
parent 0387671cae
commit 6e1254fd54
6 changed files with 65 additions and 34 deletions

View file

@ -1,23 +1,28 @@
import { import {
Db, Db,
IExternalHookFunctions, IExternalHooksFunctions,
IExternalHooks, IExternalHooksClass,
} from './'; } from './';
import * as config from '../config'; import * as config from '../config';
// export EXTERNAL_HOOK_FILES=/data/packages/cli/dist/src/externalHooksTemp/test-hooks.js // export EXTERNAL_HOOK_FILES=/data/packages/cli/dist/src/externalHooksTemp/test-hooks.js
class ExternalHooksClass implements IExternalHooks { class ExternalHooksClass implements IExternalHooksClass {
externalHooks: { externalHooks: {
[key: string]: Array<() => {}> [key: string]: Array<() => {}>
} = {}; } = {};
initDidRun = false;
async init(): Promise<void> { async init(): Promise<void> {
console.log('ExternalHooks.init'); console.log('ExternalHooks.init');
if (this.initDidRun === true) {
return;
}
const externalHookFiles = config.get('externalHookFiles').split(':'); const externalHookFiles = config.get('externalHookFiles').split(':');
console.log('externalHookFiles'); console.log('externalHookFiles');
@ -48,13 +53,15 @@ class ExternalHooksClass implements IExternalHooks {
} }
} }
} }
this.initDidRun = true;
} }
async run(hookName: string, hookParameters?: any[]): Promise<void> { // tslint:disable-line:no-any async run(hookName: string, hookParameters?: any[]): Promise<void> { // tslint:disable-line:no-any
console.log('RUN NOW: ' + hookName); console.log('RUN NOW: ' + hookName);
const externalHookFunctions: IExternalHookFunctions = { const externalHookFunctions: IExternalHooksFunctions = {
DbCollections: Db.collections, dbCollections: Db.collections,
}; };
if (this.externalHooks[hookName] === undefined) { if (this.externalHooks[hookName] === undefined) {

View file

@ -188,11 +188,26 @@ export interface IExecutingWorkflowData {
workflowExecution?: PCancelable<IRun>; workflowExecution?: PCancelable<IRun>;
} }
export interface IExternalHookFunctions { export interface IExternalHooks {
DbCollections: IDatabaseCollections; 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 IExternalHooks { export interface IExternalHooksFunctions {
dbCollections: IDatabaseCollections;
}
export interface IExternalHooksClass {
init(): Promise<void>; init(): Promise<void>;
run(hookName: string, hookParameters?: any[]): Promise<void>; // tslint:disable-line:no-any run(hookName: string, hookParameters?: any[]): Promise<void>; // tslint:disable-line:no-any
} }

View file

@ -48,7 +48,6 @@ import {
WorkflowCredentials, WorkflowCredentials,
WebhookHelpers, WebhookHelpers,
WorkflowExecuteAdditionalData, WorkflowExecuteAdditionalData,
WorkflowHelpers,
WorkflowRunner, WorkflowRunner,
GenericHelpers, GenericHelpers,
} from './'; } from './';
@ -477,6 +476,8 @@ class App {
if (responseData.active === true) { if (responseData.active === true) {
// When the workflow is supposed to be active add it again // When the workflow is supposed to be active add it again
try { try {
await this.externalHooks.run('workflow.activate', [responseData]);
await this.activeWorkflowRunner.add(id); await this.activeWorkflowRunner.add(id);
} catch (error) { } catch (error) {
// If workflow could not be activated set it again to inactive // If workflow could not be activated set it again to inactive
@ -680,8 +681,6 @@ class App {
nodeAccess.date = this.getCurrentDate(); nodeAccess.date = this.getCurrentDate();
} }
await this.externalHooks.run('credentials.create');
const encryptionKey = await UserSettings.getEncryptionKey(); const encryptionKey = await UserSettings.getEncryptionKey();
if (encryptionKey === undefined) { if (encryptionKey === undefined) {
throw new Error('No encryption key got found to encrypt the credentials!'); throw new Error('No encryption key got found to encrypt the credentials!');
@ -709,6 +708,8 @@ class App {
credentials.setData(incomingData.data, encryptionKey); credentials.setData(incomingData.data, encryptionKey);
const newCredentialsData = credentials.getDataToSave() as ICredentialsDb; const newCredentialsData = credentials.getDataToSave() as ICredentialsDb;
await this.externalHooks.run('credentials.create', [newCredentialsData]);
// Add special database related data // Add special database related data
newCredentialsData.createdAt = this.getCurrentDate(); newCredentialsData.createdAt = this.getCurrentDate();
newCredentialsData.updatedAt = this.getCurrentDate(); newCredentialsData.updatedAt = this.getCurrentDate();
@ -730,8 +731,6 @@ class App {
const id = req.params.id; const id = req.params.id;
await this.externalHooks.run('credentials.update', [id]);
if (incomingData.name === '') { if (incomingData.name === '') {
throw new Error('Credentials have to have a name set!'); throw new Error('Credentials have to have a name set!');
} }
@ -770,6 +769,8 @@ class App {
// Add special database related data // Add special database related data
newCredentialsData.updatedAt = this.getCurrentDate(); newCredentialsData.updatedAt = this.getCurrentDate();
await this.externalHooks.run('credentials.update', [newCredentialsData]);
// Update the credentials in DB // Update the credentials in DB
await Db.collections.Credentials!.update(id, newCredentialsData); await Db.collections.Credentials!.update(id, newCredentialsData);

View file

@ -1,5 +1,6 @@
import { import {
Db, Db,
ExternalHooks,
IExecutionDb, IExecutionDb,
IExecutionFlattedDb, IExecutionFlattedDb,
IPushDataExecutionFinished, IPushDataExecutionFinished,
@ -302,6 +303,10 @@ export async function executeWorkflow(workflowInfo: IExecuteWorkflowInfo, additi
workflowData = workflowInfo.code; workflowData = workflowInfo.code;
} }
const externalHooks = ExternalHooks();
await externalHooks.init();
await externalHooks.run('workflow.execute', [workflowData, mode]);
const nodeTypes = NodeTypes(); const nodeTypes = NodeTypes();
const workflowName = workflowData ? workflowData.name : undefined; const workflowName = workflowData ? workflowData.name : undefined;

View file

@ -1,5 +1,6 @@
import { import {
ActiveExecutions, ActiveExecutions,
ExternalHooks,
IProcessMessageDataHook, IProcessMessageDataHook,
ITransferNodeTypes, ITransferNodeTypes,
IWorkflowExecutionDataProcess, IWorkflowExecutionDataProcess,
@ -94,6 +95,9 @@ export class WorkflowRunner {
* @memberof WorkflowRunner * @memberof WorkflowRunner
*/ */
async run(data: IWorkflowExecutionDataProcess, loadStaticData?: boolean): Promise<string> { 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; const executionsProcess = config.get('executions.process') as string;
if (executionsProcess === 'main') { if (executionsProcess === 'main') {
return this.runMainProcess(data, loadStaticData); return this.runMainProcess(data, loadStaticData);

View file

@ -1,45 +1,44 @@
import { import {
IExternalHookFunctions, WorkflowExecuteMode,
} from 'n8n-workflow';
import {
IExternalHooks,
IExternalHooksFunctions,
IWorkflowBase, IWorkflowBase,
IWorkflowDb,
} from '../'; } from '../';
// TODO: Move that to interfaces
interface IExternalHooks {
credentials?: {
create?: Array<{ (this: IExternalHookFunctions): Promise<void>; }>
delete?: Array<{ (this: IExternalHookFunctions, credentialId: string): Promise<void>; }>
update?: Array<{ (this: IExternalHookFunctions, credentialId: string): Promise<void>; }>
};
workflow?: {
create?: Array<{ (this: IExternalHookFunctions, workflowData: IWorkflowBase): Promise<void>; }>
delete?: Array<{ (this: IExternalHookFunctions, workflowId: string): Promise<void>; }>
update?: Array<{ (this: IExternalHookFunctions, workflowData: IWorkflowBase): Promise<void>; }>
};
}
export = { export = {
credentials: { credentials: {
create: [ create: [
async function (this: IExternalHookFunctions) { async function (this: IExternalHooksFunctions) {
// console.log(this.DbCollections.Workflow);
// Here any additional code can run or the creation blocked // Here any additional code can run or the creation blocked
throw new Error('No additional credentials can be created.'); // throw new Error('No additional credentials can be created.');
}, },
], ],
}, },
workflow: { workflow: {
execute: [
async function (this: IExternalHooksFunctions, workflowData: IWorkflowDb, mode: WorkflowExecuteMode) {
console.log('execute: ' + mode);
// if (mode === 'integrated') {
// throw new Error('Workflow can not be executed.');
// }
}
],
update: [ update: [
async function (this: IExternalHookFunctions, workflowData: IWorkflowBase) { async function (this: IExternalHooksFunctions, workflowData: IWorkflowBase) {
console.log('update workflow hook'); console.log('update workflow hook');
// const responseData = await this.DbCollections.Workflow!.findOne(workflowData.id); // const responseData = await this.dbCollections.Workflow!.findOne(workflowData.id);
// console.log('workflowData'); // console.log('workflowData');
// console.log(responseData); // console.log(responseData);
// console.log(workflowData); // console.log(workflowData);
// Here any additional code can run or the creation blocked // Here any additional code can run or the creation blocked
throw new Error('Workflow can not be updated.'); // throw new Error('Workflow can not be updated.');
}, },
], ],
}, },