UNPKG

n8n

Version:

n8n Workflow Automation Tool

260 lines 13.5 kB
"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