mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-12 05:17:28 -08:00
⚡ Add additional external hooks and provide additional data
This commit is contained in:
parent
a380a9a394
commit
0387671cae
|
@ -253,7 +253,7 @@ const config = convict({
|
|||
},
|
||||
|
||||
externalHookFiles: {
|
||||
doc: 'Files containing external hooks',
|
||||
doc: 'Files containing external hooks. Multiple files can be separated by colon (":")',
|
||||
format: String,
|
||||
default: '',
|
||||
env: 'EXTERNAL_HOOK_FILES'
|
||||
|
|
|
@ -1,21 +1,10 @@
|
|||
import {
|
||||
Db,
|
||||
IDatabaseCollections,
|
||||
IExternalHookFunctions,
|
||||
IExternalHooks,
|
||||
} from "./";
|
||||
} from './';
|
||||
|
||||
import * as config from '../config';
|
||||
// import {
|
||||
// access as fsAccess,
|
||||
// readdir as fsReaddir,
|
||||
// readFile as fsReadFile,
|
||||
// stat as fsStat,
|
||||
// } from 'fs';
|
||||
|
||||
// TODO: Give different name
|
||||
interface IHookData {
|
||||
DbCollections: IDatabaseCollections;
|
||||
}
|
||||
|
||||
// export EXTERNAL_HOOK_FILES=/data/packages/cli/dist/src/externalHooksTemp/test-hooks.js
|
||||
|
||||
|
@ -29,39 +18,42 @@ class ExternalHooksClass implements IExternalHooks {
|
|||
async init(): Promise<void> {
|
||||
console.log('ExternalHooks.init');
|
||||
|
||||
const externalHookFiles = config.get('externalHookFiles').split(',');
|
||||
const externalHookFiles = config.get('externalHookFiles').split(':');
|
||||
|
||||
console.log('externalHookFiles');
|
||||
console.log(externalHookFiles);
|
||||
|
||||
// Load all the provided hook-files
|
||||
for (let hookFilePath of externalHookFiles) {
|
||||
hookFilePath = hookFilePath.trim();
|
||||
if (hookFilePath !== '') {
|
||||
console.log(' --- load: ' + hookFilePath);
|
||||
const hookFile = require(hookFilePath);
|
||||
try {
|
||||
const hookFile = require(hookFilePath);
|
||||
|
||||
for (const resource of Object.keys(hookFile)) {
|
||||
// if (this.externalHooks[resource] === undefined) {
|
||||
// this.externalHooks[resource] = {};
|
||||
// }
|
||||
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] = [];
|
||||
}
|
||||
|
||||
for (const operation of Object.keys(hookFile[resource])) {
|
||||
const hookString = `${resource}.${operation}`;
|
||||
if (this.externalHooks[hookString] === undefined) {
|
||||
this.externalHooks[hookString] = [];
|
||||
this.externalHooks[hookString].push.apply(this.externalHooks[hookString], hookFile[resource][operation]);
|
||||
}
|
||||
|
||||
this.externalHooks[hookString].push.apply(this.externalHooks[hookString], hookFile[resource][operation]);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`Problem loading external hook file "${hookFilePath}": ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async run(hookName: string): Promise<void> {
|
||||
async run(hookName: string, hookParameters?: any[]): Promise<void> { // tslint:disable-line:no-any
|
||||
console.log('RUN NOW: ' + hookName);
|
||||
|
||||
const hookData: IHookData = {
|
||||
const externalHookFunctions: IExternalHookFunctions = {
|
||||
DbCollections: Db.collections,
|
||||
};
|
||||
|
||||
|
@ -70,7 +62,7 @@ class ExternalHooksClass implements IExternalHooks {
|
|||
}
|
||||
|
||||
for(const externalHookFunction of this.externalHooks[hookName]) {
|
||||
externalHookFunction.call(hookData);
|
||||
await externalHookFunction.apply(externalHookFunctions, hookParameters);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -188,9 +188,13 @@ export interface IExecutingWorkflowData {
|
|||
workflowExecution?: PCancelable<IRun>;
|
||||
}
|
||||
|
||||
export interface IExternalHookFunctions {
|
||||
DbCollections: IDatabaseCollections;
|
||||
}
|
||||
|
||||
export interface IExternalHooks {
|
||||
init(): Promise<void>;
|
||||
run(hookName: string): Promise<void>;
|
||||
run(hookName: string, hookParameters?: any[]): Promise<void>; // tslint:disable-line:no-any
|
||||
}
|
||||
|
||||
export interface IN8nConfig {
|
||||
|
|
|
@ -346,7 +346,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();
|
||||
|
@ -354,6 +354,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);
|
||||
|
||||
|
@ -429,9 +431,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
|
||||
|
@ -497,6 +501,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);
|
||||
|
@ -658,6 +664,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;
|
||||
|
@ -672,6 +680,8 @@ class App {
|
|||
nodeAccess.date = this.getCurrentDate();
|
||||
}
|
||||
|
||||
await this.externalHooks.run('credentials.create');
|
||||
|
||||
const encryptionKey = await UserSettings.getEncryptionKey();
|
||||
if (encryptionKey === undefined) {
|
||||
throw new Error('No encryption key got found to encrypt the credentials!');
|
||||
|
@ -694,8 +704,6 @@ class App {
|
|||
throw new ResponseHelper.ResponseError(`Credentials with the same type and name exist already.`, undefined, 400);
|
||||
}
|
||||
|
||||
await this.externalHooks.run('credentials.new');
|
||||
|
||||
// Encrypt the data
|
||||
const credentials = new Credentials(incomingData.name, incomingData.type, incomingData.nodesAccess);
|
||||
credentials.setData(incomingData.data, encryptionKey);
|
||||
|
@ -722,6 +730,8 @@ class App {
|
|||
|
||||
const id = req.params.id;
|
||||
|
||||
await this.externalHooks.run('credentials.update', [id]);
|
||||
|
||||
if (incomingData.name === '') {
|
||||
throw new Error('Credentials have to have a name set!');
|
||||
}
|
||||
|
|
|
@ -1,10 +1,46 @@
|
|||
import {
|
||||
IExternalHookFunctions,
|
||||
IWorkflowBase,
|
||||
} 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 = {
|
||||
credentials: {
|
||||
new: [
|
||||
() => {
|
||||
create: [
|
||||
async function (this: IExternalHookFunctions) {
|
||||
// console.log(this.DbCollections.Workflow);
|
||||
|
||||
// Here any additional code can run or the creation blocked
|
||||
throw new Error('No additional credentials can be created.');
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
workflow: {
|
||||
update: [
|
||||
async function (this: IExternalHookFunctions, workflowData: IWorkflowBase) {
|
||||
console.log('update workflow hook');
|
||||
|
||||
// const responseData = await this.DbCollections.Workflow!.findOne(workflowData.id);
|
||||
// console.log('workflowData');
|
||||
// console.log(responseData);
|
||||
// console.log(workflowData);
|
||||
|
||||
// Here any additional code can run or the creation blocked
|
||||
throw new Error('Workflow can not be updated.');
|
||||
},
|
||||
],
|
||||
},
|
||||
} as IExternalHooks;
|
||||
|
|
Loading…
Reference in a new issue