mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2026-08-06 20:08:37 +02:00
* ✨ Inicial setup * ⚡ Add authentication handler * ⚡ Add GET /users route * ⚡ Improvements * 👕 Fix linting issues * ⚡ Add GET /users/:identifier endpoint * ⚡ Add POST /users endpoint * ⚡ Add DELETE /users/:identifier endpoint * ⚡ Return error using express native functions * 👕 Fix linting issue * ⚡ Possibility to add custom middleware * ⚡ Refactor POST /users * ⚡ Refactor DELETE /users * ⚡ Improve cleaning function * ⚡ Refactor GET /users and /users/:identifier * ⚡ Add API spec to route * ⚡ Add raw option to response helper * 🐛 Fix issue adding custom middleware * ⚡ Enable includeRole parameter in GET /users/:identifier * ⚡ Fix linting issues after merge * ⚡ Add missing config variable * ⚡ General improvements ⚡ asasas * ⚡ Add POST /users tests * Debug public API tests * Fix both sets of tests * ⚡ Improvements * ⚡ Load api versions dynamically * ⚡ Add endpoints to UM to create/delete an API Key * ⚡ Add index to apiKey column * 👕 Fix linting issue * ⚡ Clean open api spec * ⚡ Improvements * ⚡ Skip tests * 🐛 Fix bug with test * ⚡ Fix issue with the open api spec * ⚡ Fix merge issue * ⚡ Move token enpoints from /users to /me * ⚡ Apply feedback to openapi.yml * ⚡ Improvements to api-key endpoints * 🐛 Fix test to suport API dynamic loading * ⚡ Expose swagger ui in GET /{version}/docs * ⚡ Allow to disable public api via env variable * ⚡ Change handlers structure * 🚧 WIP create credential, delete credential complete * 🐛 fix route for creating api key * ⚡ return api key of authenticated user * ⚡ Expose public api activation to the settings * ⬆️ Update package-lock.json file * ⚡ Add execution resource * ⚡ Fix linting issues * 🛠 conditional public api endpoints excluding * ⚡️ create credential complete * ✨ Added n8n-card component. Added spacing utility classes. * ♻️ Made use of n8n-card in existing components. * ✨ Added api key setup view. * ✨ Added api keys get/create/delete actions. * ✨ Added public api permissions handling. * ♻️ Temporarily disabling card tests. * ♻️ Changed translations. Storing api key only in component. * ✨ Added utilities storybook entry * ♻️ Changed default value for generic copy input. * 🧹 clean up createCredential * ⚡ Add workflow resource to openapi spec * 🐛 Fix naming with env variable * ⚡ Allow multifile openapi spec * ⚡ Add POST /workflows/:workflowId/activate * fix up view, fix issues * remove delete api key modal * remove unused prop * clean up store api * remove getter * remove unused dispatch * fix component size to match * use existing components * match figma closely * fix bug when um is disabled in sidebar * set copy input color * remove unused import * ⚡ Remove css path * ⚡ Add POST /workflows/:workflowId/desactivate * ⚡ Add POST /workflows * Revert "⚡ Remove css path" a3d0a71719834ef37c88c23c83dfe662e96185aa * attempt to fix docker image issue * revert dockerfile test * disable public api * disable api differently * Revert "disable api differently" b70e29433e45934975e41ffdc32e288988aba9b0 * Revert "disable public api" 886e5164fb4135c164f77561bdb4427e5cd44ac1 * remove unused box * ⚡ PUT /workflows/:workflowId * ⚡ Refactor workflow endpoints * ⚡ Refactor executions endpoints * ⚡ Fix typo * ✅ add credentials tests * ✅ adjust users tests * update text * add try it out link * ⚡ Add delete, getAll and get to the workflow resource * address spacing comments * ⚡️ apply correct structure * ⚡ Add missing test to user resource and fix some issues * ⚡ Add workflow tests * ⚡ Add missing workflow tests and fix some issues * ⚡ Executions tests * ⚡ finish execution tests * ⚡ Validate credentials data depending on type * ⚡️ implement review comments * 👕 fix lint issues * ⚡ Add apiKey to sanatizeUser * ⚡ Fix issues with spec and tests * ⚡ Add new structure * ⚡ Validate credentials type and properties * ⚡ Make all endpoints except /users independent on UM * ⚡ Add instance base path to swagger UI * ⚡ Remove testing endpoints * ⚡ Fix issue with openapi tags * ⚡ Add endpoint GET /credentialTypes/:id/schema * 🐛 Fix issue adding json middleware to public api * ⚡ Add API playground path to FE * ⚡ Add telemetry and external hooks * 🐛 Fix issue with user tests * ⚡ Move /credentialTypes under /credentials * ⚡ Add test to GET /credentials/schema/:id * 🛠 refactor schema naming * ⚡ Add DB migrations asas * ✅ add tests for crd apiKey * ✨ Added API View telemetry events. * ⚡ Remove rsync from the building process as it is missing on alpine base image * ⚡ add missing BE telemetry events * 🐛 Fix credential tests * ⚡ address outstanding feedback * 🔨 Remove move:openapi script * ⬆️ update dependency * ⬆️ update package-lock.json * 👕 Fix linting issue * 🐛 Fix package.json issue * 🐛 fix migrations and tests * 🐛 fix typos + naming * 🚧 WIP fixing tests * ⚡ Add json schema validation * ⚡ Add missing fields to node schema * ⚡ Add limit max upper limit * ⚡ Rename id paths * 🐛 Fix tests * Add package-lock.jsonto custom dockerfile * ⬆️ Update package-lock.json * 🐛 Fix issue with build * ✏️ add beta label to api view * 🔥 Remove user endpoints * ⚡ Add schema examples to GET /credentials/schema/:id * 🔥 Remove user endpoints tests * 🐛 Fix tests * 🎨 adapt points from design review * 🔥 remove unnecessary text-align * ⚡️ update UI * 🐛 Fix issue with executions filter * ⚡ Add tags filter to GET /workflows * ⚡ Add missing error messages * ✅ add and update public api tests * ✅ add tests for owner activiating/deactivating non-owned wfs * 🧪 add tests for filter for tags * 🧪 add tests for more filter params * 🐛 fix inclusion of tags * 🛠 enhance readability * ⚡️ small refactorings * 💄 improving readability/naming * ⚡ Set API latest version dinamically * Add comments to toJsonSchema function * ⚡ Fix issue * ⚡ Make execution data usable * ⚡ Fix validation issue * ⚡ Rename data field and change parameter and options * 🐛 Fix issue parameter "detailsFieldFormat" not resolving correctly * Skip executions tests * skip workflow failing test * Rename details property to data * ⚡ Add includeData parameter * 🐛 Fix issue with openapi spec * 🐛 Fix linting issue * ⚡ Fix execution schema Co-authored-by: Iván Ovejero <ivov.src@gmail.com> Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Alex Grozav <alex@grozav.com> Co-authored-by: Mutasem <mutdmour@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
227 lines
6.1 KiB
TypeScript
227 lines
6.1 KiB
TypeScript
/* eslint-disable import/no-cycle */
|
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
/* eslint-disable no-console */
|
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
/* eslint-disable no-param-reassign */
|
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
import { Request, Response } from 'express';
|
|
import { parse, stringify } from 'flatted';
|
|
|
|
// eslint-disable-next-line import/no-cycle
|
|
import {
|
|
IExecutionDb,
|
|
IExecutionFlatted,
|
|
IExecutionFlattedDb,
|
|
IExecutionResponse,
|
|
IWorkflowDb,
|
|
} from '.';
|
|
|
|
/**
|
|
* Special Error which allows to return also an error code and http status code
|
|
*
|
|
* @export
|
|
* @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;
|
|
|
|
/**
|
|
* Creates an instance of ResponseError.
|
|
* @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)
|
|
* @memberof ResponseError
|
|
*/
|
|
constructor(message: string, errorCode?: number, httpStatusCode?: number, hint?: string) {
|
|
super(message);
|
|
this.name = 'ResponseError';
|
|
|
|
if (errorCode) {
|
|
this.errorCode = errorCode;
|
|
}
|
|
if (httpStatusCode) {
|
|
this.httpStatusCode = httpStatusCode;
|
|
}
|
|
if (hint) {
|
|
this.hint = hint;
|
|
}
|
|
}
|
|
}
|
|
|
|
export function basicAuthAuthorizationError(resp: Response, realm: string, message?: string) {
|
|
resp.statusCode = 401;
|
|
resp.setHeader('WWW-Authenticate', `Basic realm="${realm}"`);
|
|
resp.json({ code: resp.statusCode, message });
|
|
}
|
|
|
|
export function jwtAuthAuthorizationError(resp: Response, message?: string) {
|
|
resp.statusCode = 403;
|
|
resp.json({ code: resp.statusCode, message });
|
|
}
|
|
|
|
export function sendSuccessResponse(
|
|
res: Response,
|
|
data: any,
|
|
raw?: boolean,
|
|
responseCode?: number,
|
|
responseHeader?: object,
|
|
) {
|
|
if (responseCode !== undefined) {
|
|
res.status(responseCode);
|
|
}
|
|
|
|
if (responseHeader) {
|
|
res.header(responseHeader);
|
|
}
|
|
|
|
if (raw === true) {
|
|
if (typeof data === 'string') {
|
|
res.send(data);
|
|
} else {
|
|
res.json(data);
|
|
}
|
|
} else {
|
|
res.json({
|
|
data,
|
|
});
|
|
}
|
|
}
|
|
|
|
export function sendErrorResponse(res: Response, error: ResponseError) {
|
|
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 = {
|
|
code: 0,
|
|
message: 'Unknown error',
|
|
hint: '',
|
|
};
|
|
|
|
if (error.name === 'NodeApiError') {
|
|
Object.assign(response, error);
|
|
}
|
|
|
|
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;
|
|
}
|
|
res.status(httpStatusCode).json(response);
|
|
}
|
|
|
|
const isUniqueConstraintError = (error: Error) =>
|
|
['unique', 'duplicate'].some((s) => error.message.toLowerCase().includes(s));
|
|
|
|
/**
|
|
* A helper function which does not just allow to return Promises it also makes sure that
|
|
* all the responses have the same format
|
|
*
|
|
*
|
|
* @export
|
|
* @param {(req: Request, res: Response) => Promise<any>} processFunction The actual function to process the request
|
|
* @returns
|
|
*/
|
|
|
|
export function send(processFunction: (req: Request, res: Response) => Promise<any>, raw = false) {
|
|
// eslint-disable-next-line consistent-return
|
|
return async (req: Request, res: Response) => {
|
|
try {
|
|
const data = await processFunction(req, res);
|
|
|
|
sendSuccessResponse(res, data, raw);
|
|
} catch (error) {
|
|
if (error instanceof Error && isUniqueConstraintError(error)) {
|
|
error.message = 'There is already an entry with this name';
|
|
}
|
|
|
|
sendErrorResponse(res, error);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Flattens the Execution data.
|
|
* As it contains a lot of references which normally would be saved as duplicate data
|
|
* with regular JSON.stringify it gets flattened which keeps the references in place.
|
|
*
|
|
* @export
|
|
* @param {IExecutionDb} fullExecutionData The data to flatten
|
|
* @returns {IExecutionFlatted}
|
|
*/
|
|
export function flattenExecutionData(fullExecutionData: IExecutionDb): IExecutionFlatted {
|
|
// Flatten the data
|
|
const returnData: IExecutionFlatted = {
|
|
data: stringify(fullExecutionData.data),
|
|
mode: fullExecutionData.mode,
|
|
// @ts-ignore
|
|
waitTill: fullExecutionData.waitTill,
|
|
startedAt: fullExecutionData.startedAt,
|
|
stoppedAt: fullExecutionData.stoppedAt,
|
|
finished: fullExecutionData.finished ? fullExecutionData.finished : false,
|
|
workflowId: fullExecutionData.workflowId,
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
workflowData: fullExecutionData.workflowData!,
|
|
};
|
|
|
|
if (fullExecutionData.id !== undefined) {
|
|
returnData.id = fullExecutionData.id.toString();
|
|
}
|
|
|
|
if (fullExecutionData.retryOf !== undefined) {
|
|
returnData.retryOf = fullExecutionData.retryOf.toString();
|
|
}
|
|
|
|
if (fullExecutionData.retrySuccessId !== undefined) {
|
|
returnData.retrySuccessId = fullExecutionData.retrySuccessId.toString();
|
|
}
|
|
|
|
return returnData;
|
|
}
|
|
|
|
/**
|
|
* Unflattens the Execution data.
|
|
*
|
|
* @export
|
|
* @param {IExecutionFlattedDb} fullExecutionData The data to unflatten
|
|
* @returns {IExecutionResponse}
|
|
*/
|
|
export function unflattenExecutionData(fullExecutionData: IExecutionFlattedDb): IExecutionResponse {
|
|
const returnData: IExecutionResponse = {
|
|
id: fullExecutionData.id.toString(),
|
|
workflowData: fullExecutionData.workflowData as IWorkflowDb,
|
|
data: parse(fullExecutionData.data),
|
|
mode: fullExecutionData.mode,
|
|
waitTill: fullExecutionData.waitTill ? fullExecutionData.waitTill : undefined,
|
|
startedAt: fullExecutionData.startedAt,
|
|
stoppedAt: fullExecutionData.stoppedAt,
|
|
finished: fullExecutionData.finished ? fullExecutionData.finished : false,
|
|
workflowId: fullExecutionData.workflowId,
|
|
};
|
|
|
|
return returnData;
|
|
}
|