🔀 Merge branch 'RicardoE105-feature/mailchimp-node'

This commit is contained in:
Jan Oberhauser 2019-11-15 21:45:30 +01:00
commit 76e92157d4
5 changed files with 635 additions and 0 deletions

View file

@ -0,0 +1,17 @@
import {
ICredentialType,
NodePropertyTypes,
} from 'n8n-workflow';
export class MailchimpApi implements ICredentialType {
name = 'mailchimpApi';
displayName = 'Mailchimp API';
properties = [
{
displayName: 'API Key',
name: 'apiKey',
type: 'string' as NodePropertyTypes,
default: '',
},
];
}

View file

@ -0,0 +1,58 @@
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
IExecuteSingleFunctions
} from 'n8n-core';
export async function mailchimpApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, endpoint: string, method: string, body: any = {}, headers?: object): Promise<any> { // tslint:disable-line:no-any
const credentials = this.getCredentials('mailchimpApi');
if (credentials === undefined) {
throw new Error('No credentials got returned!');
}
const headerWithAuthentication = Object.assign({}, headers, { Authorization: `apikey ${credentials.apiKey}` });
if (!(credentials.apiKey as string).includes('-')) {
throw new Error('The API key is not valid!');
}
const datacenter = (credentials.apiKey as string).split('-').pop();
const host = 'api.mailchimp.com/3.0';
const options: OptionsWithUri = {
headers: headerWithAuthentication,
method,
uri: `https://${datacenter}.${host}${endpoint}`,
json: true,
};
if (Object.keys(body).length !== 0) {
options.body = body;
}
try {
return await this.helpers.request!(options);
} catch (error) {
const errorMessage = error.response.body.message || error.response.body.Message;
if (errorMessage !== undefined) {
throw errorMessage;
}
throw error.response.body;
}
}
export function validateJSON(json: string | undefined): any { // tslint:disable-line:no-any
let result;
try {
result = JSON.parse(json!);
} catch (exception) {
result = '';
}
return result;
}

View file

