n8n
Version:
n8n Workflow Automation Tool
260 lines • 13.5 kB
JavaScript
"use strict";
const api_types_1 = require("@n8n/api-types");
const db_1 = require("@n8n/db");
const di_1 = require("@n8n/di");
const typeorm_1 = require("@n8n/typeorm");
const n8n_workflow_1 = require("n8n-workflow");
const active_executions_1 = require("../../../../active-executions");
const concurrency_control_service_1 = require("../../../../concurrency/concurrency-control.service");
const aborted_execution_retry_error_1 = require("../../../../errors/aborted-execution-retry.error");
const missing_execution_stop_error_1 = require("../../../../errors/missing-execution-stop.error");
const queued_execution_retry_error_1 = require("../../../../errors/queued-execution-retry.error");
const bad_request_error_1 = require("../../../../errors/response-errors/bad-request.error");
const conflict_error_1 = require("../../../../errors/response-errors/conflict.error");
const not_found_error_1 = require("../../../../errors/response-errors/not-found.error");
const event_service_1 = require("../../../../events/event.service");
const execution_persistence_1 = require("../../../../executions/execution-persistence");
const execution_redaction_proxy_service_1 = require("../../../../executions/execution-redaction-proxy.service");
const execution_service_1 = require("../../../../executions/execution.service");
const executions_service_1 = require("./executions.service");
const global_middleware_1 = require("../../shared/middlewares/global.middleware");
const pagination_service_1 = require("../../shared/services/pagination.service");
const workflows_service_1 = require("../workflows/workflows.service");
const handleError = (error) => {
if (error instanceof queued_execution_retry_error_1.QueuedExecutionRetryError || error instanceof aborted_execution_retry_error_1.AbortedExecutionRetryError) {
throw new conflict_error_1.ConflictError(error.message);
}
if (error instanceof missing_execution_stop_error_1.MissingExecutionStopError) {
throw new not_found_error_1.NotFoundError(error.message);
}
throw error;
};
function isRedactableExecution(execution) {
return 'data' in execution && 'workflowData' in execution;
}
const executionHandlers = {
deleteExecution: [
(0, global_middleware_1.publicApiScope)('execution:delete'),
async (req, res) => {
const sharedWorkflowsIds = await (0, workflows_service_1.getSharedWorkflowIds)(req.user, ['workflow:delete']);
if (!sharedWorkflowsIds.length) {
throw new not_found_error_1.NotFoundError('Not Found');
}
const { id } = req.params;
const execution = await di_1.Container.get(db_1.ExecutionRepository).getExecutionInWorkflowsForPublicApi(id, sharedWorkflowsIds, false);
if (!execution) {
throw new not_found_error_1.NotFoundError('Not Found');
}
if (execution.status === 'running') {
throw new bad_request_error_1.BadRequestError('Cannot delete a running execution');
}
if (execution.status === 'new') {
di_1.Container.get(concurrency_control_service_1.ConcurrencyControlService).remove({
executionId: execution.id,
mode: execution.mode,
});
}
await di_1.Container.get(execution_persistence_1.ExecutionPersistence).hardDelete({
workflowId: execution.workflowId,
executionId: execution.id,
storedAt: execution.storedAt,
});
execution.id = id;
return res.json((0, n8n_workflow_1.replaceCircularReferences)(execution));
},
],
getExecution: [
(0, global_middleware_1.publicApiScope)('execution:read'),
async (req, res) => {
const sharedWorkflowsIds = await (0, workflows_service_1.getSharedWorkflowIds)(req.user, ['workflow:read']);
if (!sharedWorkflowsIds.length) {
throw new not_found_error_1.NotFoundError('Not Found');
}
const { id } = req.params;
const { includeData = false } = req.query;
const execution = await di_1.Container.get(db_1.ExecutionRepository).getExecutionInWorkflowsForPublicApi(id, sharedWorkflowsIds, includeData);
if (!execution) {
throw new not_found_error_1.NotFoundError('Not Found');
}
if (includeData && isRedactableExecution(execution)) {
const redactQuery = api_types_1.ExecutionRedactionQueryDtoSchema.safeParse(req.query);
const redactExecutionData = redactQuery.success
? redactQuery.data.redactExecutionData
: undefined;
await di_1.Container.get(execution_redaction_proxy_service_1.ExecutionRedactionServiceProxy).processExecution(execution, {
user: req.user,
redactExecutionData,
ipAddress: req.ip ?? '',
userAgent: req.headers['user-agent'] ?? '',
});
}
di_1.Container.get(event_service_1.EventService).emit('user-retrieved-execution', {
userId: req.user.id,
publicApi: true,
});
return res.json((0, n8n_workflow_1.replaceCircularReferences)(execution));
},
],
getExecutions: [
(0, global_middleware_1.publicApiScope)('execution:list'),
global_middleware_1.validCursor,
async (req, res) => {
const { lastId = undefined, limit = 100, status = undefined, includeData = false, workflowId = undefined, projectId, } = req.query;
const sharedWorkflowsIds = await (0, workflows_service_1.getSharedWorkflowIds)(req.user, ['workflow:read'], projectId);
if (!sharedWorkflowsIds.length || (workflowId && !sharedWorkflowsIds.includes(workflowId))) {
return res.status(200).json({ data: [], nextCursor: null });
}
const runningExecutionsIds = di_1.Container.get(active_executions_1.ActiveExecutions)
.getActiveExecutions()
.map(({ id }) => id);
const filters = {
status,
limit,
lastId,
includeData,
workflowIds: workflowId ? [workflowId] : sharedWorkflowsIds,
excludedExecutionsIds: status !== 'running' ? runningExecutionsIds : undefined,
};
const executions = await di_1.Container.get(db_1.ExecutionRepository).getExecutionsForPublicApi(filters);
const newLastId = !executions.length ? '0' : executions.slice(-1)[0].id;
filters.lastId = newLastId;
const count = await di_1.Container.get(db_1.ExecutionRepository).getExecutionsCountForPublicApi(filters);
if (includeData) {
const redactQuery = api_types_1.ExecutionRedactionQueryDtoSchema.safeParse(req.query);
const redactExecutionData = redactQuery.success
? redactQuery.data.redactExecutionData
: undefined;
const redactableExecutions = executions.filter(isRedactableExecution);
await di_1.Container.get(execution_redaction_proxy_service_1.ExecutionRedactionServiceProxy).processExecutions(redactableExecutions, {
user: req.user,
redactExecutionData,
ipAddress: req.ip ?? '',
userAgent: req.headers['user-agent'] ?? '',
});
}
di_1.Container.get(event_service_1.EventService).emit('user-retrieved-all-executions', {
userId: req.user.id,
publicApi: true,
});
return res.json({
data: (0, n8n_workflow_1.replaceCircularReferences)(executions),
nextCursor: (0, pagination_service_1.encodeNextCursor)({
lastId: newLastId,
limit,
numberOfNextRecords: count,
}),
});
},
],
retryExecution: [
(0, global_middleware_1.publicApiScope)('execution:retry'),
async (req, res) => {
const sharedWorkflowsIds = await (0, workflows_service_1.getSharedWorkflowIds)(req.user, ['workflow:read']);
if (!sharedWorkflowsIds.length) {
throw new not_found_error_1.NotFoundError('Not Found');
}
try {
const retriedExecution = await di_1.Container.get(execution_service_1.ExecutionService).retry(req, sharedWorkflowsIds);
di_1.Container.get(event_service_1.EventService).emit('user-retried-execution', {
userId: req.user.id,
publicApi: true,
});
return res.json((0, n8n_workflow_1.replaceCircularReferences)(retriedExecution));
}
catch (error) {
return handleError(error);
}
},
],
getExecutionTags: [
(0, global_middleware_1.publicApiScope)('executionTags:list'),
async (req, res) => {
const { id } = req.params;
const sharedWorkflowsIds = await (0, workflows_service_1.getSharedWorkflowIds)(req.user, ['workflow:read']);
if (!sharedWorkflowsIds.length) {
throw new not_found_error_1.NotFoundError('Not Found');
}
const execution = await di_1.Container.get(db_1.ExecutionRepository).getExecutionInWorkflowsForPublicApi(id, sharedWorkflowsIds, false);
if (!execution) {
throw new not_found_error_1.NotFoundError('Not Found');
}
const tags = await (0, executions_service_1.getExecutionTags)(id);
return res.json(tags);
},
],
updateExecutionTags: [
(0, global_middleware_1.publicApiScope)('executionTags:update'),
async (req, res) => {
const { id } = req.params;
const newTagIds = req.body.map((tag) => tag.id);
const sharedWorkflowsIds = await (0, workflows_service_1.getSharedWorkflowIds)(req.user, ['workflow:update']);
if (!sharedWorkflowsIds.length) {
throw new not_found_error_1.NotFoundError('Not Found');
}
const execution = await di_1.Container.get(db_1.ExecutionRepository).getExecutionInWorkflowsForPublicApi(id, sharedWorkflowsIds, false);
if (!execution) {
throw new not_found_error_1.NotFoundError('Not Found');
}
try {
const updatedTags = await (0, executions_service_1.updateExecutionTags)(id, newTagIds);
const tags = (0, executions_service_1.mapAnnotationTags)(updatedTags);
return res.json(tags);
}
catch (error) {
if (error instanceof typeorm_1.QueryFailedError) {
throw new not_found_error_1.NotFoundError('Some tags not found');
}
return handleError(error);
}
},
],
stopExecution: [
(0, global_middleware_1.publicApiScope)('execution:stop'),
async (req, res) => {
const sharedWorkflowsIds = await (0, workflows_service_1.getSharedWorkflowIds)(req.user, ['workflow:execute']);
if (!sharedWorkflowsIds.length) {
throw new not_found_error_1.NotFoundError('Not Found');
}
const { id } = req.params;
try {
const stopResult = await di_1.Container.get(execution_service_1.ExecutionService).stop(id, sharedWorkflowsIds);
return res.json((0, n8n_workflow_1.replaceCircularReferences)(stopResult));
}
catch (error) {
return handleError(error);
}
},
],
stopManyExecutions: [
(0, global_middleware_1.publicApiScope)('execution:stop'),
async (req, res) => {
const { status: rawStatus, workflowId, startedAfter, startedBefore } = req.body;
const status = rawStatus.map((x) => (x === 'queued' ? 'new' : x));
if (!status || status.length === 0) {
return res.status(400).json({
message: 'Status filter is required. Please provide at least one status to stop executions.',
example: {
status: ['running', 'waiting', 'queued'],
},
});
}
const sharedWorkflowsIds = await (0, workflows_service_1.getSharedWorkflowIds)(req.user, ['workflow:execute']);
if (!sharedWorkflowsIds.length) {
return res.json({ stopped: 0 });
}
if (workflowId && workflowId !== 'all' && !sharedWorkflowsIds.includes(workflowId)) {
throw new not_found_error_1.NotFoundError('Workflow not found or not accessible');
}
const filter = {
workflowId: workflowId ?? 'all',
status,
startedAfter,
startedBefore,
};
const stopped = await di_1.Container.get(execution_service_1.ExecutionService).stopMany(filter, sharedWorkflowsIds);
return res.json({ stopped });
},
],
};
module.exports = executionHandlers;
//# sourceMappingURL=executions.handler.js.map