Extend Mautic node (#2839)

* re-submit for #2218

*  small fixes

*  nodelinter fixes

*  Improvements

*  Improvements

*  Add description and fix default value

Co-authored-by: Luiz Eduardo de Oliveira Fonseca <luizeof@gmail.com>
Co-authored-by: michael-radency <michael.k@radency.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
Ricardo Espinoza
2022-02-28 03:04:55 -05:00
committed by GitHub
parent 7d5f65d8c0
commit 2ec4ed6592
5 changed files with 514 additions and 123 deletions

View File

@@ -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: '',
},
];

View File

@@ -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<any> { // 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);
}
}

View File

@@ -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<INodePropertyOptions[]> {
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<INodePropertyOptions[]> {
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<INodePropertyOptions[]> {
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;

View File

@@ -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: '',
},
];