@ -0,0 +1,558 @@
import * as moment from 'moment';
import {
IExecuteSingleFunctions,
} from 'n8n-core';
import {
IDataObject,
ILoadOptionsFunctions,
INodeTypeDescription,
INodeExecutionData,
INodeType,
INodePropertyOptions,
} from 'n8n-workflow';
import {
mailchimpApiRequest,
validateJSON,
} from './GenericFunctions';
enum Status {
subscribe = 'subscribe',
unsubscribed = 'unsubscribe',
cleaned = 'cleaned',
pending = 'pending',
transactional = 'transactional',
}
interface ILocation {
latitude?: number;
longitude?: number;
}
interface ICreateMemberBody {
listId: string;
email_address: string;
email_type?: string;
status?: Status;
language?: string;
vip?: boolean;
location?: ILocation;
ips_signup?: string;
timestamp_signup?: string;
ip_opt?: string;
timestamp_opt?: string;
tags?: string[];
merge_fields?: IDataObject;
}
export class Mailchimp implements INodeType {
description: INodeTypeDescription = {
displayName: 'Mailchimp',
name: 'mailchimp',
icon: 'file:mailchimp.png',
group: ['output'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume Mailchimp API',
defaults: {
name: 'Mailchimp',
color: '#c02428',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'mailchimpApi',
required: true,
}
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
options: [
{
name: 'Member',
value: 'member',
description: 'Add member to list',
},
],
default: 'member',
required: true,
description: 'Resource to consume.',
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
required: true,
displayOptions: {
show: {
resource: [
'member',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new member on list',
},
],
default: 'create',
description: 'The operation to perform.',
},
{
displayName: 'List',
name: 'list',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getLists',
},
displayOptions: {
show: {
resource: [
'member',
],
operation: [
'create',
],
},
},
default: '',
options: [],
required: true,
description: 'List of lists',
},
{
displayName: 'Email',
name: 'email',
type: 'string',
required: true,
displayOptions: {
show: {
resource: [
'member',
],
operation: [
'create',
],
},
},
default: '',
description: 'Email address for a subscriber.',
},
{
displayName: 'Status',
name: 'status',
type: 'options',
required: true,
displayOptions: {
show: {
resource: [
'member',
],
operation: [
'create',
],
},
},
options: [
{
name: 'Subscribed',
value: 'subscribed',
description: '',
},
{
name: 'Unsubscribed',
value: 'unsubscribed',
description: '',
},
{
name: 'Cleaned',
value: 'cleaned',
description: '',
},
{
name: 'Pending',
value: 'pending',
description: '',
},
{
name: 'Transactional',
value: 'transactional',
description: '',
},
],
default: '',
description: `Subscriber's current status.`,
},
{
displayName: 'JSON Parameters',
name: 'jsonParameters',
type: 'boolean',
default: false,
description: '',
displayOptions: {
show: {
resource:[
'member'
],
operation: [
'create',
],
},
},
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource:[
'member',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Email Type',
name: 'emailType',
type: 'options',
options: [
{
name: 'Email',
value: 'email',
description: '',
},
{
name: 'Text',
value: 'text',
description: '',
},
],
default: '',
description: 'Type of email this member asked to get',
},
{
displayName: 'Signup IP',
name: 'ipSignup',
type: 'string',
default: '',
description: 'IP address the subscriber signed up from.',
},
{
displayName: 'Opt-in IP',
name: 'ipOptIn',
type: 'string',
default: '',
description: 'The IP address the subscriber used to confirm their opt-in status.',
},
{
displayName: 'Signup Timestamp',
name: 'timestampSignup',
type: 'dateTime',
default: '',
description: 'The date and time the subscriber signed up for the list in ISO 8601 format.',
},
{
displayName: 'Language',
name: 'language',
type: 'string',
default: '',
description: `If set/detected, the subscriber's language.`,
},
{
displayName: 'Vip',
name: 'vip',
type: 'boolean',
default: false,
description: `Vip status for subscribers`,
},
{
displayName: 'Opt-in Timestamp',
name: 'timestampOpt',
type: 'dateTime',
default: '',
description: `The date and time the subscribe confirmed their opt-in status in ISO 8601 format.`,
},
{
displayName: 'Tags',
name: 'tags',
type: 'string',
default: '',
description: `The tags that are associated with a member separeted by ,.`,
},
]
},
{
displayName: 'Location',
name: 'locationFieldsUi',
type: 'fixedCollection',
placeholder: 'Add Location',
default: {},
description: `Subscriber location information.n`,
displayOptions: {
show: {
resource:[
'member',
],
operation: [
'create',
],
jsonParameters: [
false,
],
},
},
options: [
{
name: 'locationFieldsValues',
displayName: 'Location',
values: [
{
displayName: 'Latitude',
name: 'latitude',
type: 'string',
required: true,
description: 'The location latitude.',
default: '',
},
{
displayName: 'Longitude',
name: 'longitude',
type: 'string',
required: true,
description: 'The location longitude.',
default: '',
},
],
}
],
},
{
displayName: 'Merge Fields',
name: 'mergeFieldsUi',
placeholder: 'Add Merge Fields',
type: 'fixedCollection',
default: {},
typeOptions: {
multipleValues: true,
},
displayOptions: {
show: {
resource:[
'member'
],
operation: [
'create',
],
jsonParameters: [
false,
],
},
},
description: 'An individual merge var and value for a member.',
options: [
{
name: 'mergeFieldsValues',
displayName: 'Field',
typeOptions: {
multipleValueButtonText: 'Add Field',
},
values: [
{
displayName: 'Field Name',
name: 'name',
type: 'string',
required: true,
description: 'Merge Field name',
default: '',
},
{
displayName: 'Field Value',
name: 'value',
required: true,
type: 'string',
default: '',
description: 'Merge field value.',
},
],
},
],
},
{
displayName: 'Merge Fields',
name: 'mergeFieldsJson',
type: 'json',
typeOptions: {
alwaysOpenEditWindow: true,
},
default: '',
description: '',
displayOptions: {
show: {
resource:[
'member',
],
operation: [
'create',
],
jsonParameters: [
true,
],
},
},
},
{
displayName: 'Location',
name: 'locationJson',
type: 'json',
typeOptions: {
alwaysOpenEditWindow: true,
},
default: '',
description: '',
displayOptions: {
show: {
resource:[
'member',
],
operation: [
'create',
],
jsonParameters: [
true,
],
},
},
},
]
};
methods = {
loadOptions: {
// Get all the available lists to display them to user so that he can
// select them easily
async getLists(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
let lists, response;
try {
response = await mailchimpApiRequest.call(this, '/lists', 'GET');
lists = response.lists;
} catch (err) {
throw new Error(`Mailchimp Error: ${err}`);
}
for (const list of lists) {
const listName = list.name;
const listId = list.id;
returnData.push({
name: listName,
value: listId,
});
}
return returnData;
},
}
};
async executeSingle(this: IExecuteSingleFunctions): Promise<INodeExecutionData> {
let response = {};
const resource = this.getNodeParameter('resource') as string;
const operation = this.getNodeParameter('operation') as string;
if (resource === 'member') {
if (operation === 'create') {
const listId = this.getNodeParameter('list') as string;
const email = this.getNodeParameter('email') as string;
const status = this.getNodeParameter('status') as Status;
const options = this.getNodeParameter('options') as IDataObject;
const jsonActive = this.getNodeParameter('jsonParameters') as IDataObject;
const body: ICreateMemberBody = {
listId,
email_address: email,
status
};
if (options.emailType) {
body.email_type = options.emailType as string;
}
if (options.languaje) {
body.language = options.language as string;
}
if (options.vip) {
body.vip = options.vip as boolean;
}
if (options.ipSignup) {
body.ips_signup = options.ipSignup as string;
}
if (options.ipOptIn) {
body.ip_opt = options.ipOptIn as string;
}
if (options.timestampOpt) {
body.timestamp_opt = moment(options.timestampOpt as string).format('YYYY-MM-DD HH:MM:SS') as string;
}
if (options.timestampSignup) {
body.timestamp_signup = moment(options.timestampSignup as string).format('YYYY-MM-DD HH:MM:SS') as string;
}
if (options.tags) {
// @ts-ignore
body.tags = options.tags.split(',') as string[];
}
if (!jsonActive) {
const locationValues = (this.getNodeParameter('locationFieldsUi') as IDataObject).locationFieldsValues as IDataObject;
if (locationValues) {
const location: ILocation = {};
for (const key of Object.keys(locationValues)) {
if (key === 'latitude') {
location.latitude = parseInt(locationValues[key] as string, 10) as number;
} else if (key === 'longitude') {
location.longitude = parseInt(locationValues[key] as string, 10) as number;
}
}
body.location = location;
}
const mergeFieldsValues = (this.getNodeParameter('mergeFieldsUi') as IDataObject).mergeFieldsValues as IDataObject[];
if (mergeFieldsValues) {
const mergeFields = {};
for (let i = 0; i < mergeFieldsValues.length; i++) {
// @ts-ignore
mergeFields[mergeFieldsValues[i].name] = mergeFieldsValues[i].value;
}
body.merge_fields = mergeFields;
}
} else {
const locationJson = validateJSON(this.getNodeParameter('locationJson') as string);
const mergeFieldsJson = validateJSON(this.getNodeParameter('mergeFieldsJson') as string);
if (locationJson) {
body.location = locationJson;
}
if (mergeFieldsJson) {
body.merge_fields = mergeFieldsJson;
}
}
try {
response = await mailchimpApiRequest.call(this, `/lists/${listId}/members`, 'POST', body);
} catch (err) {
throw new Error(`Mailchimp Error: ${JSON.stringify(err)}`);
}
}
}
return {
json: response,
};
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -42,6 +42,7 @@
"dist/credentials/HttpHeaderAuth.credentials.js",
"dist/credentials/Imap.credentials.js",
"dist/credentials/LinkFishApi.credentials.js",
"dist/credentials/MailchimpApi.credentials.js",
"dist/credentials/MailgunApi.credentials.js",
"dist/credentials/MandrillApi.credentials.js",
"dist/credentials/MattermostApi.credentials.js",
@ -97,6 +98,7 @@
"dist/nodes/If.node.js",
"dist/nodes/Interval.node.js",
"dist/nodes/LinkFish/LinkFish.node.js",
"dist/nodes/Mailchimp/Mailchimp.node.js",
"dist/nodes/Mailgun/Mailgun.node.js",
"dist/nodes/Mandrill/Mandrill.node.js",
"dist/nodes/Mattermost/Mattermost.node.js",