n8n 0.192.2 → 0.193.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/Server.js +3 -517
- package/dist/src/Server.js.map +1 -1
- package/dist/src/UserManagement/routes/users.js +4 -4
- package/dist/src/UserManagement/routes/users.js.map +1 -1
- package/dist/src/api/executions.api.d.ts +1 -0
- package/dist/src/api/executions.api.js +325 -0
- package/dist/src/api/executions.api.js.map +1 -0
- package/dist/src/api/nodes.api.js +3 -3
- package/dist/src/api/nodes.api.js.map +1 -1
- package/dist/src/api/oauth2Credential.api.js +3 -2
- package/dist/src/api/oauth2Credential.api.js.map +1 -1
- package/dist/src/api/workflows.api.js +262 -0
- package/dist/src/api/workflows.api.js.map +1 -1
- package/dist/src/databases/migrations/mysqldb/1646992772331-CreateUserManagement.js +1 -1
- package/dist/src/databases/migrations/mysqldb/1646992772331-CreateUserManagement.js.map +1 -1
- package/dist/src/databases/ormconfig.d.ts +3 -3
- package/dist/test/integration/credentials.api.test.js +27 -33
- package/dist/test/integration/credentials.api.test.js.map +1 -1
- package/dist/test/integration/nodes.api.test.js +2 -2
- package/dist/test/integration/nodes.api.test.js.map +1 -1
- package/dist/test/integration/shared/random.d.ts +10 -0
- package/dist/test/integration/shared/random.js +10 -1
- package/dist/test/integration/shared/random.js.map +1 -1
- package/dist/test/integration/shared/testDb.d.ts +1 -1
- package/dist/test/integration/shared/testDb.js +1 -1
- package/dist/test/integration/shared/testDb.js.map +1 -1
- package/dist/test/integration/users.api.test.js +9 -36
- package/dist/test/integration/users.api.test.js.map +1 -1
- package/dist/test/unit/ActiveExecutions.test.d.ts +1 -0
- package/dist/test/unit/ActiveExecutions.test.js +81 -0
- package/dist/test/unit/ActiveExecutions.test.js.map +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +12 -12
package/dist/src/Server.js
CHANGED
|
@@ -22,17 +22,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
26
|
-
var t = {};
|
|
27
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
28
|
-
t[p] = s[p];
|
|
29
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
30
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
31
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
32
|
-
t[p[i]] = s[p[i]];
|
|
33
|
-
}
|
|
34
|
-
return t;
|
|
35
|
-
};
|
|
36
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
27
|
};
|
|
@@ -42,7 +31,7 @@ const express_1 = __importDefault(require("express"));
|
|
|
42
31
|
const fs_1 = require("fs");
|
|
43
32
|
const promises_1 = require("fs/promises");
|
|
44
33
|
const child_process_1 = require("child_process");
|
|
45
|
-
const lodash_1 =
|
|
34
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
46
35
|
const path_1 = require("path");
|
|
47
36
|
const typeorm_1 = require("typeorm");
|
|
48
37
|
const body_parser_1 = __importDefault(require("body-parser"));
|
|
@@ -69,7 +58,6 @@ const config_1 = __importDefault(require("../config"));
|
|
|
69
58
|
const TagHelpers = __importStar(require("./TagHelpers"));
|
|
70
59
|
const InternalHooksManager_1 = require("./InternalHooksManager");
|
|
71
60
|
const TagEntity_1 = require("./databases/entities/TagEntity");
|
|
72
|
-
const WorkflowEntity_1 = require("./databases/entities/WorkflowEntity");
|
|
73
61
|
const WorkflowHelpers_1 = require("./WorkflowHelpers");
|
|
74
62
|
const TranslationHelpers_1 = require("./TranslationHelpers");
|
|
75
63
|
const WebhookHelpers_1 = require("./WebhookHelpers");
|
|
@@ -78,6 +66,7 @@ const jwt_1 = require("./UserManagement/auth/jwt");
|
|
|
78
66
|
const GenericHelpers_1 = require("./GenericHelpers");
|
|
79
67
|
const constants_1 = require("./constants");
|
|
80
68
|
const credentials_api_1 = require("./api/credentials.api");
|
|
69
|
+
const executions_api_1 = require("./api/executions.api");
|
|
81
70
|
const workflows_api_1 = require("./api/workflows.api");
|
|
82
71
|
const nodes_api_1 = require("./api/nodes.api");
|
|
83
72
|
const oauth2Credential_api_1 = require("./api/oauth2Credential.api");
|
|
@@ -453,243 +442,6 @@ class App {
|
|
|
453
442
|
_1.ResponseHelper.sendSuccessResponse(res, response, true, 200);
|
|
454
443
|
});
|
|
455
444
|
}
|
|
456
|
-
this.app.get(`/${this.restEndpoint}/workflows/from-url`, _1.ResponseHelper.send(async (req, res) => {
|
|
457
|
-
if (req.query.url === undefined) {
|
|
458
|
-
throw new _1.ResponseHelper.ResponseError(`The parameter "url" is missing!`, undefined, 400);
|
|
459
|
-
}
|
|
460
|
-
if (!/^http[s]?:\/\/.*\.json$/i.exec(req.query.url)) {
|
|
461
|
-
throw new _1.ResponseHelper.ResponseError(`The parameter "url" is not valid! It does not seem to be a URL pointing to a n8n workflow JSON file.`, undefined, 400);
|
|
462
|
-
}
|
|
463
|
-
let workflowData;
|
|
464
|
-
try {
|
|
465
|
-
const { data } = await axios_1.default.get(req.query.url);
|
|
466
|
-
workflowData = data;
|
|
467
|
-
}
|
|
468
|
-
catch (error) {
|
|
469
|
-
throw new _1.ResponseHelper.ResponseError(`The URL does not point to valid JSON file!`, undefined, 400);
|
|
470
|
-
}
|
|
471
|
-
if (workflowData === undefined ||
|
|
472
|
-
workflowData.nodes === undefined ||
|
|
473
|
-
!Array.isArray(workflowData.nodes) ||
|
|
474
|
-
workflowData.connections === undefined ||
|
|
475
|
-
typeof workflowData.connections !== 'object' ||
|
|
476
|
-
Array.isArray(workflowData.connections)) {
|
|
477
|
-
throw new _1.ResponseHelper.ResponseError(`The data in the file does not seem to be a n8n workflow JSON file!`, undefined, 400);
|
|
478
|
-
}
|
|
479
|
-
return workflowData;
|
|
480
|
-
}));
|
|
481
|
-
this.app.get(`/${this.restEndpoint}/workflows`, _1.ResponseHelper.send(async (req) => {
|
|
482
|
-
let workflows = [];
|
|
483
|
-
const filter = req.query.filter ? JSON.parse(req.query.filter) : {};
|
|
484
|
-
const query = {
|
|
485
|
-
select: ['id', 'name', 'active', 'createdAt', 'updatedAt'],
|
|
486
|
-
relations: ['tags'],
|
|
487
|
-
};
|
|
488
|
-
if (config_1.default.getEnv('workflowTagsDisabled')) {
|
|
489
|
-
delete query.relations;
|
|
490
|
-
}
|
|
491
|
-
if (req.user.globalRole.name === 'owner') {
|
|
492
|
-
workflows = await _1.Db.collections.Workflow.find(Object.assign(query, {
|
|
493
|
-
where: filter,
|
|
494
|
-
}));
|
|
495
|
-
}
|
|
496
|
-
else {
|
|
497
|
-
const shared = await _1.Db.collections.SharedWorkflow.find({
|
|
498
|
-
relations: ['workflow'],
|
|
499
|
-
where: (0, WorkflowHelpers_1.whereClause)({
|
|
500
|
-
user: req.user,
|
|
501
|
-
entityType: 'workflow',
|
|
502
|
-
}),
|
|
503
|
-
});
|
|
504
|
-
if (!shared.length)
|
|
505
|
-
return [];
|
|
506
|
-
workflows = await _1.Db.collections.Workflow.find(Object.assign(query, {
|
|
507
|
-
where: Object.assign({ id: (0, typeorm_1.In)(shared.map(({ workflow }) => workflow.id)) }, filter),
|
|
508
|
-
}));
|
|
509
|
-
}
|
|
510
|
-
return workflows.map((workflow) => {
|
|
511
|
-
const { id } = workflow, rest = __rest(workflow, ["id"]);
|
|
512
|
-
return Object.assign({ id: id.toString() }, rest);
|
|
513
|
-
});
|
|
514
|
-
}));
|
|
515
|
-
this.app.get(`/${this.restEndpoint}/workflows/new`, _1.ResponseHelper.send(async (req) => {
|
|
516
|
-
var _a;
|
|
517
|
-
const requestedName = req.query.name && req.query.name !== '' ? req.query.name : this.defaultWorkflowName;
|
|
518
|
-
const name = await _1.GenericHelpers.generateUniqueName(requestedName, 'workflow');
|
|
519
|
-
const onboardingFlowEnabled = !config_1.default.getEnv('workflows.onboardingFlowDisabled') &&
|
|
520
|
-
!((_a = req.user.settings) === null || _a === void 0 ? void 0 : _a.isOnboarded) &&
|
|
521
|
-
(await (0, WorkflowHelpers_1.isBelowOnboardingThreshold)(req.user));
|
|
522
|
-
return { name, onboardingFlowEnabled };
|
|
523
|
-
}));
|
|
524
|
-
this.app.patch(`/${this.restEndpoint}/workflows/:id`, _1.ResponseHelper.send(async (req) => {
|
|
525
|
-
var _a;
|
|
526
|
-
const { id: workflowId } = req.params;
|
|
527
|
-
const updateData = new WorkflowEntity_1.WorkflowEntity();
|
|
528
|
-
const _b = req.body, { tags } = _b, rest = __rest(_b, ["tags"]);
|
|
529
|
-
Object.assign(updateData, rest);
|
|
530
|
-
const shared = await _1.Db.collections.SharedWorkflow.findOne({
|
|
531
|
-
relations: ['workflow'],
|
|
532
|
-
where: (0, WorkflowHelpers_1.whereClause)({
|
|
533
|
-
user: req.user,
|
|
534
|
-
entityType: 'workflow',
|
|
535
|
-
entityId: workflowId,
|
|
536
|
-
}),
|
|
537
|
-
});
|
|
538
|
-
if (!shared) {
|
|
539
|
-
n8n_workflow_1.LoggerProxy.info('User attempted to update a workflow without permissions', {
|
|
540
|
-
workflowId,
|
|
541
|
-
userId: req.user.id,
|
|
542
|
-
});
|
|
543
|
-
throw new _1.ResponseHelper.ResponseError(`Workflow with ID "${workflowId}" could not be found to be updated.`, undefined, 404);
|
|
544
|
-
}
|
|
545
|
-
await _1.WorkflowHelpers.replaceInvalidCredentials(updateData);
|
|
546
|
-
_1.WorkflowHelpers.addNodeIds(updateData);
|
|
547
|
-
await this.externalHooks.run('workflow.update', [updateData]);
|
|
548
|
-
if (shared.workflow.active) {
|
|
549
|
-
await this.activeWorkflowRunner.remove(workflowId);
|
|
550
|
-
}
|
|
551
|
-
if (updateData.settings) {
|
|
552
|
-
if (updateData.settings.timezone === 'DEFAULT') {
|
|
553
|
-
delete updateData.settings.timezone;
|
|
554
|
-
}
|
|
555
|
-
if (updateData.settings.saveDataErrorExecution === 'DEFAULT') {
|
|
556
|
-
delete updateData.settings.saveDataErrorExecution;
|
|
557
|
-
}
|
|
558
|
-
if (updateData.settings.saveDataSuccessExecution === 'DEFAULT') {
|
|
559
|
-
delete updateData.settings.saveDataSuccessExecution;
|
|
560
|
-
}
|
|
561
|
-
if (updateData.settings.saveManualExecutions === 'DEFAULT') {
|
|
562
|
-
delete updateData.settings.saveManualExecutions;
|
|
563
|
-
}
|
|
564
|
-
if (parseInt(updateData.settings.executionTimeout, 10) === this.executionTimeout) {
|
|
565
|
-
delete updateData.settings.executionTimeout;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
if (updateData.name) {
|
|
569
|
-
updateData.updatedAt = this.getCurrentDate();
|
|
570
|
-
await (0, GenericHelpers_1.validateEntity)(updateData);
|
|
571
|
-
}
|
|
572
|
-
await _1.Db.collections.Workflow.update(workflowId, updateData);
|
|
573
|
-
if (tags && !config_1.default.getEnv('workflowTagsDisabled')) {
|
|
574
|
-
const tablePrefix = config_1.default.getEnv('database.tablePrefix');
|
|
575
|
-
await TagHelpers.removeRelations(workflowId, tablePrefix);
|
|
576
|
-
if (tags.length) {
|
|
577
|
-
await TagHelpers.createRelations(workflowId, tags, tablePrefix);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
const options = {
|
|
581
|
-
relations: ['tags'],
|
|
582
|
-
};
|
|
583
|
-
if (config_1.default.getEnv('workflowTagsDisabled')) {
|
|
584
|
-
delete options.relations;
|
|
585
|
-
}
|
|
586
|
-
const updatedWorkflow = await _1.Db.collections.Workflow.findOne(workflowId, options);
|
|
587
|
-
if (updatedWorkflow === undefined) {
|
|
588
|
-
throw new _1.ResponseHelper.ResponseError(`Workflow with ID "${workflowId}" could not be found to be updated.`, undefined, 400);
|
|
589
|
-
}
|
|
590
|
-
if (((_a = updatedWorkflow.tags) === null || _a === void 0 ? void 0 : _a.length) && (tags === null || tags === void 0 ? void 0 : tags.length)) {
|
|
591
|
-
updatedWorkflow.tags = TagHelpers.sortByRequestOrder(updatedWorkflow.tags, {
|
|
592
|
-
requestOrder: tags,
|
|
593
|
-
});
|
|
594
|
-
}
|
|
595
|
-
await this.externalHooks.run('workflow.afterUpdate', [updatedWorkflow]);
|
|
596
|
-
void InternalHooksManager_1.InternalHooksManager.getInstance().onWorkflowSaved(req.user.id, updatedWorkflow, false);
|
|
597
|
-
if (updatedWorkflow.active) {
|
|
598
|
-
try {
|
|
599
|
-
await this.externalHooks.run('workflow.activate', [updatedWorkflow]);
|
|
600
|
-
await this.activeWorkflowRunner.add(workflowId, shared.workflow.active ? 'update' : 'activate');
|
|
601
|
-
}
|
|
602
|
-
catch (error) {
|
|
603
|
-
updateData.active = false;
|
|
604
|
-
await _1.Db.collections.Workflow.update(workflowId, updateData);
|
|
605
|
-
updatedWorkflow.active = false;
|
|
606
|
-
throw error;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
const { id } = updatedWorkflow, remainder = __rest(updatedWorkflow, ["id"]);
|
|
610
|
-
return Object.assign({ id: id.toString() }, remainder);
|
|
611
|
-
}));
|
|
612
|
-
this.app.delete(`/${this.restEndpoint}/workflows/:id`, _1.ResponseHelper.send(async (req) => {
|
|
613
|
-
const { id: workflowId } = req.params;
|
|
614
|
-
await this.externalHooks.run('workflow.delete', [workflowId]);
|
|
615
|
-
const shared = await _1.Db.collections.SharedWorkflow.findOne({
|
|
616
|
-
relations: ['workflow'],
|
|
617
|
-
where: (0, WorkflowHelpers_1.whereClause)({
|
|
618
|
-
user: req.user,
|
|
619
|
-
entityType: 'workflow',
|
|
620
|
-
entityId: workflowId,
|
|
621
|
-
}),
|
|
622
|
-
});
|
|
623
|
-
if (!shared) {
|
|
624
|
-
n8n_workflow_1.LoggerProxy.info('User attempted to delete a workflow without permissions', {
|
|
625
|
-
workflowId,
|
|
626
|
-
userId: req.user.id,
|
|
627
|
-
});
|
|
628
|
-
throw new _1.ResponseHelper.ResponseError(`Workflow with ID "${workflowId}" could not be found to be deleted.`, undefined, 400);
|
|
629
|
-
}
|
|
630
|
-
if (shared.workflow.active) {
|
|
631
|
-
await this.activeWorkflowRunner.remove(workflowId);
|
|
632
|
-
}
|
|
633
|
-
await _1.Db.collections.Workflow.delete(workflowId);
|
|
634
|
-
void InternalHooksManager_1.InternalHooksManager.getInstance().onWorkflowDeleted(req.user.id, workflowId, false);
|
|
635
|
-
await this.externalHooks.run('workflow.afterDelete', [workflowId]);
|
|
636
|
-
return true;
|
|
637
|
-
}));
|
|
638
|
-
this.app.post(`/${this.restEndpoint}/workflows/run`, _1.ResponseHelper.send(async (req, res) => {
|
|
639
|
-
var _a;
|
|
640
|
-
const { workflowData } = req.body;
|
|
641
|
-
const { runData } = req.body;
|
|
642
|
-
const { pinData } = req.body;
|
|
643
|
-
const { startNodes } = req.body;
|
|
644
|
-
const { destinationNode } = req.body;
|
|
645
|
-
const executionMode = 'manual';
|
|
646
|
-
const activationMode = 'manual';
|
|
647
|
-
const sessionId = _1.GenericHelpers.getSessionId(req);
|
|
648
|
-
const pinnedTrigger = findFirstPinnedTrigger(workflowData, pinData);
|
|
649
|
-
if (pinnedTrigger === undefined &&
|
|
650
|
-
(runData === undefined ||
|
|
651
|
-
startNodes === undefined ||
|
|
652
|
-
startNodes.length === 0 ||
|
|
653
|
-
destinationNode === undefined)) {
|
|
654
|
-
const additionalData = await _1.WorkflowExecuteAdditionalData.getBase(req.user.id);
|
|
655
|
-
const nodeTypes = (0, _1.NodeTypes)();
|
|
656
|
-
const workflowInstance = new n8n_workflow_1.Workflow({
|
|
657
|
-
id: (_a = workflowData.id) === null || _a === void 0 ? void 0 : _a.toString(),
|
|
658
|
-
name: workflowData.name,
|
|
659
|
-
nodes: workflowData.nodes,
|
|
660
|
-
connections: workflowData.connections,
|
|
661
|
-
active: false,
|
|
662
|
-
nodeTypes,
|
|
663
|
-
staticData: undefined,
|
|
664
|
-
settings: workflowData.settings,
|
|
665
|
-
});
|
|
666
|
-
const needsWebhook = await this.testWebhooks.needsWebhookData(workflowData, workflowInstance, additionalData, executionMode, activationMode, sessionId, destinationNode);
|
|
667
|
-
if (needsWebhook) {
|
|
668
|
-
return {
|
|
669
|
-
waitingForWebhook: true,
|
|
670
|
-
};
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
workflowData.active = false;
|
|
674
|
-
const data = {
|
|
675
|
-
destinationNode,
|
|
676
|
-
executionMode,
|
|
677
|
-
runData,
|
|
678
|
-
pinData,
|
|
679
|
-
sessionId,
|
|
680
|
-
startNodes,
|
|
681
|
-
workflowData,
|
|
682
|
-
userId: req.user.id,
|
|
683
|
-
};
|
|
684
|
-
if (pinnedTrigger) {
|
|
685
|
-
data.startNodes = [pinnedTrigger.name];
|
|
686
|
-
}
|
|
687
|
-
const workflowRunner = new _1.WorkflowRunner();
|
|
688
|
-
const executionId = await workflowRunner.run(data);
|
|
689
|
-
return {
|
|
690
|
-
executionId,
|
|
691
|
-
};
|
|
692
|
-
}));
|
|
693
445
|
this.app.use(`/${this.restEndpoint}/workflows`, workflows_api_1.workflowsController);
|
|
694
446
|
this.app.get(`/${this.restEndpoint}/tags`, _1.ResponseHelper.send(async (req, res) => {
|
|
695
447
|
if (config_1.default.getEnv('workflowTagsDisabled')) {
|
|
@@ -1071,238 +823,7 @@ class App {
|
|
|
1071
823
|
}
|
|
1072
824
|
});
|
|
1073
825
|
this.app.use(`/${this.restEndpoint}/oauth2-credential`, oauth2Credential_api_1.oauth2CredentialController);
|
|
1074
|
-
this.app.
|
|
1075
|
-
const filter = req.query.filter ? JSON.parse(req.query.filter) : {};
|
|
1076
|
-
const limit = req.query.limit
|
|
1077
|
-
? parseInt(req.query.limit, 10)
|
|
1078
|
-
: GenericHelpers_1.DEFAULT_EXECUTIONS_GET_ALL_LIMIT;
|
|
1079
|
-
const executingWorkflowIds = [];
|
|
1080
|
-
if (config_1.default.getEnv('executions.mode') === 'queue') {
|
|
1081
|
-
const currentJobs = await Queue.getInstance().getJobs(['active', 'waiting']);
|
|
1082
|
-
executingWorkflowIds.push(...currentJobs.map(({ data }) => data.executionId));
|
|
1083
|
-
}
|
|
1084
|
-
executingWorkflowIds.push(...this.activeExecutionsInstance.getActiveExecutions().map(({ id }) => id));
|
|
1085
|
-
const countFilter = (0, lodash_1.cloneDeep)(filter);
|
|
1086
|
-
countFilter.waitTill && (countFilter.waitTill = (0, typeorm_1.Not)((0, typeorm_1.IsNull)()));
|
|
1087
|
-
countFilter.id = (0, typeorm_1.Not)((0, typeorm_1.In)(executingWorkflowIds));
|
|
1088
|
-
const sharedWorkflowIds = await (0, WorkflowHelpers_1.getSharedWorkflowIds)(req.user);
|
|
1089
|
-
const findOptions = {
|
|
1090
|
-
select: [
|
|
1091
|
-
'id',
|
|
1092
|
-
'finished',
|
|
1093
|
-
'mode',
|
|
1094
|
-
'retryOf',
|
|
1095
|
-
'retrySuccessId',
|
|
1096
|
-
'waitTill',
|
|
1097
|
-
'startedAt',
|
|
1098
|
-
'stoppedAt',
|
|
1099
|
-
'workflowData',
|
|
1100
|
-
],
|
|
1101
|
-
where: { workflowId: (0, typeorm_1.In)(sharedWorkflowIds) },
|
|
1102
|
-
order: { id: 'DESC' },
|
|
1103
|
-
take: limit,
|
|
1104
|
-
};
|
|
1105
|
-
Object.entries(filter).forEach(([key, value]) => {
|
|
1106
|
-
let filterToAdd = {};
|
|
1107
|
-
if (key === 'waitTill') {
|
|
1108
|
-
filterToAdd = { waitTill: (0, typeorm_1.Not)((0, typeorm_1.IsNull)()) };
|
|
1109
|
-
}
|
|
1110
|
-
else if (key === 'finished' && value === false) {
|
|
1111
|
-
filterToAdd = { finished: false, waitTill: (0, typeorm_1.IsNull)() };
|
|
1112
|
-
}
|
|
1113
|
-
else {
|
|
1114
|
-
filterToAdd = { [key]: value };
|
|
1115
|
-
}
|
|
1116
|
-
Object.assign(findOptions.where, filterToAdd);
|
|
1117
|
-
});
|
|
1118
|
-
const rangeQuery = [];
|
|
1119
|
-
const rangeQueryParams = {};
|
|
1120
|
-
if (req.query.lastId) {
|
|
1121
|
-
rangeQuery.push('id < :lastId');
|
|
1122
|
-
rangeQueryParams.lastId = req.query.lastId;
|
|
1123
|
-
}
|
|
1124
|
-
if (req.query.firstId) {
|
|
1125
|
-
rangeQuery.push('id > :firstId');
|
|
1126
|
-
rangeQueryParams.firstId = req.query.firstId;
|
|
1127
|
-
}
|
|
1128
|
-
if (executingWorkflowIds.length > 0) {
|
|
1129
|
-
rangeQuery.push(`id NOT IN (:...executingWorkflowIds)`);
|
|
1130
|
-
rangeQueryParams.executingWorkflowIds = executingWorkflowIds;
|
|
1131
|
-
}
|
|
1132
|
-
if (rangeQuery.length) {
|
|
1133
|
-
Object.assign(findOptions.where, {
|
|
1134
|
-
id: (0, typeorm_1.Raw)(() => rangeQuery.join(' and '), rangeQueryParams),
|
|
1135
|
-
});
|
|
1136
|
-
}
|
|
1137
|
-
const executions = await _1.Db.collections.Execution.find(findOptions);
|
|
1138
|
-
const { count, estimated } = await getExecutionsCount(countFilter, req.user);
|
|
1139
|
-
const formattedExecutions = executions.map((execution) => {
|
|
1140
|
-
var _a, _b, _c, _d, _e;
|
|
1141
|
-
return {
|
|
1142
|
-
id: execution.id.toString(),
|
|
1143
|
-
finished: execution.finished,
|
|
1144
|
-
mode: execution.mode,
|
|
1145
|
-
retryOf: (_a = execution.retryOf) === null || _a === void 0 ? void 0 : _a.toString(),
|
|
1146
|
-
retrySuccessId: (_b = execution === null || execution === void 0 ? void 0 : execution.retrySuccessId) === null || _b === void 0 ? void 0 : _b.toString(),
|
|
1147
|
-
waitTill: execution.waitTill,
|
|
1148
|
-
startedAt: execution.startedAt,
|
|
1149
|
-
stoppedAt: execution.stoppedAt,
|
|
1150
|
-
workflowId: (_e = (_d = (_c = execution.workflowData) === null || _c === void 0 ? void 0 : _c.id) === null || _d === void 0 ? void 0 : _d.toString()) !== null && _e !== void 0 ? _e : '',
|
|
1151
|
-
workflowName: execution.workflowData.name,
|
|
1152
|
-
};
|
|
1153
|
-
});
|
|
1154
|
-
return {
|
|
1155
|
-
count,
|
|
1156
|
-
results: formattedExecutions,
|
|
1157
|
-
estimated,
|
|
1158
|
-
};
|
|
1159
|
-
}));
|
|
1160
|
-
this.app.get(`/${this.restEndpoint}/executions/:id`, _1.ResponseHelper.send(async (req) => {
|
|
1161
|
-
const { id: executionId } = req.params;
|
|
1162
|
-
const sharedWorkflowIds = await (0, WorkflowHelpers_1.getSharedWorkflowIds)(req.user);
|
|
1163
|
-
if (!sharedWorkflowIds.length)
|
|
1164
|
-
return undefined;
|
|
1165
|
-
const execution = await _1.Db.collections.Execution.findOne({
|
|
1166
|
-
where: {
|
|
1167
|
-
id: executionId,
|
|
1168
|
-
workflowId: (0, typeorm_1.In)(sharedWorkflowIds),
|
|
1169
|
-
},
|
|
1170
|
-
});
|
|
1171
|
-
if (!execution) {
|
|
1172
|
-
n8n_workflow_1.LoggerProxy.info('Attempt to read execution was blocked due to insufficient permissions', {
|
|
1173
|
-
userId: req.user.id,
|
|
1174
|
-
executionId,
|
|
1175
|
-
});
|
|
1176
|
-
return undefined;
|
|
1177
|
-
}
|
|
1178
|
-
if (req.query.unflattedResponse === 'true') {
|
|
1179
|
-
return _1.ResponseHelper.unflattenExecutionData(execution);
|
|
1180
|
-
}
|
|
1181
|
-
const { id } = execution, rest = __rest(execution, ["id"]);
|
|
1182
|
-
return Object.assign({ id: id.toString() }, rest);
|
|
1183
|
-
}));
|
|
1184
|
-
this.app.post(`/${this.restEndpoint}/executions/:id/retry`, _1.ResponseHelper.send(async (req) => {
|
|
1185
|
-
const { id: executionId } = req.params;
|
|
1186
|
-
const sharedWorkflowIds = await (0, WorkflowHelpers_1.getSharedWorkflowIds)(req.user);
|
|
1187
|
-
if (!sharedWorkflowIds.length)
|
|
1188
|
-
return false;
|
|
1189
|
-
const execution = await _1.Db.collections.Execution.findOne({
|
|
1190
|
-
where: {
|
|
1191
|
-
id: executionId,
|
|
1192
|
-
workflowId: (0, typeorm_1.In)(sharedWorkflowIds),
|
|
1193
|
-
},
|
|
1194
|
-
});
|
|
1195
|
-
if (!execution) {
|
|
1196
|
-
n8n_workflow_1.LoggerProxy.info('Attempt to retry an execution was blocked due to insufficient permissions', {
|
|
1197
|
-
userId: req.user.id,
|
|
1198
|
-
executionId,
|
|
1199
|
-
});
|
|
1200
|
-
throw new _1.ResponseHelper.ResponseError(`The execution with the ID "${executionId}" does not exist.`, 404, 404);
|
|
1201
|
-
}
|
|
1202
|
-
const fullExecutionData = _1.ResponseHelper.unflattenExecutionData(execution);
|
|
1203
|
-
if (fullExecutionData.finished) {
|
|
1204
|
-
throw new Error('The execution succeeded, so it cannot be retried.');
|
|
1205
|
-
}
|
|
1206
|
-
const executionMode = 'retry';
|
|
1207
|
-
fullExecutionData.workflowData.active = false;
|
|
1208
|
-
const data = {
|
|
1209
|
-
executionMode,
|
|
1210
|
-
executionData: fullExecutionData.data,
|
|
1211
|
-
retryOf: req.params.id,
|
|
1212
|
-
workflowData: fullExecutionData.workflowData,
|
|
1213
|
-
userId: req.user.id,
|
|
1214
|
-
};
|
|
1215
|
-
const { lastNodeExecuted } = data.executionData.resultData;
|
|
1216
|
-
if (lastNodeExecuted) {
|
|
1217
|
-
delete data.executionData.resultData.error;
|
|
1218
|
-
const { length } = data.executionData.resultData.runData[lastNodeExecuted];
|
|
1219
|
-
if (length > 0 &&
|
|
1220
|
-
data.executionData.resultData.runData[lastNodeExecuted][length - 1].error !== undefined) {
|
|
1221
|
-
data.executionData.resultData.runData[lastNodeExecuted].pop();
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
if (req.body.loadWorkflow) {
|
|
1225
|
-
const workflowId = fullExecutionData.workflowData.id;
|
|
1226
|
-
const workflowData = (await _1.Db.collections.Workflow.findOne(workflowId));
|
|
1227
|
-
if (workflowData === undefined) {
|
|
1228
|
-
throw new Error(`The workflow with the ID "${workflowId}" could not be found and so the data not be loaded for the retry.`);
|
|
1229
|
-
}
|
|
1230
|
-
data.workflowData = workflowData;
|
|
1231
|
-
const nodeTypes = (0, _1.NodeTypes)();
|
|
1232
|
-
const workflowInstance = new n8n_workflow_1.Workflow({
|
|
1233
|
-
id: workflowData.id,
|
|
1234
|
-
name: workflowData.name,
|
|
1235
|
-
nodes: workflowData.nodes,
|
|
1236
|
-
connections: workflowData.connections,
|
|
1237
|
-
active: false,
|
|
1238
|
-
nodeTypes,
|
|
1239
|
-
staticData: undefined,
|
|
1240
|
-
settings: workflowData.settings,
|
|
1241
|
-
});
|
|
1242
|
-
for (const stack of data.executionData.executionData.nodeExecutionStack) {
|
|
1243
|
-
const node = workflowInstance.getNode(stack.node.name);
|
|
1244
|
-
if (node === null) {
|
|
1245
|
-
n8n_workflow_1.LoggerProxy.error('Failed to retry an execution because a node could not be found', {
|
|
1246
|
-
userId: req.user.id,
|
|
1247
|
-
executionId,
|
|
1248
|
-
nodeName: stack.node.name,
|
|
1249
|
-
});
|
|
1250
|
-
throw new Error(`Could not find the node "${stack.node.name}" in workflow. It probably got deleted or renamed. Without it the workflow can sadly not be retried.`);
|
|
1251
|
-
}
|
|
1252
|
-
stack.node = node;
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
|
-
const workflowRunner = new _1.WorkflowRunner();
|
|
1256
|
-
const retriedExecutionId = await workflowRunner.run(data);
|
|
1257
|
-
const executionData = await this.activeExecutionsInstance.getPostExecutePromise(retriedExecutionId);
|
|
1258
|
-
if (!executionData) {
|
|
1259
|
-
throw new Error('The retry did not start for an unknown reason.');
|
|
1260
|
-
}
|
|
1261
|
-
return !!executionData.finished;
|
|
1262
|
-
}));
|
|
1263
|
-
this.app.post(`/${this.restEndpoint}/executions/delete`, _1.ResponseHelper.send(async (req) => {
|
|
1264
|
-
const { deleteBefore, ids, filters: requestFilters } = req.body;
|
|
1265
|
-
if (!deleteBefore && !ids) {
|
|
1266
|
-
throw new Error('Either "deleteBefore" or "ids" must be present in the request body');
|
|
1267
|
-
}
|
|
1268
|
-
const sharedWorkflowIds = await (0, WorkflowHelpers_1.getSharedWorkflowIds)(req.user);
|
|
1269
|
-
const binaryDataManager = n8n_core_1.BinaryDataManager.getInstance();
|
|
1270
|
-
if (deleteBefore) {
|
|
1271
|
-
const filters = {
|
|
1272
|
-
startedAt: (0, typeorm_1.LessThanOrEqual)(deleteBefore),
|
|
1273
|
-
};
|
|
1274
|
-
if (filters) {
|
|
1275
|
-
Object.assign(filters, requestFilters);
|
|
1276
|
-
}
|
|
1277
|
-
const executions = await _1.Db.collections.Execution.find({
|
|
1278
|
-
where: Object.assign({ workflowId: (0, typeorm_1.In)(sharedWorkflowIds) }, filters),
|
|
1279
|
-
});
|
|
1280
|
-
if (!executions.length)
|
|
1281
|
-
return;
|
|
1282
|
-
const idsToDelete = executions.map(({ id }) => id.toString());
|
|
1283
|
-
await Promise.all(idsToDelete.map(async (id) => binaryDataManager.deleteBinaryDataByExecutionId(id)));
|
|
1284
|
-
await _1.Db.collections.Execution.delete({ id: (0, typeorm_1.In)(idsToDelete) });
|
|
1285
|
-
return;
|
|
1286
|
-
}
|
|
1287
|
-
if (ids) {
|
|
1288
|
-
const executions = await _1.Db.collections.Execution.find({
|
|
1289
|
-
where: {
|
|
1290
|
-
id: (0, typeorm_1.In)(ids),
|
|
1291
|
-
workflowId: (0, typeorm_1.In)(sharedWorkflowIds),
|
|
1292
|
-
},
|
|
1293
|
-
});
|
|
1294
|
-
if (!executions.length) {
|
|
1295
|
-
n8n_workflow_1.LoggerProxy.error('Failed to delete an execution due to insufficient permissions', {
|
|
1296
|
-
userId: req.user.id,
|
|
1297
|
-
executionIds: ids,
|
|
1298
|
-
});
|
|
1299
|
-
return;
|
|
1300
|
-
}
|
|
1301
|
-
const idsToDelete = executions.map(({ id }) => id.toString());
|
|
1302
|
-
await Promise.all(idsToDelete.map(async (id) => binaryDataManager.deleteBinaryDataByExecutionId(id)));
|
|
1303
|
-
await _1.Db.collections.Execution.delete(idsToDelete);
|
|
1304
|
-
}
|
|
1305
|
-
}));
|
|
826
|
+
this.app.use(`/${this.restEndpoint}/executions`, executions_api_1.executionsController);
|
|
1306
827
|
this.app.get(`/${this.restEndpoint}/executions-current`, _1.ResponseHelper.send(async (req) => {
|
|
1307
828
|
if (config_1.default.getEnv('executions.mode') === 'queue') {
|
|
1308
829
|
const currentJobs = await Queue.getInstance().getJobs(['active', 'waiting']);
|
|
@@ -1627,35 +1148,6 @@ async function start() {
|
|
|
1627
1148
|
});
|
|
1628
1149
|
}
|
|
1629
1150
|
exports.start = start;
|
|
1630
|
-
async function getExecutionsCount(countFilter, user) {
|
|
1631
|
-
const dbType = (await _1.GenericHelpers.getConfigValue('database.type'));
|
|
1632
|
-
const filteredFields = Object.keys(countFilter).filter((field) => field !== 'id');
|
|
1633
|
-
if (dbType !== 'postgresdb' || filteredFields.length > 0 || user.globalRole.name !== 'owner') {
|
|
1634
|
-
const sharedWorkflowIds = await (0, WorkflowHelpers_1.getSharedWorkflowIds)(user);
|
|
1635
|
-
const count = await _1.Db.collections.Execution.count({
|
|
1636
|
-
where: Object.assign({ workflowId: (0, typeorm_1.In)(sharedWorkflowIds) }, countFilter),
|
|
1637
|
-
});
|
|
1638
|
-
return { count, estimated: false };
|
|
1639
|
-
}
|
|
1640
|
-
try {
|
|
1641
|
-
const estimateRowsNumberSql = "SELECT n_live_tup FROM pg_stat_all_tables WHERE relname = 'execution_entity';";
|
|
1642
|
-
const rows = await _1.Db.collections.Execution.query(estimateRowsNumberSql);
|
|
1643
|
-
const estimate = parseInt(rows[0].n_live_tup, 10);
|
|
1644
|
-
if (estimate > 100000) {
|
|
1645
|
-
return { count: estimate, estimated: true };
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
catch (error) {
|
|
1649
|
-
n8n_workflow_1.LoggerProxy.warn(`Failed to get executions count from Postgres: ${error}`);
|
|
1650
|
-
}
|
|
1651
|
-
const sharedWorkflowIds = await (0, WorkflowHelpers_1.getSharedWorkflowIds)(user);
|
|
1652
|
-
const count = await _1.Db.collections.Execution.count({
|
|
1653
|
-
where: {
|
|
1654
|
-
workflowId: (0, typeorm_1.In)(sharedWorkflowIds),
|
|
1655
|
-
},
|
|
1656
|
-
});
|
|
1657
|
-
return { count, estimated: false };
|
|
1658
|
-
}
|
|
1659
1151
|
const CUSTOM_API_CALL_NAME = 'Custom API Call';
|
|
1660
1152
|
const CUSTOM_API_CALL_KEY = '__CUSTOM_API_CALL__';
|
|
1661
1153
|
function injectCustomApiCallOption(description) {
|
|
@@ -1689,10 +1181,4 @@ function isOAuth(credType) {
|
|
|
1689
1181
|
return (Array.isArray(credType.extends) &&
|
|
1690
1182
|
credType.extends.some((parentType) => ['oAuth2Api', 'googleOAuth2Api', 'oAuth1Api'].includes(parentType)));
|
|
1691
1183
|
}
|
|
1692
|
-
const isTrigger = (nodeType) => ['trigger', 'webhook'].some((suffix) => nodeType.toLowerCase().includes(suffix));
|
|
1693
|
-
function findFirstPinnedTrigger(workflow, pinData) {
|
|
1694
|
-
if (!pinData)
|
|
1695
|
-
return;
|
|
1696
|
-
return workflow.nodes.find((node) => !node.disabled && isTrigger(node.type) && pinData[node.name]);
|
|
1697
|
-
}
|
|
1698
1184
|
//# sourceMappingURL=Server.js.map
|