n8n
Version:
n8n Workflow Automation Tool
137 lines • 7.41 kB
JavaScript
"use strict";
const backend_common_1 = require("@n8n/backend-common");
const constants_1 = require("@n8n/constants");
const db_1 = require("@n8n/db");
const di_1 = require("@n8n/di");
const n8n_core_1 = require("n8n-core");
const n8n_workflow_1 = require("n8n-workflow");
const conflict_error_1 = require("../../../../errors/response-errors/conflict.error");
const forbidden_error_1 = require("../../../../errors/response-errors/forbidden.error");
const not_found_error_1 = require("../../../../errors/response-errors/not-found.error");
const payment_required_error_1 = require("../../../../errors/response-errors/payment-required.error");
const test_runner_service_ee_1 = require("../../../../evaluation.ee/test-runner/test-runner.service.ee");
const workflow_finder_service_1 = require("../../../../workflows/workflow-finder.service");
const evaluations_mapper_1 = require("./evaluations.mapper");
const global_middleware_1 = require("../../shared/middlewares/global.middleware");
const pagination_service_1 = require("../../shared/services/pagination.service");
function assertEvaluationsEnabled() {
if (di_1.Container.get(backend_common_1.LicenseState).getMaxWorkflowsWithEvaluations() === 0) {
throw new forbidden_error_1.ForbiddenError('Evaluations are not available on your plan');
}
}
async function assertEvaluationQuotaAvailable(workflowId) {
const limit = di_1.Container.get(backend_common_1.LicenseState).getMaxWorkflowsWithEvaluations();
if (limit === constants_1.UNLIMITED_LICENSE_QUOTA)
return;
const alreadyCounts = (await di_1.Container.get(db_1.TestRunRepository).countByWorkflowId(workflowId)) > 0;
if (alreadyCounts)
return;
const used = await di_1.Container.get(db_1.WorkflowRepository).getWorkflowsWithEvaluationCount();
if (used >= limit) {
throw new payment_required_error_1.PaymentRequiredError(`Evaluation quota exceeded: ${used}/${limit} workflows already have evaluations`);
}
}
const evaluationsHandlers = {
getTestRuns: [
(0, global_middleware_1.publicApiScope)('testRun:list'),
(0, global_middleware_1.projectScope)('workflow:read', 'workflow'),
global_middleware_1.validCursor,
async (req, res) => {
const { id: workflowId } = req.params;
const { offset = 0, limit = 100, status } = req.query;
const testRunRepository = di_1.Container.get(db_1.TestRunRepository);
const [testRuns, count] = await Promise.all([
testRunRepository.getMany(workflowId, { skip: offset, take: limit }, status),
testRunRepository.countByWorkflowId(workflowId, status),
]);
return res.json({
data: testRuns.map(evaluations_mapper_1.toTestRunSummaryDto),
nextCursor: (0, pagination_service_1.encodeNextCursor)({ offset, limit, numberOfTotalRecords: count }),
});
},
],
getTestRun: [
(0, global_middleware_1.publicApiScope)('testRun:read'),
(0, global_middleware_1.projectScope)('workflow:read', 'workflow'),
async (req, res) => {
const { id: workflowId, runId } = req.params;
const summary = await di_1.Container.get(db_1.TestRunRepository).getTestRunSummaryByWorkflowId(runId, workflowId);
if (!summary)
throw new not_found_error_1.NotFoundError('Test run not found');
return res.json((0, evaluations_mapper_1.toTestRunSummaryDto)({
...summary,
testCaseCount: summary.testCaseExecutions?.length ?? 0,
}));
},
],
getTestCases: [
(0, global_middleware_1.publicApiScope)('testRun:read'),
(0, global_middleware_1.projectScope)('workflow:read', 'workflow'),
global_middleware_1.validCursor,
async (req, res) => {
const { id: workflowId, runId } = req.params;
const { offset = 0, limit = 100 } = req.query;
if (!(await di_1.Container.get(db_1.TestRunRepository).existsInWorkflow(runId, workflowId))) {
throw new not_found_error_1.NotFoundError('Test run not found');
}
const testCaseExecutionRepository = di_1.Container.get(db_1.TestCaseExecutionRepository);
const [testCases, count] = await Promise.all([
testCaseExecutionRepository.getManyByTestRunId(runId, { skip: offset, take: limit }),
testCaseExecutionRepository.countByTestRunId(runId),
]);
return res.json({
data: testCases.map(evaluations_mapper_1.toTestCaseExecutionDto),
nextCursor: (0, pagination_service_1.encodeNextCursor)({ offset, limit, numberOfTotalRecords: count }),
});
},
],
createTestRun: [
(0, global_middleware_1.publicApiScope)('testRun:create'),
(0, global_middleware_1.projectScope)('workflow:execute', 'workflow'),
async (req, res) => {
const { id: workflowId } = req.params;
const testRunnerService = di_1.Container.get(test_runner_service_ee_1.TestRunnerService);
assertEvaluationsEnabled();
const workflow = await di_1.Container.get(workflow_finder_service_1.WorkflowFinderService).findWorkflowForUser(workflowId, req.user, ['workflow:execute']);
if (!workflow)
throw new not_found_error_1.NotFoundError('Workflow not found');
const hasTrigger = workflow.nodes.some((node) => node.type === n8n_workflow_1.EVALUATION_TRIGGER_NODE_TYPE);
if (!hasTrigger) {
throw new conflict_error_1.ConflictError('Workflow has no evaluation trigger');
}
await assertEvaluationQuotaAvailable(workflowId);
const { testRun, finished } = await testRunnerService.startTestRun(req.user, workflowId, 1, {
via: 'public-api',
});
void finished.catch((error) => di_1.Container.get(n8n_core_1.ErrorReporter).error(error));
const body = {
id: testRun.id,
status: testRun.status,
createdAt: testRun.createdAt.toISOString(),
};
return res.status(201).json(body);
},
],
cancelTestRun: [
(0, global_middleware_1.publicApiScope)('testRun:cancel'),
(0, global_middleware_1.projectScope)('workflow:execute', 'workflow'),
async (req, res) => {
const { id: workflowId, runId } = req.params;
assertEvaluationsEnabled();
const testRunnerService = di_1.Container.get(test_runner_service_ee_1.TestRunnerService);
const testRun = await di_1.Container.get(db_1.TestRunRepository).findOne({
where: { id: runId, workflow: { id: workflowId } },
});
if (!testRun)
throw new not_found_error_1.NotFoundError('Test run not found');
if (testRunnerService.canBeCancelled(testRun)) {
throw new conflict_error_1.ConflictError(`The test run "${runId}" cannot be cancelled`);
}
await testRunnerService.cancelTestRun(runId);
const body = { id: runId, status: 'cancelled' };
return res.status(202).json(body);
},
],
};
module.exports = evaluationsHandlers;
//# sourceMappingURL=evaluations.handler.js.map