mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 12:44:07 -08:00
refactor: Improve error logging/reporting for cli
(#4691)
* use response error classes instead of `ResponseError` everywhere * improve error logging in dev mode or when telemetry is disabled
This commit is contained in:
parent
5364e7fc92
commit
0b754a4f85
|
@ -161,6 +161,7 @@
|
|||
"passport": "^0.6.0",
|
||||
"passport-cookie": "^1.0.9",
|
||||
"passport-jwt": "^4.0.0",
|
||||
"picocolors": "^1.0.0",
|
||||
"pg": "^8.3.0",
|
||||
"posthog-node": "^1.3.0",
|
||||
"prom-client": "^13.1.0",
|
||||
|
|
|
@ -191,10 +191,8 @@ export class ActiveWorkflowRunner {
|
|||
): Promise<IResponseCallbackData> {
|
||||
Logger.debug(`Received webhook "${httpMethod}" for path "${path}"`);
|
||||
if (this.activeWorkflows === null) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
'The "activeWorkflows" instance did not get initialized yet.',
|
||||
404,
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -224,10 +222,8 @@ export class ActiveWorkflowRunner {
|
|||
});
|
||||
if (dynamicWebhooks === undefined || dynamicWebhooks.length === 0) {
|
||||
// The requested webhook is not registered
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`The requested webhook "${httpMethod} ${path}" is not registered.`,
|
||||
404,
|
||||
404,
|
||||
WEBHOOK_PROD_UNREGISTERED_HINT,
|
||||
);
|
||||
}
|
||||
|
@ -252,10 +248,8 @@ export class ActiveWorkflowRunner {
|
|||
}
|
||||
});
|
||||
if (webhook === undefined) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`The requested webhook "${httpMethod} ${path}" is not registered.`,
|
||||
404,
|
||||
404,
|
||||
WEBHOOK_PROD_UNREGISTERED_HINT,
|
||||
);
|
||||
}
|
||||
|
@ -277,10 +271,8 @@ export class ActiveWorkflowRunner {
|
|||
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
|
||||
});
|
||||
if (workflowData === undefined) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`Could not find workflow with id "${webhook.workflowId}"`,
|
||||
404,
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -313,7 +305,7 @@ export class ActiveWorkflowRunner {
|
|||
const workflowStartNode = workflow.getNode(webhookData.node);
|
||||
|
||||
if (workflowStartNode === null) {
|
||||
throw new ResponseHelper.ResponseError('Could not find node to process webhook.', 404, 404);
|
||||
throw new ResponseHelper.NotFoundError('Could not find node to process webhook.');
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
|
@ -212,7 +212,7 @@ export async function validateEntity(
|
|||
.join(' | ');
|
||||
|
||||
if (errorMessages) {
|
||||
throw new ResponseHelper.ResponseError(errorMessages, undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(errorMessages);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Request, Response } from 'express';
|
||||
import { parse, stringify } from 'flatted';
|
||||
import { ErrorReporterProxy as ErrorReporter } from 'n8n-workflow';
|
||||
import picocolors from 'picocolors';
|
||||
import { ErrorReporterProxy as ErrorReporter, NodeApiError } from 'n8n-workflow';
|
||||
|
||||
import type {
|
||||
IExecutionDb,
|
||||
|
@ -15,44 +16,69 @@ import type {
|
|||
IWorkflowDb,
|
||||
} from './Interfaces';
|
||||
|
||||
const inDevelopment = !process.env.NODE_ENV || process.env.NODE_ENV === 'development';
|
||||
|
||||
/**
|
||||
* Special Error which allows to return also an error code and http status code
|
||||
*
|
||||
* @class ResponseError
|
||||
* @extends {Error}
|
||||
*/
|
||||
export class ResponseError extends Error {
|
||||
// The HTTP status code of response
|
||||
httpStatusCode?: number;
|
||||
|
||||
// The error code in the response
|
||||
errorCode?: number;
|
||||
|
||||
// The error hint the response
|
||||
hint?: string;
|
||||
|
||||
abstract class ResponseError extends Error {
|
||||
/**
|
||||
* Creates an instance of ResponseError.
|
||||
* Must be used inside a block with `ResponseHelper.send()`.
|
||||
*
|
||||
* @param {string} message The error message
|
||||
* @param {number} [errorCode] The error code which can be used by frontend to identify the actual error
|
||||
* @param {number} [httpStatusCode] The HTTP status code the response should have
|
||||
* @param {string} [hint] The error hint to provide a context (webhook related)
|
||||
*/
|
||||
constructor(message: string, errorCode?: number, httpStatusCode?: number, hint?: string) {
|
||||
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';
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
export class BadRequestError extends ResponseError {
|
||||
constructor(message: string) {
|
||||
super(message, 400);
|
||||
}
|
||||
if (httpStatusCode) {
|
||||
this.httpStatusCode = httpStatusCode;
|
||||
}
|
||||
|
||||
export class AuthError extends ResponseError {
|
||||
constructor(message: string) {
|
||||
super(message, 401);
|
||||
}
|
||||
if (hint) {
|
||||
this.hint = hint;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,40 +121,49 @@ export function sendSuccessResponse(
|
|||
}
|
||||
}
|
||||
|
||||
export function sendErrorResponse(res: Response, error: ResponseError) {
|
||||
interface ErrorResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
hint?: string;
|
||||
stacktrace?: string;
|
||||
}
|
||||
|
||||
export function sendErrorResponse(res: Response, error: Error) {
|
||||
let httpStatusCode = 500;
|
||||
if (error.httpStatusCode) {
|
||||
httpStatusCode = error.httpStatusCode;
|
||||
}
|
||||
|
||||
if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
|
||||
console.error('ERROR RESPONSE');
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
const response = {
|
||||
const response: ErrorResponse = {
|
||||
code: 0,
|
||||
message: 'Unknown error',
|
||||
hint: '',
|
||||
};
|
||||
|
||||
if (error.name === 'NodeApiError') {
|
||||
Object.assign(response, error);
|
||||
if (error instanceof ResponseError) {
|
||||
if (inDevelopment) {
|
||||
console.error(picocolors.red(error.httpStatusCode), error.message);
|
||||
}
|
||||
|
||||
response.message = error.message;
|
||||
httpStatusCode = error.httpStatusCode;
|
||||
|
||||
if (error.errorCode) {
|
||||
response.code = error.errorCode;
|
||||
}
|
||||
if (error.message) {
|
||||
response.message = error.message;
|
||||
}
|
||||
if (error.hint) {
|
||||
response.hint = error.hint;
|
||||
}
|
||||
if (error.stack && process.env.NODE_ENV !== 'production') {
|
||||
// @ts-ignore
|
||||
response.stack = error.stack;
|
||||
}
|
||||
|
||||
if (error instanceof NodeApiError) {
|
||||
if (inDevelopment) {
|
||||
console.error(picocolors.red(error.name), error.message);
|
||||
}
|
||||
|
||||
Object.assign(response, error);
|
||||
}
|
||||
|
||||
if (error.stack && inDevelopment) {
|
||||
response.stacktrace = error.stack;
|
||||
}
|
||||
|
||||
res.status(httpStatusCode).json(response);
|
||||
}
|
||||
|
||||
|
@ -154,7 +189,9 @@ export function send<T, R extends Request, S extends Response>(
|
|||
sendSuccessResponse(res, data, raw);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
if (!(error instanceof ResponseError) || error.httpStatusCode > 404) {
|
||||
ErrorReporter.error(error);
|
||||
}
|
||||
|
||||
if (isUniqueConstraintError(error)) {
|
||||
error.message = 'There is already an entry with this name';
|
||||
|
|
|
@ -157,7 +157,6 @@ import { WaitTracker, WaitTrackerClass } from '@/WaitTracker';
|
|||
import * as WebhookHelpers from '@/WebhookHelpers';
|
||||
import * as WebhookServer from '@/WebhookServer';
|
||||
import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData';
|
||||
import { ResponseError } from '@/ResponseHelper';
|
||||
import { toHttpNodeParameters } from '@/CurlConverterHelper';
|
||||
import { setupErrorMiddleware } from '@/ErrorReporting';
|
||||
import { getLicense } from '@/License';
|
||||
|
@ -725,7 +724,7 @@ class App {
|
|||
// eslint-disable-next-line consistent-return
|
||||
this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
if (!Db.isInitialized) {
|
||||
const error = new ResponseHelper.ResponseError('Database is not ready!', undefined, 503);
|
||||
const error = new ResponseHelper.ServiceUnavailableError('Database is not ready!');
|
||||
return ResponseHelper.sendErrorResponse(res, error);
|
||||
}
|
||||
|
||||
|
@ -766,7 +765,7 @@ class App {
|
|||
} catch (err) {
|
||||
ErrorReporter.error(err);
|
||||
LoggerProxy.error('No Database connection!', err);
|
||||
const error = new ResponseHelper.ResponseError('No Database connection!', undefined, 503);
|
||||
const error = new ResponseHelper.ServiceUnavailableError('No Database connection!');
|
||||
return ResponseHelper.sendErrorResponse(res, error);
|
||||
}
|
||||
|
||||
|
@ -869,7 +868,9 @@ class App {
|
|||
const { path, methodName } = req.query;
|
||||
|
||||
if (!req.query.currentNodeParameters) {
|
||||
throw new ResponseError('Parameter currentNodeParameters is required.', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
'Parameter currentNodeParameters is required.',
|
||||
);
|
||||
}
|
||||
|
||||
const currentNodeParameters = jsonParse(
|
||||
|
@ -904,7 +905,7 @@ class App {
|
|||
);
|
||||
}
|
||||
|
||||
throw new ResponseError('Parameter methodName is required.', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Parameter methodName is required.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -1076,10 +1077,8 @@ class App {
|
|||
userId: req.user.id,
|
||||
});
|
||||
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
`Workflow with ID "${workflowId}" could not be found.`,
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1103,7 +1102,7 @@ class App {
|
|||
const parameters = toHttpNodeParameters(curlCommand);
|
||||
return ResponseHelper.flattenObject(parameters, 'parameters');
|
||||
} catch (e) {
|
||||
throw new ResponseHelper.ResponseError(`Invalid cURL command`, undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(`Invalid cURL command`);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
@ -1178,11 +1177,7 @@ class App {
|
|||
|
||||
if (!credentialId) {
|
||||
LoggerProxy.error('OAuth1 credential authorization failed due to missing credential ID');
|
||||
throw new ResponseHelper.ResponseError(
|
||||
'Required credential ID is missing',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
throw new ResponseHelper.BadRequestError('Required credential ID is missing');
|
||||
}
|
||||
|
||||
const credential = await getCredentialForUser(credentialId, req.user);
|
||||
|
@ -1192,18 +1187,14 @@ class App {
|
|||
'OAuth1 credential authorization failed because the current user does not have the correct permissions',
|
||||
{ userId: req.user.id },
|
||||
);
|
||||
throw new ResponseHelper.ResponseError(
|
||||
RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL,
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
throw new ResponseHelper.NotFoundError(RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL);
|
||||
}
|
||||
|
||||
let encryptionKey: string;
|
||||
try {
|
||||
encryptionKey = await UserSettings.getEncryptionKey();
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError(error.message, undefined, 500);
|
||||
throw new ResponseHelper.InternalServerError(error.message);
|
||||
}
|
||||
|
||||
const mode: WorkflowExecuteMode = 'internal';
|
||||
|
@ -1304,12 +1295,10 @@ class App {
|
|||
const { oauth_verifier, oauth_token, cid: credentialId } = req.query;
|
||||
|
||||
if (!oauth_verifier || !oauth_token) {
|
||||
const errorResponse = new ResponseHelper.ResponseError(
|
||||
const errorResponse = new ResponseHelper.ServiceUnavailableError(
|
||||
`Insufficient parameters for OAuth1 callback. Received following query parameters: ${JSON.stringify(
|
||||
req.query,
|
||||
)}`,
|
||||
undefined,
|
||||
503,
|
||||
);
|
||||
LoggerProxy.error(
|
||||
'OAuth1 callback failed because of insufficient parameters received',
|
||||
|
@ -1328,10 +1317,8 @@ class App {
|
|||
userId: req.user?.id,
|
||||
credentialId,
|
||||
});
|
||||
const errorResponse = new ResponseHelper.ResponseError(
|
||||
const errorResponse = new ResponseHelper.NotFoundError(
|
||||
RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL,
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||
}
|
||||
|
@ -1340,7 +1327,7 @@ class App {
|
|||
try {
|
||||
encryptionKey = await UserSettings.getEncryptionKey();
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError(error.message, undefined, 500);
|
||||
throw new ResponseHelper.InternalServerError(error.message);
|
||||
}
|
||||
|
||||
const mode: WorkflowExecuteMode = 'internal';
|
||||
|
@ -1378,11 +1365,7 @@ class App {
|
|||
userId: req.user?.id,
|
||||
credentialId,
|
||||
});
|
||||
const errorResponse = new ResponseHelper.ResponseError(
|
||||
'Unable to get access tokens!',
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
const errorResponse = new ResponseHelper.NotFoundError('Unable to get access tokens!');
|
||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||
}
|
||||
|
||||
|
@ -1539,7 +1522,7 @@ class App {
|
|||
const sharedWorkflowIds = await getSharedWorkflowIds(req.user);
|
||||
|
||||
if (!sharedWorkflowIds.length) {
|
||||
throw new ResponseHelper.ResponseError('Execution not found', undefined, 404);
|
||||
throw new ResponseHelper.NotFoundError('Execution not found');
|
||||
}
|
||||
|
||||
const execution = await Db.collections.Execution.findOne({
|
||||
|
@ -1550,7 +1533,7 @@ class App {
|
|||
});
|
||||
|
||||
if (!execution) {
|
||||
throw new ResponseHelper.ResponseError('Execution not found', undefined, 404);
|
||||
throw new ResponseHelper.NotFoundError('Execution not found');
|
||||
}
|
||||
|
||||
if (config.getEnv('executions.mode') === 'queue') {
|
||||
|
|
|
@ -67,10 +67,8 @@ export class TestWebhooks {
|
|||
webhookData = this.activeWebhooks!.get(httpMethod, pathElements.join('/'), webhookId);
|
||||
if (webhookData === undefined) {
|
||||
// The requested webhook is not registered
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`The requested webhook "${httpMethod} ${path}" is not registered.`,
|
||||
404,
|
||||
404,
|
||||
WEBHOOK_TEST_UNREGISTERED_HINT,
|
||||
);
|
||||
}
|
||||
|
@ -94,10 +92,8 @@ export class TestWebhooks {
|
|||
// TODO: Clean that duplication up one day and improve code generally
|
||||
if (this.testWebhookData[webhookKey] === undefined) {
|
||||
// The requested webhook is not registered
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`The requested webhook "${httpMethod} ${path}" is not registered.`,
|
||||
404,
|
||||
404,
|
||||
WEBHOOK_TEST_UNREGISTERED_HINT,
|
||||
);
|
||||
}
|
||||
|
@ -108,7 +104,7 @@ export class TestWebhooks {
|
|||
// get additional data
|
||||
const workflowStartNode = workflow.getNode(webhookData.node);
|
||||
if (workflowStartNode === null) {
|
||||
throw new ResponseHelper.ResponseError('Could not find node to process webhook.', 404, 404);
|
||||
throw new ResponseHelper.NotFoundError('Could not find node to process webhook.');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
|
@ -173,10 +169,8 @@ export class TestWebhooks {
|
|||
|
||||
if (webhookMethods === undefined) {
|
||||
// The requested webhook is not registered
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`The requested webhook "${path}" is not registered.`,
|
||||
404,
|
||||
404,
|
||||
WEBHOOK_TEST_UNREGISTERED_HINT,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ export function getInstanceBaseUrl(): string {
|
|||
// TODO: Enforce at model level
|
||||
export function validatePassword(password?: string): string {
|
||||
if (!password) {
|
||||
throw new ResponseHelper.ResponseError('Password is mandatory', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Password is mandatory');
|
||||
}
|
||||
|
||||
const hasInvalidLength =
|
||||
|
@ -117,7 +117,7 @@ export function validatePassword(password?: string): string {
|
|||
message.push('Password must contain at least 1 uppercase letter.');
|
||||
}
|
||||
|
||||
throw new ResponseHelper.ResponseError(message.join(' '), undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(message.join(' '));
|
||||
}
|
||||
|
||||
return password;
|
||||
|
|
|
@ -77,24 +77,20 @@ export function authenticationMethods(this: N8nApp): void {
|
|||
}
|
||||
|
||||
if (config.get('userManagement.isInstanceOwnerSetUp')) {
|
||||
throw new ResponseHelper.ResponseError('Not logged in', undefined, 401);
|
||||
throw new ResponseHelper.AuthError('Not logged in');
|
||||
}
|
||||
|
||||
try {
|
||||
user = await Db.collections.User.findOneOrFail({ relations: ['globalRole'] });
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
'No users found in database - did you wipe the users table? Create at least one user.',
|
||||
undefined,
|
||||
500,
|
||||
);
|
||||
}
|
||||
|
||||
if (user.email || user.password) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
'Invalid database state - user has password set.',
|
||||
undefined,
|
||||
500,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ export function meNamespace(this: N8nApp): void {
|
|||
userId: req.user.id,
|
||||
payload: req.body,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError('Email is mandatory', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Email is mandatory');
|
||||
}
|
||||
|
||||
if (!validator.isEmail(email)) {
|
||||
|
@ -47,7 +47,7 @@ export function meNamespace(this: N8nApp): void {
|
|||
userId: req.user.id,
|
||||
invalidEmail: email,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError('Invalid email address', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid email address');
|
||||
}
|
||||
|
||||
const { email: currentEmail } = req.user;
|
||||
|
@ -84,20 +84,16 @@ export function meNamespace(this: N8nApp): void {
|
|||
const { currentPassword, newPassword } = req.body;
|
||||
|
||||
if (typeof currentPassword !== 'string' || typeof newPassword !== 'string') {
|
||||
throw new ResponseHelper.ResponseError('Invalid payload.', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid payload.');
|
||||
}
|
||||
|
||||
if (!req.user.password) {
|
||||
throw new ResponseHelper.ResponseError('Requesting user not set up.');
|
||||
throw new ResponseHelper.BadRequestError('Requesting user not set up.');
|
||||
}
|
||||
|
||||
const isCurrentPwCorrect = await compareHash(currentPassword, req.user.password);
|
||||
if (!isCurrentPwCorrect) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
'Provided current password is incorrect.',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
throw new ResponseHelper.BadRequestError('Provided current password is incorrect.');
|
||||
}
|
||||
|
||||
const validPassword = validatePassword(newPassword);
|
||||
|
@ -135,11 +131,7 @@ export function meNamespace(this: N8nApp): void {
|
|||
userId: req.user.id,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.ResponseError(
|
||||
'Personalization answers are mandatory',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
throw new ResponseHelper.BadRequestError('Personalization answers are mandatory');
|
||||
}
|
||||
|
||||
await Db.collections.User.save({
|
||||
|
|
|
@ -31,7 +31,7 @@ export function ownerNamespace(this: N8nApp): void {
|
|||
userId,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Invalid request', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid request');
|
||||
}
|
||||
|
||||
if (!email || !validator.isEmail(email)) {
|
||||
|
@ -39,7 +39,7 @@ export function ownerNamespace(this: N8nApp): void {
|
|||
userId,
|
||||
invalidEmail: email,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError('Invalid email address', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid email address');
|
||||
}
|
||||
|
||||
const validPassword = validatePassword(password);
|
||||
|
@ -49,11 +49,7 @@ export function ownerNamespace(this: N8nApp): void {
|
|||
'Request to claim instance ownership failed because of missing first name or last name in payload',
|
||||
{ userId, payload: req.body },
|
||||
);
|
||||
throw new ResponseHelper.ResponseError(
|
||||
'First and last names are mandatory',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
throw new ResponseHelper.BadRequestError('First and last names are mandatory');
|
||||
}
|
||||
|
||||
let owner = await Db.collections.User.findOne(userId, {
|
||||
|
@ -67,7 +63,7 @@ export function ownerNamespace(this: N8nApp): void {
|
|||
userId,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Invalid request', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid request');
|
||||
}
|
||||
|
||||
owner = Object.assign(owner, {
|
||||
|
|
|
@ -28,10 +28,8 @@ export function passwordResetNamespace(this: N8nApp): void {
|
|||
ResponseHelper.send(async (req: PasswordResetRequest.Email) => {
|
||||
if (config.getEnv('userManagement.emails.mode') === '') {
|
||||
Logger.debug('Request to send password reset email failed because emailing was not set up');
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
'Email sending must be set up in order to request a password reset email',
|
||||
undefined,
|
||||
500,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -42,7 +40,7 @@ export function passwordResetNamespace(this: N8nApp): void {
|
|||
'Request to send password reset email failed because of missing email in payload',
|
||||
{ payload: req.body },
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Email is mandatory', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Email is mandatory');
|
||||
}
|
||||
|
||||
if (!validator.isEmail(email)) {
|
||||
|
@ -50,7 +48,7 @@ export function passwordResetNamespace(this: N8nApp): void {
|
|||
'Request to send password reset email failed because of invalid email in payload',
|
||||
{ invalidEmail: email },
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Invalid email address', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid email address');
|
||||
}
|
||||
|
||||
// User should just be able to reset password if one is already present
|
||||
|
@ -93,10 +91,8 @@ export function passwordResetNamespace(this: N8nApp): void {
|
|||
public_api: false,
|
||||
});
|
||||
if (error instanceof Error) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
`Please contact your administrator: ${error.message}`,
|
||||
undefined,
|
||||
500,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +127,7 @@ export function passwordResetNamespace(this: N8nApp): void {
|
|||
queryString: req.query,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('');
|
||||
}
|
||||
|
||||
// Timestamp is saved in seconds
|
||||
|
@ -151,7 +147,7 @@ export function passwordResetNamespace(this: N8nApp): void {
|
|||
resetPasswordToken,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('', undefined, 404);
|
||||
throw new ResponseHelper.NotFoundError('');
|
||||
}
|
||||
|
||||
Logger.info('Reset-password token resolved successfully', { userId: id });
|
||||
|
@ -178,10 +174,8 @@ export function passwordResetNamespace(this: N8nApp): void {
|
|||
payload: req.body,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
'Missing user ID or password or reset password token',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -204,7 +198,7 @@ export function passwordResetNamespace(this: N8nApp): void {
|
|||
resetPasswordToken,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('', undefined, 404);
|
||||
throw new ResponseHelper.NotFoundError('');
|
||||
}
|
||||
|
||||
await Db.collections.User.update(userId, {
|
||||
|
|
|
@ -37,10 +37,8 @@ export function usersNamespace(this: N8nApp): void {
|
|||
Logger.debug(
|
||||
'Request to send email invite(s) to user(s) failed because emailing was not set up',
|
||||
);
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
'Email sending must be set up in order to request a password reset email',
|
||||
undefined,
|
||||
500,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -49,10 +47,8 @@ export function usersNamespace(this: N8nApp): void {
|
|||
mailer = await UserManagementMailer.getInstance();
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
`There is a problem with your SMTP setup! ${error.message}`,
|
||||
undefined,
|
||||
500,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -62,17 +58,15 @@ export function usersNamespace(this: N8nApp): void {
|
|||
Logger.debug(
|
||||
'Request to send email invite(s) to user(s) failed because user management is disabled',
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('User management is disabled');
|
||||
throw new ResponseHelper.BadRequestError('User management is disabled');
|
||||
}
|
||||
|
||||
if (!config.getEnv('userManagement.isInstanceOwnerSetUp')) {
|
||||
Logger.debug(
|
||||
'Request to send email invite(s) to user(s) failed because the owner account is not set up',
|
||||
);
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
'You must set up your own account before inviting others',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -83,7 +77,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
payload: req.body,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Invalid payload', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid payload');
|
||||
}
|
||||
|
||||
if (!req.body.length) return [];
|
||||
|
@ -92,19 +86,15 @@ export function usersNamespace(this: N8nApp): void {
|
|||
// Validate payload
|
||||
req.body.forEach((invite) => {
|
||||
if (typeof invite !== 'object' || !invite.email) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
'Request to send email invite(s) to user(s) failed because the payload is not an array shaped Array<{ email: string }>',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
if (!validator.isEmail(invite.email)) {
|
||||
Logger.debug('Invalid email in payload', { invalidEmail: invite.email });
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
`Request to send email invite(s) to user(s) failed because of an invalid email address: ${invite.email}`,
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
createUsers[invite.email.toLowerCase()] = null;
|
||||
|
@ -116,10 +106,8 @@ export function usersNamespace(this: N8nApp): void {
|
|||
Logger.error(
|
||||
'Request to send email invite(s) to user(s) failed because no global member role was found in database',
|
||||
);
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
'Members role not found in database - inconsistent state',
|
||||
undefined,
|
||||
500,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -163,7 +151,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
} catch (error) {
|
||||
ErrorReporter.error(error);
|
||||
Logger.error('Failed to create user shells', { userShells: createUsers });
|
||||
throw new ResponseHelper.ResponseError('An error occurred during user creation');
|
||||
throw new ResponseHelper.InternalServerError('An error occurred during user creation');
|
||||
}
|
||||
|
||||
Logger.info('Created user shell(s) successfully', { userId: req.user.id });
|
||||
|
@ -245,7 +233,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
'Request to resolve signup token failed because of missing user IDs in query string',
|
||||
{ inviterId, inviteeId },
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Invalid payload', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid payload');
|
||||
}
|
||||
|
||||
// Postgres validates UUID format
|
||||
|
@ -254,7 +242,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
Logger.debug('Request to resolve signup token failed because of invalid user ID', {
|
||||
userId,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError('Invalid userId', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid userId');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,7 +253,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
'Request to resolve signup token failed because the ID of the inviter and/or the ID of the invitee were not found in database',
|
||||
{ inviterId, inviteeId },
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Invalid invite URL', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid invite URL');
|
||||
}
|
||||
|
||||
const invitee = users.find((user) => user.id === inviteeId);
|
||||
|
@ -275,10 +263,8 @@ export function usersNamespace(this: N8nApp): void {
|
|||
inviterId,
|
||||
inviteeId,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
'The invitation was likely either deleted or already claimed',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -291,7 +277,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
inviterId: inviter?.id,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Invalid request', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid request');
|
||||
}
|
||||
|
||||
void InternalHooksManager.getInstance().onUserInviteEmailClick({
|
||||
|
@ -321,7 +307,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
'Request to fill out a user shell failed because of missing properties in payload',
|
||||
{ payload: req.body },
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Invalid payload', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid payload');
|
||||
}
|
||||
|
||||
const validPassword = validatePassword(password);
|
||||
|
@ -339,7 +325,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
inviteeId,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Invalid payload or URL', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Invalid payload or URL');
|
||||
}
|
||||
|
||||
const invitee = users.find((user) => user.id === inviteeId) as User;
|
||||
|
@ -349,11 +335,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
'Request to fill out a user shell failed because the invite had already been accepted',
|
||||
{ inviteeId },
|
||||
);
|
||||
throw new ResponseHelper.ResponseError(
|
||||
'This invite has been accepted already',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
throw new ResponseHelper.BadRequestError('This invite has been accepted already');
|
||||
}
|
||||
|
||||
invitee.firstName = firstName;
|
||||
|
@ -398,16 +380,14 @@ export function usersNamespace(this: N8nApp): void {
|
|||
'Request to delete a user failed because it attempted to delete the requesting user',
|
||||
{ userId: req.user.id },
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Cannot delete your own user', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Cannot delete your own user');
|
||||
}
|
||||
|
||||
const { transferId } = req.query;
|
||||
|
||||
if (transferId === idToDelete) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
'Request to delete a user failed because the user to delete and the transferee are the same user',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -416,10 +396,8 @@ export function usersNamespace(this: N8nApp): void {
|
|||
});
|
||||
|
||||
if (!users.length || (transferId && users.length !== 2)) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
'Request to delete a user failed because the ID of the user to delete and/or the ID of the transferee were not found in DB',
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -502,10 +480,8 @@ export function usersNamespace(this: N8nApp): void {
|
|||
|
||||
if (!isEmailSetUp()) {
|
||||
Logger.error('Request to reinvite a user failed because email sending was not set up');
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
'Email sending must be set up in order to invite other users',
|
||||
undefined,
|
||||
500,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -515,7 +491,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
Logger.debug(
|
||||
'Request to reinvite a user failed because the ID of the reinvitee was not found in database',
|
||||
);
|
||||
throw new ResponseHelper.ResponseError('Could not find user', undefined, 404);
|
||||
throw new ResponseHelper.NotFoundError('Could not find user');
|
||||
}
|
||||
|
||||
if (reinvitee.password) {
|
||||
|
@ -523,11 +499,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
'Request to reinvite a user failed because the invite had already been accepted',
|
||||
{ userId: reinvitee.id },
|
||||
);
|
||||
throw new ResponseHelper.ResponseError(
|
||||
'User has already accepted the invite',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
throw new ResponseHelper.BadRequestError('User has already accepted the invite');
|
||||
}
|
||||
|
||||
const baseUrl = getInstanceBaseUrl();
|
||||
|
@ -538,7 +510,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
mailer = await UserManagementMailer.getInstance();
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new ResponseHelper.ResponseError(error.message, undefined, 500);
|
||||
throw new ResponseHelper.InternalServerError(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -559,11 +531,7 @@ export function usersNamespace(this: N8nApp): void {
|
|||
inviteAcceptUrl,
|
||||
domain: baseUrl,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError(
|
||||
`Failed to send email to ${reinvitee.email}`,
|
||||
undefined,
|
||||
500,
|
||||
);
|
||||
throw new ResponseHelper.InternalServerError(`Failed to send email to ${reinvitee.email}`);
|
||||
}
|
||||
|
||||
void InternalHooksManager.getInstance().onUserReinvite({
|
||||
|
|
|
@ -44,21 +44,13 @@ export class WaitingWebhooks {
|
|||
const execution = await Db.collections.Execution.findOne(executionId);
|
||||
|
||||
if (execution === undefined) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
`The execution "${executionId} does not exist.`,
|
||||
404,
|
||||
404,
|
||||
);
|
||||
throw new ResponseHelper.NotFoundError(`The execution "${executionId} does not exist.`);
|
||||
}
|
||||
|
||||
const fullExecutionData = ResponseHelper.unflattenExecutionData(execution);
|
||||
|
||||
if (fullExecutionData.finished || fullExecutionData.data.resultData.error) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
`The execution "${executionId} has finished already.`,
|
||||
409,
|
||||
409,
|
||||
);
|
||||
throw new ResponseHelper.ConflictError(`The execution "${executionId} has finished already.`);
|
||||
}
|
||||
|
||||
return this.startExecution(httpMethod, path, fullExecutionData, req, res);
|
||||
|
@ -107,7 +99,7 @@ export class WaitingWebhooks {
|
|||
try {
|
||||
workflowOwner = await getWorkflowOwner(workflowData.id!.toString());
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError('Could not find workflow', undefined, 404);
|
||||
throw new ResponseHelper.NotFoundError('Could not find workflow');
|
||||
}
|
||||
|
||||
const additionalData = await WorkflowExecuteAdditionalData.getBase(workflowOwner.id);
|
||||
|
@ -128,13 +120,13 @@ export class WaitingWebhooks {
|
|||
// 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 execution "${executionId}" with webhook suffix path "${path}" is not known.`;
|
||||
throw new ResponseHelper.ResponseError(errorMessage, 404, 404);
|
||||
throw new ResponseHelper.NotFoundError(errorMessage);
|
||||
}
|
||||
|
||||
const workflowStartNode = workflow.getNode(lastNodeExecuted);
|
||||
|
||||
if (workflowStartNode === null) {
|
||||
throw new ResponseHelper.ResponseError('Could not find node to process webhook.', 404, 404);
|
||||
throw new ResponseHelper.NotFoundError('Could not find node to process webhook.');
|
||||
}
|
||||
|
||||
const runExecutionData = fullExecutionData.data;
|
||||
|
|
|
@ -152,7 +152,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.ResponseError(errorMessage, 500, 500);
|
||||
throw new ResponseHelper.InternalServerError(errorMessage);
|
||||
}
|
||||
|
||||
const additionalKeys: IWorkflowDataProxyAdditionalKeys = {
|
||||
|
@ -169,7 +169,7 @@ export async function executeWebhook(
|
|||
try {
|
||||
user = await getWorkflowOwner(workflowData.id.toString());
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError('Cannot find workflow', undefined, 404);
|
||||
throw new ResponseHelper.NotFoundError('Cannot find workflow');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,7 +212,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.ResponseError(errorMessage, 500, 500);
|
||||
throw new ResponseHelper.InternalServerError(errorMessage);
|
||||
}
|
||||
|
||||
// Add the Response and Request so that this data can be accessed in the node
|
||||
|
@ -661,7 +661,7 @@ export async function executeWebhook(
|
|||
responseCallback(new Error('There was a problem executing the workflow'), {});
|
||||
}
|
||||
|
||||
throw new ResponseHelper.ResponseError(e.message, 500, 500);
|
||||
throw new ResponseHelper.InternalServerError(e.message);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line consistent-return
|
||||
|
@ -671,7 +671,7 @@ export async function executeWebhook(
|
|||
responseCallback(new Error('There was a problem executing the workflow'), {});
|
||||
}
|
||||
|
||||
throw new ResponseHelper.ResponseError(e.message, 500, 500);
|
||||
throw new ResponseHelper.InternalServerError(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ class App {
|
|||
|
||||
this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
if (!Db.isInitialized) {
|
||||
const error = new ResponseHelper.ResponseError('Database is not ready!', undefined, 503);
|
||||
const error = new ResponseHelper.ServiceUnavailableError('Database is not ready!');
|
||||
return ResponseHelper.sendErrorResponse(res, error);
|
||||
}
|
||||
|
||||
|
@ -318,7 +318,7 @@ class App {
|
|||
await connection.query('SELECT 1');
|
||||
// eslint-disable-next-line id-denylist
|
||||
} catch (err) {
|
||||
const error = new ResponseHelper.ResponseError('No Database connection!', undefined, 503);
|
||||
const error = new ResponseHelper.ServiceUnavailableError('No Database connection!');
|
||||
return ResponseHelper.sendErrorResponse(res, error);
|
||||
}
|
||||
|
||||
|
|
|
@ -172,10 +172,8 @@ executionsController.get(
|
|||
userId: req.user.id,
|
||||
filter: req.query.filter,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
`Parameter "filter" contained invalid JSON string.`,
|
||||
500,
|
||||
500,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -363,10 +361,8 @@ executionsController.post(
|
|||
executionId,
|
||||
},
|
||||
);
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`The execution with the ID "${executionId}" does not exist.`,
|
||||
404,
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -485,10 +481,8 @@ executionsController.post(
|
|||
requestFilters = requestFiltersRaw as IGetExecutionsQueryFilter;
|
||||
}
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
`Parameter "filter" contained invalid JSON string.`,
|
||||
500,
|
||||
500,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ nodesController.post(
|
|||
const { name } = req.body;
|
||||
|
||||
if (!name) {
|
||||
throw new ResponseHelper.ResponseError(PACKAGE_NAME_NOT_PROVIDED, undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(PACKAGE_NAME_NOT_PROVIDED);
|
||||
}
|
||||
|
||||
let parsed: CommunityPackages.ParsedPackageName;
|
||||
|
@ -79,21 +79,17 @@ nodesController.post(
|
|||
try {
|
||||
parsed = parseNpmPackageName(name);
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
error instanceof Error ? error.message : 'Failed to parse package name',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
if (parsed.packageName === STARTER_TEMPLATE_NAME) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
[
|
||||
`Package "${parsed.packageName}" is only a template`,
|
||||
'Please enter an actual package to install',
|
||||
].join('.'),
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -101,23 +97,19 @@ nodesController.post(
|
|||
const hasLoaded = hasPackageLoaded(name);
|
||||
|
||||
if (isInstalled && hasLoaded) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
[
|
||||
`Package "${parsed.packageName}" is already installed`,
|
||||
'To update it, click the corresponding button in the UI',
|
||||
].join('.'),
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
const packageStatus = await checkNpmPackageStatus(name);
|
||||
|
||||
if (packageStatus.status !== 'OK') {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
`Package "${name}" is banned so it cannot be installed`,
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -144,7 +136,7 @@ nodesController.post(
|
|||
|
||||
const clientError = error instanceof Error ? isClientError(error) : false;
|
||||
|
||||
throw new ResponseHelper.ResponseError(message, undefined, clientError ? 400 : 500);
|
||||
throw new ResponseHelper[clientError ? 'BadRequestError' : 'InternalServerError'](message);
|
||||
}
|
||||
|
||||
if (!hasLoaded) removePackageFromMissingList(name);
|
||||
|
@ -228,7 +220,7 @@ nodesController.delete(
|
|||
const { name } = req.query;
|
||||
|
||||
if (!name) {
|
||||
throw new ResponseHelper.ResponseError(PACKAGE_NAME_NOT_PROVIDED, undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(PACKAGE_NAME_NOT_PROVIDED);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -236,13 +228,13 @@ nodesController.delete(
|
|||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : UNKNOWN_FAILURE_REASON;
|
||||
|
||||
throw new ResponseHelper.ResponseError(message, undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(message);
|
||||
}
|
||||
|
||||
const installedPackage = await findInstalledPackage(name);
|
||||
|
||||
if (!installedPackage) {
|
||||
throw new ResponseHelper.ResponseError(PACKAGE_NOT_INSTALLED, undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(PACKAGE_NOT_INSTALLED);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -253,7 +245,7 @@ nodesController.delete(
|
|||
error instanceof Error ? error.message : UNKNOWN_FAILURE_REASON,
|
||||
].join(':');
|
||||
|
||||
throw new ResponseHelper.ResponseError(message, undefined, 500);
|
||||
throw new ResponseHelper.InternalServerError(message);
|
||||
}
|
||||
|
||||
const pushInstance = Push.getInstance();
|
||||
|
@ -288,13 +280,13 @@ nodesController.patch(
|
|||
const { name } = req.body;
|
||||
|
||||
if (!name) {
|
||||
throw new ResponseHelper.ResponseError(PACKAGE_NAME_NOT_PROVIDED, undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(PACKAGE_NAME_NOT_PROVIDED);
|
||||
}
|
||||
|
||||
const previouslyInstalledPackage = await findInstalledPackage(name);
|
||||
|
||||
if (!previouslyInstalledPackage) {
|
||||
throw new ResponseHelper.ResponseError(PACKAGE_NOT_INSTALLED, undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(PACKAGE_NOT_INSTALLED);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -345,7 +337,7 @@ nodesController.patch(
|
|||
error instanceof Error ? error.message : UNKNOWN_FAILURE_REASON,
|
||||
].join(':');
|
||||
|
||||
throw new ResponseHelper.ResponseError(message, undefined, 500);
|
||||
throw new ResponseHelper.InternalServerError(message);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -21,13 +21,18 @@ export const externalHooks: IExternalHooksClass = ExternalHooks();
|
|||
|
||||
export const tagsController = express.Router();
|
||||
|
||||
const workflowsEnabledMiddleware: express.RequestHandler = (req, res, next) => {
|
||||
if (config.getEnv('workflowTagsDisabled')) {
|
||||
throw new ResponseHelper.BadRequestError('Workflow tags are disabled');
|
||||
}
|
||||
next();
|
||||
};
|
||||
|
||||
// Retrieves all tags, with or without usage count
|
||||
tagsController.get(
|
||||
'/',
|
||||
workflowsEnabledMiddleware,
|
||||
ResponseHelper.send(async (req: express.Request): Promise<TagEntity[] | ITagWithCountDb[]> => {
|
||||
if (config.getEnv('workflowTagsDisabled')) {
|
||||
throw new ResponseHelper.ResponseError('Workflow tags are disabled');
|
||||
}
|
||||
if (req.query.withUsageCount === 'true') {
|
||||
const tablePrefix = config.getEnv('database.tablePrefix');
|
||||
return TagHelpers.getTagsWithCountDb(tablePrefix);
|
||||
|
@ -40,10 +45,8 @@ tagsController.get(
|
|||
// Creates a tag
|
||||
tagsController.post(
|
||||
'/',
|
||||
workflowsEnabledMiddleware,
|
||||
ResponseHelper.send(async (req: express.Request): Promise<TagEntity | void> => {
|
||||
if (config.getEnv('workflowTagsDisabled')) {
|
||||
throw new ResponseHelper.ResponseError('Workflow tags are disabled');
|
||||
}
|
||||
const newTag = new TagEntity();
|
||||
newTag.name = req.body.name.trim();
|
||||
|
||||
|
@ -61,11 +64,8 @@ tagsController.post(
|
|||
// Updates a tag
|
||||
tagsController.patch(
|
||||
'/:id',
|
||||
workflowsEnabledMiddleware,
|
||||
ResponseHelper.send(async (req: express.Request): Promise<TagEntity | void> => {
|
||||
if (config.getEnv('workflowTagsDisabled')) {
|
||||
throw new ResponseHelper.ResponseError('Workflow tags are disabled');
|
||||
}
|
||||
|
||||
const { name } = req.body;
|
||||
const { id } = req.params;
|
||||
|
||||
|
@ -87,18 +87,14 @@ tagsController.patch(
|
|||
|
||||
tagsController.delete(
|
||||
'/:id',
|
||||
workflowsEnabledMiddleware,
|
||||
ResponseHelper.send(async (req: TagsRequest.Delete): Promise<boolean> => {
|
||||
if (config.getEnv('workflowTagsDisabled')) {
|
||||
throw new ResponseHelper.ResponseError('Workflow tags are disabled');
|
||||
}
|
||||
if (
|
||||
config.getEnv('userManagement.isInstanceOwnerSetUp') === true &&
|
||||
req.user.globalRole.name !== 'owner'
|
||||
) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.UnauthorizedError(
|
||||
'You are not allowed to perform this action',
|
||||
undefined,
|
||||
403,
|
||||
'Only owners can remove tags',
|
||||
);
|
||||
}
|
||||
|
|
|
@ -391,11 +391,7 @@ export class Worker extends Command {
|
|||
await connection.query('SELECT 1');
|
||||
} catch (e) {
|
||||
LoggerProxy.error('No Database connection!', e);
|
||||
const error = new ResponseHelper.ResponseError(
|
||||
'No Database connection!',
|
||||
undefined,
|
||||
503,
|
||||
);
|
||||
const error = new ResponseHelper.ServiceUnavailableError('No Database connection!');
|
||||
return ResponseHelper.sendErrorResponse(res, error);
|
||||
}
|
||||
|
||||
|
@ -406,11 +402,7 @@ export class Worker extends Command {
|
|||
await Worker.jobQueue.client.ping();
|
||||
} catch (e) {
|
||||
LoggerProxy.error('No Redis connection!', e);
|
||||
const error = new ResponseHelper.ResponseError(
|
||||
'No Redis connection!',
|
||||
undefined,
|
||||
503,
|
||||
);
|
||||
const error = new ResponseHelper.ServiceUnavailableError('No Redis connection!');
|
||||
return ResponseHelper.sendErrorResponse(res, error);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ EECredentialsController.get(
|
|||
const includeDecryptedData = req.query.includeData === 'true';
|
||||
|
||||
if (Number.isNaN(Number(credentialId))) {
|
||||
throw new ResponseHelper.ResponseError(`Credential ID must be a number.`, undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(`Credential ID must be a number.`);
|
||||
}
|
||||
|
||||
let credential = (await EECredentials.get(
|
||||
|
@ -63,17 +63,15 @@ EECredentialsController.get(
|
|||
)) as CredentialsEntity & CredentialWithSharings;
|
||||
|
||||
if (!credential) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
'Could not load the credential. If you think this is an error, ask the owner to share it with you again',
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
const userSharing = credential.shared?.find((shared) => shared.user.id === req.user.id);
|
||||
|
||||
if (!userSharing && req.user.globalRole.name !== 'owner') {
|
||||
throw new ResponseHelper.ResponseError(`Forbidden.`, undefined, 403);
|
||||
throw new ResponseHelper.UnauthorizedError(`Forbidden.`);
|
||||
}
|
||||
|
||||
credential = EECredentials.addOwnerAndSharings(credential);
|
||||
|
@ -117,7 +115,7 @@ EECredentialsController.post(
|
|||
if (!ownsCredential) {
|
||||
const sharing = await EECredentials.getSharing(req.user, credentials.id);
|
||||
if (!sharing) {
|
||||
throw new ResponseHelper.ResponseError(`Forbidden`, undefined, 403);
|
||||
throw new ResponseHelper.UnauthorizedError(`Forbidden`);
|
||||
}
|
||||
|
||||
const decryptedData = await EECredentials.decrypt(encryptionKey, sharing.credentials);
|
||||
|
@ -144,13 +142,13 @@ EECredentialsController.put(
|
|||
!Array.isArray(shareWithIds) ||
|
||||
!shareWithIds.every((userId) => typeof userId === 'string')
|
||||
) {
|
||||
throw new ResponseHelper.ResponseError('Bad request', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Bad request');
|
||||
}
|
||||
|
||||
const { ownsCredential, credential } = await EECredentials.isOwned(req.user, credentialId);
|
||||
|
||||
if (!ownsCredential || !credential) {
|
||||
throw new ResponseHelper.ResponseError('Forbidden', undefined, 403);
|
||||
throw new ResponseHelper.UnauthorizedError('Forbidden');
|
||||
}
|
||||
|
||||
let amountRemoved: number | null = null;
|
||||
|
|
|
@ -75,16 +75,14 @@ credentialsController.get(
|
|||
const includeDecryptedData = req.query.includeData === 'true';
|
||||
|
||||
if (Number.isNaN(Number(credentialId))) {
|
||||
throw new ResponseHelper.ResponseError(`Credential ID must be a number.`, undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(`Credential ID must be a number.`);
|
||||
}
|
||||
|
||||
const sharing = await CredentialsService.getSharing(req.user, credentialId, ['credentials']);
|
||||
|
||||
if (!sharing) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`Credential with ID "${credentialId}" could not be found.`,
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -159,10 +157,8 @@ credentialsController.patch(
|
|||
credentialId,
|
||||
userId: req.user.id,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
'Credential to be updated not found. You can only update credentials owned by you',
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -183,10 +179,8 @@ credentialsController.patch(
|
|||
const responseData = await CredentialsService.update(credentialId, newCredentialData);
|
||||
|
||||
if (responseData === undefined) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
`Credential ID "${credentialId}" could not be found to be updated.`,
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -217,10 +211,8 @@ credentialsController.delete(
|
|||
credentialId,
|
||||
userId: req.user.id,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
'Credential to be deleted not found. You can only removed credentials owned by you',
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -206,11 +206,7 @@ export class CredentialsService {
|
|||
try {
|
||||
return await UserSettings.getEncryptionKey();
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY,
|
||||
undefined,
|
||||
500,
|
||||
);
|
||||
throw new ResponseHelper.InternalServerError(RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ oauth2CredentialController.get(
|
|||
const { id: credentialId } = req.query;
|
||||
|
||||
if (!credentialId) {
|
||||
throw new ResponseHelper.ResponseError('Required credential ID is missing', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Required credential ID is missing');
|
||||
}
|
||||
|
||||
const credential = await getCredentialForUser(credentialId, req.user);
|
||||
|
@ -68,14 +68,14 @@ oauth2CredentialController.get(
|
|||
userId: req.user.id,
|
||||
credentialId,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError(RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL, undefined, 404);
|
||||
throw new ResponseHelper.NotFoundError(RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL);
|
||||
}
|
||||
|
||||
let encryptionKey: string;
|
||||
try {
|
||||
encryptionKey = await UserSettings.getEncryptionKey();
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError((error as Error).message, undefined, 500);
|
||||
throw new ResponseHelper.InternalServerError((error as Error).message);
|
||||
}
|
||||
|
||||
const mode: WorkflowExecuteMode = 'internal';
|
||||
|
@ -173,12 +173,10 @@ oauth2CredentialController.get(
|
|||
const { code, state: stateEncoded } = req.query;
|
||||
|
||||
if (!code || !stateEncoded) {
|
||||
const errorResponse = new ResponseHelper.ResponseError(
|
||||
const errorResponse = new ResponseHelper.ServiceUnavailableError(
|
||||
`Insufficient parameters for OAuth2 callback. Received following query parameters: ${JSON.stringify(
|
||||
req.query,
|
||||
)}`,
|
||||
undefined,
|
||||
503,
|
||||
);
|
||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||
}
|
||||
|
@ -190,10 +188,8 @@ oauth2CredentialController.get(
|
|||
token: string;
|
||||
};
|
||||
} catch (error) {
|
||||
const errorResponse = new ResponseHelper.ResponseError(
|
||||
const errorResponse = new ResponseHelper.ServiceUnavailableError(
|
||||
'Invalid state format returned',
|
||||
undefined,
|
||||
503,
|
||||
);
|
||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||
}
|
||||
|
@ -205,10 +201,8 @@ oauth2CredentialController.get(
|
|||
userId: req.user?.id,
|
||||
credentialId: state.cid,
|
||||
});
|
||||
const errorResponse = new ResponseHelper.ResponseError(
|
||||
const errorResponse = new ResponseHelper.NotFoundError(
|
||||
RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL,
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||
}
|
||||
|
@ -217,11 +211,7 @@ oauth2CredentialController.get(
|
|||
try {
|
||||
encryptionKey = await UserSettings.getEncryptionKey();
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
(error as IDataObject).message as string,
|
||||
undefined,
|
||||
500,
|
||||
);
|
||||
throw new ResponseHelper.InternalServerError((error as IDataObject).message as string);
|
||||
}
|
||||
|
||||
const mode: WorkflowExecuteMode = 'internal';
|
||||
|
@ -250,10 +240,8 @@ oauth2CredentialController.get(
|
|||
userId: req.user?.id,
|
||||
credentialId: state.cid,
|
||||
});
|
||||
const errorResponse = new ResponseHelper.ResponseError(
|
||||
const errorResponse = new ResponseHelper.NotFoundError(
|
||||
'The OAuth2 callback state is invalid!',
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||
}
|
||||
|
@ -299,11 +287,7 @@ oauth2CredentialController.get(
|
|||
userId: req.user?.id,
|
||||
credentialId: state.cid,
|
||||
});
|
||||
const errorResponse = new ResponseHelper.ResponseError(
|
||||
'Unable to get access tokens!',
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
const errorResponse = new ResponseHelper.NotFoundError('Unable to get access tokens!');
|
||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,13 +46,13 @@ EEWorkflowController.put(
|
|||
!Array.isArray(shareWithIds) ||
|
||||
!shareWithIds.every((userId) => typeof userId === 'string')
|
||||
) {
|
||||
throw new ResponseHelper.ResponseError('Bad request', undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError('Bad request');
|
||||
}
|
||||
|
||||
const { ownsWorkflow, workflow } = await EEWorkflows.isOwned(req.user, workflowId);
|
||||
|
||||
if (!ownsWorkflow || !workflow) {
|
||||
throw new ResponseHelper.ResponseError('Forbidden', undefined, 403);
|
||||
throw new ResponseHelper.UnauthorizedError('Forbidden');
|
||||
}
|
||||
|
||||
let newShareeIds: string[] = [];
|
||||
|
@ -86,20 +86,14 @@ EEWorkflowController.get(
|
|||
);
|
||||
|
||||
if (!workflow) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
`Workflow with ID "${workflowId}" does not exist`,
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
throw new ResponseHelper.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.ResponseError(
|
||||
throw new ResponseHelper.UnauthorizedError(
|
||||
'It looks like you cannot access this workflow. Ask the owner to share it with you.',
|
||||
undefined,
|
||||
403,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -143,10 +137,8 @@ EEWorkflowController.post(
|
|||
try {
|
||||
EEWorkflows.validateCredentialPermissionsToUser(newWorkflow, allCredentials);
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
'The workflow you are trying to save contains credentials that are not shared with you',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -173,7 +165,7 @@ EEWorkflowController.post(
|
|||
|
||||
if (!savedWorkflow) {
|
||||
LoggerProxy.error('Failed to create workflow', { userId: req.user.id });
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
'An error occurred while saving your workflow. Please try again.',
|
||||
);
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ workflowsController.post(
|
|||
|
||||
if (!savedWorkflow) {
|
||||
LoggerProxy.error('Failed to create workflow', { userId: req.user.id });
|
||||
throw new ResponseHelper.ResponseError('Failed to save workflow');
|
||||
throw new ResponseHelper.InternalServerError('Failed to save workflow');
|
||||
}
|
||||
|
||||
if (tagIds && !config.getEnv('workflowTagsDisabled') && savedWorkflow.tags) {
|
||||
|
@ -152,13 +152,11 @@ workflowsController.get(
|
|||
`/from-url`,
|
||||
ResponseHelper.send(async (req: express.Request): Promise<IWorkflowResponse> => {
|
||||
if (req.query.url === undefined) {
|
||||
throw new ResponseHelper.ResponseError(`The parameter "url" is missing!`, undefined, 400);
|
||||
throw new ResponseHelper.BadRequestError(`The parameter "url" is missing!`);
|
||||
}
|
||||
if (!/^http[s]?:\/\/.*\.json$/i.exec(req.query.url as string)) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
`The parameter "url" is not valid! It does not seem to be a URL pointing to a n8n workflow JSON file.`,
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
let workflowData: IWorkflowResponse | undefined;
|
||||
|
@ -166,11 +164,7 @@ workflowsController.get(
|
|||
const { data } = await axios.get<IWorkflowResponse>(req.query.url as string);
|
||||
workflowData = data;
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
`The URL does not point to valid JSON file!`,
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
throw new ResponseHelper.BadRequestError(`The URL does not point to valid JSON file!`);
|
||||
}
|
||||
|
||||
// Do a very basic check if it is really a n8n-workflow-json
|
||||
|
@ -182,10 +176,8 @@ workflowsController.get(
|
|||
typeof workflowData.connections !== 'object' ||
|
||||
Array.isArray(workflowData.connections)
|
||||
) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
`The data in the file does not seem to be a n8n workflow JSON file!`,
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -222,10 +214,8 @@ workflowsController.get(
|
|||
workflowId,
|
||||
userId: req.user.id,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
'Could not load the workflow - you can only access workflows owned by you',
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -297,10 +287,8 @@ workflowsController.delete(
|
|||
workflowId,
|
||||
userId: req.user.id,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
'Could not delete the workflow - you can only remove workflows owned by you',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ export class EEWorkflowsService extends WorkflowsService {
|
|||
const previousVersion = await EEWorkflowsService.get({ id: parseInt(workflowId, 10) });
|
||||
|
||||
if (!previousVersion) {
|
||||
throw new ResponseHelper.ResponseError('Workflow not found', undefined, 404);
|
||||
throw new ResponseHelper.NotFoundError('Workflow not found');
|
||||
}
|
||||
|
||||
const allCredentials = await EECredentials.getAll(user);
|
||||
|
@ -180,10 +180,8 @@ export class EEWorkflowsService extends WorkflowsService {
|
|||
allCredentials,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
'Invalid workflow credentials - make sure you have access to all credentials and try again.',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,10 +124,8 @@ export class WorkflowsService {
|
|||
userId: user.id,
|
||||
filter,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.InternalServerError(
|
||||
`Parameter "filter" contained invalid JSON string.`,
|
||||
500,
|
||||
500,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -196,18 +194,14 @@ export class WorkflowsService {
|
|||
workflowId,
|
||||
userId: user.id,
|
||||
});
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
'You do not have permission to update this workflow. Ask the owner to share it with you.',
|
||||
undefined,
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
if (!forceSave && workflow.hash !== '' && workflow.hash !== shared.workflow.hash) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
'We are sorry, but the workflow has been changed in the meantime. Please reload the workflow and try again.',
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -290,10 +284,8 @@ export class WorkflowsService {
|
|||
const updatedWorkflow = await Db.collections.Workflow.findOne(workflowId, options);
|
||||
|
||||
if (updatedWorkflow === undefined) {
|
||||
throw new ResponseHelper.ResponseError(
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
`Workflow with ID "${workflowId}" could not be found to be updated.`,
|
||||
undefined,
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,10 +11,9 @@ interface ErrorReporter {
|
|||
report: (error: Error | string, options?: ReportingOptions) => void;
|
||||
}
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
const instance: ErrorReporter = {
|
||||
report: (error, options) => isProduction && Logger.error('ERROR', { error, options }),
|
||||
report: (error) =>
|
||||
error instanceof Error && Logger.error(`${error.constructor.name}: ${error.message}`),
|
||||
};
|
||||
|
||||
export function init(errorReporter: ErrorReporter) {
|
||||
|
|
|
@ -183,6 +183,7 @@ importers:
|
|||
passport-cookie: ^1.0.9
|
||||
passport-jwt: ^4.0.0
|
||||
pg: ^8.3.0
|
||||
picocolors: ^1.0.0
|
||||
posthog-node: ^1.3.0
|
||||
prom-client: ^13.1.0
|
||||
psl: ^1.8.0
|
||||
|
@ -263,6 +264,7 @@ importers:
|
|||
passport-cookie: 1.0.9
|
||||
passport-jwt: 4.0.0
|
||||
pg: 8.8.0
|
||||
picocolors: 1.0.0
|
||||
posthog-node: 1.3.0
|
||||
prom-client: 13.2.0
|
||||
psl: 1.9.0
|
||||
|
|
Loading…
Reference in a new issue