refactor(core): move tags endpoints to a separate file

This commit is contained in:
Michael Kret 2022-09-09 13:30:24 +03:00 committed by GitHub
parent e1025e888c
commit eebc51ec7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 123 additions and 134 deletions

View file

@ -19,7 +19,6 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable @typescript-eslint/no-shadow */ /* eslint-disable @typescript-eslint/no-shadow */
/* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/return-await */
/* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable no-continue */ /* eslint-disable no-continue */
@ -34,25 +33,17 @@ import express from 'express';
import { readFileSync, promises } from 'fs'; import { readFileSync, promises } from 'fs';
import { readFile } from 'fs/promises'; import { readFile } from 'fs/promises';
import { exec as callbackExec } from 'child_process'; import { exec as callbackExec } from 'child_process';
import _, { cloneDeep } from 'lodash'; import _ from 'lodash';
import { dirname as pathDirname, join as pathJoin, resolve as pathResolve } from 'path'; import { dirname as pathDirname, join as pathJoin, resolve as pathResolve } from 'path';
import { import { FindManyOptions, getConnectionManager, In } from 'typeorm';
FindManyOptions,
getConnectionManager,
In,
IsNull,
LessThanOrEqual,
Not,
Raw,
} from 'typeorm';
import bodyParser from 'body-parser'; import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser'; import cookieParser from 'cookie-parser';
import history from 'connect-history-api-fallback'; import history from 'connect-history-api-fallback';
import os from 'os'; import os from 'os';
// eslint-disable-next-line import/no-extraneous-dependencies // eslint-disable-next-line import/no-extraneous-dependencies
import clientOAuth1, { RequestOptions } from 'oauth-1.0a'; import clientOAuth1, { RequestOptions } from 'oauth-1.0a';
import axios, { AxiosRequestConfig, AxiosPromise } from 'axios'; import axios, { AxiosRequestConfig } from 'axios';
import { createHmac, randomBytes } from 'crypto'; import { createHmac } from 'crypto';
// IMPORTANT! Do not switch to anther bcrypt library unless really necessary and // IMPORTANT! Do not switch to anther bcrypt library unless really necessary and
// tested with all possible systems like Windows, Alpine on ARM, FreeBSD, ... // tested with all possible systems like Windows, Alpine on ARM, FreeBSD, ...
import { compare } from 'bcryptjs'; import { compare } from 'bcryptjs';
@ -61,7 +52,6 @@ import { BinaryDataManager, Credentials, LoadNodeParameterOptions, UserSettings
import { import {
ICredentialType, ICredentialType,
IDataObject,
INodeCredentials, INodeCredentials,
INodeCredentialsDetails, INodeCredentialsDetails,
INodeParameters, INodeParameters,
@ -70,11 +60,9 @@ import {
INodeTypeDescription, INodeTypeDescription,
INodeTypeNameVersion, INodeTypeNameVersion,
ITelemetrySettings, ITelemetrySettings,
IWorkflowBase,
LoggerProxy, LoggerProxy,
NodeHelpers, NodeHelpers,
WebhookHttpMethod, WebhookHttpMethod,
Workflow,
WorkflowExecuteMode, WorkflowExecuteMode,
} from 'n8n-workflow'; } from 'n8n-workflow';
@ -103,16 +91,11 @@ import {
ICustomRequest, ICustomRequest,
IDiagnosticInfo, IDiagnosticInfo,
IExecutionFlattedDb, IExecutionFlattedDb,
IExecutionFlattedResponse,
IExecutionResponse,
IExecutionsListResponse,
IExecutionsStopData, IExecutionsStopData,
IExecutionsSummary, IExecutionsSummary,
IExternalHooksClass, IExternalHooksClass,
IN8nUISettings, IN8nUISettings,
IPackageVersions, IPackageVersions,
ITagWithCountDb,
IWorkflowExecutionDataProcess,
NodeTypes, NodeTypes,
Push, Push,
ResponseHelper, ResponseHelper,
@ -122,39 +105,32 @@ import {
WebhookHelpers, WebhookHelpers,
WebhookServer, WebhookServer,
WorkflowExecuteAdditionalData, WorkflowExecuteAdditionalData,
WorkflowRunner,
getCredentialForUser, getCredentialForUser,
getCredentialWithoutUser, getCredentialWithoutUser,
} from '.'; } from '.';
import config from '../config'; import config from '../config';
import * as TagHelpers from './TagHelpers';
import { InternalHooksManager } from './InternalHooksManager'; import { InternalHooksManager } from './InternalHooksManager';
import { TagEntity } from './databases/entities/TagEntity';
import { getSharedWorkflowIds, whereClause } from './WorkflowHelpers'; import { getSharedWorkflowIds, whereClause } from './WorkflowHelpers';
import { getCredentialTranslationPath, getNodeTranslationPath } from './TranslationHelpers'; import { getCredentialTranslationPath, getNodeTranslationPath } from './TranslationHelpers';
import { WEBHOOK_METHODS } from './WebhookHelpers'; import { WEBHOOK_METHODS } from './WebhookHelpers';
import { userManagementRouter } from './UserManagement'; import { userManagementRouter } from './UserManagement';
import { resolveJwt } from './UserManagement/auth/jwt'; import { resolveJwt } from './UserManagement/auth/jwt';
import { User } from './databases/entities/User';
import type { import type {
ExecutionRequest, ExecutionRequest,
NodeParameterOptionsRequest, NodeParameterOptionsRequest,
OAuthRequest, OAuthRequest,
TagsRequest,
WorkflowRequest, WorkflowRequest,
} from './requests'; } from './requests';
import { DEFAULT_EXECUTIONS_GET_ALL_LIMIT, validateEntity } from './GenericHelpers';
import { ExecutionEntity } from './databases/entities/ExecutionEntity';
import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES } from './constants'; import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES } from './constants';
import { credentialsController } from './api/credentials.api'; import { credentialsController } from './api/credentials.api';
import { executionsController } from './api/executions.api'; import { executionsController } from './api/executions.api';
import { workflowsController } from './api/workflows.api'; import { workflowsController } from './api/workflows.api';
import { nodesController } from './api/nodes.api'; import { nodesController } from './api/nodes.api';
import { oauth2CredentialController } from './api/oauth2Credential.api'; import { oauth2CredentialController } from './api/oauth2Credential.api';
import { tagsController } from './api/tags.api';
import { import {
getInstanceBaseUrl, getInstanceBaseUrl,
isEmailSetUp, isEmailSetUp,
@ -783,110 +759,10 @@ class App {
// ---------------------------------------- // ----------------------------------------
this.app.use(`/${this.restEndpoint}/workflows`, workflowsController); this.app.use(`/${this.restEndpoint}/workflows`, workflowsController);
// Retrieves all tags, with or without usage count // ----------------------------------------
this.app.get( // Tags
`/${this.restEndpoint}/tags`, // ----------------------------------------
ResponseHelper.send( this.app.use(`/${this.restEndpoint}/tags`, tagsController);
async (
req: express.Request,
res: express.Response,
): 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);
}
return Db.collections.Tag.find({ select: ['id', 'name', 'createdAt', 'updatedAt'] });
},
),
);
// Creates a tag
this.app.post(
`/${this.restEndpoint}/tags`,
ResponseHelper.send(
async (req: express.Request, res: express.Response): 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();
await this.externalHooks.run('tag.beforeCreate', [newTag]);
await validateEntity(newTag);
const tag = await Db.collections.Tag.save(newTag);
await this.externalHooks.run('tag.afterCreate', [tag]);
return tag;
},
),
);
// Updates a tag
this.app.patch(
`/${this.restEndpoint}/tags/:id`,
ResponseHelper.send(
async (req: express.Request, res: express.Response): Promise<TagEntity | void> => {
if (config.getEnv('workflowTagsDisabled')) {
throw new ResponseHelper.ResponseError('Workflow tags are disabled');
}
const { name } = req.body;
const { id } = req.params;
const newTag = new TagEntity();
// @ts-ignore
newTag.id = id;
newTag.name = name.trim();
await this.externalHooks.run('tag.beforeUpdate', [newTag]);
await validateEntity(newTag);
const tag = await Db.collections.Tag.save(newTag);
await this.externalHooks.run('tag.afterUpdate', [tag]);
return tag;
},
),
);
// Deletes a tag
this.app.delete(
`/${this.restEndpoint}/tags/:id`,
ResponseHelper.send(
async (req: TagsRequest.Delete, res: express.Response): 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(
'You are not allowed to perform this action',
undefined,
403,
'Only owners can remove tags',
);
}
const id = Number(req.params.id);
await this.externalHooks.run('tag.beforeDelete', [id]);
await Db.collections.Tag.delete({ id });
await this.externalHooks.run('tag.afterDelete', [id]);
return true;
},
),
);
// Returns parameter values which normally get loaded from an external API or // Returns parameter values which normally get loaded from an external API or
// get generated dynamically // get generated dynamically
@ -1523,7 +1399,7 @@ class App {
if (!currentlyRunningExecutionIds.length) return []; if (!currentlyRunningExecutionIds.length) return [];
const findOptions: FindManyOptions<ExecutionEntity> = { const findOptions: FindManyOptions<IExecutionFlattedDb> = {
select: ['id', 'workflowId', 'mode', 'retryOf', 'startedAt'], select: ['id', 'workflowId', 'mode', 'retryOf', 'startedAt'],
order: { id: 'DESC' }, order: { id: 'DESC' },
where: { where: {

View file

@ -0,0 +1,113 @@
/* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
/* eslint-disable @typescript-eslint/no-invalid-void-type */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable no-param-reassign */
/* eslint-disable import/no-cycle */
import express from 'express';
import { Db, ExternalHooks, IExternalHooksClass, ITagWithCountDb, ResponseHelper } from '..';
import config from '../../config';
import * as TagHelpers from '../TagHelpers';
import { validateEntity } from '../GenericHelpers';
import { TagEntity } from '../databases/entities/TagEntity';
import { TagsRequest } from '../requests';
export const externalHooks: IExternalHooksClass = ExternalHooks();
export const tagsController = express.Router();
// Retrieves all tags, with or without usage count
tagsController.get(
'/',
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);
}
return Db.collections.Tag.find({ select: ['id', 'name', 'createdAt', 'updatedAt'] });
}),
);
// Creates a tag
tagsController.post(
'/',
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();
await externalHooks.run('tag.beforeCreate', [newTag]);
await validateEntity(newTag);
const tag = await Db.collections.Tag.save(newTag);
await externalHooks.run('tag.afterCreate', [tag]);
return tag;
}),
);
// Updates a tag
tagsController.patch(
'/:id',
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;
const newTag = new TagEntity();
// @ts-ignore
newTag.id = id;
newTag.name = name.trim();
await externalHooks.run('tag.beforeUpdate', [newTag]);
await validateEntity(newTag);
const tag = await Db.collections.Tag.save(newTag);
await externalHooks.run('tag.afterUpdate', [tag]);
return tag;
}),
);
tagsController.delete(
'/:id',
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(
'You are not allowed to perform this action',
undefined,
403,
'Only owners can remove tags',
);
}
const id = Number(req.params.id);
await externalHooks.run('tag.beforeDelete', [id]);
await Db.collections.Tag.delete({ id });
await externalHooks.run('tag.afterDelete', [id]);
return true;
}),
);