UNPKG

n8n-nodes-base

Version:

Base nodes of n8n

484 lines 18 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SEND_AND_WAIT_WAITING_TOOLTIP = void 0; exports.getSendAndWaitProperties = getSendAndWaitProperties; exports.sendAndWaitWebhook = sendAndWaitWebhook; exports.getSendAndWaitConfig = getSendAndWaitConfig; exports.createButton = createButton; exports.createEmail = createEmail; const isbot_1 = __importDefault(require("isbot")); const n8n_core_1 = require("n8n-core"); const n8n_workflow_1 = require("n8n-workflow"); const descriptions_1 = require("./descriptions"); const email_templates_1 = require("./email-templates"); const cssVariables_1 = require("../../nodes/Form/cssVariables"); const Form_node_1 = require("../../nodes/Form/Form.node"); const utils_1 = require("../../nodes/Form/utils/utils"); const utilities_1 = require("../utilities"); const INPUT_FIELD_IDENTIFIER = 'field-0'; const appendAttributionOption = { displayName: 'Append n8n Attribution', name: 'appendAttribution', type: 'boolean', default: true, description: 'Whether to include the phrase "This message was sent automatically with n8n" to the end of the message', }; // Operation Properties ---------------------------------------------------------- function getSendAndWaitProperties(targetProperties, resource = 'message', additionalProperties = [], options) { const buttonStyle = { displayName: 'Button Style', name: 'buttonStyle', type: 'options', default: 'primary', options: [ { name: 'Primary', value: 'primary', }, { name: 'Secondary', value: 'secondary', }, ], }; const approvalOptionsValues = [ { displayName: 'Type of Approval', name: 'approvalType', type: 'options', placeholder: 'Add option', default: 'single', options: [ { name: 'Approve Only', value: 'single', }, { name: 'Approve and Disapprove', value: 'double', }, ], }, { displayName: 'Approve Button Label', name: 'approveLabel', type: 'string', default: options?.defaultApproveLabel || 'Approve', displayOptions: { show: { approvalType: ['single', 'double'], }, }, }, ...[ options?.noButtonStyle ? {} : { ...buttonStyle, displayName: 'Approve Button Style', name: 'buttonApprovalStyle', displayOptions: { show: { approvalType: ['single', 'double'], }, }, }, ], { displayName: 'Disapprove Button Label', name: 'disapproveLabel', type: 'string', default: options?.defaultDisapproveLabel || 'Decline', displayOptions: { show: { approvalType: ['double'], }, }, }, ...[ options?.noButtonStyle ? {} : { ...buttonStyle, displayName: 'Disapprove Button Style', name: 'buttonDisapprovalStyle', default: 'secondary', displayOptions: { show: { approvalType: ['double'], }, }, }, ], ].filter((p) => Object.keys(p).length); const sendAndWait = [ ...targetProperties, { displayName: 'Subject', name: 'subject', type: 'string', default: '', required: true, placeholder: 'e.g. Approval required', }, { displayName: 'Message', name: 'message', type: 'string', default: '', required: true, typeOptions: { rows: 4, }, }, { displayName: 'Response Type', name: 'responseType', type: 'options', default: 'approval', options: [ { name: 'Approval', value: 'approval', description: 'User can approve/disapprove from within the message', }, { name: 'Free Text', value: 'freeText', description: 'User can submit a response via a form', }, { name: 'Custom Form', value: 'customForm', description: 'User can submit a response via a custom form', }, ], }, ...(0, n8n_workflow_1.updateDisplayOptions)({ show: { responseType: ['customForm'], }, }, Form_node_1.formFieldsProperties), { displayName: 'Approval Options', name: 'approvalOptions', type: 'fixedCollection', placeholder: 'Add option', default: {}, options: [ { displayName: 'Values', name: 'values', values: approvalOptionsValues, }, ], displayOptions: { show: { responseType: ['approval'], }, }, }, { displayName: 'Options', name: 'options', type: 'collection', placeholder: 'Add option', default: {}, options: [descriptions_1.limitWaitTimeOption, appendAttributionOption, ...(options?.extraOptions ?? [])], displayOptions: { show: { responseType: ['approval'], }, }, }, { displayName: 'Options', name: 'options', type: 'collection', placeholder: 'Add option', default: {}, options: [ { displayName: 'Message Button Label', name: 'messageButtonLabel', type: 'string', default: 'Respond', }, { displayName: 'Response Form Title', name: 'responseFormTitle', description: 'Title of the form that the user can access to provide their response', type: 'string', default: '', }, { displayName: 'Response Form Description', name: 'responseFormDescription', description: 'Description of the form that the user can access to provide their response', type: 'string', default: '', }, { displayName: 'Response Form Button Label', name: 'responseFormButtonLabel', type: 'string', default: 'Submit', }, { displayName: 'Response Form Custom Styling', name: 'responseFormCustomCss', type: 'string', typeOptions: { rows: 10, editor: 'cssEditor', }, default: cssVariables_1.cssVariables.trim(), description: 'Override default styling of the response form with CSS', }, descriptions_1.limitWaitTimeOption, appendAttributionOption, ...(options?.extraOptions ?? []), ], displayOptions: { show: { responseType: ['freeText', 'customForm'], }, }, }, ...additionalProperties, ]; return (0, n8n_workflow_1.updateDisplayOptions)({ show: { ...(resource ? { resource: [resource] } : {}), operation: [n8n_workflow_1.SEND_AND_WAIT_OPERATION], }, }, sendAndWait); } // Webhook Function -------------------------------------------------------------- const getFormResponseCustomizations = (context) => { const message = context.getNodeParameter('message', ''); const options = context.getNodeParameter('options', {}); let formTitle = ''; if (options.responseFormTitle) { formTitle = options.responseFormTitle; } let formDescription = message; if (options.responseFormDescription) { formDescription = options.responseFormDescription; } formDescription = formDescription.replace(/\\n/g, '\n').replace(/<br>/g, '\n'); let buttonLabel = 'Submit'; if (options.responseFormButtonLabel) { buttonLabel = options.responseFormButtonLabel; } return { formTitle, formDescription, buttonLabel, customCss: options.responseFormCustomCss, }; }; async function sendAndWaitWebhook() { const method = this.getRequestObject().method; const res = this.getResponseObject(); const req = this.getRequestObject(); const responseType = this.getNodeParameter('responseType', 'approval'); if (responseType === 'approval' && (0, isbot_1.default)(req.headers['user-agent'])) { res.send(''); return { noWebhookResponse: true }; } if (responseType === 'freeText') { if (method === 'GET') { const { formTitle, formDescription, buttonLabel, customCss } = getFormResponseCustomizations(this); const data = (0, utils_1.prepareFormData)({ formTitle, formDescription, formSubmittedHeader: 'Got it, thanks', formSubmittedText: 'This page can be closed now', buttonLabel, redirectUrl: undefined, formFields: [ { fieldLabel: 'Response', fieldType: 'textarea', requiredField: true, }, ], testRun: false, query: {}, customCss, }); res.setHeader('Content-Security-Policy', (0, n8n_core_1.getWebhookSandboxCSP)()); res.render('form-trigger', data); return { noWebhookResponse: true, }; } if (method === 'POST') { const data = this.getBodyData().data; return { webhookResponse: email_templates_1.ACTION_RECORDED_PAGE, workflowData: [[{ json: { data: { text: data[INPUT_FIELD_IDENTIFIER] } } }]], }; } } if (responseType === 'customForm') { const defineForm = this.getNodeParameter('defineForm', 'fields'); let fields = []; if (defineForm === 'json') { try { const jsonOutput = this.getNodeParameter('jsonOutput', '', { rawExpressions: true, }); fields = (0, n8n_workflow_1.tryToParseJsonToFormFields)((0, utils_1.resolveRawData)(this, jsonOutput)); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), error.message, { description: error.message, }); } } else { fields = this.getNodeParameter('formFields.values', []); } if (method === 'GET') { const { formTitle, formDescription, buttonLabel, customCss } = getFormResponseCustomizations(this); fields = (0, utils_1.prepareFormFields)(this, fields); const data = (0, utils_1.prepareFormData)({ formTitle, formDescription, formSubmittedHeader: 'Got it, thanks', formSubmittedText: 'This page can be closed now', buttonLabel, redirectUrl: undefined, formFields: fields, testRun: false, query: {}, customCss, }); res.setHeader('Content-Security-Policy', (0, n8n_core_1.getWebhookSandboxCSP)()); res.render('form-trigger', data); return { noWebhookResponse: true, }; } if (method === 'POST') { const returnItem = await (0, utils_1.prepareFormReturnItem)(this, fields, 'production', true); const json = returnItem.json; delete json.submittedAt; delete json.formMode; returnItem.json = { data: json }; return { webhookResponse: email_templates_1.ACTION_RECORDED_PAGE, workflowData: [[returnItem]], }; } } const query = req.query; const approved = query.approved === 'true'; return { webhookResponse: email_templates_1.ACTION_RECORDED_PAGE, workflowData: [[{ json: { data: { approved } } }]], }; } // Send and Wait Config ----------------------------------------------------------- function getSendAndWaitConfig(context) { const message = (0, utilities_1.escapeHtml)(context.getNodeParameter('message', 0, '').trim()) .replace(/\\n/g, '\n') .replace(/<br>/g, '\n'); const subject = (0, utilities_1.escapeHtml)(context.getNodeParameter('subject', 0, '')); const approvalOptions = context.getNodeParameter('approvalOptions.values', 0, {}); const options = context.getNodeParameter('options', 0, {}); const config = { title: subject, message, options: [], appendAttribution: options?.appendAttribution, }; const responseType = context.getNodeParameter('responseType', 0, 'approval'); context.setSignatureValidationRequired(); const approvedSignedResumeUrl = context.getSignedResumeUrl({ approved: 'true' }); if (responseType === 'freeText' || responseType === 'customForm') { const label = context.getNodeParameter('options.messageButtonLabel', 0, 'Respond'); config.options.push({ label, url: approvedSignedResumeUrl, style: 'primary', }); } else if (approvalOptions.approvalType === 'double') { const approveLabel = (0, utilities_1.escapeHtml)(approvalOptions.approveLabel || 'Approve'); const buttonApprovalStyle = approvalOptions.buttonApprovalStyle || 'primary'; const disapproveLabel = (0, utilities_1.escapeHtml)(approvalOptions.disapproveLabel || 'Disapprove'); const buttonDisapprovalStyle = approvalOptions.buttonDisapprovalStyle || 'secondary'; const disapprovedSignedResumeUrl = context.getSignedResumeUrl({ approved: 'false' }); config.options.push({ label: disapproveLabel, url: disapprovedSignedResumeUrl, style: buttonDisapprovalStyle, }); config.options.push({ label: approveLabel, url: approvedSignedResumeUrl, style: buttonApprovalStyle, }); } else { const label = (0, utilities_1.escapeHtml)(approvalOptions.approveLabel || 'Approve'); const style = approvalOptions.buttonApprovalStyle || 'primary'; config.options.push({ label, url: approvedSignedResumeUrl, style, }); } return config; } function createButton(url, label, style) { let buttonStyle = email_templates_1.BUTTON_STYLE_PRIMARY; if (style === 'secondary') { buttonStyle = email_templates_1.BUTTON_STYLE_SECONDARY; } return `<a href="${url}" target="_blank" style="${buttonStyle}">${label}</a>`; } function createEmail(context) { const to = context.getNodeParameter('sendTo', 0, '').trim(); const config = getSendAndWaitConfig(context); if (to.indexOf('@') === -1 || (to.match(/@/g) || []).length > 1) { const description = `The email address '${to}' in the 'To' field isn't valid or contains multiple addresses. Please provide only a single email address.`; throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Invalid email address', { description, itemIndex: 0, }); } const buttons = []; for (const option of config.options) { buttons.push(createButton(option.url, option.label, option.style)); } let emailBody; if (config.appendAttribution !== false) { const instanceId = context.getInstanceId(); emailBody = (0, email_templates_1.createEmailBodyWithN8nAttribution)(config.message, buttons.join('\n'), instanceId); } else { emailBody = (0, email_templates_1.createEmailBodyWithoutN8nAttribution)(config.message, buttons.join('\n')); } const email = { to, subject: config.title, body: '', htmlBody: emailBody, }; return email; } const sendAndWaitWaitingTooltip = (parameters) => { if (parameters?.operation === 'sendAndWait') { return "Execution will continue after the user's response"; } return ''; }; exports.SEND_AND_WAIT_WAITING_TOOLTIP = `={{ (${sendAndWaitWaitingTooltip})($parameter) }}`; //# sourceMappingURL=utils.js.map