refactor(core): move node-types endpoints to a separate file n8n-4584 (#4068)

This commit is contained in:
Michael Kret
2022-09-09 18:31:06 +03:00
committed by GitHub
parent a73ac1d94f
commit 2c7ef1e550
3 changed files with 169 additions and 154 deletions

View File

@@ -26,9 +26,9 @@ import {
NodeTypes,
WorkflowRunner,
ResponseHelper,
IExecutionFlattedDb,
} from '..';
import * as config from '../../config';
import { ExecutionEntity } from '../databases/entities/ExecutionEntity';
import { User } from '../databases/entities/User';
import { DEFAULT_EXECUTIONS_GET_ALL_LIMIT } from '../GenericHelpers';
import { getLogger } from '../Logger';
@@ -137,7 +137,7 @@ executionsController.get(
const sharedWorkflowIds = await getSharedWorkflowIds(req.user);
const findOptions: FindManyOptions<ExecutionEntity> = {
const findOptions: FindManyOptions<IExecutionFlattedDb> = {
select: [
'id',
'finished',

View File

@@ -0,0 +1,164 @@
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import/no-cycle */
import express from 'express';
import { readFile } from 'fs/promises';
import _ from 'lodash';
import {
ICredentialType,
INodeType,
INodeTypeDescription,
INodeTypeNameVersion,
NodeHelpers,
} from 'n8n-workflow';
import { CredentialTypes, NodeTypes, ResponseHelper } from '..';
import config from '../../config';
import { getNodeTranslationPath } from '../TranslationHelpers';
function isOAuth(credType: ICredentialType) {
return (
Array.isArray(credType.extends) &&
credType.extends.some((parentType) =>
['oAuth2Api', 'googleOAuth2Api', 'oAuth1Api'].includes(parentType),
)
);
}
/**
* Whether any of the node's credential types may be used to
* make a request from a node other than itself.
*/
function supportsProxyAuth(description: INodeTypeDescription) {
if (!description.credentials) return false;
const credentialTypes = CredentialTypes();
return description.credentials.some(({ name }) => {
const credType = credentialTypes.getByName(name);
if (credType.authenticate !== undefined) return true;
return isOAuth(credType);
});
}
const CUSTOM_API_CALL_NAME = 'Custom API Call';
const CUSTOM_API_CALL_KEY = '__CUSTOM_API_CALL__';
/**
* Inject a `Custom API Call` option into `resource` and `operation`
* parameters in a node that supports proxy auth.
*/
function injectCustomApiCallOption(description: INodeTypeDescription) {
if (!supportsProxyAuth(description)) return description;
description.properties.forEach((p) => {
if (
['resource', 'operation'].includes(p.name) &&
Array.isArray(p.options) &&
p.options[p.options.length - 1].name !== CUSTOM_API_CALL_NAME
) {
p.options.push({
name: CUSTOM_API_CALL_NAME,
value: CUSTOM_API_CALL_KEY,
});
}
return p;
});
return description;
}
export const nodeTypesController = express.Router();
// Returns all the node-types
nodeTypesController.get(
'/',
ResponseHelper.send(async (req: express.Request): Promise<INodeTypeDescription[]> => {
const returnData: INodeTypeDescription[] = [];
const onlyLatest = req.query.onlyLatest === 'true';
const nodeTypes = NodeTypes();
const allNodes = nodeTypes.getAll();
const getNodeDescription = (nodeType: INodeType): INodeTypeDescription => {
const nodeInfo: INodeTypeDescription = { ...nodeType.description };
if (req.query.includeProperties !== 'true') {
// @ts-ignore
delete nodeInfo.properties;
}
return nodeInfo;
};
if (onlyLatest) {
allNodes.forEach((nodeData) => {
const nodeType = NodeHelpers.getVersionedNodeType(nodeData);
const nodeInfo: INodeTypeDescription = getNodeDescription(nodeType);
returnData.push(nodeInfo);
});
} else {
allNodes.forEach((nodeData) => {
const allNodeTypes = NodeHelpers.getVersionedNodeTypeAll(nodeData);
allNodeTypes.forEach((element) => {
const nodeInfo: INodeTypeDescription = getNodeDescription(element);
returnData.push(nodeInfo);
});
});
}
return returnData;
}),
);
// Returns node information based on node names and versions
nodeTypesController.post(
'/',
ResponseHelper.send(async (req: express.Request): Promise<INodeTypeDescription[]> => {
const nodeInfos = _.get(req, 'body.nodeInfos', []) as INodeTypeNameVersion[];
const defaultLocale = config.getEnv('defaultLocale');
if (defaultLocale === 'en') {
return nodeInfos.reduce<INodeTypeDescription[]>((acc, { name, version }) => {
const { description } = NodeTypes().getByNameAndVersion(name, version);
acc.push(injectCustomApiCallOption(description));
return acc;
}, []);
}
async function populateTranslation(
name: string,
version: number,
nodeTypes: INodeTypeDescription[],
) {
const { description, sourcePath } = NodeTypes().getWithSourcePath(name, version);
const translationPath = await getNodeTranslationPath({
nodeSourcePath: sourcePath,
longNodeType: description.name,
locale: defaultLocale,
});
try {
const translation = await readFile(translationPath, 'utf8');
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
description.translation = JSON.parse(translation);
} catch (error) {
// ignore - no translation exists at path
}
nodeTypes.push(injectCustomApiCallOption(description));
}
const nodeTypes: INodeTypeDescription[] = [];
const promises = nodeInfos.map(async ({ name, version }) =>
populateTranslation(name, version, nodeTypes),
);
await Promise.all(promises);
return nodeTypes;
}),
);