UNPKG

@vwork-digital/n8n-nodes-fillout

Version:

N8N nodes for Fillout forms - includes both trigger and action nodes.

780 lines 34.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Fillout = void 0; const n8n_workflow_1 = require("n8n-workflow"); class Fillout { constructor() { this.description = { displayName: 'Fillout', name: 'fillout', icon: 'file:fillout.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Interact with Fillout API', defaults: { name: 'Fillout', }, inputs: ["main"], outputs: ["main"], credentials: [ { name: 'filloutApi', required: true, }, ], properties: [ { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'Form', value: 'form', }, { name: 'Submission', value: 'submission', }, ], default: 'form', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: [ 'form', ], }, }, options: [ { name: 'Get All', value: 'getAll', description: 'Get many forms', action: 'Get many forms', }, { name: 'Get Metadata', value: 'getMetadata', description: 'Get form metadata and questions', action: 'Get form metadata', }, ], default: 'getAll', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: [ 'submission', ], }, }, options: [ { name: 'Get All', value: 'getAll', description: 'Get many submissions', action: 'Get many submissions', }, { name: 'Get', value: 'get', description: 'Get a submission (set to always include edit link)', action: 'Get a submission', }, { name: 'Create', value: 'create', description: 'Create a submission', action: 'Create a submission', }, { name: 'Delete', value: 'delete', description: 'Delete a submission', action: 'Delete a submission', }, ], default: 'getAll', }, { displayName: 'Form', name: 'formId', type: 'options', typeOptions: { loadOptionsMethod: 'getForms', }, required: true, default: '', displayOptions: { show: { resource: [ 'form', ], operation: [ 'getMetadata', ], }, }, description: 'The form to get metadata for', }, { displayName: 'Form', name: 'formId', type: 'options', typeOptions: { loadOptionsMethod: 'getForms', }, required: true, default: '', displayOptions: { show: { resource: [ 'submission', ], operation: [ 'getAll', 'get', 'create', 'delete', ], }, }, description: 'The form to work with', }, { displayName: 'Submission ID', name: 'submissionId', type: 'string', required: true, default: '', displayOptions: { show: { resource: [ 'submission', ], operation: [ 'get', 'delete', ], }, }, description: 'The submission to retrieve (set to always include edit link)', }, { displayName: 'Limit', name: 'limit', type: 'number', default: 50, description: 'Max number of results to return', typeOptions: { minValue: 1 }, displayOptions: { show: { resource: [ 'submission', ], operation: [ 'getAll', ], }, }, }, { displayName: 'Additional Options', name: 'additionalOptions', type: 'collection', placeholder: 'Add Option', default: {}, displayOptions: { show: { resource: [ 'submission', ], operation: [ 'getAll', ], }, }, options: [ { displayName: 'After Date', name: 'afterDate', type: 'dateTime', default: '', description: 'Filter submissions submitted after this date', }, { displayName: 'Before Date', name: 'beforeDate', type: 'dateTime', default: '', description: 'Filter submissions submitted before this date', }, { displayName: 'Include Edit Link', name: 'includeEditLink', type: 'boolean', default: false, description: 'Whether to include a link to edit the submission', }, { displayName: 'Search', name: 'search', type: 'string', default: '', description: 'Search text to filter submissions', }, { displayName: 'Sort', name: 'sort', type: 'options', options: [ { name: 'Ascending', value: 'asc', }, { name: 'Descending', value: 'desc', }, ], default: 'asc', description: 'Sort order of submissions', }, { displayName: 'Status', name: 'status', type: 'options', options: [ { name: 'Finished', value: 'finished', }, { name: 'In Progress', value: 'in_progress', }, ], default: 'finished', description: 'Status of the submissions to retrieve (etching in progress submissions available on business plan or higher).', }, ], }, { displayName: 'Questions', name: 'questions', placeholder: 'Add Question', type: 'fixedCollection', typeOptions: { multipleValues: true, }, displayOptions: { show: { resource: [ 'submission', ], operation: [ 'create', ], }, }, default: {}, options: [ { name: 'questionValues', displayName: 'Question', values: [ { displayName: 'Question ID', name: 'id', type: 'string', default: '', description: 'ID of the question', required: true, }, { displayName: 'Value', name: 'value', type: 'string', default: '', description: 'Value of the answer', required: true, }, ], }, ], }, { displayName: 'Submission Time', name: 'submissionTime', type: 'dateTime', default: '', displayOptions: { show: { resource: [ 'submission', ], operation: [ 'create', ], }, }, description: 'The time when the submission was created', }, { displayName: 'Last Updated At', name: 'lastUpdatedAt', type: 'dateTime', default: '', displayOptions: { show: { resource: [ 'submission', ], operation: [ 'create', ], }, }, description: 'The time when the submission was last updated', }, { displayName: 'URL Parameters', name: 'urlParameters', placeholder: 'Add URL Parameter', type: 'json', displayOptions: { show: { resource: [ 'submission', ], operation: [ 'create', ], }, }, default: '', description: 'URL parameters in JSON format. Must include id, name, and value fields. Example: [{"id":"email","name":"email","value":"example@example.com"}]', }, { displayName: 'Scheduling', name: 'scheduling', placeholder: 'Add Scheduling Details', type: 'json', displayOptions: { show: { resource: [ 'submission', ], operation: [ 'create', ], }, }, default: '', description: 'Scheduling data in JSON format. Must include id and value fields. Example: [{"id":"nLJtxBJgPA","value":{"fullName":"John Smith","email":"john@smith.com","eventStartTime":"2024-05-20T09:00:00.000Z"}}]', }, { displayName: 'Payments', name: 'payments', placeholder: 'Add Payment Details', type: 'json', displayOptions: { show: { resource: [ 'submission', ], operation: [ 'create', ], }, }, default: '', description: 'Payment data in JSON format. Must include id and value fields. Example: [{"id":"cLJtxCKgdL","value":{"paymentId":"pi_3PRF2cFMP2ckdpfG0s0ZdJqf"}}]', }, { displayName: 'Login', name: 'login', placeholder: 'Add Login Details', type: 'json', displayOptions: { show: { resource: [ 'submission', ], operation: [ 'create', ], }, }, default: '', description: 'Login data in JSON format. Must contain email field. Example: {"email":"verified@email.com"}', }, ], }; this.methods = { loadOptions: { async getForms() { const credentials = await this.getCredentials('filloutApi'); try { const response = await this.helpers.request({ method: 'GET', url: `${credentials.apiUrl}/v1/api/forms`, headers: { Authorization: `Bearer ${credentials.apiKey}`, }, json: true, }); const forms = response; return forms.map(form => ({ name: form.name, value: form.formId, })); } catch (error) { console.error('[Fillout] Error loading forms:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), error); } }, async getSubmissions() { const credentials = await this.getCredentials('filloutApi'); const formId = this.getCurrentNodeParameter('formId'); if (!formId) { return [{ name: 'Please select a form first', value: '' }]; } try { const response = await this.helpers.request({ method: 'GET', url: `${credentials.apiUrl}/v1/api/forms/${formId}/submissions`, qs: { sort: 'desc', limit: 50, }, headers: { Authorization: `Bearer ${credentials.apiKey}`, }, json: true, }); const data = response; if (!data.responses || !data.responses.length) { return [{ name: 'No submissions found', value: '' }]; } return data.responses.map(submission => ({ name: `Submission from ${new Date(submission.submissionTime).toLocaleString()}`, value: submission.submissionId, })); } catch (error) { console.error('[Fillout] Error loading submissions:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), error); } }, }, }; } async execute() { const returnData = []; const credentials = await this.getCredentials('filloutApi'); const resource = this.getNodeParameter('resource', 0); const operation = this.getNodeParameter('operation', 0); if (resource === 'form') { if (operation === 'getAll') { try { const response = await this.helpers.request({ method: 'GET', url: `${credentials.apiUrl}/v1/api/forms`, headers: { Authorization: `Bearer ${credentials.apiKey}`, }, json: true, }); returnData.push({ json: { forms: response } }); } catch (error) { console.error('[Fillout] Error getting forms:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), error); } } else if (operation === 'getMetadata') { const formId = this.getNodeParameter('formId', 0); try { const response = await this.helpers.request({ method: 'GET', url: `${credentials.apiUrl}/v1/api/forms/${formId}`, headers: { Authorization: `Bearer ${credentials.apiKey}`, }, json: true, }); returnData.push({ json: response }); } catch (error) { console.error('[Fillout] Error getting form metadata:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), error); } } } else if (resource === 'submission') { if (operation === 'getAll') { const formId = this.getNodeParameter('formId', 0); const limit = this.getNodeParameter('limit', 0); const additionalOptions = this.getNodeParameter('additionalOptions', 0, {}); try { const qs = { limit }; if (additionalOptions.afterDate) { qs.afterDate = additionalOptions.afterDate; } if (additionalOptions.beforeDate) { qs.beforeDate = additionalOptions.beforeDate; } if (additionalOptions.status) { qs.status = additionalOptions.status; } if (additionalOptions.includeEditLink) { qs.includeEditLink = additionalOptions.includeEditLink; } if (additionalOptions.sort) { qs.sort = additionalOptions.sort; } if (additionalOptions.search) { qs.search = additionalOptions.search; } const response = await this.helpers.request({ method: 'GET', url: `${credentials.apiUrl}/v1/api/forms/${formId}/submissions`, qs, headers: { Authorization: `Bearer ${credentials.apiKey}`, }, json: true, }); returnData.push({ json: response }); } catch (error) { console.error('[Fillout] Error getting submissions:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), error); } } else if (operation === 'get') { const formId = this.getNodeParameter('formId', 0); const submissionId = this.getNodeParameter('submissionId', 0); try { const response = await this.helpers.request({ method: 'GET', url: `${credentials.apiUrl}/v1/api/forms/${formId}/submissions/${submissionId}?includeEditLink=true`, headers: { Authorization: `Bearer ${credentials.apiKey}`, }, json: true, }); returnData.push({ json: response }); } catch (error) { console.error('[Fillout] Error getting submission:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), error); } } else if (operation === 'create') { const formId = this.getNodeParameter('formId', 0); const questionValues = this.getNodeParameter('questions.questionValues', 0, []); const submissionTime = this.getNodeParameter('submissionTime', 0, ''); const lastUpdatedAt = this.getNodeParameter('lastUpdatedAt', 0, ''); let urlParameters = []; let scheduling = []; let payments = []; let login = null; try { const urlParametersJson = this.getNodeParameter('urlParameters', 0, ''); if (urlParametersJson) { urlParameters = JSON.parse(urlParametersJson); console.log('[Fillout] URL Parameters:', urlParameters); if (!Array.isArray(urlParameters)) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'URL Parameters must be an array', }); } for (const param of urlParameters) { if (!param.id || !param.name || !param.value) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Each URL Parameter must have id, name, and value fields', }); } } } } catch (error) { console.error('[Fillout] Error parsing URL Parameters JSON:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Invalid URL Parameters JSON format', description: 'Please provide a valid JSON array with each item containing id, name, and value fields. Example: [{"id":"email","name":"email","value":"example@example.com"}]', }); } try { const schedulingJson = this.getNodeParameter('scheduling', 0, ''); if (schedulingJson) { scheduling = JSON.parse(schedulingJson); console.log('[Fillout] Scheduling:', scheduling); if (!Array.isArray(scheduling)) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Scheduling must be an array', }); } for (const item of scheduling) { if (!item.id || !item.value || typeof item.value !== 'object') { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Each scheduling item must have id and value (object) fields', }); } } } } catch (error) { console.error('[Fillout] Error parsing Scheduling JSON:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Invalid Scheduling JSON format', description: 'Please provide a valid JSON array with each item containing id and value fields. Example: [{"id":"nLJtxBJgPA","value":{"fullName":"John Smith","email":"john@smith.com"}}]', }); } try { const paymentsJson = this.getNodeParameter('payments', 0, ''); if (paymentsJson) { payments = JSON.parse(paymentsJson); console.log('[Fillout] Payments:', payments); if (!Array.isArray(payments)) { throw new Error('Payments must be an array'); } for (const item of payments) { if (!item.id || !item.value || typeof item.value !== 'object') { throw new Error('Each payment item must have id and value (object) fields'); } if (!item.value.paymentId) { throw new Error('Payment value must contain paymentId field'); } } } } catch (error) { console.error('[Fillout] Error parsing Payments JSON:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Invalid Payments JSON format', description: 'Please provide a valid JSON array with each item containing id and value fields. The value object must contain paymentId. Example: [{"id":"cLJtxCKgdL","value":{"paymentId":"pi_3PRF2cFMP2ckdpfG0s0ZdJqf"}}]', }); } try { const loginJson = this.getNodeParameter('login', 0, ''); if (loginJson) { login = JSON.parse(loginJson); console.log('[Fillout] Login:', login); if (typeof login !== 'object' || login === null) { throw new Error('Login must be an object'); } if (!login.email || typeof login.email !== 'string') { throw new Error('Login object must contain email field as a string'); } } } catch (error) { console.error('[Fillout] Error parsing Login JSON:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Invalid Login JSON format', description: 'Please provide a valid JSON object with an email field. Example: {"email":"verified@email.com"}', }); } try { const questions = questionValues.map(q => ({ id: q.id, value: q.value, })); const submissionObj = { questions, }; if (submissionTime) { submissionObj.submissionTime = submissionTime; } else { submissionObj.submissionTime = new Date().toISOString(); } if (lastUpdatedAt) { submissionObj.lastUpdatedAt = lastUpdatedAt; } if (urlParameters.length > 0) { submissionObj.urlParameters = urlParameters; } if (scheduling.length > 0) { submissionObj.scheduling = scheduling; } if (payments.length > 0) { submissionObj.payments = payments; } if (login) { submissionObj.login = login; } const body = { submissions: [submissionObj], }; console.log('[Fillout] Creating submission with body:', JSON.stringify(body, null, 2)); const response = await this.helpers.request({ method: 'POST', url: `${credentials.apiUrl}/v1/api/forms/${formId}/submissions`, body, headers: { Authorization: `Bearer ${credentials.apiKey}`, 'Content-Type': 'application/json', }, json: true, }); returnData.push({ json: response }); } catch (error) { console.error('[Fillout] Error creating submission:', error); if (error.response) { console.error('[Fillout] Error response data:', JSON.stringify(error.response.data)); console.error('[Fillout] Error response status:', error.response.status); console.error('[Fillout] Error response headers:', JSON.stringify(error.response.headers)); } throw new n8n_workflow_1.NodeApiError(this.getNode(), error); } } else if (operation === 'delete') { const formId = this.getNodeParameter('formId', 0); const submissionId = this.getNodeParameter('submissionId', 0); try { await this.helpers.request({ method: 'DELETE', url: `${credentials.apiUrl}/v1/api/forms/${formId}/submissions/${submissionId}`, headers: { Authorization: `Bearer ${credentials.apiKey}`, }, }); returnData.push({ json: { success: true, message: `Submission ${submissionId} deleted successfully`, }, }); } catch (error) { console.error('[Fillout] Error deleting submission:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), error); } } } return [returnData]; } } exports.Fillout = Fillout; //# sourceMappingURL=Fillout.node.js.map