From 2ec4ed6592842e583f5d206819c8220c7066c0ee Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Mon, 28 Feb 2022 03:04:55 -0500 Subject: [PATCH] :zap: Extend Mautic node (#2839) * re-submit for #2218 * :zap: small fixes * :zap: nodelinter fixes * :zap: Improvements * :zap: Improvements * :zap: Add description and fix default value Co-authored-by: Luiz Eduardo de Oliveira Fonseca Co-authored-by: michael-radency Co-authored-by: Jan Oberhauser --- package-lock.json | 236 ++++++++--------- .../nodes/Mautic/ContactDescription.ts | 244 +++++++++++++++++- .../nodes/Mautic/GenericFunctions.ts | 4 +- .../nodes-base/nodes/Mautic/Mautic.node.ts | 100 ++++++- .../nodes/Mautic/SegmentEmailDescription.ts | 53 ++++ 5 files changed, 514 insertions(+), 123 deletions(-) create mode 100644 packages/nodes-base/nodes/Mautic/SegmentEmailDescription.ts diff --git a/package-lock.json b/package-lock.json index c457345ead..e5e85fc76b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13646,6 +13646,15 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", @@ -13681,6 +13690,21 @@ } } }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -13743,6 +13767,58 @@ "worker-rpc": "^0.1.0" } }, + "fork-ts-checker-webpack-plugin-v5": { + "version": "npm:fork-ts-checker-webpack-plugin@5.2.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz", + "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==", + "optional": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "optional": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "optional": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, "glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", @@ -13777,6 +13853,12 @@ "slash": "^2.0.0" } }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "optional": true + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -13805,6 +13887,16 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "optional": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -13840,6 +13932,17 @@ } } }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "optional": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -13850,6 +13953,15 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + }, "to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", @@ -13943,6 +14055,12 @@ "requires": { "tslib": "^1.8.1" } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "optional": true } } }, @@ -23416,124 +23534,6 @@ } } }, - "fork-ts-checker-webpack-plugin-v5": { - "version": "npm:fork-ts-checker-webpack-plugin@5.2.1", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz", - "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==", - "optional": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "optional": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "optional": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "optional": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "optional": true - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "optional": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "optional": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "optional": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "optional": true, - "requires": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "optional": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "optional": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "optional": true - } - } - }, "form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", diff --git a/packages/nodes-base/nodes/Mautic/ContactDescription.ts b/packages/nodes-base/nodes/Mautic/ContactDescription.ts index fa974f3250..cda3cb04ad 100644 --- a/packages/nodes-base/nodes/Mautic/ContactDescription.ts +++ b/packages/nodes-base/nodes/Mautic/ContactDescription.ts @@ -25,6 +25,16 @@ export const contactOperations: INodeProperties[] = [ value: 'delete', description: 'Delete a contact', }, + { + name: 'Edit Contact Points', + value: 'editContactPoint', + description: 'Edit contact\'s points', + }, + { + name: 'Edit Do Not Contact List', + value: 'editDoNotContactList', + description: 'Add/remove contacts from/to the do not contact list', + }, { name: 'Get', value: 'get', @@ -35,6 +45,11 @@ export const contactOperations: INodeProperties[] = [ value: 'getAll', description: 'Get data of all contacts', }, + { + name: 'Send Email', + value: 'sendEmail', + description: 'Send email to contact', + }, { name: 'Update', value: 'update', @@ -1029,6 +1044,187 @@ export const contactFields: INodeProperties[] = [ ], }, + /* -------------------------------------------------------------------------- */ + /* contact:editDoNotContactList */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Contact ID', + name: 'contactId', + type: 'string', + displayOptions: { + show: { + operation: [ + 'editDoNotContactList', + ], + resource: [ + 'contact', + ], + }, + }, + default: '', + description: 'Contact ID', + }, + { + displayName: 'Action', + name: 'action', + type: 'options', + displayOptions: { + show: { + operation: [ + 'editDoNotContactList', + ], + resource: [ + 'contact', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'add', + }, + { + name: 'Remove', + value: 'remove', + }, + ], + default: 'add', + }, + { + displayName: 'Channel', + name: 'channel', + type: 'options', + required: true, + displayOptions: { + show: { + resource: [ + 'contact', + ], + operation: [ + 'editDoNotContactList', + ], + }, + }, + options: [ + { + name: 'Email', + value: 'email', + }, + { + name: 'SMS', + value: 'sms', + }, + ], + default: 'email', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'contact', + ], + operation: [ + 'editDoNotContactList', + ], + }, + }, + options: [ + { + displayName: 'Reason To Do Not Contact', + name: 'reason', + type: 'options', + options: [ + { + name: 'Unsubscribed', + value: '1', + }, + { + name: 'Bounced', + value: '2', + }, + { + name: 'Manual', + value: '3', + }, + ], + default: '3', + }, + { + displayName: 'Comments', + name: 'comments', + type: 'string', + default: '', + description: 'A text describing details of Do Not Contact entry', + }, + ], + }, + /* -------------------------------------------------------------------------- */ + /* contact:editContactPoint */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Contact ID', + name: 'contactId', + type: 'string', + displayOptions: { + show: { + operation: [ + 'editContactPoint', + ], + resource: [ + 'contact', + ], + }, + }, + default: '', + description: 'Contact ID', + }, + { + displayName: 'Action', + name: 'action', + type: 'options', + displayOptions: { + show: { + operation: [ + 'editContactPoint', + ], + resource: [ + 'contact', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'add', + }, + { + name: 'Remove', + value: 'remove', + }, + ], + default: 'add', + }, + { + displayName: 'Points', + name: 'points', + type: 'number', + displayOptions: { + show: { + operation: [ + 'editContactPoint', + ], + resource: [ + 'contact', + ], + }, + }, + default: 0, + }, /* -------------------------------------------------------------------------- */ /* contact:get */ /* -------------------------------------------------------------------------- */ @@ -1129,6 +1325,13 @@ export const contactFields: INodeProperties[] = [ 'contact', ], }, + hide: { + operation: [ + 'sendEmail', + 'editDoNotContactList', + 'editContactPoint', + ], + }, }, placeholder: 'Add Option', default: {}, @@ -1238,5 +1441,44 @@ export const contactFields: INodeProperties[] = [ }, ], }, - + /* -------------------------------------------------------------------------- */ + /* contact:sendEmail */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Campaign Email ID', + name: 'campaignEmailId', + type: 'options', + required: true, + displayOptions: { + show: { + resource: [ + 'contact', + ], + operation: [ + 'sendEmail', + ], + }, + }, + typeOptions: { + loadOptionsMethod: 'getCampaignEmails', + }, + default: '', + }, + { + displayName: 'Contact ID', + name: 'contactId', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'contact', + ], + operation: [ + 'sendEmail', + ], + }, + }, + default: '', + }, ]; diff --git a/packages/nodes-base/nodes/Mautic/GenericFunctions.ts b/packages/nodes-base/nodes/Mautic/GenericFunctions.ts index 39ca8db645..c0ff315d9e 100644 --- a/packages/nodes-base/nodes/Mautic/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mautic/GenericFunctions.ts @@ -10,7 +10,7 @@ import { } from 'n8n-core'; import { - IDataObject, NodeApiError, + IDataObject, JsonObject, NodeApiError, } from 'n8n-workflow'; export async function mauticApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any @@ -55,7 +55,7 @@ export async function mauticApiRequest(this: IHookFunctions | IExecuteFunctions return returnData; } catch (error) { - throw new NodeApiError(this.getNode(), error); + throw new NodeApiError(this.getNode(), error as JsonObject); } } diff --git a/packages/nodes-base/nodes/Mautic/Mautic.node.ts b/packages/nodes-base/nodes/Mautic/Mautic.node.ts index 4a8de19ac8..d84dbdde09 100644 --- a/packages/nodes-base/nodes/Mautic/Mautic.node.ts +++ b/packages/nodes-base/nodes/Mautic/Mautic.node.ts @@ -9,6 +9,7 @@ import { INodePropertyOptions, INodeType, INodeTypeDescription, + JsonObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; @@ -24,6 +25,11 @@ import { contactOperations, } from './ContactDescription'; +import { + segmentEmailFields, + segmentEmailOperations, +} from './SegmentEmailDescription'; + import { companyFields, companyOperations, @@ -59,6 +65,7 @@ export class Mautic implements INodeType { description: 'Consume Mautic API', defaults: { name: 'Mautic', + color: '#52619b', }, inputs: ['main'], outputs: ['main'], @@ -107,6 +114,7 @@ export class Mautic implements INodeType { displayName: 'Resource', name: 'resource', type: 'options', + noDataExpression: true, options: [ { name: 'Campaign Contact', @@ -133,9 +141,14 @@ export class Mautic implements INodeType { value: 'contactSegment', description: 'Add/remove contacts to/from a segment', }, + { + name: 'Segment Email', + value: 'segmentEmail', + description: 'Send an email', + }, ], default: 'contact', - description: 'Resource to consume.', + description: 'Resource to consume', }, ...companyOperations, ...companyFields, @@ -147,6 +160,8 @@ export class Mautic implements INodeType { ...campaignContactFields, ...companyContactOperations, ...companyContactFields, + ...segmentEmailOperations, + ...segmentEmailFields, ], }; @@ -258,6 +273,49 @@ export class Mautic implements INodeType { } return returnData; }, + // Get all the available emails to display them to user so that he can + // select them easily + async getEmails(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const emails = await mauticApiRequestAllItems.call(this, 'emails', 'GET', '/emails'); + for (const email of emails) { + returnData.push({ + name: email.name, + value: email.id, + }); + } + return returnData; + }, + // Get all the available list / segment emails to display them to user so that he can + // select them easily + async getSegmentEmails(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const emails = await mauticApiRequestAllItems.call(this, 'emails', 'GET', '/emails'); + for (const email of emails) { + if (email.emailType === 'list') { + returnData.push({ + name: email.name, + value: email.id, + }); + } + } + return returnData; + }, + // Get all the available campaign / template emails to display them to user so that he can + // select them easily + async getCampaignEmails(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const emails = await mauticApiRequestAllItems.call(this, 'emails', 'GET', '/emails'); + for (const email of emails) { + if (email.emailType === 'template') { + returnData.push({ + name: email.name, + value: email.id, + }); + } + } + return returnData; + }, }, }; @@ -781,6 +839,36 @@ export class Mautic implements INodeType { responseData = responseData.map(item => item.fields.all); } } + //https://developer.mautic.org/#send-email-to-contact + if (operation === 'sendEmail') { + const contactId = this.getNodeParameter('contactId', i) as string; + const campaignEmailId = this.getNodeParameter('campaignEmailId', i) as string; + responseData = await mauticApiRequest.call(this, 'POST', `/emails/${campaignEmailId}/contact/${contactId}/send`); + } + //https://developer.mautic.org/#add-do-not-contact + //https://developer.mautic.org/#remove-from-do-not-contact + if (operation === 'editDoNotContactList') { + const contactId = this.getNodeParameter('contactId', i) as string; + const action = this.getNodeParameter('action', i) as string; + const channel = this.getNodeParameter('channel', i) as string; + const body: IDataObject = {}; + if (action === 'add') { + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + Object.assign(body, additionalFields); + } + responseData = await mauticApiRequest.call(this, 'POST', `/contacts/${contactId}/dnc/${channel}/${action}`, body); + responseData = responseData.contact; + } + + //https://developer.mautic.org/#add-points + //https://developer.mautic.org/#subtract-points + if (operation === 'editContactPoint') { + const contactId = this.getNodeParameter('contactId', i) as string; + const action = this.getNodeParameter('action', i) as string; + const points = this.getNodeParameter('points', i) as string; + const path = (action === 'add') ? 'plus' : 'minus'; + responseData = await mauticApiRequest.call(this, 'POST', `/contacts/${contactId}/points/${path}/${points}`); + } } if (resource === 'contactSegment') { @@ -813,6 +901,14 @@ export class Mautic implements INodeType { } } + if (resource === 'segmentEmail') { + //https://developer.mautic.org/#send-email-to-segment + if (operation === 'send') { + const segmentEmailId = this.getNodeParameter('segmentEmailId', i) as string; + responseData = await mauticApiRequest.call(this, 'POST', `/emails/${segmentEmailId}/send`); + } + } + if (resource === 'companyContact') { //https://developer.mautic.org/#add-contact-to-a-company if (operation === 'add') { @@ -843,7 +939,7 @@ export class Mautic implements INodeType { } } catch (error) { if (this.continueOnFail()) { - returnData.push({ error: error.message }); + returnData.push({ error: (error as JsonObject).message }); continue; } throw error; diff --git a/packages/nodes-base/nodes/Mautic/SegmentEmailDescription.ts b/packages/nodes-base/nodes/Mautic/SegmentEmailDescription.ts new file mode 100644 index 0000000000..767fbf4547 --- /dev/null +++ b/packages/nodes-base/nodes/Mautic/SegmentEmailDescription.ts @@ -0,0 +1,53 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const segmentEmailOperations: INodeProperties[] = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + noDataExpression: true, + displayOptions: { + show: { + resource: [ + 'segmentEmail', + ], + }, + }, + options: [ + { + name: 'Send', + value: 'send', + }, + ], + default: 'send', + }, +]; + +export const segmentEmailFields: INodeProperties[] = [ + + /* -------------------------------------------------------------------------- */ + /* segmentEmail:send */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Segment Email ID', + name: 'segmentEmailId', + type: 'options', + required: true, + displayOptions: { + show: { + resource: [ + 'segmentEmail', + ], + operation: [ + 'send', + ], + }, + }, + typeOptions: { + loadOptionsMethod: 'getSegmentEmails', + }, + default: '', + }, +];