Skip to content

Commit

Permalink
refactor(core): Refactor node-details endpoints (no-changelog)
Browse files Browse the repository at this point in the history
  • Loading branch information
netroy committed Oct 6, 2023
1 parent b8608ce commit 93db1ad
Show file tree
Hide file tree
Showing 14 changed files with 344 additions and 557 deletions.
190 changes: 4 additions & 186 deletions packages/cli/src/Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,15 @@ import axios from 'axios';
import type { RequestOptions } from 'oauth-1.0a';
import clientOAuth1 from 'oauth-1.0a';

import {
Credentials,
LoadMappingOptions,
LoadNodeParameterOptions,
LoadNodeListSearch,
UserSettings,
} from 'n8n-core';
import { Credentials, UserSettings } from 'n8n-core';

import type {
INodeCredentials,
INodeCredentialsDetails,
INodeListSearchResult,
INodeParameters,
INodePropertyOptions,
INodeTypeNameVersion,
ITelemetrySettings,
WorkflowExecuteMode,
ICredentialTypes,
ExecutionStatus,
IExecutionsSummary,
ResourceMapperFields,
IN8nUISettings,
} from 'n8n-workflow';
import { LoggerProxy, jsonParse } from 'n8n-workflow';
Expand All @@ -71,22 +59,15 @@ import {
} from '@/constants';
import { credentialsController } from '@/credentials/credentials.controller';
import { oauth2CredentialController } from '@/credentials/oauth2Credential.api';
import type {
CurlHelper,
ExecutionRequest,
NodeListSearchRequest,
NodeParameterOptionsRequest,
OAuthRequest,
ResourceMapperRequest,
WorkflowRequest,
} from '@/requests';
import type { CurlHelper, ExecutionRequest, OAuthRequest, WorkflowRequest } from '@/requests';
import { registerController } from '@/decorators';
import {
AuthController,
LdapController,
MeController,
MFAController,
NodesController,
NodeDetailsController,
NodeTypesController,
OwnerController,
PasswordResetController,
Expand Down Expand Up @@ -543,6 +524,7 @@ export class Server extends AbstractServer {
postHog,
),
new MeController(logger, externalHooks, internalHooks, userService),
Container.get(NodeDetailsController),
new NodeTypesController(config, nodeTypes),
new PasswordResetController(
config,
Expand Down Expand Up @@ -720,170 +702,6 @@ export class Server extends AbstractServer {
LoggerProxy.warn(`Source Control initialization failed: ${error.message}`);
}

// ----------------------------------------

// Returns parameter values which normally get loaded from an external API or
// get generated dynamically
this.app.get(
`/${this.restEndpoint}/node-parameter-options`,
ResponseHelper.send(
async (req: NodeParameterOptionsRequest): Promise<INodePropertyOptions[]> => {
const nodeTypeAndVersion = jsonParse(
req.query.nodeTypeAndVersion,
) as INodeTypeNameVersion;

const { path, methodName } = req.query;

const currentNodeParameters = jsonParse(
req.query.currentNodeParameters,
) as INodeParameters;

let credentials: INodeCredentials | undefined;

if (req.query.credentials) {
credentials = jsonParse(req.query.credentials);
}

const loadDataInstance = new LoadNodeParameterOptions(
nodeTypeAndVersion,
this.nodeTypes,
path,
currentNodeParameters,
credentials,
);

const additionalData = await WorkflowExecuteAdditionalData.getBase(
req.user.id,
currentNodeParameters,
);

if (methodName) {
return loadDataInstance.getOptionsViaMethodName(methodName, additionalData);
}
// @ts-ignore
if (req.query.loadOptions) {
return loadDataInstance.getOptionsViaRequestProperty(
// @ts-ignore
jsonParse(req.query.loadOptions as string),
additionalData,
);
}

return [];
},
),
);

// Returns parameter values which normally get loaded from an external API or
// get generated dynamically
this.app.get(
`/${this.restEndpoint}/nodes-list-search`,
ResponseHelper.send(
async (
req: NodeListSearchRequest,
res: express.Response,
): Promise<INodeListSearchResult | undefined> => {
const nodeTypeAndVersion = jsonParse(
req.query.nodeTypeAndVersion,
) as INodeTypeNameVersion;

const { path, methodName } = req.query;

if (!req.query.currentNodeParameters) {
throw new ResponseHelper.BadRequestError(
'Parameter currentNodeParameters is required.',
);
}

const currentNodeParameters = jsonParse(
req.query.currentNodeParameters,
) as INodeParameters;

let credentials: INodeCredentials | undefined;

if (req.query.credentials) {
credentials = jsonParse(req.query.credentials);
}

const listSearchInstance = new LoadNodeListSearch(
nodeTypeAndVersion,
this.nodeTypes,
path,
currentNodeParameters,
credentials,
);

const additionalData = await WorkflowExecuteAdditionalData.getBase(
req.user.id,
currentNodeParameters,
);

if (methodName) {
return listSearchInstance.getOptionsViaMethodName(
methodName,
additionalData,
req.query.filter,
req.query.paginationToken,
);
}

throw new ResponseHelper.BadRequestError('Parameter methodName is required.');
},
),
);

this.app.get(
`/${this.restEndpoint}/get-mapping-fields`,
ResponseHelper.send(
async (
req: ResourceMapperRequest,
res: express.Response,
): Promise<ResourceMapperFields | undefined> => {
const nodeTypeAndVersion = jsonParse(
req.query.nodeTypeAndVersion,
) as INodeTypeNameVersion;

const { path, methodName } = req.query;

if (!req.query.currentNodeParameters) {
throw new ResponseHelper.BadRequestError(
'Parameter currentNodeParameters is required.',
);
}

const currentNodeParameters = jsonParse(
req.query.currentNodeParameters,
) as INodeParameters;

let credentials: INodeCredentials | undefined;

if (req.query.credentials) {
credentials = jsonParse(req.query.credentials);
}

const loadMappingOptionsInstance = new LoadMappingOptions(
nodeTypeAndVersion,
this.nodeTypes,
path,
currentNodeParameters,
credentials,
);

const additionalData = await WorkflowExecuteAdditionalData.getBase(
req.user.id,
currentNodeParameters,
);

const fields = await loadMappingOptionsInstance.getOptionsViaMethodName(
methodName,
additionalData,
);

return fields;
},
),
);

// ----------------------------------------
// Active Workflows
// ----------------------------------------
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/controllers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export { LdapController } from './ldap.controller';
export { MeController } from './me.controller';
export { MFAController } from './mfa.controller';
export { NodesController } from './nodes.controller';
export { NodeDetailsController } from './nodeDetails.controller';
export { NodeTypesController } from './nodeTypes.controller';
export { OwnerController } from './owner.controller';
export { PasswordResetController } from './passwordReset.controller';
Expand Down
113 changes: 113 additions & 0 deletions packages/cli/src/controllers/nodeDetails.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Service } from 'typedi';
import { NextFunction, Response } from 'express';
import type {
INodeListSearchResult,
INodePropertyOptions,
ResourceMapperFields,
} from 'n8n-workflow';
import { jsonParse } from 'n8n-workflow';
import { LoadNodeDetails } from 'n8n-core';

import { Authorized, Get, Middleware, RestController } from '@/decorators';
import {
NodeListSearchRequest,
NodeParameterOptionsRequest,
NodesOptionsRequest,
ResourceMapperRequest,
} from '@/requests';
import { getBase } from '@/WorkflowExecuteAdditionalData';
import { NodeTypes } from '@/NodeTypes';
import { BadRequestError } from '@/ResponseHelper';

@Service()
@Authorized()
@RestController('/node-details')
export class NodeDetailsController {
constructor(private readonly nodeTypes: NodeTypes) {}

@Middleware()
parseQueryParams(req: NodesOptionsRequest, res: Response, next: NextFunction) {
const { credentials, currentNodeParameters, nodeTypeAndVersion } = req.query;
if (!nodeTypeAndVersion) {
throw new BadRequestError('Parameter nodeTypeAndVersion is required.');
}
if (!currentNodeParameters) {
throw new BadRequestError('Parameter currentNodeParameters is required.');
}

req.params = {
nodeTypeAndVersion: jsonParse(nodeTypeAndVersion),
currentNodeParameters: jsonParse(currentNodeParameters),
credentials: credentials !== undefined ? jsonParse(credentials) : undefined,
};

next();
}

/** Returns parameter values which normally get loaded from an external API or get generated dynamically */
@Get('/parameter-options')
async getParameterOptions(req: NodeParameterOptionsRequest): Promise<INodePropertyOptions[]> {
const { path, methodName, loadOptions } = req.query;
const { credentials, currentNodeParameters, nodeTypeAndVersion } = req.params;
const additionalData = await getBase(req.user.id, currentNodeParameters);
const loadDataInstance = new LoadNodeDetails(
nodeTypeAndVersion,
this.nodeTypes,
currentNodeParameters,
credentials,
);

if (methodName) {
return loadDataInstance.getParamOptionsViaMethodName(methodName, path, additionalData);
}

if (loadOptions) {
return loadDataInstance.getParamOptionsViaLoadOptions(jsonParse(loadOptions), additionalData);
}

return [];
}

@Get('/list-search')
async listSearch(req: NodeListSearchRequest): Promise<INodeListSearchResult | undefined> {
const { path, methodName, filter, paginationToken } = req.query;
if (!methodName) {
throw new BadRequestError('Parameter methodName is required.');
}

const { credentials, currentNodeParameters, nodeTypeAndVersion } = req.params;
const additionalData = await getBase(req.user.id, currentNodeParameters);
const listSearchInstance = new LoadNodeDetails(
nodeTypeAndVersion,
this.nodeTypes,
currentNodeParameters,
credentials,
);
return listSearchInstance.getNodeListSearchResult(
methodName,
path,
additionalData,
filter,
paginationToken,
);
}

@Get('/mapping-fields')
async getMappingFields(req: ResourceMapperRequest): Promise<ResourceMapperFields | undefined> {
const { path, methodName } = req.query;
if (!methodName) {
throw new BadRequestError('Parameter methodName is required.');
}

const { credentials, currentNodeParameters, nodeTypeAndVersion } = req.params;
const additionalData = await getBase(req.user.id, currentNodeParameters);
const loadMappingOptionsInstance = new LoadNodeDetails(
nodeTypeAndVersion,
this.nodeTypes,
currentNodeParameters,
credentials,
);

return loadMappingOptionsInstance.getMapperFields(methodName, path, additionalData);
}
}
Loading

0 comments on commit 93db1ad

Please sign in to comment.