mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
fix(n8n Form Node): Resolve expressions in HTML fields (#13755)
This commit is contained in:
@@ -336,15 +336,7 @@ export class Form extends Node {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
fields = (context.getNodeParameter('formFields.values', []) as FormFieldsParameter).map(
|
||||
(field) => {
|
||||
if (field.fieldType === 'hiddenField') {
|
||||
field.fieldLabel = field.fieldName as string;
|
||||
}
|
||||
|
||||
return field;
|
||||
},
|
||||
);
|
||||
fields = context.getNodeParameter('formFields.values', []) as FormFieldsParameter;
|
||||
}
|
||||
|
||||
const method = context.getRequestObject().method;
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
type IWebhookResponseData,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { renderForm, sanitizeHtml } from './utils';
|
||||
import { renderForm } from './utils';
|
||||
|
||||
export const renderFormNode = async (
|
||||
context: IWebhookFunctions,
|
||||
@@ -42,12 +42,6 @@ export const renderFormNode = async (
|
||||
) as string) || 'Submit';
|
||||
}
|
||||
|
||||
for (const field of fields) {
|
||||
if (field.fieldType === 'html') {
|
||||
field.html = sanitizeHtml(field.html as string);
|
||||
}
|
||||
}
|
||||
|
||||
const appendAttribution = context.evaluateExpression(
|
||||
`{{ $('${trigger?.name}').params.options?.appendAttribution === false ? false : true }}`,
|
||||
) as boolean;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { type Response } from 'express';
|
||||
import type { MockProxy } from 'jest-mock-extended';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import {
|
||||
type FormFieldsParameter,
|
||||
@@ -9,10 +10,19 @@ import {
|
||||
import { renderFormNode } from '../formNodeUtils';
|
||||
|
||||
describe('formNodeUtils', () => {
|
||||
let webhookFunctions: MockProxy<IWebhookFunctions>;
|
||||
|
||||
beforeEach(() => {
|
||||
webhookFunctions = mock<IWebhookFunctions>();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should sanitize custom html', async () => {
|
||||
const executeFunctions = mock<IWebhookFunctions>();
|
||||
executeFunctions.getNode.mockReturnValue({ typeVersion: 2.1 } as any);
|
||||
executeFunctions.getNodeParameter.calledWith('options').mockReturnValue({
|
||||
webhookFunctions.getNode.mockReturnValue({ typeVersion: 2.1 } as any);
|
||||
webhookFunctions.getNodeParameter.calledWith('options').mockReturnValue({
|
||||
formTitle: 'Test Title',
|
||||
formDescription: 'Test Description',
|
||||
buttonLabel: 'Test Button Label',
|
||||
@@ -47,12 +57,12 @@ describe('formNodeUtils', () => {
|
||||
},
|
||||
];
|
||||
|
||||
executeFunctions.getNodeParameter.calledWith('formFields.values').mockReturnValue(formFields);
|
||||
webhookFunctions.getNodeParameter.calledWith('formFields.values').mockReturnValue(formFields);
|
||||
|
||||
const responseMock = mock<Response>({ render: mockRender } as any);
|
||||
const triggerMock = mock<NodeTypeAndVersion>({ name: 'triggerName' } as any);
|
||||
|
||||
await renderFormNode(executeFunctions, responseMock, triggerMock, formFields, 'test');
|
||||
await renderFormNode(webhookFunctions, responseMock, triggerMock, formFields, 'test');
|
||||
|
||||
expect(mockRender).toHaveBeenCalledWith('form-trigger', {
|
||||
appendAttribution: true,
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
isFormConnected,
|
||||
sanitizeHtml,
|
||||
validateResponseModeConfiguration,
|
||||
prepareFormFields,
|
||||
} from '../utils';
|
||||
|
||||
describe('FormTrigger, parseFormDescription', () => {
|
||||
@@ -994,4 +995,40 @@ describe('validateResponseModeConfiguration', () => {
|
||||
|
||||
expect(() => validateResponseModeConfiguration(webhookFunctions)).not.toThrow();
|
||||
});
|
||||
|
||||
describe('prepareFormFields', () => {
|
||||
it('should resolve expressions in html fields', async () => {
|
||||
webhookFunctions.evaluateExpression.mockImplementation((expression) => {
|
||||
if (expression === '{{ $json.formMode }}') {
|
||||
return 'Title';
|
||||
}
|
||||
});
|
||||
|
||||
const result = prepareFormFields(webhookFunctions, [
|
||||
{
|
||||
fieldLabel: 'Custom HTML',
|
||||
fieldType: 'html',
|
||||
elementName: 'test',
|
||||
html: '<h1>{{ $json.formMode }}</h1>',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result[0].html).toBe('<h1>Title</h1>');
|
||||
});
|
||||
it('should prepare hiddenField', async () => {
|
||||
const result = prepareFormFields(webhookFunctions, [
|
||||
{
|
||||
fieldLabel: '',
|
||||
fieldName: 'test',
|
||||
fieldType: 'hiddenField',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result[0]).toEqual({
|
||||
fieldLabel: 'test',
|
||||
fieldName: 'test',
|
||||
fieldType: 'hiddenField',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -72,6 +72,28 @@ export function sanitizeHtml(text: string) {
|
||||
});
|
||||
}
|
||||
|
||||
export const prepareFormFields = (context: IWebhookFunctions, fields: FormFieldsParameter) => {
|
||||
return fields.map((field) => {
|
||||
if (field.fieldType === 'html') {
|
||||
let { html } = field;
|
||||
|
||||
if (!html) return field;
|
||||
|
||||
for (const resolvable of getResolvables(html)) {
|
||||
html = html.replace(resolvable, context.evaluateExpression(resolvable) as string);
|
||||
}
|
||||
|
||||
field.html = sanitizeHtml(html as string);
|
||||
}
|
||||
|
||||
if (field.fieldType === 'hiddenField') {
|
||||
field.fieldLabel = field.fieldName as string;
|
||||
}
|
||||
|
||||
return field;
|
||||
});
|
||||
};
|
||||
|
||||
export function sanitizeCustomCss(css: string | undefined): string | undefined {
|
||||
if (!css) return undefined;
|
||||
|
||||
@@ -411,6 +433,8 @@ export function renderForm({
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
formFields = prepareFormFields(context, formFields);
|
||||
|
||||
const data = prepareFormData({
|
||||
formTitle,
|
||||
formDescription,
|
||||
@@ -476,17 +500,8 @@ export async function formWebhook(
|
||||
}
|
||||
|
||||
const mode = context.getMode() === 'manual' ? 'test' : 'production';
|
||||
const formFields = (context.getNodeParameter('formFields.values', []) as FormFieldsParameter).map(
|
||||
(field) => {
|
||||
if (field.fieldType === 'html') {
|
||||
field.html = sanitizeHtml(field.html as string);
|
||||
}
|
||||
if (field.fieldType === 'hiddenField') {
|
||||
field.fieldLabel = field.fieldName as string;
|
||||
}
|
||||
return field;
|
||||
},
|
||||
);
|
||||
const formFields = context.getNodeParameter('formFields.values', []) as FormFieldsParameter;
|
||||
|
||||
const method = context.getRequestObject().method;
|
||||
|
||||
validateResponseModeConfiguration(context);
|
||||
|
||||
Reference in New Issue
Block a user