mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-09 22:24:05 -08:00
refactor(core): Reorganize error hierarchy in cli
package (no-changelog) (#7839)
Ensure all errors in `cli` inherit from `ApplicationError` to continue normalizing all the errors we report to Sentry Follow-up to: https://github.com/n8n-io/n8n/pull/7820
This commit is contained in:
parent
38f24a6184
commit
1c6178759c
|
@ -11,13 +11,14 @@ import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
|||
import * as Db from '@/Db';
|
||||
import type { N8nInstanceType, IExternalHooksClass } from '@/Interfaces';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { send, sendErrorResponse, ServiceUnavailableError } from '@/ResponseHelper';
|
||||
import { send, sendErrorResponse } from '@/ResponseHelper';
|
||||
import { rawBodyReader, bodyParser, corsMiddleware } from '@/middlewares';
|
||||
import { TestWebhooks } from '@/TestWebhooks';
|
||||
import { WaitingWebhooks } from '@/WaitingWebhooks';
|
||||
import { webhookRequestHandler } from '@/WebhookHelpers';
|
||||
import { generateHostInstanceId } from './databases/utils/generators';
|
||||
import { Logger } from '@/Logger';
|
||||
import { ServiceUnavailableError } from './errors/response-errors/service-unavailable.error';
|
||||
|
||||
export abstract class AbstractServer {
|
||||
protected logger: Logger;
|
||||
|
|
|
@ -42,7 +42,6 @@ import type {
|
|||
WebhookAccessControlOptions,
|
||||
WebhookRequest,
|
||||
} from '@/Interfaces';
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import * as WebhookHelpers from '@/WebhookHelpers';
|
||||
import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData';
|
||||
|
||||
|
@ -68,6 +67,7 @@ import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.reposi
|
|||
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||
import { MultiMainSetup } from '@/services/orchestration/main/MultiMainSetup.ee';
|
||||
import { ActivationErrorsService } from '@/ActivationErrors.service';
|
||||
import { NotFoundError } from './errors/response-errors/not-found.error';
|
||||
|
||||
const WEBHOOK_PROD_UNREGISTERED_HINT =
|
||||
"The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)";
|
||||
|
@ -165,9 +165,7 @@ export class ActiveWorkflowRunner implements IWebhookManager {
|
|||
});
|
||||
|
||||
if (workflowData === null) {
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`Could not find workflow with id "${webhook.workflowId}"`,
|
||||
);
|
||||
throw new NotFoundError(`Could not find workflow with id "${webhook.workflowId}"`);
|
||||
}
|
||||
|
||||
const workflow = new Workflow({
|
||||
|
@ -196,7 +194,7 @@ export class ActiveWorkflowRunner implements IWebhookManager {
|
|||
const workflowStartNode = workflow.getNode(webhookData.node);
|
||||
|
||||
if (workflowStartNode === null) {
|
||||
throw new ResponseHelper.NotFoundError('Could not find node to process webhook.');
|
||||
throw new NotFoundError('Could not find node to process webhook.');
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -252,7 +250,7 @@ export class ActiveWorkflowRunner implements IWebhookManager {
|
|||
|
||||
const webhook = await this.webhookService.findWebhook(httpMethod, path);
|
||||
if (webhook === null) {
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
throw new NotFoundError(
|
||||
webhookNotFoundErrorMessage(path, httpMethod),
|
||||
WEBHOOK_PROD_UNREGISTERED_HINT,
|
||||
);
|
||||
|
|
|
@ -32,7 +32,6 @@ import type {
|
|||
INodeTypes,
|
||||
IWorkflowExecuteAdditionalData,
|
||||
ICredentialTestFunctions,
|
||||
Severity,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
ICredentialsHelper,
|
||||
|
@ -55,6 +54,7 @@ import { isObjectLiteral } from './utils';
|
|||
import { Logger } from '@/Logger';
|
||||
import { CredentialsRepository } from '@db/repositories/credentials.repository';
|
||||
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
|
||||
import { CredentialNotFoundError } from './errors/credential-not-found.error';
|
||||
|
||||
const { OAUTH2_CREDENTIAL_TEST_SUCCEEDED, OAUTH2_CREDENTIAL_TEST_FAILED } = RESPONSE_ERROR_MESSAGES;
|
||||
|
||||
|
@ -87,15 +87,6 @@ const mockNodeTypes: INodeTypes = {
|
|||
},
|
||||
};
|
||||
|
||||
class CredentialNotFoundError extends Error {
|
||||
severity: Severity;
|
||||
|
||||
constructor(credentialId: string, credentialType: string) {
|
||||
super(`Credential with ID "${credentialId}" does not exist for type "${credentialType}".`);
|
||||
this.severity = 'warning';
|
||||
}
|
||||
}
|
||||
|
||||
@Service()
|
||||
export class CredentialsHelper extends ICredentialsHelper {
|
||||
constructor(
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Authorized, Get, Post, RestController } from '@/decorators';
|
||||
import { ExternalSecretsRequest } from '@/requests';
|
||||
import { NotFoundError } from '@/ResponseHelper';
|
||||
import { Response } from 'express';
|
||||
import { Service } from 'typedi';
|
||||
import { ProviderNotFoundError, ExternalSecretsService } from './ExternalSecrets.service.ee';
|
||||
import { ExternalSecretsService } from './ExternalSecrets.service.ee';
|
||||
import { ExternalSecretsProviderNotFoundError } from '@/errors/external-secrets-provider-not-found.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
|
||||
@Service()
|
||||
@Authorized(['global', 'owner'])
|
||||
|
@ -22,7 +23,7 @@ export class ExternalSecretsController {
|
|||
try {
|
||||
return this.secretsService.getProvider(providerName);
|
||||
} catch (e) {
|
||||
if (e instanceof ProviderNotFoundError) {
|
||||
if (e instanceof ExternalSecretsProviderNotFoundError) {
|
||||
throw new NotFoundError(`Could not find provider "${e.providerName}"`);
|
||||
}
|
||||
throw e;
|
||||
|
@ -41,7 +42,7 @@ export class ExternalSecretsController {
|
|||
}
|
||||
return result;
|
||||
} catch (e) {
|
||||
if (e instanceof ProviderNotFoundError) {
|
||||
if (e instanceof ExternalSecretsProviderNotFoundError) {
|
||||
throw new NotFoundError(`Could not find provider "${e.providerName}"`);
|
||||
}
|
||||
throw e;
|
||||
|
@ -54,7 +55,7 @@ export class ExternalSecretsController {
|
|||
try {
|
||||
await this.secretsService.saveProviderSettings(providerName, req.body, req.user.id);
|
||||
} catch (e) {
|
||||
if (e instanceof ProviderNotFoundError) {
|
||||
if (e instanceof ExternalSecretsProviderNotFoundError) {
|
||||
throw new NotFoundError(`Could not find provider "${e.providerName}"`);
|
||||
}
|
||||
throw e;
|
||||
|
@ -68,7 +69,7 @@ export class ExternalSecretsController {
|
|||
try {
|
||||
await this.secretsService.saveProviderConnected(providerName, req.body.connected);
|
||||
} catch (e) {
|
||||
if (e instanceof ProviderNotFoundError) {
|
||||
if (e instanceof ExternalSecretsProviderNotFoundError) {
|
||||
throw new NotFoundError(`Could not find provider "${e.providerName}"`);
|
||||
}
|
||||
throw e;
|
||||
|
@ -88,7 +89,7 @@ export class ExternalSecretsController {
|
|||
}
|
||||
return { updated: resp };
|
||||
} catch (e) {
|
||||
if (e instanceof ProviderNotFoundError) {
|
||||
if (e instanceof ExternalSecretsProviderNotFoundError) {
|
||||
throw new NotFoundError(`Could not find provider "${e.providerName}"`);
|
||||
}
|
||||
throw e;
|
||||
|
|
|
@ -5,12 +5,7 @@ import type { IDataObject } from 'n8n-workflow';
|
|||
import { deepCopy } from 'n8n-workflow';
|
||||
import Container, { Service } from 'typedi';
|
||||
import { ExternalSecretsManager } from './ExternalSecretsManager.ee';
|
||||
|
||||
export class ProviderNotFoundError extends Error {
|
||||
constructor(public providerName: string) {
|
||||
super(undefined);
|
||||
}
|
||||
}
|
||||
import { ExternalSecretsProviderNotFoundError } from '@/errors/external-secrets-provider-not-found.error';
|
||||
|
||||
@Service()
|
||||
export class ExternalSecretsService {
|
||||
|
@ -18,7 +13,7 @@ export class ExternalSecretsService {
|
|||
const providerAndSettings =
|
||||
Container.get(ExternalSecretsManager).getProviderWithSettings(providerName);
|
||||
if (!providerAndSettings) {
|
||||
throw new ProviderNotFoundError(providerName);
|
||||
throw new ExternalSecretsProviderNotFoundError(providerName);
|
||||
}
|
||||
const { provider, settings } = providerAndSettings;
|
||||
return {
|
||||
|
@ -110,7 +105,7 @@ export class ExternalSecretsService {
|
|||
const providerAndSettings =
|
||||
Container.get(ExternalSecretsManager).getProviderWithSettings(providerName);
|
||||
if (!providerAndSettings) {
|
||||
throw new ProviderNotFoundError(providerName);
|
||||
throw new ExternalSecretsProviderNotFoundError(providerName);
|
||||
}
|
||||
const { settings } = providerAndSettings;
|
||||
const newData = this.unredact(data, settings.settings);
|
||||
|
@ -121,7 +116,7 @@ export class ExternalSecretsService {
|
|||
const providerAndSettings =
|
||||
Container.get(ExternalSecretsManager).getProviderWithSettings(providerName);
|
||||
if (!providerAndSettings) {
|
||||
throw new ProviderNotFoundError(providerName);
|
||||
throw new ExternalSecretsProviderNotFoundError(providerName);
|
||||
}
|
||||
await Container.get(ExternalSecretsManager).setProviderConnected(providerName, connected);
|
||||
return this.getProvider(providerName);
|
||||
|
@ -135,7 +130,7 @@ export class ExternalSecretsService {
|
|||
const providerAndSettings =
|
||||
Container.get(ExternalSecretsManager).getProviderWithSettings(providerName);
|
||||
if (!providerAndSettings) {
|
||||
throw new ProviderNotFoundError(providerName);
|
||||
throw new ExternalSecretsProviderNotFoundError(providerName);
|
||||
}
|
||||
const { settings } = providerAndSettings;
|
||||
const newData = this.unredact(data, settings.settings);
|
||||
|
@ -146,7 +141,7 @@ export class ExternalSecretsService {
|
|||
const providerAndSettings =
|
||||
Container.get(ExternalSecretsManager).getProviderWithSettings(providerName);
|
||||
if (!providerAndSettings) {
|
||||
throw new ProviderNotFoundError(providerName);
|
||||
throw new ExternalSecretsProviderNotFoundError(providerName);
|
||||
}
|
||||
return Container.get(ExternalSecretsManager).updateProvider(providerName);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import { Container } from 'typedi';
|
|||
import { Like } from 'typeorm';
|
||||
import config from '@/config';
|
||||
import type { ExecutionPayload, ICredentialsDb, IWorkflowDb } from '@/Interfaces';
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import type { TagEntity } from '@db/entities/TagEntity';
|
||||
|
@ -20,6 +19,7 @@ import type { UserUpdatePayload } from '@/requests';
|
|||
import { CredentialsRepository } from '@db/repositories/credentials.repository';
|
||||
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||
import { BadRequestError } from './errors/response-errors/bad-request.error';
|
||||
|
||||
/**
|
||||
* Returns the base URL n8n is reachable from
|
||||
|
@ -109,7 +109,7 @@ export async function validateEntity(
|
|||
.join(' | ');
|
||||
|
||||
if (errorMessages) {
|
||||
throw new ResponseHelper.BadRequestError(errorMessages);
|
||||
throw new BadRequestError(errorMessages);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,13 +29,14 @@ import {
|
|||
isLdapCurrentAuthenticationMethod,
|
||||
setCurrentAuthenticationMethod,
|
||||
} from '@/sso/ssoHelpers';
|
||||
import { BadRequestError, InternalServerError } from '../ResponseHelper';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { Logger } from '@/Logger';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||
import { AuthProviderSyncHistoryRepository } from '@db/repositories/authProviderSyncHistory.repository';
|
||||
import { AuthIdentityRepository } from '@db/repositories/authIdentity.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
|
||||
/**
|
||||
* Check whether the LDAP feature is disabled in the instance
|
||||
|
|
|
@ -24,14 +24,6 @@ type FeatureReturnType = Partial<
|
|||
} & { [K in NumericLicenseFeature]: number } & { [K in BooleanLicenseFeature]: boolean }
|
||||
>;
|
||||
|
||||
export class FeatureNotLicensedError extends Error {
|
||||
constructor(feature: (typeof LICENSE_FEATURES)[keyof typeof LICENSE_FEATURES]) {
|
||||
super(
|
||||
`Your license does not allow for ${feature}. To enable ${feature}, please upgrade to a license that supports this feature.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Service()
|
||||
export class License {
|
||||
private manager: LicenseManager | undefined;
|
||||
|
|
|
@ -12,14 +12,7 @@ import { LoadNodesAndCredentials } from './LoadNodesAndCredentials';
|
|||
import { join, dirname } from 'path';
|
||||
import { readdir } from 'fs/promises';
|
||||
import type { Dirent } from 'fs';
|
||||
|
||||
class UnrecognizedNodeError extends Error {
|
||||
severity = 'warning';
|
||||
|
||||
constructor(nodeType: string) {
|
||||
super(`Unrecognized node type: ${nodeType}".`);
|
||||
}
|
||||
}
|
||||
import { UnrecognizedNodeTypeError } from './errors/unrecognized-node-type.error';
|
||||
|
||||
@Service()
|
||||
export class NodeTypes implements INodeTypes {
|
||||
|
@ -75,7 +68,7 @@ export class NodeTypes implements INodeTypes {
|
|||
return loadedNodes[type];
|
||||
}
|
||||
|
||||
throw new UnrecognizedNodeError(type);
|
||||
throw new UnrecognizedNodeTypeError(type);
|
||||
}
|
||||
|
||||
async getNodeTranslationPath({
|
||||
|
|
|
@ -12,76 +12,7 @@ import type {
|
|||
IWorkflowDb,
|
||||
} from '@/Interfaces';
|
||||
import { inDevelopment } from '@/constants';
|
||||
|
||||
/**
|
||||
* Special Error which allows to return also an error code and http status code
|
||||
*/
|
||||
abstract class ResponseError extends Error {
|
||||
/**
|
||||
* Creates an instance of ResponseError.
|
||||
* Must be used inside a block with `ResponseHelper.send()`.
|
||||
*/
|
||||
constructor(
|
||||
message: string,
|
||||
// The HTTP status code of response
|
||||
readonly httpStatusCode: number,
|
||||
// The error code in the response
|
||||
readonly errorCode: number = httpStatusCode,
|
||||
// The error hint the response
|
||||
readonly hint: string | undefined = undefined,
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'ResponseError';
|
||||
}
|
||||
}
|
||||
|
||||
export class BadRequestError extends ResponseError {
|
||||
constructor(message: string, errorCode?: number) {
|
||||
super(message, 400, errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
export class AuthError extends ResponseError {
|
||||
constructor(message: string, errorCode?: number) {
|
||||
super(message, 401, errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnauthorizedError extends ResponseError {
|
||||
constructor(message: string, hint: string | undefined = undefined) {
|
||||
super(message, 403, 403, hint);
|
||||
}
|
||||
}
|
||||
|
||||
export class NotFoundError extends ResponseError {
|
||||
constructor(message: string, hint: string | undefined = undefined) {
|
||||
super(message, 404, 404, hint);
|
||||
}
|
||||
}
|
||||
|
||||
export class ConflictError extends ResponseError {
|
||||
constructor(message: string, hint: string | undefined = undefined) {
|
||||
super(message, 409, 409, hint);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnprocessableRequestError extends ResponseError {
|
||||
constructor(message: string, hint: string | undefined = undefined) {
|
||||
super(message, 422, 422, hint);
|
||||
}
|
||||
}
|
||||
|
||||
export class InternalServerError extends ResponseError {
|
||||
constructor(message: string, errorCode = 500) {
|
||||
super(message, 500, errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
export class ServiceUnavailableError extends ResponseError {
|
||||
constructor(message: string, errorCode = 503) {
|
||||
super(message, 503, errorCode);
|
||||
}
|
||||
}
|
||||
import { ResponseError } from './errors/response-errors/abstract/response.error';
|
||||
|
||||
export function sendSuccessResponse(
|
||||
res: Response,
|
||||
|
|
|
@ -117,6 +117,8 @@ import { OrchestrationController } from './controllers/orchestration.controller'
|
|||
import { WorkflowHistoryController } from './workflows/workflowHistory/workflowHistory.controller.ee';
|
||||
import { InvitationController } from './controllers/invitation.controller';
|
||||
import { CollaborationService } from './collaboration/collaboration.service';
|
||||
import { BadRequestError } from './errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from './errors/response-errors/not-found.error';
|
||||
|
||||
const exec = promisify(callbackExec);
|
||||
|
||||
|
@ -466,9 +468,7 @@ export class Server extends AbstractServer {
|
|||
userId: req.user.id,
|
||||
});
|
||||
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
`Workflow with ID "${workflowId}" could not be found.`,
|
||||
);
|
||||
throw new BadRequestError(`Workflow with ID "${workflowId}" could not be found.`);
|
||||
}
|
||||
|
||||
return this.activeWorkflowRunner.getActivationError(workflowId);
|
||||
|
@ -491,7 +491,7 @@ export class Server extends AbstractServer {
|
|||
const parameters = toHttpNodeParameters(curlCommand);
|
||||
return ResponseHelper.flattenObject(parameters, 'parameters');
|
||||
} catch (e) {
|
||||
throw new ResponseHelper.BadRequestError('Invalid cURL command');
|
||||
throw new BadRequestError('Invalid cURL command');
|
||||
}
|
||||
},
|
||||
),
|
||||
|
@ -624,7 +624,7 @@ export class Server extends AbstractServer {
|
|||
const sharedWorkflowIds = await getSharedWorkflowIds(req.user);
|
||||
|
||||
if (!sharedWorkflowIds.length) {
|
||||
throw new ResponseHelper.NotFoundError('Execution not found');
|
||||
throw new NotFoundError('Execution not found');
|
||||
}
|
||||
|
||||
const fullExecutionData = await Container.get(ExecutionRepository).findSingleExecution(
|
||||
|
@ -637,7 +637,7 @@ export class Server extends AbstractServer {
|
|||
);
|
||||
|
||||
if (!fullExecutionData) {
|
||||
throw new ResponseHelper.NotFoundError('Execution not found');
|
||||
throw new NotFoundError('Execution not found');
|
||||
}
|
||||
|
||||
if (config.getEnv('executions.mode') === 'queue') {
|
||||
|
|
|
@ -20,9 +20,9 @@ import type {
|
|||
} from '@/Interfaces';
|
||||
import { Push } from '@/push';
|
||||
import { NodeTypes } from '@/NodeTypes';
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import * as WebhookHelpers from '@/WebhookHelpers';
|
||||
import { webhookNotFoundErrorMessage } from './utils';
|
||||
import { NotFoundError } from './errors/response-errors/not-found.error';
|
||||
|
||||
const WEBHOOK_TEST_UNREGISTERED_HINT =
|
||||
"Click the 'Execute workflow' button on the canvas, then try again. (In test mode, the webhook only works for one call after you click this button)";
|
||||
|
@ -80,7 +80,7 @@ export class TestWebhooks implements IWebhookManager {
|
|||
if (webhookData === undefined) {
|
||||
// The requested webhook is not registered
|
||||
const methods = await this.getWebhookMethods(path);
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
throw new NotFoundError(
|
||||
webhookNotFoundErrorMessage(path, httpMethod, methods),
|
||||
WEBHOOK_TEST_UNREGISTERED_HINT,
|
||||
);
|
||||
|
@ -108,7 +108,7 @@ export class TestWebhooks implements IWebhookManager {
|
|||
if (testWebhookData[webhookKey] === undefined) {
|
||||
// The requested webhook is not registered
|
||||
const methods = await this.getWebhookMethods(path);
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
throw new NotFoundError(
|
||||
webhookNotFoundErrorMessage(path, httpMethod, methods),
|
||||
WEBHOOK_TEST_UNREGISTERED_HINT,
|
||||
);
|
||||
|
@ -121,7 +121,7 @@ export class TestWebhooks implements IWebhookManager {
|
|||
// get additional data
|
||||
const workflowStartNode = workflow.getNode(webhookData.node);
|
||||
if (workflowStartNode === null) {
|
||||
throw new ResponseHelper.NotFoundError('Could not find node to process webhook.');
|
||||
throw new NotFoundError('Could not find node to process webhook.');
|
||||
}
|
||||
|
||||
return new Promise(async (resolve, reject) => {
|
||||
|
@ -168,10 +168,7 @@ export class TestWebhooks implements IWebhookManager {
|
|||
const webhookMethods = this.activeWebhooks.getWebhookMethods(path);
|
||||
if (!webhookMethods.length) {
|
||||
// The requested webhook is not registered
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
webhookNotFoundErrorMessage(path),
|
||||
WEBHOOK_TEST_UNREGISTERED_HINT,
|
||||
);
|
||||
throw new NotFoundError(webhookNotFoundErrorMessage(path), WEBHOOK_TEST_UNREGISTERED_HINT);
|
||||
}
|
||||
|
||||
return webhookMethods;
|
||||
|
|
|
@ -2,7 +2,6 @@ import { In } from 'typeorm';
|
|||
import { compare, genSaltSync, hash } from 'bcryptjs';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import type { WhereClause } from '@/Interfaces';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { MAX_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH } from '@db/entities/User';
|
||||
|
@ -11,6 +10,7 @@ import { License } from '@/License';
|
|||
import { getWebhookBaseUrl } from '@/WebhookHelpers';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
export function isSharingEnabled(): boolean {
|
||||
return Container.get(License).isSharingEnabled();
|
||||
|
@ -43,7 +43,7 @@ export function generateUserInviteUrl(inviterId: string, inviteeId: string): str
|
|||
// TODO: Enforce at model level
|
||||
export function validatePassword(password?: string): string {
|
||||
if (!password) {
|
||||
throw new ResponseHelper.BadRequestError('Password is mandatory');
|
||||
throw new BadRequestError('Password is mandatory');
|
||||
}
|
||||
|
||||
const hasInvalidLength =
|
||||
|
@ -70,7 +70,7 @@ export function validatePassword(password?: string): string {
|
|||
message.push('Password must contain at least 1 uppercase letter.');
|
||||
}
|
||||
|
||||
throw new ResponseHelper.BadRequestError(message.join(' '));
|
||||
throw new BadRequestError(message.join(' '));
|
||||
}
|
||||
|
||||
return password;
|
||||
|
|
|
@ -2,7 +2,6 @@ import { NodeHelpers, Workflow } from 'n8n-workflow';
|
|||
import { Service } from 'typedi';
|
||||
import type express from 'express';
|
||||
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import * as WebhookHelpers from '@/WebhookHelpers';
|
||||
import { NodeTypes } from '@/NodeTypes';
|
||||
import type {
|
||||
|
@ -15,6 +14,8 @@ import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData'
|
|||
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||
import { OwnershipService } from './services/ownership.service';
|
||||
import { Logger } from '@/Logger';
|
||||
import { ConflictError } from './errors/response-errors/conflict.error';
|
||||
import { NotFoundError } from './errors/response-errors/not-found.error';
|
||||
|
||||
@Service()
|
||||
export class WaitingWebhooks implements IWebhookManager {
|
||||
|
@ -43,11 +44,11 @@ export class WaitingWebhooks implements IWebhookManager {
|
|||
});
|
||||
|
||||
if (!execution) {
|
||||
throw new ResponseHelper.NotFoundError(`The execution "${executionId} does not exist.`);
|
||||
throw new NotFoundError(`The execution "${executionId} does not exist.`);
|
||||
}
|
||||
|
||||
if (execution.finished || execution.data.resultData.error) {
|
||||
throw new ResponseHelper.ConflictError(`The execution "${executionId} has finished already.`);
|
||||
throw new ConflictError(`The execution "${executionId} has finished already.`);
|
||||
}
|
||||
|
||||
const lastNodeExecuted = execution.data.resultData.lastNodeExecuted as string;
|
||||
|
@ -79,12 +80,12 @@ export class WaitingWebhooks implements IWebhookManager {
|
|||
try {
|
||||
workflowOwner = await this.ownershipService.getWorkflowOwnerCached(workflowData.id!);
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.NotFoundError('Could not find workflow');
|
||||
throw new NotFoundError('Could not find workflow');
|
||||
}
|
||||
|
||||
const workflowStartNode = workflow.getNode(lastNodeExecuted);
|
||||
if (workflowStartNode === null) {
|
||||
throw new ResponseHelper.NotFoundError('Could not find node to process webhook.');
|
||||
throw new NotFoundError('Could not find node to process webhook.');
|
||||
}
|
||||
|
||||
const additionalData = await WorkflowExecuteAdditionalData.getBase(workflowOwner.id);
|
||||
|
@ -103,7 +104,7 @@ export class WaitingWebhooks implements IWebhookManager {
|
|||
// If no data got found it means that the execution can not be started via a webhook.
|
||||
// Return 404 because we do not want to give any data if the execution exists or not.
|
||||
const errorMessage = `The workflow for execution "${executionId}" does not contain a waiting webhook with a matching path/method.`;
|
||||
throw new ResponseHelper.NotFoundError(errorMessage);
|
||||
throw new NotFoundError(errorMessage);
|
||||
}
|
||||
|
||||
const runExecutionData = execution.data;
|
||||
|
|
|
@ -63,6 +63,9 @@ import { OwnershipService } from './services/ownership.service';
|
|||
import { parseBody } from './middlewares';
|
||||
import { WorkflowsService } from './workflows/workflows.services';
|
||||
import { Logger } from './Logger';
|
||||
import { NotFoundError } from './errors/response-errors/not-found.error';
|
||||
import { InternalServerError } from './errors/response-errors/internal-server.error';
|
||||
import { UnprocessableRequestError } from './errors/response-errors/unprocessable.error';
|
||||
|
||||
const pipeline = promisify(stream.pipeline);
|
||||
|
||||
|
@ -237,7 +240,7 @@ export async function executeWebhook(
|
|||
if (nodeType === undefined) {
|
||||
const errorMessage = `The type of the webhook node "${workflowStartNode.name}" is not known`;
|
||||
responseCallback(new Error(errorMessage), {});
|
||||
throw new ResponseHelper.InternalServerError(errorMessage);
|
||||
throw new InternalServerError(errorMessage);
|
||||
}
|
||||
|
||||
const additionalKeys: IWorkflowDataProxyAdditionalKeys = {
|
||||
|
@ -254,7 +257,7 @@ export async function executeWebhook(
|
|||
try {
|
||||
user = await Container.get(OwnershipService).getWorkflowOwnerCached(workflowData.id);
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.NotFoundError('Cannot find workflow');
|
||||
throw new NotFoundError('Cannot find workflow');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,7 +297,7 @@ export async function executeWebhook(
|
|||
// that something does not resolve properly.
|
||||
const errorMessage = `The response mode '${responseMode}' is not valid!`;
|
||||
responseCallback(new Error(errorMessage), {});
|
||||
throw new ResponseHelper.InternalServerError(errorMessage);
|
||||
throw new InternalServerError(errorMessage);
|
||||
}
|
||||
|
||||
// Add the Response and Request so that this data can be accessed in the node
|
||||
|
@ -781,13 +784,13 @@ export async function executeWebhook(
|
|||
responseCallback(new Error('There was a problem executing the workflow'), {});
|
||||
}
|
||||
|
||||
throw new ResponseHelper.InternalServerError(e.message);
|
||||
throw new InternalServerError(e.message);
|
||||
});
|
||||
}
|
||||
return executionId;
|
||||
} catch (e) {
|
||||
const error =
|
||||
e instanceof ResponseHelper.UnprocessableRequestError
|
||||
e instanceof UnprocessableRequestError
|
||||
? e
|
||||
: new Error('There was a problem executing the workflow', { cause: e });
|
||||
if (didSendResponse) throw error;
|
||||
|
|
|
@ -4,11 +4,12 @@ import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES } from '@/constants';
|
|||
import type { JwtPayload, JwtToken } from '@/Interfaces';
|
||||
import type { User } from '@db/entities/User';
|
||||
import config from '@/config';
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import { License } from '@/License';
|
||||
import { Container } from 'typedi';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { JwtService } from '@/services/jwt.service';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
|
||||
export function issueJWT(user: User): JwtToken {
|
||||
const { id, email, password } = user;
|
||||
|
@ -26,7 +27,7 @@ export function issueJWT(user: User): JwtToken {
|
|||
!user.isOwner &&
|
||||
!isWithinUsersLimit
|
||||
) {
|
||||
throw new ResponseHelper.UnauthorizedError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED);
|
||||
throw new UnauthorizedError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED);
|
||||
}
|
||||
if (password) {
|
||||
payload.password = createHash('sha256')
|
||||
|
@ -63,7 +64,7 @@ export async function resolveJwtContent(jwtPayload: JwtPayload): Promise<User> {
|
|||
// currently only LDAP users during synchronization
|
||||
// can be set to disabled
|
||||
if (user?.disabled) {
|
||||
throw new ResponseHelper.AuthError('Unauthorized');
|
||||
throw new AuthError('Unauthorized');
|
||||
}
|
||||
|
||||
if (!user || jwtPayload.password !== passwordHash || user.email !== jwtPayload.email) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import type { User } from '@db/entities/User';
|
||||
import { compareHash } from '@/UserManagement/UserManagementHelper';
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import { Container } from 'typedi';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { isLdapLoginEnabled } from '@/Ldap/helpers';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
|
||||
export const handleEmailLogin = async (
|
||||
email: string,
|
||||
|
@ -27,7 +27,7 @@ export const handleEmailLogin = async (
|
|||
user_id: user.id,
|
||||
});
|
||||
|
||||
throw new ResponseHelper.AuthError('Reset your password to gain access to the instance.');
|
||||
throw new AuthError('Reset your password to gain access to the instance.');
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
|
|
@ -23,7 +23,7 @@ import { EDITOR_UI_DIST_DIR, LICENSE_FEATURES } from '@/constants';
|
|||
import { eventBus } from '@/eventbus';
|
||||
import { BaseCommand } from './BaseCommand';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { License, FeatureNotLicensedError } from '@/License';
|
||||
import { License } from '@/License';
|
||||
import type { IConfig } from '@oclif/config';
|
||||
import { SingleMainSetup } from '@/services/orchestration/main/SingleMainSetup';
|
||||
import { OrchestrationHandlerMainService } from '@/services/orchestration/main/orchestration.handler.main.service';
|
||||
|
@ -31,6 +31,7 @@ import { PruningService } from '@/services/pruning.service';
|
|||
import { MultiMainSetup } from '@/services/orchestration/main/MultiMainSetup.ee';
|
||||
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||
import { FeatureNotLicensedError } from '@/errors/feature-not-licensed.error';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
|
||||
const open = require('open');
|
||||
|
|
|
@ -40,6 +40,7 @@ import type { IConfig } from '@oclif/config';
|
|||
import { OrchestrationHandlerWorkerService } from '@/services/orchestration/worker/orchestration.handler.worker.service';
|
||||
import { OrchestrationWorkerService } from '@/services/orchestration/worker/orchestration.worker.service';
|
||||
import type { WorkerJobStatusSummary } from '../services/orchestration/worker/types';
|
||||
import { ServiceUnavailableError } from '@/errors/response-errors/service-unavailable.error';
|
||||
|
||||
export class Worker extends BaseCommand {
|
||||
static description = '\nStarts a n8n worker';
|
||||
|
@ -413,7 +414,7 @@ export class Worker extends BaseCommand {
|
|||
await connection.query('SELECT 1');
|
||||
} catch (e) {
|
||||
this.logger.error('No Database connection!', e as Error);
|
||||
const error = new ResponseHelper.ServiceUnavailableError('No Database connection!');
|
||||
const error = new ServiceUnavailableError('No Database connection!');
|
||||
return ResponseHelper.sendErrorResponse(res, error);
|
||||
}
|
||||
|
||||
|
@ -424,7 +425,7 @@ export class Worker extends BaseCommand {
|
|||
await Worker.jobQueue.ping();
|
||||
} catch (e) {
|
||||
this.logger.error('No Redis connection!', e as Error);
|
||||
const error = new ResponseHelper.ServiceUnavailableError('No Redis connection!');
|
||||
const error = new ServiceUnavailableError('No Redis connection!');
|
||||
return ResponseHelper.sendErrorResponse(res, error);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
import { NotStringArrayError } from '@/errors/not-string-array.error';
|
||||
import type { SchemaObj } from 'convict';
|
||||
|
||||
class NotStringArrayError extends Error {
|
||||
constructor(env: string) {
|
||||
super(`${env} is not a string array.`);
|
||||
}
|
||||
}
|
||||
|
||||
export const ensureStringArray = (values: string[], { env }: SchemaObj<string>) => {
|
||||
if (!env) throw new Error(`Missing env: ${env}`);
|
||||
|
||||
|
|
|
@ -2,12 +2,6 @@ import validator from 'validator';
|
|||
import { In } from 'typeorm';
|
||||
import { Service } from 'typedi';
|
||||
import { Authorized, Get, Post, RestController } from '@/decorators';
|
||||
import {
|
||||
AuthError,
|
||||
BadRequestError,
|
||||
InternalServerError,
|
||||
UnauthorizedError,
|
||||
} from '@/ResponseHelper';
|
||||
import { issueCookie, resolveJwt } from '@/auth/jwt';
|
||||
import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES } from '@/constants';
|
||||
import { Request, Response } from 'express';
|
||||
|
@ -27,6 +21,10 @@ import { License } from '@/License';
|
|||
import { UserService } from '@/services/user.service';
|
||||
import { MfaService } from '@/Mfa/mfa.service';
|
||||
import { Logger } from '@/Logger';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
|
||||
@Service()
|
||||
@RestController()
|
||||
|
|
|
@ -8,12 +8,13 @@ import {
|
|||
} from '@/constants';
|
||||
import { Authorized, Delete, Get, Middleware, Patch, Post, RestController } from '@/decorators';
|
||||
import { NodeRequest } from '@/requests';
|
||||
import { BadRequestError, InternalServerError } from '@/ResponseHelper';
|
||||
import type { InstalledPackages } from '@db/entities/InstalledPackages';
|
||||
import type { CommunityPackages } from '@/Interfaces';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { Push } from '@/push';
|
||||
import { CommunityPackagesService } from '@/services/communityPackages.service';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
|
||||
const {
|
||||
PACKAGE_NOT_INSTALLED,
|
||||
|
|
|
@ -12,7 +12,7 @@ import { Authorized, Get, Middleware, RestController } from '@/decorators';
|
|||
import { getBase } from '@/WorkflowExecuteAdditionalData';
|
||||
import { DynamicNodeParametersService } from '@/services/dynamicNodeParameters.service';
|
||||
import { DynamicNodeParametersRequest } from '@/requests';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
const assertMethodName: RequestHandler = (req, res, next) => {
|
||||
const { methodName } = req.query as DynamicNodeParametersRequest.BaseRequest['query'];
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { In } from 'typeorm';
|
||||
import Container, { Service } from 'typedi';
|
||||
import { Authorized, NoAuthRequired, Post, RestController } from '@/decorators';
|
||||
import { BadRequestError, UnauthorizedError } from '@/ResponseHelper';
|
||||
import { issueCookie } from '@/auth/jwt';
|
||||
import { RESPONSE_ERROR_MESSAGES } from '@/constants';
|
||||
import { Response } from 'express';
|
||||
|
@ -16,6 +15,8 @@ import { hashPassword, validatePassword } from '@/UserManagement/UserManagementH
|
|||
import { PostHogClient } from '@/posthog';
|
||||
import type { User } from '@/databases/entities/User';
|
||||
import validator from 'validator';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
|
||||
@Service()
|
||||
@RestController('/invitations')
|
||||
|
|
|
@ -4,9 +4,9 @@ import { getLdapConfig, getLdapSynchronizations, updateLdapConfig } from '@/Ldap
|
|||
import { LdapService } from '@/Ldap/LdapService.ee';
|
||||
import { LdapSync } from '@/Ldap/LdapSync.ee';
|
||||
import { LdapConfiguration } from '@/Ldap/types';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import { NON_SENSIBLE_LDAP_CONFIG_PROPERTIES } from '@/Ldap/constants';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@Authorized(['global', 'owner'])
|
||||
@RestController('/ldap')
|
||||
|
|
|
@ -5,7 +5,6 @@ import { Service } from 'typedi';
|
|||
import { randomBytes } from 'crypto';
|
||||
import { Authorized, Delete, Get, Patch, Post, RestController } from '@/decorators';
|
||||
import { compareHash, hashPassword, validatePassword } from '@/UserManagement/UserManagementHelper';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import { issueCookie } from '@/auth/jwt';
|
||||
import type { User } from '@db/entities/User';
|
||||
|
@ -21,6 +20,7 @@ import { UserService } from '@/services/user.service';
|
|||
import { Logger } from '@/Logger';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Service } from 'typedi';
|
||||
import { Authorized, Delete, Get, Post, RestController } from '@/decorators';
|
||||
import { AuthenticatedRequest, MFA } from '@/requests';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import { MfaService } from '@/Mfa/mfa.service';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
|
|
|
@ -9,12 +9,13 @@ import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.
|
|||
import type { ICredentialsDb } from '@/Interfaces';
|
||||
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
|
||||
import type { OAuthRequest } from '@/requests';
|
||||
import { BadRequestError, NotFoundError } from '@/ResponseHelper';
|
||||
import { RESPONSE_ERROR_MESSAGES } from '@/constants';
|
||||
import { CredentialsHelper } from '@/CredentialsHelper';
|
||||
import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData';
|
||||
import { Logger } from '@/Logger';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
|
||||
@Service()
|
||||
export abstract class AbstractOAuthController {
|
||||
|
|
|
@ -8,8 +8,10 @@ import { createHmac } from 'crypto';
|
|||
import { RESPONSE_ERROR_MESSAGES } from '@/constants';
|
||||
import { Authorized, Get, RestController } from '@/decorators';
|
||||
import { OAuthRequest } from '@/requests';
|
||||
import { NotFoundError, sendErrorResponse, ServiceUnavailableError } from '@/ResponseHelper';
|
||||
import { sendErrorResponse } from '@/ResponseHelper';
|
||||
import { AbstractOAuthController } from './abstractOAuth.controller';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { ServiceUnavailableError } from '@/errors/response-errors/service-unavailable.error';
|
||||
|
||||
interface OAuth1CredentialData {
|
||||
signatureMethod: 'HMAC-SHA256' | 'HMAC-SHA512' | 'HMAC-SHA1';
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import validator from 'validator';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import { Authorized, Post, RestController } from '@/decorators';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import { hashPassword, validatePassword } from '@/UserManagement/UserManagementHelper';
|
||||
import { issueCookie } from '@/auth/jwt';
|
||||
import { Response } from 'express';
|
||||
|
@ -12,6 +11,7 @@ import { SettingsRepository } from '@db/repositories/settings.repository';
|
|||
import { PostHogClient } from '@/posthog';
|
||||
import { UserService } from '@/services/user.service';
|
||||
import { Logger } from '@/Logger';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@Authorized(['global', 'owner'])
|
||||
@RestController('/owner')
|
||||
|
|
|
@ -5,13 +5,6 @@ import { IsNull, Not } from 'typeorm';
|
|||
import validator from 'validator';
|
||||
|
||||
import { Get, Post, RestController } from '@/decorators';
|
||||
import {
|
||||
BadRequestError,
|
||||
InternalServerError,
|
||||
NotFoundError,
|
||||
UnauthorizedError,
|
||||
UnprocessableRequestError,
|
||||
} from '@/ResponseHelper';
|
||||
import {
|
||||
getInstanceBaseUrl,
|
||||
hashPassword,
|
||||
|
@ -29,6 +22,11 @@ import { MfaService } from '@/Mfa/mfa.service';
|
|||
import { Logger } from '@/Logger';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { UnprocessableRequestError } from '@/errors/response-errors/unprocessable.error';
|
||||
|
||||
const throttle = rateLimit({
|
||||
windowMs: 5 * 60 * 1000, // 5 minutes
|
||||
|
|
|
@ -2,9 +2,9 @@ import { Request, Response, NextFunction } from 'express';
|
|||
import config from '@/config';
|
||||
import { Authorized, Delete, Get, Middleware, Patch, Post, RestController } from '@/decorators';
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import { TagsRequest } from '@/requests';
|
||||
import { Service } from 'typedi';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@Authorized()
|
||||
@RestController('/tags')
|
||||
|
|
|
@ -3,9 +3,10 @@ import { ICredentialTypes } from 'n8n-workflow';
|
|||
import { join } from 'path';
|
||||
import { access } from 'fs/promises';
|
||||
import { Authorized, Get, RestController } from '@/decorators';
|
||||
import { BadRequestError, InternalServerError } from '@/ResponseHelper';
|
||||
import { Config } from '@/config';
|
||||
import { NODES_BASE_DIR } from '@/constants';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
|
||||
export const CREDENTIAL_TRANSLATIONS_DIR = 'n8n-nodes-base/dist/credentials/translations';
|
||||
export const NODE_HEADERS_PATH = join(NODES_BASE_DIR, 'dist/nodes/headers');
|
||||
|
|
|
@ -4,7 +4,6 @@ import { User } from '@db/entities/User';
|
|||
import { SharedCredentials } from '@db/entities/SharedCredentials';
|
||||
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import { Authorized, Delete, Get, RestController, Patch } from '@/decorators';
|
||||
import { BadRequestError, NotFoundError, UnauthorizedError } from '@/ResponseHelper';
|
||||
import { ListQuery, UserRequest, UserSettingsUpdatePayload } from '@/requests';
|
||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||
import { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces';
|
||||
|
@ -17,6 +16,9 @@ import { RoleService } from '@/services/role.service';
|
|||
import { UserService } from '@/services/user.service';
|
||||
import { listQueryMiddleware } from '@/middlewares';
|
||||
import { Logger } from '@/Logger';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@Authorized()
|
||||
@RestController('/users')
|
||||
|
|
|
@ -7,9 +7,9 @@ import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.reposi
|
|||
import { WorkflowStatisticsRepository } from '@db/repositories/workflowStatistics.repository';
|
||||
import { ExecutionRequest } from '@/requests';
|
||||
import { whereClause } from '@/UserManagement/UserManagementHelper';
|
||||
import { NotFoundError } from '@/ResponseHelper';
|
||||
import type { IWorkflowStatisticsDataLoaded } from '@/Interfaces';
|
||||
import { Logger } from '@/Logger';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
|
||||
interface WorkflowStatisticsData<T> {
|
||||
productionSuccess: T;
|
||||
|
|
|
@ -11,6 +11,9 @@ import { OwnershipService } from '@/services/ownership.service';
|
|||
import { Container } from 'typedi';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
|
||||
export const EECredentialsController = express.Router();
|
||||
|
||||
|
@ -40,7 +43,7 @@ EECredentialsController.get(
|
|||
)) as CredentialsEntity;
|
||||
|
||||
if (!credential) {
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
throw new NotFoundError(
|
||||
'Could not load the credential. If you think this is an error, ask the owner to share it with you again',
|
||||
);
|
||||
}
|
||||
|
@ -48,7 +51,7 @@ EECredentialsController.get(
|
|||
const userSharing = credential.shared?.find((shared) => shared.user.id === req.user.id);
|
||||
|
||||
if (!userSharing && req.user.globalRole.name !== 'owner') {
|
||||
throw new ResponseHelper.UnauthorizedError('Forbidden.');
|
||||
throw new UnauthorizedError('Forbidden.');
|
||||
}
|
||||
|
||||
credential = Container.get(OwnershipService).addOwnedByAndSharedWith(credential);
|
||||
|
@ -82,7 +85,7 @@ EECredentialsController.post(
|
|||
const sharing = await EECredentials.getSharing(req.user, credentialId);
|
||||
if (!ownsCredential) {
|
||||
if (!sharing) {
|
||||
throw new ResponseHelper.UnauthorizedError('Forbidden');
|
||||
throw new UnauthorizedError('Forbidden');
|
||||
}
|
||||
|
||||
const decryptedData = EECredentials.decrypt(sharing.credentials);
|
||||
|
@ -115,12 +118,12 @@ EECredentialsController.put(
|
|||
!Array.isArray(shareWithIds) ||
|
||||
!shareWithIds.every((userId) => typeof userId === 'string')
|
||||
) {
|
||||
throw new ResponseHelper.BadRequestError('Bad request');
|
||||
throw new BadRequestError('Bad request');
|
||||
}
|
||||
|
||||
const { ownsCredential, credential } = await EECredentials.isOwned(req.user, credentialId);
|
||||
if (!ownsCredential || !credential) {
|
||||
throw new ResponseHelper.UnauthorizedError('Forbidden');
|
||||
throw new UnauthorizedError('Forbidden');
|
||||
}
|
||||
|
||||
let amountRemoved: number | null = null;
|
||||
|
|
|
@ -14,6 +14,7 @@ import { Container } from 'typedi';
|
|||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { listQueryMiddleware } from '@/middlewares';
|
||||
import { Logger } from '@/Logger';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
|
||||
export const credentialsController = express.Router();
|
||||
credentialsController.use('/', EECredentialsController);
|
||||
|
@ -60,9 +61,7 @@ credentialsController.get(
|
|||
const sharing = await CredentialsService.getSharing(req.user, credentialId, ['credentials']);
|
||||
|
||||
if (!sharing) {
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`Credential with ID "${credentialId}" could not be found.`,
|
||||
);
|
||||
throw new NotFoundError(`Credential with ID "${credentialId}" could not be found.`);
|
||||
}
|
||||
|
||||
const { credentials: credential } = sharing;
|
||||
|
@ -145,7 +144,7 @@ credentialsController.patch(
|
|||
userId: req.user.id,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
throw new NotFoundError(
|
||||
'Credential to be updated not found. You can only update credentials owned by you',
|
||||
);
|
||||
}
|
||||
|
@ -165,9 +164,7 @@ credentialsController.patch(
|
|||
const responseData = await CredentialsService.update(credentialId, newCredentialData);
|
||||
|
||||
if (responseData === null) {
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`Credential ID "${credentialId}" could not be found to be updated.`,
|
||||
);
|
||||
throw new NotFoundError(`Credential ID "${credentialId}" could not be found to be updated.`);
|
||||
}
|
||||
|
||||
// Remove the encrypted data as it is not needed in the frontend
|
||||
|
@ -197,7 +194,7 @@ credentialsController.delete(
|
|||
userId: req.user.id,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
throw new NotFoundError(
|
||||
'Credential to be deleted not found. You can only removed credentials owned by you',
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,11 +12,11 @@ import { SourceControlPreferencesService } from './sourceControlPreferences.serv
|
|||
import type { SourceControlPreferences } from './types/sourceControlPreferences';
|
||||
import type { SourceControlledFile } from './types/sourceControlledFile';
|
||||
import { SOURCE_CONTROL_API_ROOT, SOURCE_CONTROL_DEFAULT_BRANCH } from './constants';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import type { ImportResult } from './types/importResult';
|
||||
import { InternalHooks } from '../../InternalHooks';
|
||||
import { getRepoType } from './sourceControlHelper.ee';
|
||||
import { SourceControlGetStatus } from './types/sourceControlGetStatus';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@Service()
|
||||
@RestController(`/${SOURCE_CONTROL_API_ROOT}`)
|
||||
|
|
|
@ -17,7 +17,6 @@ import {
|
|||
import { SourceControlGitService } from './sourceControlGit.service.ee';
|
||||
import type { PushResult } from 'simple-git';
|
||||
import { SourceControlExportService } from './sourceControlExport.service.ee';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import type { ImportResult } from './types/importResult';
|
||||
import type { SourceControlPushWorkFolder } from './types/sourceControlPushWorkFolder';
|
||||
import type { SourceControllPullOptions } from './types/sourceControlPullWorkFolder';
|
||||
|
@ -35,6 +34,7 @@ import type { ExportableCredential } from './types/exportableCredential';
|
|||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { TagRepository } from '@db/repositories/tag.repository';
|
||||
import { Logger } from '@/Logger';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@Service()
|
||||
export class SourceControlService {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { Container, Service } from 'typedi';
|
||||
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import { VariablesRequest } from '@/requests';
|
||||
import { Authorized, Delete, Get, Licensed, Patch, Post, RestController } from '@/decorators';
|
||||
import {
|
||||
VariablesService,
|
||||
VariablesLicenseError,
|
||||
VariablesValidationError,
|
||||
} from './variables.service.ee';
|
||||
import { VariablesService } from './variables.service.ee';
|
||||
import { Logger } from '@/Logger';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { VariableValidationError } from '@/errors/variable-validation.error';
|
||||
import { VariableCountLimitReachedError } from '@/errors/variable-count-limit-reached.error';
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
|
@ -31,17 +31,17 @@ export class VariablesController {
|
|||
this.logger.info('Attempt to update a variable blocked due to lack of permissions', {
|
||||
userId: req.user.id,
|
||||
});
|
||||
throw new ResponseHelper.UnauthorizedError('Unauthorized');
|
||||
throw new UnauthorizedError('Unauthorized');
|
||||
}
|
||||
const variable = req.body;
|
||||
delete variable.id;
|
||||
try {
|
||||
return await Container.get(VariablesService).create(variable);
|
||||
} catch (error) {
|
||||
if (error instanceof VariablesLicenseError) {
|
||||
throw new ResponseHelper.BadRequestError(error.message);
|
||||
} else if (error instanceof VariablesValidationError) {
|
||||
throw new ResponseHelper.BadRequestError(error.message);
|
||||
if (error instanceof VariableCountLimitReachedError) {
|
||||
throw new BadRequestError(error.message);
|
||||
} else if (error instanceof VariableValidationError) {
|
||||
throw new BadRequestError(error.message);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ export class VariablesController {
|
|||
const id = req.params.id;
|
||||
const variable = await Container.get(VariablesService).getCached(id);
|
||||
if (variable === null) {
|
||||
throw new ResponseHelper.NotFoundError(`Variable with id ${req.params.id} not found`);
|
||||
throw new NotFoundError(`Variable with id ${req.params.id} not found`);
|
||||
}
|
||||
return variable;
|
||||
}
|
||||
|
@ -66,17 +66,17 @@ export class VariablesController {
|
|||
id,
|
||||
userId: req.user.id,
|
||||
});
|
||||
throw new ResponseHelper.UnauthorizedError('Unauthorized');
|
||||
throw new UnauthorizedError('Unauthorized');
|
||||
}
|
||||
const variable = req.body;
|
||||
delete variable.id;
|
||||
try {
|
||||
return await Container.get(VariablesService).update(id, variable);
|
||||
} catch (error) {
|
||||
if (error instanceof VariablesLicenseError) {
|
||||
throw new ResponseHelper.BadRequestError(error.message);
|
||||
} else if (error instanceof VariablesValidationError) {
|
||||
throw new ResponseHelper.BadRequestError(error.message);
|
||||
if (error instanceof VariableCountLimitReachedError) {
|
||||
throw new BadRequestError(error.message);
|
||||
} else if (error instanceof VariableValidationError) {
|
||||
throw new BadRequestError(error.message);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ export class VariablesController {
|
|||
id,
|
||||
userId: req.user.id,
|
||||
});
|
||||
throw new ResponseHelper.UnauthorizedError('Unauthorized');
|
||||
throw new UnauthorizedError('Unauthorized');
|
||||
}
|
||||
await this.variablesService.delete(id);
|
||||
|
||||
|
|
|
@ -6,9 +6,8 @@ import { canCreateNewVariable } from './enviromentHelpers';
|
|||
import { CacheService } from '@/services/cache.service';
|
||||
import { VariablesRepository } from '@db/repositories/variables.repository';
|
||||
import type { DeepPartial } from 'typeorm';
|
||||
|
||||
export class VariablesLicenseError extends Error {}
|
||||
export class VariablesValidationError extends Error {}
|
||||
import { VariableCountLimitReachedError } from '@/errors/variable-count-limit-reached.error';
|
||||
import { VariableValidationError } from '@/errors/variable-validation.error';
|
||||
|
||||
@Service()
|
||||
export class VariablesService {
|
||||
|
@ -59,19 +58,19 @@ export class VariablesService {
|
|||
|
||||
validateVariable(variable: Omit<Variables, 'id'>): void {
|
||||
if (variable.key.length > 50) {
|
||||
throw new VariablesValidationError('key cannot be longer than 50 characters');
|
||||
throw new VariableValidationError('key cannot be longer than 50 characters');
|
||||
}
|
||||
if (variable.key.replace(/[A-Za-z0-9_]/g, '').length !== 0) {
|
||||
throw new VariablesValidationError('key can only contain characters A-Za-z0-9_');
|
||||
throw new VariableValidationError('key can only contain characters A-Za-z0-9_');
|
||||
}
|
||||
if (variable.value?.length > 255) {
|
||||
throw new VariablesValidationError('value cannot be longer than 255 characters');
|
||||
throw new VariableValidationError('value cannot be longer than 255 characters');
|
||||
}
|
||||
}
|
||||
|
||||
async create(variable: Omit<Variables, 'id'>): Promise<Variables> {
|
||||
if (!canCreateNewVariable(await this.getCount())) {
|
||||
throw new VariablesLicenseError('Variables limit reached');
|
||||
throw new VariableCountLimitReachedError('Variables limit reached');
|
||||
}
|
||||
this.validateVariable(variable);
|
||||
|
||||
|
|
10
packages/cli/src/errors/credential-not-found.error.ts
Normal file
10
packages/cli/src/errors/credential-not-found.error.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { ApplicationError, type Severity } from 'n8n-workflow';
|
||||
|
||||
export class CredentialNotFoundError extends ApplicationError {
|
||||
severity: Severity;
|
||||
|
||||
constructor(credentialId: string, credentialType: string) {
|
||||
super(`Credential with ID "${credentialId}" does not exist for type "${credentialType}".`);
|
||||
this.severity = 'warning';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
export class ExternalSecretsProviderNotFoundError extends ApplicationError {
|
||||
constructor(public providerName: string) {
|
||||
super(`External secrets provider not found: ${providerName}`);
|
||||
}
|
||||
}
|
10
packages/cli/src/errors/feature-not-licensed.error.ts
Normal file
10
packages/cli/src/errors/feature-not-licensed.error.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import type { LICENSE_FEATURES } from '@/constants';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
export class FeatureNotLicensedError extends ApplicationError {
|
||||
constructor(feature: (typeof LICENSE_FEATURES)[keyof typeof LICENSE_FEATURES]) {
|
||||
super(
|
||||
`Your license does not allow for ${feature}. To enable ${feature}, please upgrade to a license that supports this feature.`,
|
||||
);
|
||||
}
|
||||
}
|
3
packages/cli/src/errors/invalid-role.error.ts
Normal file
3
packages/cli/src/errors/invalid-role.error.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
export class InvalidRoleError extends ApplicationError {}
|
7
packages/cli/src/errors/not-string-array.error.ts
Normal file
7
packages/cli/src/errors/not-string-array.error.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
export class NotStringArrayError extends ApplicationError {
|
||||
constructor(env: string) {
|
||||
super(`${env} is not a string array.`);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
/**
|
||||
* Special Error which allows to return also an error code and http status code
|
||||
*/
|
||||
export abstract class ResponseError extends ApplicationError {
|
||||
/**
|
||||
* Creates an instance of ResponseError.
|
||||
* Must be used inside a block with `ResponseHelper.send()`.
|
||||
*/
|
||||
constructor(
|
||||
message: string,
|
||||
// The HTTP status code of response
|
||||
readonly httpStatusCode: number,
|
||||
// The error code in the response
|
||||
readonly errorCode: number = httpStatusCode,
|
||||
// The error hint the response
|
||||
readonly hint: string | undefined = undefined,
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'ResponseError';
|
||||
}
|
||||
}
|
7
packages/cli/src/errors/response-errors/auth.error.ts
Normal file
7
packages/cli/src/errors/response-errors/auth.error.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { ResponseError } from './abstract/response.error';
|
||||
|
||||
export class AuthError extends ResponseError {
|
||||
constructor(message: string, errorCode?: number) {
|
||||
super(message, 401, errorCode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { ResponseError } from './abstract/response.error';
|
||||
|
||||
export class BadRequestError extends ResponseError {
|
||||
constructor(message: string, errorCode?: number) {
|
||||
super(message, 400, errorCode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { ResponseError } from './abstract/response.error';
|
||||
|
||||
export class ConflictError extends ResponseError {
|
||||
constructor(message: string, hint: string | undefined = undefined) {
|
||||
super(message, 409, 409, hint);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { ResponseError } from './abstract/response.error';
|
||||
|
||||
export class InternalServerError extends ResponseError {
|
||||
constructor(message: string, errorCode = 500) {
|
||||
super(message, 500, errorCode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { ResponseError } from './abstract/response.error';
|
||||
|
||||
export class NotFoundError extends ResponseError {
|
||||
constructor(message: string, hint: string | undefined = undefined) {
|
||||
super(message, 404, 404, hint);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { ResponseError } from './abstract/response.error';
|
||||
|
||||
export class ServiceUnavailableError extends ResponseError {
|
||||
constructor(message: string, errorCode = 503) {
|
||||
super(message, 503, errorCode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { ResponseError } from './abstract/response.error';
|
||||
|
||||
export class UnauthorizedError extends ResponseError {
|
||||
constructor(message: string, hint: string | undefined = undefined) {
|
||||
super(message, 403, 403, hint);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { ResponseError } from './abstract/response.error';
|
||||
|
||||
export class UnprocessableRequestError extends ResponseError {
|
||||
constructor(message: string, hint: string | undefined = undefined) {
|
||||
super(message, 422, 422, hint);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
export class SharedWorkflowNotFoundError extends ApplicationError {}
|
9
packages/cli/src/errors/unrecognized-node-type.error.ts
Normal file
9
packages/cli/src/errors/unrecognized-node-type.error.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
export class UnrecognizedNodeTypeError extends ApplicationError {
|
||||
severity = 'warning';
|
||||
|
||||
constructor(nodeType: string) {
|
||||
super(`Unrecognized node type: ${nodeType}".`);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
export class VariableCountLimitReachedError extends ApplicationError {}
|
3
packages/cli/src/errors/variable-validation.error.ts
Normal file
3
packages/cli/src/errors/variable-validation.error.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
export class VariableValidationError extends ApplicationError {}
|
|
@ -0,0 +1,3 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
export class WorkflowHistoryVersionNotFoundError extends ApplicationError {}
|
|
@ -9,7 +9,6 @@ import {
|
|||
MessageEventBusDestinationSyslog,
|
||||
} from './MessageEventBusDestination/MessageEventBusDestinationSyslog.ee';
|
||||
import { MessageEventBusDestinationWebhook } from './MessageEventBusDestination/MessageEventBusDestinationWebhook.ee';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import type {
|
||||
MessageEventBusDestinationWebhookOptions,
|
||||
MessageEventBusDestinationOptions,
|
||||
|
@ -20,6 +19,7 @@ import type { MessageEventBusDestination } from './MessageEventBusDestination/Me
|
|||
import type { DeleteResult } from 'typeorm';
|
||||
import { AuthenticatedRequest } from '@/requests';
|
||||
import { logStreamingLicensedMiddleware } from './middleware/logStreamingEnabled.middleware.ee';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
// ----------------------------------------
|
||||
// TypeGuards
|
||||
|
|
|
@ -9,13 +9,13 @@ import type { EventMessageTypes, FailedEventSummary } from './EventMessageClasse
|
|||
import { eventNamesAll } from './EventMessageClasses';
|
||||
import type { EventMessageAuditOptions } from './EventMessageClasses/EventMessageAudit';
|
||||
import { EventMessageAudit } from './EventMessageClasses/EventMessageAudit';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import type { IRunExecutionData } from 'n8n-workflow';
|
||||
import { EventMessageTypeNames } from 'n8n-workflow';
|
||||
import type { EventMessageNodeOptions } from './EventMessageClasses/EventMessageNode';
|
||||
import { EventMessageNode } from './EventMessageClasses/EventMessageNode';
|
||||
import { recoverExecutionDataFromEventLogMessages } from './MessageEventBus/recoverEvents';
|
||||
import { RestController, Get, Post, Authorized } from '@/decorators';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
// ----------------------------------------
|
||||
// TypeGuards
|
||||
|
|
|
@ -15,7 +15,6 @@ import type {
|
|||
import { NodeTypes } from '@/NodeTypes';
|
||||
import { Queue } from '@/Queue';
|
||||
import type { ExecutionRequest } from '@/requests';
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import { getSharedWorkflowIds } from '@/WorkflowHelpers';
|
||||
import { WorkflowRunner } from '@/WorkflowRunner';
|
||||
import * as GenericHelpers from '@/GenericHelpers';
|
||||
|
@ -24,6 +23,8 @@ import { getStatusUsingPreviousExecutionStatusMethod } from './executionHelpers'
|
|||
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||
import { Logger } from '@/Logger';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
|
||||
export interface IGetExecutionsQueryFilter {
|
||||
id?: FindOperator<string> | string;
|
||||
|
@ -114,9 +115,7 @@ export class ExecutionsService {
|
|||
userId: req.user.id,
|
||||
filter: req.query.filter,
|
||||
});
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
'Parameter "filter" contained invalid JSON string.',
|
||||
);
|
||||
throw new InternalServerError('Parameter "filter" contained invalid JSON string.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,9 +230,7 @@ export class ExecutionsService {
|
|||
executionId,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`The execution with the ID "${executionId}" does not exist.`,
|
||||
);
|
||||
throw new NotFoundError(`The execution with the ID "${executionId}" does not exist.`);
|
||||
}
|
||||
|
||||
if (execution.finished) {
|
||||
|
@ -351,9 +348,7 @@ export class ExecutionsService {
|
|||
requestFilters = requestFiltersRaw as IGetExecutionsQueryFilter;
|
||||
}
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
'Parameter "filter" contained invalid JSON string.',
|
||||
);
|
||||
throw new InternalServerError('Parameter "filter" contained invalid JSON string.');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ import { LicenseService } from './License.service';
|
|||
import { License } from '@/License';
|
||||
import type { AuthenticatedRequest, LicenseRequest } from '@/requests';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
export const licenseController = express.Router();
|
||||
|
||||
|
@ -24,9 +26,7 @@ licenseController.use((req: AuthenticatedRequest, res, next) => {
|
|||
});
|
||||
ResponseHelper.sendErrorResponse(
|
||||
res,
|
||||
new ResponseHelper.UnauthorizedError(
|
||||
'Only an instance owner may activate or renew a license',
|
||||
),
|
||||
new UnauthorizedError('Only an instance owner may activate or renew a license'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ licenseController.post(
|
|||
Container.get(Logger).error(message, { stack: error.stack ?? 'n/a' });
|
||||
}
|
||||
|
||||
throw new ResponseHelper.BadRequestError(message);
|
||||
throw new BadRequestError(message);
|
||||
}
|
||||
|
||||
// Return the read data, plus the management JWT
|
||||
|
@ -113,7 +113,7 @@ licenseController.post(
|
|||
// not awaiting so as not to make the endpoint hang
|
||||
void Container.get(InternalHooks).onLicenseRenewAttempt({ success: false });
|
||||
if (error instanceof Error) {
|
||||
throw new ResponseHelper.BadRequestError(error.message);
|
||||
throw new BadRequestError(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { Parser as XmlParser } from 'xml2js';
|
|||
import { parseIncomingMessage } from 'n8n-core';
|
||||
import { jsonParse } from 'n8n-workflow';
|
||||
import config from '@/config';
|
||||
import { UnprocessableRequestError } from '@/ResponseHelper';
|
||||
import { UnprocessableRequestError } from '@/errors/response-errors/unprocessable.error';
|
||||
|
||||
const xmlParser = new XmlParser({
|
||||
async: true,
|
||||
|
|
|
@ -3,8 +3,7 @@ import { RoleRepository } from '@db/repositories/role.repository';
|
|||
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
|
||||
import { CacheService } from './cache.service';
|
||||
import type { RoleNames, RoleScopes } from '@db/entities/Role';
|
||||
|
||||
class InvalidRoleError extends Error {}
|
||||
import { InvalidRoleError } from '@/errors/invalid-role.error';
|
||||
|
||||
@Service()
|
||||
export class RoleService {
|
||||
|
|
|
@ -15,8 +15,8 @@ import { UserManagementMailer } from '@/UserManagement/email';
|
|||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { ErrorReporterProxy as ErrorReporter } from 'n8n-workflow';
|
||||
import { InternalServerError } from '@/ResponseHelper';
|
||||
import type { UserRequest } from '@/requests';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
|
||||
@Service()
|
||||
export class UserService {
|
||||
|
|
|
@ -9,7 +9,6 @@ import {
|
|||
} from '../middleware/samlEnabledMiddleware';
|
||||
import { SamlService } from '../saml.service.ee';
|
||||
import { SamlConfiguration } from '../types/requests';
|
||||
import { AuthError, BadRequestError } from '@/ResponseHelper';
|
||||
import { getInitSSOFormView } from '../views/initSsoPost';
|
||||
import { issueCookie } from '@/auth/jwt';
|
||||
import { validate } from 'class-validator';
|
||||
|
@ -27,6 +26,8 @@ import { getSamlConnectionTestFailedView } from '../views/samlConnectionTestFail
|
|||
import { InternalHooks } from '@/InternalHooks';
|
||||
import url from 'url';
|
||||
import querystring from 'querystring';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
|
||||
@Service()
|
||||
@RestController('/sso/saml')
|
||||
|
|
|
@ -2,7 +2,6 @@ import type express from 'express';
|
|||
import Container, { Service } from 'typedi';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { jsonParse } from 'n8n-workflow';
|
||||
import { AuthError, BadRequestError } from '@/ResponseHelper';
|
||||
import { getServiceProviderInstance } from './serviceProvider.ee';
|
||||
import type { SamlUserAttributes } from './types/samlUserAttributes';
|
||||
import { isSsoJustInTimeProvisioningEnabled } from '../ssoHelpers';
|
||||
|
@ -29,6 +28,8 @@ import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
|
|||
import { Logger } from '@/Logger';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
|
||||
@Service()
|
||||
export class SamlService {
|
||||
|
|
|
@ -3,7 +3,6 @@ import config from '@/config';
|
|||
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
||||
import { User } from '@db/entities/User';
|
||||
import { License } from '@/License';
|
||||
import { AuthError, InternalServerError } from '@/ResponseHelper';
|
||||
import { hashPassword } from '@/UserManagement/UserManagementHelper';
|
||||
import type { SamlPreferences } from './types/samlPreferences';
|
||||
import type { SamlUserAttributes } from './types/samlUserAttributes';
|
||||
|
@ -21,6 +20,9 @@ import type { SamlConfiguration } from './types/requests';
|
|||
import { RoleService } from '@/services/role.service';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { AuthIdentityRepository } from '@db/repositories/authIdentity.repository';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
|
||||
/**
|
||||
* Check whether the SAML feature is licensed and enabled in the instance
|
||||
*/
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
import { Authorized, RestController, Get, Middleware } from '@/decorators';
|
||||
import { WorkflowHistoryRequest } from '@/requests';
|
||||
import { Service } from 'typedi';
|
||||
import {
|
||||
HistoryVersionNotFoundError,
|
||||
SharedWorkflowNotFoundError,
|
||||
WorkflowHistoryService,
|
||||
} from './workflowHistory.service.ee';
|
||||
import { WorkflowHistoryService } from './workflowHistory.service.ee';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { isWorkflowHistoryEnabled, isWorkflowHistoryLicensed } from './workflowHistoryHelper.ee';
|
||||
import { NotFoundError } from '@/ResponseHelper';
|
||||
|
||||
import { paginationListQueryMiddleware } from '@/middlewares/listQuery/pagination';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { SharedWorkflowNotFoundError } from '@/errors/shared-workflow-not-found.error';
|
||||
import { WorkflowHistoryVersionNotFoundError } from '@/errors/workflow-history-version-not-found.error';
|
||||
|
||||
const DEFAULT_TAKE = 20;
|
||||
|
||||
|
@ -67,7 +66,7 @@ export class WorkflowHistoryController {
|
|||
} catch (e) {
|
||||
if (e instanceof SharedWorkflowNotFoundError) {
|
||||
throw new NotFoundError('Could not find workflow');
|
||||
} else if (e instanceof HistoryVersionNotFoundError) {
|
||||
} else if (e instanceof WorkflowHistoryVersionNotFoundError) {
|
||||
throw new NotFoundError('Could not find version');
|
||||
}
|
||||
throw e;
|
||||
|
|
|
@ -7,9 +7,8 @@ import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repo
|
|||
import { Service } from 'typedi';
|
||||
import { isWorkflowHistoryEnabled } from './workflowHistoryHelper.ee';
|
||||
import { Logger } from '@/Logger';
|
||||
|
||||
export class SharedWorkflowNotFoundError extends Error {}
|
||||
export class HistoryVersionNotFoundError extends Error {}
|
||||
import { SharedWorkflowNotFoundError } from '@/errors/shared-workflow-not-found.error';
|
||||
import { WorkflowHistoryVersionNotFoundError } from '@/errors/workflow-history-version-not-found.error';
|
||||
|
||||
@Service()
|
||||
export class WorkflowHistoryService {
|
||||
|
@ -36,7 +35,7 @@ export class WorkflowHistoryService {
|
|||
): Promise<Array<Omit<WorkflowHistory, 'nodes' | 'connections'>>> {
|
||||
const sharedWorkflow = await this.getSharedWorkflow(user, workflowId);
|
||||
if (!sharedWorkflow) {
|
||||
throw new SharedWorkflowNotFoundError();
|
||||
throw new SharedWorkflowNotFoundError('');
|
||||
}
|
||||
return this.workflowHistoryRepository.find({
|
||||
where: {
|
||||
|
@ -52,7 +51,7 @@ export class WorkflowHistoryService {
|
|||
async getVersion(user: User, workflowId: string, versionId: string): Promise<WorkflowHistory> {
|
||||
const sharedWorkflow = await this.getSharedWorkflow(user, workflowId);
|
||||
if (!sharedWorkflow) {
|
||||
throw new SharedWorkflowNotFoundError();
|
||||
throw new SharedWorkflowNotFoundError('');
|
||||
}
|
||||
const hist = await this.workflowHistoryRepository.findOne({
|
||||
where: {
|
||||
|
@ -61,7 +60,7 @@ export class WorkflowHistoryService {
|
|||
},
|
||||
});
|
||||
if (!hist) {
|
||||
throw new HistoryVersionNotFoundError();
|
||||
throw new WorkflowHistoryVersionNotFoundError('');
|
||||
}
|
||||
return hist;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,10 @@ import { listQueryMiddleware } from '@/middlewares';
|
|||
import { TagService } from '@/services/tag.service';
|
||||
import { Logger } from '@/Logger';
|
||||
import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
|
||||
export const EEWorkflowController = express.Router();
|
||||
|
||||
|
@ -52,13 +56,13 @@ EEWorkflowController.put(
|
|||
!Array.isArray(shareWithIds) ||
|
||||
!shareWithIds.every((userId) => typeof userId === 'string')
|
||||
) {
|
||||
throw new ResponseHelper.BadRequestError('Bad request');
|
||||
throw new BadRequestError('Bad request');
|
||||
}
|
||||
|
||||
const { ownsWorkflow, workflow } = await EEWorkflows.isOwned(req.user, workflowId);
|
||||
|
||||
if (!ownsWorkflow || !workflow) {
|
||||
throw new ResponseHelper.UnauthorizedError('Forbidden');
|
||||
throw new UnauthorizedError('Forbidden');
|
||||
}
|
||||
|
||||
let newShareeIds: string[] = [];
|
||||
|
@ -101,13 +105,13 @@ EEWorkflowController.get(
|
|||
const workflow = await EEWorkflows.get({ id: workflowId }, { relations });
|
||||
|
||||
if (!workflow) {
|
||||
throw new ResponseHelper.NotFoundError(`Workflow with ID "${workflowId}" does not exist`);
|
||||
throw new NotFoundError(`Workflow with ID "${workflowId}" does not exist`);
|
||||
}
|
||||
|
||||
const userSharing = workflow.shared?.find((shared) => shared.user.id === req.user.id);
|
||||
|
||||
if (!userSharing && req.user.globalRole.name !== 'owner') {
|
||||
throw new ResponseHelper.UnauthorizedError(
|
||||
throw new UnauthorizedError(
|
||||
'You do not have permission to access this workflow. Ask the owner to share it with you',
|
||||
);
|
||||
}
|
||||
|
@ -156,7 +160,7 @@ EEWorkflowController.post(
|
|||
try {
|
||||
EEWorkflows.validateCredentialPermissionsToUser(newWorkflow, allCredentials);
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
throw new BadRequestError(
|
||||
'The workflow you are trying to save contains credentials that are not shared with you',
|
||||
);
|
||||
}
|
||||
|
@ -181,7 +185,7 @@ EEWorkflowController.post(
|
|||
|
||||
if (!savedWorkflow) {
|
||||
Container.get(Logger).error('Failed to create workflow', { userId: req.user.id });
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
throw new InternalServerError(
|
||||
'An error occurred while saving your workflow. Please try again.',
|
||||
);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,9 @@ import { TagService } from '@/services/tag.service';
|
|||
import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee';
|
||||
import { Logger } from '@/Logger';
|
||||
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
|
||||
export const workflowsController = express.Router();
|
||||
workflowsController.use('/', EEWorkflowController);
|
||||
|
@ -84,7 +87,7 @@ workflowsController.post(
|
|||
|
||||
if (!savedWorkflow) {
|
||||
Container.get(Logger).error('Failed to create workflow', { userId: req.user.id });
|
||||
throw new ResponseHelper.InternalServerError('Failed to save workflow');
|
||||
throw new InternalServerError('Failed to save workflow');
|
||||
}
|
||||
|
||||
await Container.get(WorkflowHistoryService).saveVersion(
|
||||
|
@ -160,10 +163,10 @@ workflowsController.get(
|
|||
'/from-url',
|
||||
ResponseHelper.send(async (req: express.Request): Promise<IWorkflowResponse> => {
|
||||
if (req.query.url === undefined) {
|
||||
throw new ResponseHelper.BadRequestError('The parameter "url" is missing!');
|
||||
throw new BadRequestError('The parameter "url" is missing!');
|
||||
}
|
||||
if (!/^http[s]?:\/\/.*\.json$/i.exec(req.query.url as string)) {
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
throw new BadRequestError(
|
||||
'The parameter "url" is not valid! It does not seem to be a URL pointing to a n8n workflow JSON file.',
|
||||
);
|
||||
}
|
||||
|
@ -172,7 +175,7 @@ workflowsController.get(
|
|||
const { data } = await axios.get<IWorkflowResponse>(req.query.url as string);
|
||||
workflowData = data;
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.BadRequestError('The URL does not point to valid JSON file!');
|
||||
throw new BadRequestError('The URL does not point to valid JSON file!');
|
||||
}
|
||||
|
||||
// Do a very basic check if it is really a n8n-workflow-json
|
||||
|
@ -183,7 +186,7 @@ workflowsController.get(
|
|||
typeof workflowData.connections !== 'object' ||
|
||||
Array.isArray(workflowData.connections)
|
||||
) {
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
throw new BadRequestError(
|
||||
'The data in the file does not seem to be a n8n workflow JSON file!',
|
||||
);
|
||||
}
|
||||
|
@ -221,7 +224,7 @@ workflowsController.get(
|
|||
workflowId,
|
||||
userId: req.user.id,
|
||||
});
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
throw new NotFoundError(
|
||||
'Could not load the workflow - you can only access workflows owned by you',
|
||||
);
|
||||
}
|
||||
|
@ -271,7 +274,7 @@ workflowsController.delete(
|
|||
workflowId,
|
||||
userId: req.user.id,
|
||||
});
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
throw new BadRequestError(
|
||||
'Could not delete the workflow - you can only remove workflows owned by you',
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { DeleteResult, EntityManager } from 'typeorm';
|
||||
import { In, Not } from 'typeorm';
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import * as WorkflowHelpers from '@/WorkflowHelpers';
|
||||
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import type { User } from '@db/entities/User';
|
||||
|
@ -17,6 +16,8 @@ import { RoleService } from '@/services/role.service';
|
|||
import Container from 'typedi';
|
||||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
|
||||
export class EEWorkflowsService extends WorkflowsService {
|
||||
static async isOwned(
|
||||
|
@ -170,7 +171,7 @@ export class EEWorkflowsService extends WorkflowsService {
|
|||
const previousVersion = await EEWorkflowsService.get({ id: workflowId });
|
||||
|
||||
if (!previousVersion) {
|
||||
throw new ResponseHelper.NotFoundError('Workflow not found');
|
||||
throw new NotFoundError('Workflow not found');
|
||||
}
|
||||
|
||||
const allCredentials = await CredentialsService.getMany(user);
|
||||
|
@ -183,9 +184,9 @@ export class EEWorkflowsService extends WorkflowsService {
|
|||
);
|
||||
} catch (error) {
|
||||
if (error instanceof NodeOperationError) {
|
||||
throw new ResponseHelper.BadRequestError(error.message);
|
||||
throw new BadRequestError(error.message);
|
||||
}
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
throw new BadRequestError(
|
||||
'Invalid workflow credentials - make sure you have access to all credentials and try again.',
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import { In, Like } from 'typeorm';
|
|||
import pick from 'lodash/pick';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import * as WorkflowHelpers from '@/WorkflowHelpers';
|
||||
import config from '@/config';
|
||||
import type { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
|
@ -34,6 +33,8 @@ import { MultiMainSetup } from '@/services/orchestration/main/MultiMainSetup.ee'
|
|||
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
|
||||
import { WorkflowTagMappingRepository } from '@db/repositories/workflowTagMapping.repository';
|
||||
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
|
||||
export class WorkflowsService {
|
||||
static async getSharing(
|
||||
|
@ -208,7 +209,7 @@ export class WorkflowsService {
|
|||
workflowId,
|
||||
userId: user.id,
|
||||
});
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
throw new NotFoundError(
|
||||
'You do not have permission to update this workflow. Ask the owner to share it with you.',
|
||||
);
|
||||
}
|
||||
|
@ -220,7 +221,7 @@ export class WorkflowsService {
|
|||
workflow.versionId !== '' &&
|
||||
workflow.versionId !== shared.workflow.versionId
|
||||
) {
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
throw new BadRequestError(
|
||||
'Your most recent changes may be lost, because someone else just updated this workflow. Open this workflow in a new tab to see those new updates.',
|
||||
100,
|
||||
);
|
||||
|
@ -330,7 +331,7 @@ export class WorkflowsService {
|
|||
});
|
||||
|
||||
if (updatedWorkflow === null) {
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
throw new BadRequestError(
|
||||
`Workflow with ID "${workflowId}" could not be found to be updated.`,
|
||||
);
|
||||
}
|
||||
|
@ -368,7 +369,7 @@ export class WorkflowsService {
|
|||
message = message ?? (error as Error).message;
|
||||
|
||||
// Now return the original error for UI to display
|
||||
throw new ResponseHelper.BadRequestError(message);
|
||||
throw new BadRequestError(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import type { PublicUser } from '@/Interfaces';
|
|||
import type { User } from '@db/entities/User';
|
||||
import { MeController } from '@/controllers/me.controller';
|
||||
import { AUTH_COOKIE_NAME } from '@/constants';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import type { AuthenticatedRequest, MeRequest } from '@/requests';
|
||||
import { UserService } from '@/services/user.service';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
|
@ -14,6 +13,7 @@ import { InternalHooks } from '@/InternalHooks';
|
|||
import { License } from '@/License';
|
||||
import { badPasswords } from '../shared/testData';
|
||||
import { mockInstance } from '../../shared/mocking';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
describe('MeController', () => {
|
||||
const externalHooks = mockInstance(ExternalHooks);
|
||||
|
|
|
@ -7,7 +7,6 @@ import { OAuth1CredentialController } from '@/controllers/oauth/oAuth1Credential
|
|||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { OAuthRequest } from '@/requests';
|
||||
import { BadRequestError, NotFoundError } from '@/ResponseHelper';
|
||||
import { CredentialsRepository } from '@db/repositories/credentials.repository';
|
||||
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
|
@ -17,6 +16,8 @@ import { SecretsHelper } from '@/SecretsHelpers';
|
|||
import { CredentialsHelper } from '@/CredentialsHelper';
|
||||
|
||||
import { mockInstance } from '../../shared/mocking';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
|
||||
describe('OAuth1CredentialController', () => {
|
||||
mockInstance(Logger);
|
||||
|
|
|
@ -9,7 +9,6 @@ import { OAuth2CredentialController } from '@/controllers/oauth/oAuth2Credential
|
|||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { OAuthRequest } from '@/requests';
|
||||
import { BadRequestError, NotFoundError } from '@/ResponseHelper';
|
||||
import { CredentialsRepository } from '@db/repositories/credentials.repository';
|
||||
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
|
@ -19,6 +18,8 @@ import { SecretsHelper } from '@/SecretsHelpers';
|
|||
import { CredentialsHelper } from '@/CredentialsHelper';
|
||||
|
||||
import { mockInstance } from '../../shared/mocking';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
|
||||
describe('OAuth2CredentialController', () => {
|
||||
mockInstance(Logger);
|
||||
|
|
|
@ -5,7 +5,6 @@ import type { IInternalHooksClass } from '@/Interfaces';
|
|||
import type { User } from '@db/entities/User';
|
||||
import type { SettingsRepository } from '@db/repositories/settings.repository';
|
||||
import type { Config } from '@/config';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import type { OwnerRequest } from '@/requests';
|
||||
import { OwnerController } from '@/controllers/owner.controller';
|
||||
import { AUTH_COOKIE_NAME } from '@/constants';
|
||||
|
@ -14,6 +13,7 @@ import { License } from '@/License';
|
|||
|
||||
import { mockInstance } from '../../shared/mocking';
|
||||
import { badPasswords } from '../shared/testData';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
describe('OwnerController', () => {
|
||||
const config = mock<Config>();
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
TranslationController,
|
||||
CREDENTIAL_TRANSLATIONS_DIR,
|
||||
} from '@/controllers/translation.controller';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
describe('TranslationController', () => {
|
||||
const config = mock<Config>();
|
||||
|
|
Loading…
Reference in a new issue