2023-11-27 06:33:21 -08:00
|
|
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
2022-07-24 08:25:01 -07:00
|
|
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
2023-07-31 02:00:48 -07:00
|
|
|
|
2022-02-05 13:55:43 -08:00
|
|
|
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
|
2023-07-31 02:00:48 -07:00
|
|
|
|
2022-02-05 13:55:43 -08:00
|
|
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
|
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
2023-07-31 02:00:48 -07:00
|
|
|
|
2023-06-16 07:26:35 -07:00
|
|
|
import get from 'lodash/get';
|
|
|
|
import merge from 'lodash/merge';
|
|
|
|
import set from 'lodash/set';
|
2024-06-06 22:39:31 -07:00
|
|
|
import url from 'node:url';
|
2022-02-05 13:55:43 -08:00
|
|
|
|
2024-09-18 00:19:33 -07:00
|
|
|
import { NodeApiError } from './errors/node-api.error';
|
|
|
|
import { NodeOperationError } from './errors/node-operation.error';
|
2023-01-27 05:56:56 -08:00
|
|
|
import type {
|
2022-02-05 13:55:43 -08:00
|
|
|
ICredentialDataDecryptedObject,
|
|
|
|
ICredentialsDecrypted,
|
|
|
|
IHttpRequestOptions,
|
|
|
|
IN8nHttpFullResponse,
|
|
|
|
INode,
|
|
|
|
INodeExecuteFunctions,
|
|
|
|
INodeExecutionData,
|
|
|
|
INodeParameters,
|
|
|
|
INodePropertyOptions,
|
|
|
|
INodeType,
|
2022-07-20 04:50:16 -07:00
|
|
|
DeclarativeRestApiSettings,
|
2022-02-05 13:55:43 -08:00
|
|
|
IRunExecutionData,
|
|
|
|
ITaskDataConnections,
|
|
|
|
IWorkflowDataProxyAdditionalKeys,
|
|
|
|
IWorkflowExecuteAdditionalData,
|
|
|
|
NodeParameterValue,
|
|
|
|
WorkflowExecuteMode,
|
|
|
|
IDataObject,
|
2022-06-03 08:25:07 -07:00
|
|
|
IExecuteData,
|
2022-02-05 13:55:43 -08:00
|
|
|
IExecuteSingleFunctions,
|
|
|
|
IN8nRequestOperations,
|
|
|
|
INodeProperties,
|
|
|
|
INodePropertyCollection,
|
2022-09-21 06:44:45 -07:00
|
|
|
NodeParameterValueType,
|
2022-02-05 13:55:43 -08:00
|
|
|
PostReceiveAction,
|
2023-10-31 05:59:33 -07:00
|
|
|
JsonObject,
|
2023-12-21 05:21:09 -08:00
|
|
|
CloseFunction,
|
2022-02-05 13:55:43 -08:00
|
|
|
} from './Interfaces';
|
2022-09-23 07:14:28 -07:00
|
|
|
import * as NodeHelpers from './NodeHelpers';
|
2024-06-06 22:39:31 -07:00
|
|
|
import { sleep } from './utils';
|
2024-09-18 00:19:33 -07:00
|
|
|
import type { Workflow } from './Workflow';
|
2022-02-05 13:55:43 -08:00
|
|
|
|
|
|
|
export class RoutingNode {
|
|
|
|
additionalData: IWorkflowExecuteAdditionalData;
|
|
|
|
|
|
|
|
connectionInputData: INodeExecutionData[];
|
|
|
|
|
|
|
|
node: INode;
|
|
|
|
|
|
|
|
mode: WorkflowExecuteMode;
|
|
|
|
|
|
|
|
runExecutionData: IRunExecutionData;
|
|
|
|
|
|
|
|
workflow: Workflow;
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
workflow: Workflow,
|
|
|
|
node: INode,
|
|
|
|
connectionInputData: INodeExecutionData[],
|
|
|
|
runExecutionData: IRunExecutionData,
|
|
|
|
additionalData: IWorkflowExecuteAdditionalData,
|
|
|
|
mode: WorkflowExecuteMode,
|
|
|
|
) {
|
|
|
|
this.additionalData = additionalData;
|
|
|
|
this.connectionInputData = connectionInputData;
|
|
|
|
this.runExecutionData = runExecutionData;
|
|
|
|
this.mode = mode;
|
|
|
|
this.node = node;
|
|
|
|
this.workflow = workflow;
|
|
|
|
}
|
|
|
|
|
2024-06-06 22:39:31 -07:00
|
|
|
// eslint-disable-next-line complexity
|
2022-02-05 13:55:43 -08:00
|
|
|
async runNode(
|
|
|
|
inputData: ITaskDataConnections,
|
|
|
|
runIndex: number,
|
|
|
|
nodeType: INodeType,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeData: IExecuteData,
|
2022-02-05 13:55:43 -08:00
|
|
|
nodeExecuteFunctions: INodeExecuteFunctions,
|
|
|
|
credentialsDecrypted?: ICredentialsDecrypted,
|
2023-11-24 09:17:06 -08:00
|
|
|
abortSignal?: AbortSignal,
|
2022-02-05 13:55:43 -08:00
|
|
|
): Promise<INodeExecutionData[][] | null | undefined> {
|
|
|
|
const items = inputData.main[0] as INodeExecutionData[];
|
|
|
|
const returnData: INodeExecutionData[] = [];
|
|
|
|
|
|
|
|
let credentialType: string | undefined;
|
|
|
|
|
|
|
|
if (nodeType.description.credentials?.length) {
|
|
|
|
credentialType = nodeType.description.credentials[0].name;
|
|
|
|
}
|
2023-12-21 05:21:09 -08:00
|
|
|
const closeFunctions: CloseFunction[] = [];
|
2022-02-05 13:55:43 -08:00
|
|
|
const executeFunctions = nodeExecuteFunctions.getExecuteFunctions(
|
|
|
|
this.workflow,
|
|
|
|
this.runExecutionData,
|
|
|
|
runIndex,
|
|
|
|
this.connectionInputData,
|
|
|
|
inputData,
|
|
|
|
this.node,
|
|
|
|
this.additionalData,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeData,
|
2022-02-05 13:55:43 -08:00
|
|
|
this.mode,
|
2023-12-21 05:21:09 -08:00
|
|
|
closeFunctions,
|
2023-11-24 09:17:06 -08:00
|
|
|
abortSignal,
|
2022-02-05 13:55:43 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
let credentials: ICredentialDataDecryptedObject | undefined;
|
|
|
|
if (credentialsDecrypted) {
|
|
|
|
credentials = credentialsDecrypted.data;
|
|
|
|
} else if (credentialType) {
|
2022-07-20 07:24:03 -07:00
|
|
|
try {
|
2024-08-27 06:23:58 -07:00
|
|
|
credentials =
|
|
|
|
(await executeFunctions.getCredentials<ICredentialDataDecryptedObject>(credentialType)) ||
|
|
|
|
{};
|
2022-07-20 07:24:03 -07:00
|
|
|
} catch (error) {
|
|
|
|
if (
|
|
|
|
nodeType.description.credentials?.length &&
|
|
|
|
nodeType.description.credentials[0].required
|
|
|
|
) {
|
|
|
|
// Only throw error if credential is mandatory
|
|
|
|
throw error;
|
|
|
|
} else {
|
|
|
|
// Do not request cred type since it doesn't exist
|
|
|
|
credentialType = undefined;
|
|
|
|
}
|
|
|
|
}
|
2022-02-05 13:55:43 -08:00
|
|
|
}
|
|
|
|
|
2024-06-06 22:39:31 -07:00
|
|
|
const { batching } = executeFunctions.getNodeParameter('requestOptions', 0, {}) as {
|
|
|
|
batching: { batch: { batchSize: number; batchInterval: number } };
|
|
|
|
};
|
|
|
|
|
|
|
|
const batchSize = batching?.batch?.batchSize > 0 ? batching?.batch?.batchSize : 1;
|
|
|
|
const batchInterval = batching?.batch.batchInterval;
|
|
|
|
|
|
|
|
const requestPromises = [];
|
|
|
|
const itemContext: Array<{
|
|
|
|
thisArgs: IExecuteSingleFunctions;
|
|
|
|
requestData: DeclarativeRestApiSettings.ResultOptions;
|
|
|
|
}> = [];
|
|
|
|
|
|
|
|
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
|
|
|
if (itemIndex > 0 && batchSize >= 0 && batchInterval > 0) {
|
|
|
|
if (itemIndex % batchSize === 0) {
|
|
|
|
await sleep(batchInterval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
itemContext.push({
|
|
|
|
thisArgs: nodeExecuteFunctions.getExecuteSingleFunctions(
|
2022-02-05 13:55:43 -08:00
|
|
|
this.workflow,
|
|
|
|
this.runExecutionData,
|
|
|
|
runIndex,
|
|
|
|
this.connectionInputData,
|
|
|
|
inputData,
|
|
|
|
this.node,
|
2024-06-06 22:39:31 -07:00
|
|
|
itemIndex,
|
2022-02-05 13:55:43 -08:00
|
|
|
this.additionalData,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeData,
|
2022-02-05 13:55:43 -08:00
|
|
|
this.mode,
|
2023-11-24 09:17:06 -08:00
|
|
|
abortSignal,
|
2024-06-06 22:39:31 -07:00
|
|
|
),
|
|
|
|
requestData: {
|
2022-02-05 13:55:43 -08:00
|
|
|
options: {
|
|
|
|
qs: {},
|
|
|
|
body: {},
|
2022-07-04 13:47:50 -07:00
|
|
|
headers: {},
|
2022-02-05 13:55:43 -08:00
|
|
|
},
|
|
|
|
preSend: [],
|
|
|
|
postReceive: [],
|
|
|
|
requestOperations: {},
|
2024-06-06 22:39:31 -07:00
|
|
|
} as DeclarativeRestApiSettings.ResultOptions,
|
|
|
|
});
|
2022-02-05 13:55:43 -08:00
|
|
|
|
2024-06-06 22:39:31 -07:00
|
|
|
const { proxy, timeout, allowUnauthorizedCerts } = itemContext[
|
|
|
|
itemIndex
|
|
|
|
].thisArgs.getNodeParameter('requestOptions', 0, {}) as {
|
|
|
|
proxy: string;
|
|
|
|
timeout: number;
|
|
|
|
allowUnauthorizedCerts: boolean;
|
|
|
|
};
|
2022-02-05 13:55:43 -08:00
|
|
|
|
2024-06-06 22:39:31 -07:00
|
|
|
if (nodeType.description.requestOperations) {
|
|
|
|
itemContext[itemIndex].requestData.requestOperations = {
|
|
|
|
...nodeType.description.requestOperations,
|
|
|
|
};
|
|
|
|
}
|
2022-02-05 13:55:43 -08:00
|
|
|
|
2024-06-06 22:39:31 -07:00
|
|
|
if (nodeType.description.requestDefaults) {
|
|
|
|
for (const key of Object.keys(nodeType.description.requestDefaults)) {
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
let value = (nodeType.description.requestDefaults as Record<string, any>)[key];
|
2022-02-05 13:55:43 -08:00
|
|
|
// If the value is an expression resolve it
|
|
|
|
value = this.getParameterValue(
|
|
|
|
value,
|
2024-06-06 22:39:31 -07:00
|
|
|
itemIndex,
|
2022-02-05 13:55:43 -08:00
|
|
|
runIndex,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeData,
|
2022-10-06 13:09:45 -07:00
|
|
|
{ $credentials: credentials, $version: this.node.typeVersion },
|
2023-02-01 06:25:43 -08:00
|
|
|
false,
|
2024-06-06 22:39:31 -07:00
|
|
|
) as string;
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
(itemContext[itemIndex].requestData.options as Record<string, any>)[key] = value;
|
|
|
|
}
|
|
|
|
}
|
2022-02-05 13:55:43 -08:00
|
|
|
|
2024-06-06 22:39:31 -07:00
|
|
|
for (const property of nodeType.description.properties) {
|
|
|
|
let value = get(this.node.parameters, property.name, []) as string | NodeParameterValue;
|
|
|
|
// If the value is an expression resolve it
|
|
|
|
value = this.getParameterValue(
|
|
|
|
value,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
executeData,
|
|
|
|
{ $credentials: credentials, $version: this.node.typeVersion },
|
|
|
|
false,
|
|
|
|
) as string | NodeParameterValue;
|
|
|
|
|
|
|
|
const tempOptions = this.getRequestOptionsFromParameters(
|
|
|
|
itemContext[itemIndex].thisArgs,
|
|
|
|
property,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
'',
|
|
|
|
{ $credentials: credentials, $value: value, $version: this.node.typeVersion },
|
|
|
|
);
|
|
|
|
|
|
|
|
this.mergeOptions(itemContext[itemIndex].requestData, tempOptions);
|
|
|
|
}
|
2022-02-05 13:55:43 -08:00
|
|
|
|
2024-06-06 22:39:31 -07:00
|
|
|
if (proxy) {
|
|
|
|
const proxyParsed = url.parse(proxy);
|
|
|
|
const proxyProperties = ['host', 'port'];
|
|
|
|
|
|
|
|
for (const property of proxyProperties) {
|
|
|
|
if (
|
|
|
|
!(property in proxyParsed) ||
|
|
|
|
proxyParsed[property as keyof typeof proxyParsed] === null
|
|
|
|
) {
|
|
|
|
throw new NodeOperationError(this.node, 'The proxy is not value', {
|
|
|
|
runIndex,
|
|
|
|
itemIndex,
|
|
|
|
description: `The proxy URL does not contain a valid value for "${property}"`,
|
|
|
|
});
|
|
|
|
}
|
2022-02-05 13:55:43 -08:00
|
|
|
}
|
|
|
|
|
2024-06-06 22:39:31 -07:00
|
|
|
itemContext[itemIndex].requestData.options.proxy = {
|
|
|
|
host: proxyParsed.hostname as string,
|
|
|
|
port: parseInt(proxyParsed.port!),
|
|
|
|
protocol: proxyParsed.protocol?.replace(/:$/, '') || undefined,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (proxyParsed.auth) {
|
|
|
|
const [username, password] = proxyParsed.auth.split(':');
|
|
|
|
itemContext[itemIndex].requestData.options.proxy!.auth = {
|
|
|
|
username,
|
|
|
|
password,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (allowUnauthorizedCerts) {
|
|
|
|
itemContext[itemIndex].requestData.options.skipSslCertificateValidation =
|
|
|
|
allowUnauthorizedCerts;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timeout) {
|
|
|
|
itemContext[itemIndex].requestData.options.timeout = timeout;
|
|
|
|
} else {
|
|
|
|
// set default timeout to 5 minutes
|
|
|
|
itemContext[itemIndex].requestData.options.timeout = 300_000;
|
|
|
|
}
|
|
|
|
|
|
|
|
requestPromises.push(
|
|
|
|
this.makeRoutingRequest(
|
|
|
|
itemContext[itemIndex].requestData,
|
|
|
|
itemContext[itemIndex].thisArgs,
|
|
|
|
itemIndex,
|
2022-02-05 13:55:43 -08:00
|
|
|
runIndex,
|
|
|
|
credentialType,
|
2024-06-06 22:39:31 -07:00
|
|
|
itemContext[itemIndex].requestData.requestOperations,
|
2022-02-05 13:55:43 -08:00
|
|
|
credentialsDecrypted,
|
2024-06-06 22:39:31 -07:00
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
2022-02-05 13:55:43 -08:00
|
|
|
|
2024-06-06 22:39:31 -07:00
|
|
|
const promisesResponses = await Promise.allSettled(requestPromises);
|
|
|
|
let responseData: any;
|
|
|
|
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
|
|
|
responseData = promisesResponses.shift();
|
|
|
|
if (responseData!.status !== 'fulfilled') {
|
|
|
|
if (responseData.reason.statusCode === 429) {
|
|
|
|
responseData.reason.message =
|
|
|
|
"Try spacing your requests out using the batching settings under 'Options'";
|
2022-02-05 13:55:43 -08:00
|
|
|
}
|
|
|
|
|
2024-06-06 22:39:31 -07:00
|
|
|
const error = responseData.reason;
|
|
|
|
|
|
|
|
if (itemContext[itemIndex].thisArgs?.continueOnFail()) {
|
2024-02-12 08:32:27 -08:00
|
|
|
returnData.push({ json: {}, error: error as NodeApiError });
|
2022-02-05 13:55:43 -08:00
|
|
|
continue;
|
|
|
|
}
|
2023-10-31 05:59:33 -07:00
|
|
|
|
2024-03-07 08:08:01 -08:00
|
|
|
if (error instanceof NodeApiError) {
|
2024-06-06 22:39:31 -07:00
|
|
|
set(error, 'context.itemIndex', itemIndex);
|
2024-03-07 08:08:01 -08:00
|
|
|
set(error, 'context.runIndex', runIndex);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
|
2023-10-31 05:59:33 -07:00
|
|
|
throw new NodeApiError(this.node, error as JsonObject, {
|
2022-09-29 17:17:46 -07:00
|
|
|
runIndex,
|
2024-06-06 22:39:31 -07:00
|
|
|
itemIndex,
|
|
|
|
message: error?.message,
|
|
|
|
description: error?.description,
|
|
|
|
httpCode: error.isAxiosError && error.response ? String(error.response?.status) : 'none',
|
2022-09-29 17:17:46 -07:00
|
|
|
});
|
2022-02-05 13:55:43 -08:00
|
|
|
}
|
2024-06-06 22:39:31 -07:00
|
|
|
|
|
|
|
if (itemContext[itemIndex].requestData.maxResults) {
|
|
|
|
// Remove not needed items in case APIs return to many
|
|
|
|
responseData.value.splice(itemContext[itemIndex].requestData.maxResults as number);
|
|
|
|
}
|
|
|
|
|
|
|
|
returnData.push(...responseData.value);
|
2022-02-05 13:55:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return [returnData];
|
|
|
|
}
|
|
|
|
|
|
|
|
mergeOptions(
|
2022-07-20 04:50:16 -07:00
|
|
|
destinationOptions: DeclarativeRestApiSettings.ResultOptions,
|
|
|
|
sourceOptions?: DeclarativeRestApiSettings.ResultOptions,
|
2022-02-05 13:55:43 -08:00
|
|
|
): void {
|
|
|
|
if (sourceOptions) {
|
|
|
|
destinationOptions.paginate = destinationOptions.paginate ?? sourceOptions.paginate;
|
|
|
|
destinationOptions.maxResults = sourceOptions.maxResults
|
|
|
|
? sourceOptions.maxResults
|
|
|
|
: destinationOptions.maxResults;
|
|
|
|
merge(destinationOptions.options, sourceOptions.options);
|
|
|
|
destinationOptions.preSend.push(...sourceOptions.preSend);
|
|
|
|
destinationOptions.postReceive.push(...sourceOptions.postReceive);
|
2022-10-05 04:36:09 -07:00
|
|
|
if (sourceOptions.requestOperations && destinationOptions.requestOperations) {
|
2022-02-05 13:55:43 -08:00
|
|
|
destinationOptions.requestOperations = Object.assign(
|
|
|
|
destinationOptions.requestOperations,
|
|
|
|
sourceOptions.requestOperations,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async runPostReceiveAction(
|
|
|
|
executeSingleFunctions: IExecuteSingleFunctions,
|
|
|
|
action: PostReceiveAction,
|
|
|
|
inputData: INodeExecutionData[],
|
|
|
|
responseData: IN8nHttpFullResponse,
|
|
|
|
parameterValue: string | IDataObject | undefined,
|
|
|
|
itemIndex: number,
|
|
|
|
runIndex: number,
|
|
|
|
): Promise<INodeExecutionData[]> {
|
|
|
|
if (typeof action === 'function') {
|
2024-01-17 07:08:50 -08:00
|
|
|
return await action.call(executeSingleFunctions, inputData, responseData);
|
2022-02-05 13:55:43 -08:00
|
|
|
}
|
|
|
|
if (action.type === 'rootProperty') {
|
|
|
|
try {
|
|
|
|
return inputData.flatMap((item) => {
|
|
|
|
let itemContent = get(item.json, action.properties.property);
|
|
|
|
|
|
|
|
if (!Array.isArray(itemContent)) {
|
|
|
|
itemContent = [itemContent];
|
|
|
|
}
|
|
|
|
return (itemContent as IDataObject[]).map((json) => {
|
|
|
|
return {
|
|
|
|
json,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
});
|
2022-10-26 02:55:39 -07:00
|
|
|
} catch (error) {
|
2023-10-31 05:59:33 -07:00
|
|
|
throw new NodeOperationError(this.node, error as Error, {
|
2022-10-26 02:55:39 -07:00
|
|
|
runIndex,
|
|
|
|
itemIndex,
|
|
|
|
description: `The rootProperty "${action.properties.property}" could not be found on item.`,
|
|
|
|
});
|
2022-02-05 13:55:43 -08:00
|
|
|
}
|
|
|
|
}
|
2022-12-15 16:05:42 -08:00
|
|
|
if (action.type === 'filter') {
|
|
|
|
const passValue = action.properties.pass;
|
|
|
|
|
|
|
|
inputData = inputData.filter((item) => {
|
|
|
|
// If the value is an expression resolve it
|
|
|
|
return this.getParameterValue(
|
|
|
|
passValue,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
executeSingleFunctions.getExecuteData(),
|
|
|
|
{
|
|
|
|
$response: responseData,
|
|
|
|
$responseItem: item.json,
|
|
|
|
$value: parameterValue,
|
|
|
|
$version: this.node.typeVersion,
|
|
|
|
},
|
|
|
|
false,
|
|
|
|
) as boolean;
|
|
|
|
});
|
|
|
|
|
|
|
|
return inputData;
|
|
|
|
}
|
2022-08-03 09:08:51 -07:00
|
|
|
if (action.type === 'limit') {
|
|
|
|
const maxResults = this.getParameterValue(
|
|
|
|
action.properties.maxResults,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
executeSingleFunctions.getExecuteData(),
|
2022-10-06 13:09:45 -07:00
|
|
|
{ $response: responseData, $value: parameterValue, $version: this.node.typeVersion },
|
2022-08-03 09:08:51 -07:00
|
|
|
false,
|
|
|
|
) as string;
|
|
|
|
return inputData.slice(0, parseInt(maxResults, 10));
|
|
|
|
}
|
2022-02-05 13:55:43 -08:00
|
|
|
if (action.type === 'set') {
|
|
|
|
const { value } = action.properties;
|
|
|
|
// If the value is an expression resolve it
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
json: this.getParameterValue(
|
|
|
|
value,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeSingleFunctions.getExecuteData(),
|
2022-10-06 13:09:45 -07:00
|
|
|
{ $response: responseData, $value: parameterValue, $version: this.node.typeVersion },
|
2022-02-05 13:55:43 -08:00
|
|
|
false,
|
|
|
|
) as IDataObject,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
}
|
|
|
|
if (action.type === 'sort') {
|
|
|
|
// Sort the returned options
|
|
|
|
const sortKey = action.properties.key;
|
|
|
|
inputData.sort((a, b) => {
|
2024-06-24 08:49:59 -07:00
|
|
|
const aSortValue = a.json[sortKey]?.toString().toLowerCase() ?? '';
|
|
|
|
const bSortValue = b.json[sortKey]?.toString().toLowerCase() ?? '';
|
2022-02-05 13:55:43 -08:00
|
|
|
if (aSortValue < bSortValue) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (aSortValue > bSortValue) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
return inputData;
|
|
|
|
}
|
|
|
|
if (action.type === 'setKeyValue') {
|
|
|
|
const returnData: INodeExecutionData[] = [];
|
|
|
|
|
|
|
|
inputData.forEach((item) => {
|
|
|
|
const returnItem: IDataObject = {};
|
|
|
|
for (const key of Object.keys(action.properties)) {
|
|
|
|
let propertyValue = (
|
|
|
|
action.properties as Record<
|
|
|
|
string,
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
any
|
|
|
|
>
|
|
|
|
)[key];
|
|
|
|
// If the value is an expression resolve it
|
|
|
|
propertyValue = this.getParameterValue(
|
|
|
|
propertyValue,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeSingleFunctions.getExecuteData(),
|
2022-02-05 13:55:43 -08:00
|
|
|
{
|
|
|
|
$response: responseData,
|
|
|
|
$responseItem: item.json,
|
|
|
|
$value: parameterValue,
|
2022-10-06 13:09:45 -07:00
|
|
|
$version: this.node.typeVersion,
|
2022-02-05 13:55:43 -08:00
|
|
|
},
|
2023-02-01 06:25:43 -08:00
|
|
|
false,
|
2022-02-05 13:55:43 -08:00
|
|
|
) as string;
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
(returnItem as Record<string, any>)[key] = propertyValue;
|
|
|
|
}
|
|
|
|
returnData.push({ json: returnItem });
|
|
|
|
});
|
|
|
|
|
|
|
|
return returnData;
|
|
|
|
}
|
|
|
|
if (action.type === 'binaryData') {
|
2022-12-23 09:27:07 -08:00
|
|
|
const body = (responseData.body = Buffer.from(responseData.body as string));
|
2022-02-05 13:55:43 -08:00
|
|
|
let { destinationProperty } = action.properties;
|
|
|
|
|
|
|
|
destinationProperty = this.getParameterValue(
|
|
|
|
destinationProperty,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeSingleFunctions.getExecuteData(),
|
2022-10-06 13:09:45 -07:00
|
|
|
{ $response: responseData, $value: parameterValue, $version: this.node.typeVersion },
|
2022-02-05 13:55:43 -08:00
|
|
|
false,
|
|
|
|
) as string;
|
|
|
|
|
2022-12-23 09:27:07 -08:00
|
|
|
const binaryData = await executeSingleFunctions.helpers.prepareBinaryData(body);
|
2022-02-05 13:55:43 -08:00
|
|
|
|
|
|
|
return inputData.map((item) => {
|
|
|
|
if (typeof item.json === 'string') {
|
|
|
|
// By default is probably the binary data as string set, in this case remove it
|
|
|
|
item.json = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
item.binary = {
|
|
|
|
[destinationProperty]: binaryData,
|
|
|
|
};
|
|
|
|
|
|
|
|
return item;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
2023-02-01 06:26:13 -08:00
|
|
|
async postProcessResponseData(
|
2022-02-05 13:55:43 -08:00
|
|
|
executeSingleFunctions: IExecuteSingleFunctions,
|
2023-02-01 06:26:13 -08:00
|
|
|
responseData: IN8nHttpFullResponse,
|
2022-07-20 04:50:16 -07:00
|
|
|
requestData: DeclarativeRestApiSettings.ResultOptions,
|
2022-02-05 13:55:43 -08:00
|
|
|
itemIndex: number,
|
|
|
|
runIndex: number,
|
|
|
|
): Promise<INodeExecutionData[]> {
|
|
|
|
let returnData: INodeExecutionData[] = [
|
|
|
|
{
|
|
|
|
json: responseData.body as IDataObject,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
if (requestData.postReceive.length) {
|
|
|
|
// If postReceive functionality got defined execute all of them
|
|
|
|
for (const postReceiveMethod of requestData.postReceive) {
|
|
|
|
for (const action of postReceiveMethod.actions) {
|
|
|
|
returnData = await this.runPostReceiveAction(
|
|
|
|
executeSingleFunctions,
|
|
|
|
action,
|
|
|
|
returnData,
|
|
|
|
responseData,
|
|
|
|
postReceiveMethod.data.parameterValue,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// No postReceive functionality got defined so simply add data as it is
|
2023-07-31 02:00:48 -07:00
|
|
|
|
2022-02-05 13:55:43 -08:00
|
|
|
if (Array.isArray(responseData.body)) {
|
|
|
|
returnData = responseData.body.map((json) => {
|
|
|
|
return {
|
|
|
|
json,
|
|
|
|
} as INodeExecutionData;
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
returnData[0].json = responseData.body as IDataObject;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return returnData;
|
|
|
|
}
|
|
|
|
|
2023-02-01 06:26:13 -08:00
|
|
|
async rawRoutingRequest(
|
|
|
|
executeSingleFunctions: IExecuteSingleFunctions,
|
|
|
|
requestData: DeclarativeRestApiSettings.ResultOptions,
|
|
|
|
credentialType?: string,
|
|
|
|
credentialsDecrypted?: ICredentialsDecrypted,
|
|
|
|
): Promise<IN8nHttpFullResponse> {
|
|
|
|
let responseData: IN8nHttpFullResponse;
|
|
|
|
requestData.options.returnFullResponse = true;
|
|
|
|
if (credentialType) {
|
|
|
|
responseData = (await executeSingleFunctions.helpers.httpRequestWithAuthentication.call(
|
|
|
|
executeSingleFunctions,
|
|
|
|
credentialType,
|
|
|
|
requestData.options as IHttpRequestOptions,
|
|
|
|
{ credentialsDecrypted },
|
|
|
|
)) as IN8nHttpFullResponse;
|
|
|
|
} else {
|
|
|
|
responseData = (await executeSingleFunctions.helpers.httpRequest(
|
|
|
|
requestData.options as IHttpRequestOptions,
|
|
|
|
)) as IN8nHttpFullResponse;
|
|
|
|
}
|
|
|
|
|
|
|
|
return responseData;
|
|
|
|
}
|
|
|
|
|
2022-02-05 13:55:43 -08:00
|
|
|
async makeRoutingRequest(
|
2022-07-20 04:50:16 -07:00
|
|
|
requestData: DeclarativeRestApiSettings.ResultOptions,
|
2022-02-05 13:55:43 -08:00
|
|
|
executeSingleFunctions: IExecuteSingleFunctions,
|
|
|
|
itemIndex: number,
|
|
|
|
runIndex: number,
|
|
|
|
credentialType?: string,
|
|
|
|
requestOperations?: IN8nRequestOperations,
|
|
|
|
credentialsDecrypted?: ICredentialsDecrypted,
|
|
|
|
): Promise<INodeExecutionData[]> {
|
|
|
|
let responseData: INodeExecutionData[];
|
|
|
|
for (const preSendMethod of requestData.preSend) {
|
|
|
|
requestData.options = await preSendMethod.call(
|
|
|
|
executeSingleFunctions,
|
|
|
|
requestData.options as IHttpRequestOptions,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const executePaginationFunctions = {
|
|
|
|
...executeSingleFunctions,
|
2022-07-20 04:50:16 -07:00
|
|
|
makeRoutingRequest: async (requestOptions: DeclarativeRestApiSettings.ResultOptions) => {
|
2024-01-17 07:08:50 -08:00
|
|
|
return await this.rawRoutingRequest(
|
2022-02-05 13:55:43 -08:00
|
|
|
executeSingleFunctions,
|
|
|
|
requestOptions,
|
|
|
|
credentialType,
|
|
|
|
credentialsDecrypted,
|
2024-01-17 07:08:50 -08:00
|
|
|
).then(
|
|
|
|
async (data) =>
|
|
|
|
await this.postProcessResponseData(
|
|
|
|
executeSingleFunctions,
|
|
|
|
data,
|
|
|
|
requestData,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
),
|
2022-02-05 13:55:43 -08:00
|
|
|
);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
if (requestData.paginate && requestOperations?.pagination) {
|
|
|
|
// Has pagination
|
|
|
|
|
|
|
|
if (typeof requestOperations.pagination === 'function') {
|
|
|
|
// Pagination via function
|
|
|
|
responseData = await requestOperations.pagination.call(
|
|
|
|
executePaginationFunctions,
|
|
|
|
requestData,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// Pagination via JSON properties
|
|
|
|
responseData = [];
|
|
|
|
if (!requestData.options.qs) {
|
|
|
|
requestData.options.qs = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Different predefined pagination types
|
2023-02-01 06:26:13 -08:00
|
|
|
if (requestOperations.pagination.type === 'generic') {
|
|
|
|
let tempResponseData: IN8nHttpFullResponse;
|
|
|
|
let tempResponseItems: INodeExecutionData[];
|
|
|
|
let makeAdditionalRequest: boolean;
|
|
|
|
let paginateRequestData: IHttpRequestOptions;
|
|
|
|
|
|
|
|
const additionalKeys = {
|
|
|
|
$request: requestData.options,
|
|
|
|
$response: {} as IN8nHttpFullResponse,
|
|
|
|
$version: this.node.typeVersion,
|
|
|
|
};
|
|
|
|
|
|
|
|
do {
|
|
|
|
additionalKeys.$request = requestData.options;
|
|
|
|
|
|
|
|
paginateRequestData = this.getParameterValue(
|
|
|
|
requestOperations.pagination.properties.request as unknown as NodeParameterValueType,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
executeSingleFunctions.getExecuteData(),
|
|
|
|
additionalKeys,
|
|
|
|
false,
|
|
|
|
) as object as IHttpRequestOptions;
|
|
|
|
|
|
|
|
// Make the HTTP request
|
|
|
|
tempResponseData = await this.rawRoutingRequest(
|
|
|
|
executeSingleFunctions,
|
|
|
|
{ ...requestData, options: { ...requestData.options, ...paginateRequestData } },
|
|
|
|
credentialType,
|
|
|
|
credentialsDecrypted,
|
|
|
|
);
|
|
|
|
|
|
|
|
additionalKeys.$response = tempResponseData;
|
|
|
|
|
|
|
|
tempResponseItems = await this.postProcessResponseData(
|
|
|
|
executeSingleFunctions,
|
|
|
|
tempResponseData,
|
|
|
|
requestData,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
);
|
|
|
|
|
|
|
|
responseData.push(...tempResponseItems);
|
|
|
|
|
|
|
|
makeAdditionalRequest = this.getParameterValue(
|
|
|
|
requestOperations.pagination.properties.continue,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
executeSingleFunctions.getExecuteData(),
|
|
|
|
additionalKeys,
|
|
|
|
false,
|
|
|
|
) as boolean;
|
|
|
|
} while (makeAdditionalRequest);
|
|
|
|
} else if (requestOperations.pagination.type === 'offset') {
|
|
|
|
const { properties } = requestOperations.pagination;
|
|
|
|
|
2022-02-05 13:55:43 -08:00
|
|
|
const optionsType = properties.type === 'body' ? 'body' : 'qs';
|
|
|
|
if (properties.type === 'body' && !requestData.options.body) {
|
|
|
|
requestData.options.body = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
(requestData.options[optionsType] as IDataObject)[properties.limitParameter] =
|
|
|
|
properties.pageSize;
|
|
|
|
(requestData.options[optionsType] as IDataObject)[properties.offsetParameter] = 0;
|
|
|
|
let tempResponseData: INodeExecutionData[];
|
|
|
|
do {
|
|
|
|
if (requestData?.maxResults) {
|
|
|
|
// Only request as many results as needed
|
|
|
|
const resultsMissing = (requestData?.maxResults as number) - responseData.length;
|
|
|
|
if (resultsMissing < 1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
(requestData.options[optionsType] as IDataObject)[properties.limitParameter] =
|
|
|
|
Math.min(properties.pageSize, resultsMissing);
|
|
|
|
}
|
|
|
|
|
|
|
|
tempResponseData = await this.rawRoutingRequest(
|
|
|
|
executeSingleFunctions,
|
|
|
|
requestData,
|
|
|
|
credentialType,
|
|
|
|
credentialsDecrypted,
|
2024-01-17 07:08:50 -08:00
|
|
|
).then(
|
|
|
|
async (data) =>
|
|
|
|
await this.postProcessResponseData(
|
|
|
|
executeSingleFunctions,
|
|
|
|
data,
|
|
|
|
requestData,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
),
|
2022-02-05 13:55:43 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
(requestData.options[optionsType] as IDataObject)[properties.offsetParameter] =
|
|
|
|
((requestData.options[optionsType] as IDataObject)[
|
|
|
|
properties.offsetParameter
|
|
|
|
] as number) + properties.pageSize;
|
|
|
|
|
|
|
|
if (properties.rootProperty) {
|
|
|
|
const tempResponseValue = get(tempResponseData[0].json, properties.rootProperty) as
|
|
|
|
| IDataObject[]
|
|
|
|
| undefined;
|
|
|
|
if (tempResponseValue === undefined) {
|
2022-06-03 08:25:07 -07:00
|
|
|
throw new NodeOperationError(
|
|
|
|
this.node,
|
2022-02-05 13:55:43 -08:00
|
|
|
`The rootProperty "${properties.rootProperty}" could not be found on item.`,
|
2022-06-03 08:25:07 -07:00
|
|
|
{ runIndex, itemIndex },
|
2022-02-05 13:55:43 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
tempResponseData = tempResponseValue.map((item) => {
|
|
|
|
return {
|
|
|
|
json: item,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
responseData.push(...tempResponseData);
|
|
|
|
} while (tempResponseData.length && tempResponseData.length === properties.pageSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// No pagination
|
|
|
|
responseData = await this.rawRoutingRequest(
|
|
|
|
executeSingleFunctions,
|
|
|
|
requestData,
|
|
|
|
credentialType,
|
|
|
|
credentialsDecrypted,
|
2024-01-17 07:08:50 -08:00
|
|
|
).then(
|
|
|
|
async (data) =>
|
|
|
|
await this.postProcessResponseData(
|
|
|
|
executeSingleFunctions,
|
|
|
|
data,
|
|
|
|
requestData,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
),
|
2022-02-05 13:55:43 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
return responseData;
|
|
|
|
}
|
|
|
|
|
|
|
|
getParameterValue(
|
2022-09-21 06:44:45 -07:00
|
|
|
parameterValue: NodeParameterValueType,
|
2022-02-05 13:55:43 -08:00
|
|
|
itemIndex: number,
|
|
|
|
runIndex: number,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeData: IExecuteData,
|
2022-02-05 13:55:43 -08:00
|
|
|
additionalKeys?: IWorkflowDataProxyAdditionalKeys,
|
|
|
|
returnObjectAsString = false,
|
2022-09-21 06:44:45 -07:00
|
|
|
): NodeParameterValueType {
|
2022-06-08 09:16:55 -07:00
|
|
|
if (
|
|
|
|
typeof parameterValue === 'object' ||
|
|
|
|
(typeof parameterValue === 'string' && parameterValue.charAt(0) === '=')
|
|
|
|
) {
|
2022-02-05 13:55:43 -08:00
|
|
|
return this.workflow.expression.getParameterValue(
|
|
|
|
parameterValue,
|
|
|
|
this.runExecutionData ?? null,
|
|
|
|
runIndex,
|
|
|
|
itemIndex,
|
|
|
|
this.node.name,
|
|
|
|
this.connectionInputData,
|
|
|
|
this.mode,
|
|
|
|
additionalKeys ?? {},
|
2022-06-03 08:25:07 -07:00
|
|
|
executeData,
|
2022-02-05 13:55:43 -08:00
|
|
|
returnObjectAsString,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return parameterValue;
|
|
|
|
}
|
|
|
|
|
2024-04-10 05:02:02 -07:00
|
|
|
// eslint-disable-next-line complexity
|
2022-02-05 13:55:43 -08:00
|
|
|
getRequestOptionsFromParameters(
|
|
|
|
executeSingleFunctions: IExecuteSingleFunctions,
|
|
|
|
nodeProperties: INodeProperties | INodePropertyOptions,
|
|
|
|
itemIndex: number,
|
|
|
|
runIndex: number,
|
|
|
|
path: string,
|
|
|
|
additionalKeys?: IWorkflowDataProxyAdditionalKeys,
|
2022-07-20 04:50:16 -07:00
|
|
|
): DeclarativeRestApiSettings.ResultOptions | undefined {
|
|
|
|
const returnData: DeclarativeRestApiSettings.ResultOptions = {
|
2022-02-05 13:55:43 -08:00
|
|
|
options: {
|
|
|
|
qs: {},
|
|
|
|
body: {},
|
2022-07-04 13:47:50 -07:00
|
|
|
headers: {},
|
2022-02-05 13:55:43 -08:00
|
|
|
},
|
|
|
|
preSend: [],
|
|
|
|
postReceive: [],
|
|
|
|
requestOperations: {},
|
|
|
|
};
|
|
|
|
let basePath = path ? `${path}.` : '';
|
|
|
|
|
2022-04-28 10:04:09 -07:00
|
|
|
if (
|
|
|
|
!NodeHelpers.displayParameter(
|
|
|
|
this.node.parameters,
|
|
|
|
nodeProperties,
|
|
|
|
this.node,
|
|
|
|
this.node.parameters,
|
|
|
|
)
|
|
|
|
) {
|
2022-02-05 13:55:43 -08:00
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
if (nodeProperties.routing) {
|
|
|
|
let parameterValue: string | undefined;
|
|
|
|
if (basePath + nodeProperties.name && 'type' in nodeProperties) {
|
2022-09-23 02:56:57 -07:00
|
|
|
// Extract value if it has extractValue defined or if it's a
|
|
|
|
// resourceLocator component. Resource locators are likely to have extractors
|
|
|
|
// and we can't know if the mode has one unless we dig all the way in.
|
|
|
|
const shouldExtractValue =
|
|
|
|
nodeProperties.extractValue !== undefined || nodeProperties.type === 'resourceLocator';
|
2022-02-05 13:55:43 -08:00
|
|
|
parameterValue = executeSingleFunctions.getNodeParameter(
|
|
|
|
basePath + nodeProperties.name,
|
2022-09-23 02:56:57 -07:00
|
|
|
undefined,
|
|
|
|
{ extractValue: shouldExtractValue },
|
2022-02-05 13:55:43 -08:00
|
|
|
) as string;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodeProperties.routing.operations) {
|
|
|
|
returnData.requestOperations = { ...nodeProperties.routing.operations };
|
|
|
|
}
|
|
|
|
if (nodeProperties.routing.request) {
|
|
|
|
for (const key of Object.keys(nodeProperties.routing.request)) {
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
let propertyValue = (nodeProperties.routing.request as Record<string, any>)[key];
|
|
|
|
// If the value is an expression resolve it
|
|
|
|
propertyValue = this.getParameterValue(
|
|
|
|
propertyValue,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeSingleFunctions.getExecuteData(),
|
2022-02-05 13:55:43 -08:00
|
|
|
{ ...additionalKeys, $value: parameterValue },
|
2022-07-04 13:47:50 -07:00
|
|
|
false,
|
2022-02-05 13:55:43 -08:00
|
|
|
) as string;
|
2022-09-21 06:44:45 -07:00
|
|
|
|
2022-02-05 13:55:43 -08:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
(returnData.options as Record<string, any>)[key] = propertyValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodeProperties.routing.send) {
|
|
|
|
let propertyName = nodeProperties.routing.send.property;
|
|
|
|
if (propertyName !== undefined) {
|
|
|
|
// If the propertyName is an expression resolve it
|
|
|
|
propertyName = this.getParameterValue(
|
|
|
|
propertyName,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeSingleFunctions.getExecuteData(),
|
2022-02-05 13:55:43 -08:00
|
|
|
additionalKeys,
|
|
|
|
true,
|
|
|
|
) as string;
|
|
|
|
|
|
|
|
let value = parameterValue;
|
|
|
|
|
|
|
|
if (nodeProperties.routing.send.value) {
|
|
|
|
const valueString = nodeProperties.routing.send.value;
|
|
|
|
// Special value got set
|
|
|
|
// If the valueString is an expression resolve it
|
|
|
|
value = this.getParameterValue(
|
|
|
|
valueString,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeSingleFunctions.getExecuteData(),
|
2022-02-05 13:55:43 -08:00
|
|
|
{ ...additionalKeys, $value: value },
|
2023-02-01 06:25:43 -08:00
|
|
|
false,
|
2022-02-05 13:55:43 -08:00
|
|
|
) as string;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodeProperties.routing.send.type === 'body') {
|
|
|
|
// Send in "body"
|
2023-07-31 02:00:48 -07:00
|
|
|
|
2022-02-05 13:55:43 -08:00
|
|
|
if (nodeProperties.routing.send.propertyInDotNotation === false) {
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
2024-03-26 06:22:57 -07:00
|
|
|
(returnData.options.body as Record<string, any>)[propertyName] = value;
|
2022-02-05 13:55:43 -08:00
|
|
|
} else {
|
|
|
|
set(returnData.options.body as object, propertyName, value);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Send in "query"
|
2023-07-31 02:00:48 -07:00
|
|
|
|
2022-02-05 13:55:43 -08:00
|
|
|
if (nodeProperties.routing.send.propertyInDotNotation === false) {
|
|
|
|
returnData.options.qs![propertyName] = value;
|
|
|
|
} else {
|
|
|
|
set(returnData.options.qs as object, propertyName, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodeProperties.routing.send.paginate !== undefined) {
|
|
|
|
let paginateValue = nodeProperties.routing.send.paginate;
|
|
|
|
if (typeof paginateValue === 'string' && paginateValue.charAt(0) === '=') {
|
|
|
|
// If the propertyName is an expression resolve it
|
|
|
|
paginateValue = this.getParameterValue(
|
|
|
|
paginateValue,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeSingleFunctions.getExecuteData(),
|
2022-02-05 13:55:43 -08:00
|
|
|
{ ...additionalKeys, $value: parameterValue },
|
|
|
|
true,
|
|
|
|
) as string;
|
|
|
|
}
|
|
|
|
|
|
|
|
returnData.paginate = !!paginateValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodeProperties.routing.send.preSend) {
|
|
|
|
returnData.preSend.push(...nodeProperties.routing.send.preSend);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nodeProperties.routing.output) {
|
|
|
|
if (nodeProperties.routing.output.maxResults !== undefined) {
|
|
|
|
let maxResultsValue = nodeProperties.routing.output.maxResults;
|
|
|
|
if (typeof maxResultsValue === 'string' && maxResultsValue.charAt(0) === '=') {
|
|
|
|
// If the propertyName is an expression resolve it
|
|
|
|
maxResultsValue = this.getParameterValue(
|
|
|
|
maxResultsValue,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
2022-06-03 08:25:07 -07:00
|
|
|
executeSingleFunctions.getExecuteData(),
|
2022-02-05 13:55:43 -08:00
|
|
|
{ ...additionalKeys, $value: parameterValue },
|
|
|
|
true,
|
|
|
|
) as string;
|
|
|
|
}
|
|
|
|
|
|
|
|
returnData.maxResults = maxResultsValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodeProperties.routing.output.postReceive) {
|
2022-07-26 05:43:36 -07:00
|
|
|
const postReceiveActions = nodeProperties.routing.output.postReceive.filter((action) => {
|
|
|
|
if (typeof action === 'function') {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof action.enabled === 'string' && action.enabled.charAt(0) === '=') {
|
|
|
|
// If the propertyName is an expression resolve it
|
|
|
|
return this.getParameterValue(
|
|
|
|
action.enabled,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
executeSingleFunctions.getExecuteData(),
|
|
|
|
{ ...additionalKeys, $value: parameterValue },
|
|
|
|
true,
|
|
|
|
) as boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
return action.enabled !== false;
|
2022-02-05 13:55:43 -08:00
|
|
|
});
|
2022-07-26 05:43:36 -07:00
|
|
|
|
|
|
|
if (postReceiveActions.length) {
|
|
|
|
returnData.postReceive.push({
|
|
|
|
data: {
|
|
|
|
parameterValue,
|
|
|
|
},
|
|
|
|
actions: postReceiveActions,
|
|
|
|
});
|
|
|
|
}
|
2022-02-05 13:55:43 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if there are any child properties
|
|
|
|
if (!Object.prototype.hasOwnProperty.call(nodeProperties, 'options')) {
|
|
|
|
// There are none so nothing else to check
|
|
|
|
return returnData;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Everything after this point can only be of type INodeProperties
|
|
|
|
nodeProperties = nodeProperties as INodeProperties;
|
|
|
|
|
|
|
|
// Check the child parameters
|
|
|
|
let value;
|
|
|
|
if (nodeProperties.type === 'options') {
|
|
|
|
const optionValue = NodeHelpers.getParameterValueByPath(
|
|
|
|
this.node.parameters,
|
|
|
|
nodeProperties.name,
|
|
|
|
basePath.slice(0, -1),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Find the selected option
|
|
|
|
const selectedOption = (nodeProperties.options as INodePropertyOptions[]).filter(
|
|
|
|
(option) => option.value === optionValue,
|
|
|
|
);
|
|
|
|
|
|
|
|
if (selectedOption.length) {
|
|
|
|
// Check only if option is set and if of type INodeProperties
|
|
|
|
const tempOptions = this.getRequestOptionsFromParameters(
|
|
|
|
executeSingleFunctions,
|
|
|
|
selectedOption[0],
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
`${basePath}${nodeProperties.name}`,
|
2022-10-06 13:09:45 -07:00
|
|
|
{ $value: optionValue, $version: this.node.typeVersion },
|
2022-02-05 13:55:43 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
this.mergeOptions(returnData, tempOptions);
|
|
|
|
}
|
|
|
|
} else if (nodeProperties.type === 'collection') {
|
|
|
|
value = NodeHelpers.getParameterValueByPath(
|
|
|
|
this.node.parameters,
|
|
|
|
nodeProperties.name,
|
|
|
|
basePath.slice(0, -1),
|
|
|
|
);
|
|
|
|
|
|
|
|
for (const propertyOption of nodeProperties.options as INodeProperties[]) {
|
|
|
|
if (
|
|
|
|
Object.keys(value as IDataObject).includes(propertyOption.name) &&
|
|
|
|
propertyOption.type !== undefined
|
|
|
|
) {
|
|
|
|
// Check only if option is set and if of type INodeProperties
|
|
|
|
const tempOptions = this.getRequestOptionsFromParameters(
|
|
|
|
executeSingleFunctions,
|
|
|
|
propertyOption,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
`${basePath}${nodeProperties.name}`,
|
2022-10-06 13:09:45 -07:00
|
|
|
{ $version: this.node.typeVersion },
|
2022-02-05 13:55:43 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
this.mergeOptions(returnData, tempOptions);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (nodeProperties.type === 'fixedCollection') {
|
|
|
|
basePath = `${basePath}${nodeProperties.name}.`;
|
|
|
|
for (const propertyOptions of nodeProperties.options as INodePropertyCollection[]) {
|
|
|
|
// Check if the option got set and if not skip it
|
|
|
|
value = NodeHelpers.getParameterValueByPath(
|
|
|
|
this.node.parameters,
|
|
|
|
propertyOptions.name,
|
|
|
|
basePath.slice(0, -1),
|
|
|
|
);
|
|
|
|
|
|
|
|
if (value === undefined) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure that it is always an array to be able to use the same code for multi and single
|
|
|
|
if (!Array.isArray(value)) {
|
|
|
|
value = [value];
|
|
|
|
}
|
|
|
|
|
2022-06-08 09:16:55 -07:00
|
|
|
// Resolve expressions
|
|
|
|
value = this.getParameterValue(
|
|
|
|
value as INodeParameters[],
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
executeSingleFunctions.getExecuteData(),
|
|
|
|
{ ...additionalKeys },
|
|
|
|
false,
|
|
|
|
) as INodeParameters[];
|
|
|
|
|
2022-02-05 13:55:43 -08:00
|
|
|
const loopBasePath = `${basePath}${propertyOptions.name}`;
|
2022-06-08 09:16:55 -07:00
|
|
|
for (let i = 0; i < value.length; i++) {
|
2022-02-05 13:55:43 -08:00
|
|
|
for (const option of propertyOptions.values) {
|
|
|
|
const tempOptions = this.getRequestOptionsFromParameters(
|
|
|
|
executeSingleFunctions,
|
|
|
|
option,
|
|
|
|
itemIndex,
|
|
|
|
runIndex,
|
|
|
|
nodeProperties.typeOptions?.multipleValues ? `${loopBasePath}[${i}]` : loopBasePath,
|
|
|
|
{ ...(additionalKeys || {}), $index: i, $parent: value[i] },
|
|
|
|
);
|
|
|
|
|
|
|
|
this.mergeOptions(returnData, tempOptions);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return returnData;
|
|
|
|
}
|
|
|
|
}
|