mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat(MailerLite Node): Update node to support new api (#11933)
This commit is contained in:
parent
271401d882
commit
d6b8e65abe
|
@ -1,4 +1,10 @@
|
||||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
import type {
|
||||||
|
ICredentialDataDecryptedObject,
|
||||||
|
ICredentialTestRequest,
|
||||||
|
ICredentialType,
|
||||||
|
IHttpRequestOptions,
|
||||||
|
INodeProperties,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
export class MailerLiteApi implements ICredentialType {
|
export class MailerLiteApi implements ICredentialType {
|
||||||
name = 'mailerLiteApi';
|
name = 'mailerLiteApi';
|
||||||
|
@ -15,5 +21,37 @@ export class MailerLiteApi implements ICredentialType {
|
||||||
typeOptions: { password: true },
|
typeOptions: { password: true },
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Classic API',
|
||||||
|
name: 'classicApi',
|
||||||
|
type: 'boolean',
|
||||||
|
default: true,
|
||||||
|
description:
|
||||||
|
'If the Classic API should be used, If this is your first time using this node this should be false.',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
async authenticate(
|
||||||
|
credentials: ICredentialDataDecryptedObject,
|
||||||
|
requestOptions: IHttpRequestOptions,
|
||||||
|
): Promise<IHttpRequestOptions> {
|
||||||
|
if (credentials.classicApi === true) {
|
||||||
|
requestOptions.headers = {
|
||||||
|
'X-MailerLite-ApiKey': credentials.apiKey as string,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
requestOptions.headers = {
|
||||||
|
Authorization: `Bearer ${credentials.apiKey as string}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return requestOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
test: ICredentialTestRequest = {
|
||||||
|
request: {
|
||||||
|
baseURL:
|
||||||
|
'={{$credentials.classicApi ? "https://api.mailerlite.com/api/v2" : "https://connect.mailerlite.com/api"}}',
|
||||||
|
url: '/groups',
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,39 +3,38 @@ import type {
|
||||||
IExecuteFunctions,
|
IExecuteFunctions,
|
||||||
IHookFunctions,
|
IHookFunctions,
|
||||||
ILoadOptionsFunctions,
|
ILoadOptionsFunctions,
|
||||||
|
INodePropertyOptions,
|
||||||
JsonObject,
|
JsonObject,
|
||||||
IRequestOptions,
|
IHttpRequestOptions,
|
||||||
IHttpRequestMethods,
|
IHttpRequestMethods,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { NodeApiError } from 'n8n-workflow';
|
import { NodeApiError } from 'n8n-workflow';
|
||||||
|
|
||||||
|
import type { CustomField } from './v2/MailerLite.Interface';
|
||||||
|
|
||||||
export async function mailerliteApiRequest(
|
export async function mailerliteApiRequest(
|
||||||
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions,
|
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions,
|
||||||
method: IHttpRequestMethods,
|
method: IHttpRequestMethods,
|
||||||
path: string,
|
path: string,
|
||||||
|
|
||||||
body: any = {},
|
body: any = {},
|
||||||
qs: IDataObject = {},
|
qs: IDataObject = {},
|
||||||
_option = {},
|
_option = {},
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
const credentials = await this.getCredentials('mailerLiteApi');
|
const options: IHttpRequestOptions = {
|
||||||
|
|
||||||
const options: IRequestOptions = {
|
|
||||||
headers: {
|
|
||||||
'X-MailerLite-ApiKey': credentials.apiKey,
|
|
||||||
},
|
|
||||||
method,
|
method,
|
||||||
body,
|
body,
|
||||||
qs,
|
qs,
|
||||||
uri: `https://api.mailerlite.com/api/v2${path}`,
|
url:
|
||||||
|
this.getNode().typeVersion === 1
|
||||||
|
? `https://api.mailerlite.com/api/v2${path}`
|
||||||
|
: `https://connect.mailerlite.com/api${path}`,
|
||||||
json: true,
|
json: true,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
if (Object.keys(body as IDataObject).length === 0) {
|
if (Object.keys(body as IDataObject).length === 0) {
|
||||||
delete options.body;
|
delete options.body;
|
||||||
}
|
}
|
||||||
//@ts-ignore
|
return await this.helpers.httpRequestWithAuthentication.call(this, 'mailerLiteApi', options);
|
||||||
return await this.helpers.request.call(this, options);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||||
}
|
}
|
||||||
|
@ -45,21 +44,56 @@ export async function mailerliteApiRequestAllItems(
|
||||||
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions,
|
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions,
|
||||||
method: IHttpRequestMethods,
|
method: IHttpRequestMethods,
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
|
|
||||||
body: any = {},
|
body: any = {},
|
||||||
query: IDataObject = {},
|
query: IDataObject = {},
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
const returnData: IDataObject[] = [];
|
const returnData: IDataObject[] = [];
|
||||||
|
|
||||||
let responseData;
|
let responseData;
|
||||||
|
|
||||||
query.limit = 1000;
|
query.limit = 1000;
|
||||||
query.offset = 0;
|
query.offset = 0;
|
||||||
|
|
||||||
|
if (this.getNode().typeVersion === 1) {
|
||||||
do {
|
do {
|
||||||
responseData = await mailerliteApiRequest.call(this, method, endpoint, body, query);
|
responseData = await mailerliteApiRequest.call(this, method, endpoint, body, query);
|
||||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
returnData.push(...(responseData as IDataObject[]));
|
||||||
query.offset = query.offset + query.limit;
|
query.offset += query.limit;
|
||||||
} while (responseData.length !== 0);
|
} while (responseData.length !== 0);
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
responseData = await mailerliteApiRequest.call(this, method, endpoint, body, query);
|
||||||
|
returnData.push(...(responseData.data as IDataObject[]));
|
||||||
|
query.cursor = responseData.meta.next_cursor;
|
||||||
|
} while (responseData.links.next !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCustomFields(
|
||||||
|
this: ILoadOptionsFunctions,
|
||||||
|
): Promise<INodePropertyOptions[]> {
|
||||||
|
const returnData: INodePropertyOptions[] = [];
|
||||||
|
const endpoint = '/fields';
|
||||||
|
const fieldsResponse = await mailerliteApiRequest.call(this, 'GET', endpoint);
|
||||||
|
|
||||||
|
if (this.getNode().typeVersion === 1) {
|
||||||
|
const fields = fieldsResponse as CustomField[];
|
||||||
|
fields.forEach((field) => {
|
||||||
|
returnData.push({
|
||||||
|
name: field.key,
|
||||||
|
value: field.key,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const fields = (fieldsResponse as IDataObject).data as CustomField[];
|
||||||
|
fields.forEach((field) => {
|
||||||
|
returnData.push({
|
||||||
|
name: field.name,
|
||||||
|
value: field.key,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return returnData;
|
return returnData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,206 +1,26 @@
|
||||||
import type {
|
import type { INodeTypeBaseDescription, IVersionedNodeType } from 'n8n-workflow';
|
||||||
IExecuteFunctions,
|
import { VersionedNodeType } from 'n8n-workflow';
|
||||||
IDataObject,
|
|
||||||
ILoadOptionsFunctions,
|
|
||||||
INodeExecutionData,
|
|
||||||
INodePropertyOptions,
|
|
||||||
INodeType,
|
|
||||||
INodeTypeDescription,
|
|
||||||
} from 'n8n-workflow';
|
|
||||||
import { NodeConnectionType } from 'n8n-workflow';
|
|
||||||
|
|
||||||
import { mailerliteApiRequest, mailerliteApiRequestAllItems } from './GenericFunctions';
|
import { MailerLiteV1 } from './v1/MailerLiteV1.node';
|
||||||
|
import { MailerLiteV2 } from './v2/MailerLiteV2.node';
|
||||||
|
|
||||||
import { subscriberFields, subscriberOperations } from './SubscriberDescription';
|
export class MailerLite extends VersionedNodeType {
|
||||||
|
constructor() {
|
||||||
export class MailerLite implements INodeType {
|
const baseDescription: INodeTypeBaseDescription = {
|
||||||
description: INodeTypeDescription = {
|
|
||||||
displayName: 'MailerLite',
|
displayName: 'MailerLite',
|
||||||
name: 'mailerLite',
|
name: 'mailerLite',
|
||||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
|
icon: 'file:MailerLite.svg',
|
||||||
icon: 'file:mailerLite.png',
|
|
||||||
group: ['input'],
|
group: ['input'],
|
||||||
version: 1,
|
|
||||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||||
description: 'Consume Mailer Lite API',
|
description: 'Consume MailerLite API',
|
||||||
defaults: {
|
defaultVersion: 2,
|
||||||
name: 'MailerLite',
|
|
||||||
},
|
|
||||||
inputs: [NodeConnectionType.Main],
|
|
||||||
outputs: [NodeConnectionType.Main],
|
|
||||||
credentials: [
|
|
||||||
{
|
|
||||||
name: 'mailerLiteApi',
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
properties: [
|
|
||||||
{
|
|
||||||
displayName: 'Resource',
|
|
||||||
name: 'resource',
|
|
||||||
type: 'options',
|
|
||||||
noDataExpression: true,
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Subscriber',
|
|
||||||
value: 'subscriber',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
default: 'subscriber',
|
|
||||||
},
|
|
||||||
...subscriberOperations,
|
|
||||||
...subscriberFields,
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
methods = {
|
const nodeVersions: IVersionedNodeType['nodeVersions'] = {
|
||||||
loadOptions: {
|
1: new MailerLiteV1(baseDescription),
|
||||||
// Get all the available custom fields to display them to user so that they can
|
2: new MailerLiteV2(baseDescription),
|
||||||
// select them easily
|
|
||||||
async getCustomFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
|
||||||
const returnData: INodePropertyOptions[] = [];
|
|
||||||
const fields = await mailerliteApiRequest.call(this, 'GET', '/fields');
|
|
||||||
for (const field of fields) {
|
|
||||||
returnData.push({
|
|
||||||
name: field.key,
|
|
||||||
value: field.key,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return returnData;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
super(nodeVersions, baseDescription);
|
||||||
const items = this.getInputData();
|
|
||||||
const returnData: INodeExecutionData[] = [];
|
|
||||||
const length = items.length;
|
|
||||||
const qs: IDataObject = {};
|
|
||||||
let responseData;
|
|
||||||
const resource = this.getNodeParameter('resource', 0);
|
|
||||||
const operation = this.getNodeParameter('operation', 0);
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
try {
|
|
||||||
if (resource === 'subscriber') {
|
|
||||||
//https://developers.mailerlite.com/reference#create-a-subscriber
|
|
||||||
if (operation === 'create') {
|
|
||||||
const email = this.getNodeParameter('email', i) as string;
|
|
||||||
|
|
||||||
const additionalFields = this.getNodeParameter('additionalFields', i);
|
|
||||||
|
|
||||||
const body: IDataObject = {
|
|
||||||
email,
|
|
||||||
fields: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.assign(body, additionalFields);
|
|
||||||
|
|
||||||
if (additionalFields.customFieldsUi) {
|
|
||||||
const customFieldsValues = (additionalFields.customFieldsUi as IDataObject)
|
|
||||||
.customFieldsValues as IDataObject[];
|
|
||||||
|
|
||||||
if (customFieldsValues) {
|
|
||||||
const fields = {};
|
|
||||||
|
|
||||||
for (const customFieldValue of customFieldsValues) {
|
|
||||||
//@ts-ignore
|
|
||||||
fields[customFieldValue.fieldId] = customFieldValue.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.fields = fields;
|
|
||||||
delete body.customFieldsUi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
responseData = await mailerliteApiRequest.call(this, 'POST', '/subscribers', body);
|
|
||||||
}
|
|
||||||
//https://developers.mailerlite.com/reference#single-subscriber
|
|
||||||
if (operation === 'get') {
|
|
||||||
const subscriberId = this.getNodeParameter('subscriberId', i) as string;
|
|
||||||
|
|
||||||
responseData = await mailerliteApiRequest.call(
|
|
||||||
this,
|
|
||||||
'GET',
|
|
||||||
`/subscribers/${subscriberId}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
//https://developers.mailerlite.com/reference#subscribers
|
|
||||||
if (operation === 'getAll') {
|
|
||||||
const returnAll = this.getNodeParameter('returnAll', i);
|
|
||||||
|
|
||||||
const filters = this.getNodeParameter('filters', i);
|
|
||||||
|
|
||||||
Object.assign(qs, filters);
|
|
||||||
|
|
||||||
if (returnAll) {
|
|
||||||
responseData = await mailerliteApiRequestAllItems.call(
|
|
||||||
this,
|
|
||||||
'GET',
|
|
||||||
'/subscribers',
|
|
||||||
{},
|
|
||||||
qs,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
qs.limit = this.getNodeParameter('limit', i);
|
|
||||||
|
|
||||||
responseData = await mailerliteApiRequest.call(this, 'GET', '/subscribers', {}, qs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//https://developers.mailerlite.com/reference#update-subscriber
|
|
||||||
if (operation === 'update') {
|
|
||||||
const subscriberId = this.getNodeParameter('subscriberId', i) as string;
|
|
||||||
|
|
||||||
const updateFields = this.getNodeParameter('updateFields', i);
|
|
||||||
|
|
||||||
const body: IDataObject = {};
|
|
||||||
|
|
||||||
Object.assign(body, updateFields);
|
|
||||||
|
|
||||||
if (updateFields.customFieldsUi) {
|
|
||||||
const customFieldsValues = (updateFields.customFieldsUi as IDataObject)
|
|
||||||
.customFieldsValues as IDataObject[];
|
|
||||||
|
|
||||||
if (customFieldsValues) {
|
|
||||||
const fields = {};
|
|
||||||
|
|
||||||
for (const customFieldValue of customFieldsValues) {
|
|
||||||
//@ts-ignore
|
|
||||||
fields[customFieldValue.fieldId] = customFieldValue.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.fields = fields;
|
|
||||||
delete body.customFieldsUi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
responseData = await mailerliteApiRequest.call(
|
|
||||||
this,
|
|
||||||
'PUT',
|
|
||||||
`/subscribers/${subscriberId}`,
|
|
||||||
body,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (this.continueOnFail()) {
|
|
||||||
const executionErrorData = this.helpers.constructExecutionMetaData(
|
|
||||||
this.helpers.returnJsonArray({ error: error.message }),
|
|
||||||
{ itemData: { item: i } },
|
|
||||||
);
|
|
||||||
returnData.push(...executionErrorData);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const executionData = this.helpers.constructExecutionMetaData(
|
|
||||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
|
||||||
{ itemData: { item: i } },
|
|
||||||
);
|
|
||||||
|
|
||||||
returnData.push(...executionData);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [returnData];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
33
packages/nodes-base/nodes/MailerLite/MailerLite.svg
Normal file
33
packages/nodes-base/nodes/MailerLite/MailerLite.svg
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns:x="ns_extend;" xmlns:i="ns_ai;" xmlns:graph="ns_graphs;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 62.8 50.2" style="enable-background:new 0 0 62.8 50.2;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#09C269;}
|
||||||
|
.st1{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<metadata>
|
||||||
|
<sfw xmlns="ns_sfw;">
|
||||||
|
<slices>
|
||||||
|
</slices>
|
||||||
|
<sliceSourceBounds bottomLeftOrigin="true" height="50.2" width="62.8" x="236.9" y="-225.3">
|
||||||
|
</sliceSourceBounds>
|
||||||
|
</sfw>
|
||||||
|
</metadata>
|
||||||
|
<g id="mailerlite-light">
|
||||||
|
<g>
|
||||||
|
<g id="lite" transform="translate(137.000000, 0.000000)">
|
||||||
|
<path id="Shape-path" class="st0" d="M-81.2,0h-48.9c-3.8,0-6.9,3.1-6.9,6.8v22.8v4.5v16.2l9.5-9.3h46.4c3.8,0,6.9-3.1,6.9-6.8
|
||||||
|
V6.8C-74.3,3.1-77.4,0-81.2,0z">
|
||||||
|
</path>
|
||||||
|
<path id="Shape-path-3" class="st1" d="M-90.2,15.8c5.2,0,7.6,4.1,7.6,8c0,1-0.8,1.8-1.8,1.8H-94c0.5,2.3,2.1,3.6,4.7,3.6
|
||||||
|
c1.9,0,2.9-0.4,3.9-0.9c0.2-0.1,0.5-0.2,0.7-0.2c0.9,0,1.7,0.7,1.7,1.6c0,0.6-0.4,1.1-1,1.5c-1.3,0.7-2.7,1.4-5.5,1.4
|
||||||
|
c-5.2,0-8.3-3.1-8.3-8.4C-97.9,18.1-93.7,15.8-90.2,15.8z M-105.5,13.2c0.6,0,1,0.5,1,1v1.9h2.9c0.9,0,1.7,0.7,1.7,1.6
|
||||||
|
c0,0.9-0.7,1.6-1.7,1.6h-2.9V28c0,1.2,0.6,1.3,1.5,1.3c0.5,0,0.8-0.1,1.1-0.1c0.2,0,0.5-0.1,0.7-0.1c0.7,0,1.6,0.6,1.6,1.5
|
||||||
|
c0,0.6-0.4,1.1-1,1.4c-0.9,0.4-1.7,0.6-2.7,0.6c-3.2,0-4.9-1.5-4.9-4.4v-8.8h-1.7c-0.6,0-1-0.5-1-1c0-0.3,0.1-0.6,0.4-0.9l4-4
|
||||||
|
C-106.3,13.5-106,13.2-105.5,13.2z M-124.2,9.4c1,0,1.8,0.8,1.8,1.8v19.4c0,1-0.8,1.8-1.8,1.8s-1.8-0.8-1.8-1.8V11.2
|
||||||
|
C-126,10.2-125.2,9.4-124.2,9.4z M-115.6,16c1,0,1.8,0.8,1.8,1.8v12.8c0,1-0.8,1.8-1.8,1.8c-1,0-1.8-0.8-1.8-1.8V17.8
|
||||||
|
C-117.4,16.8-116.6,16-115.6,16z M-90.1,19.1c-1.7,0-3.6,1-3.9,3.5h7.9C-86.6,20.1-88.4,19.1-90.1,19.1z M-115.5,9.9
|
||||||
|
c1.1,0,2,0.9,2,2V12c0,1.1-0.9,2-2,2h-0.2c-1.1,0-2-0.9-2-2v-0.1c0-1.1,0.9-2,2-2H-115.5z">
|
||||||
|
</path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -1,180 +1,25 @@
|
||||||
import type {
|
import type { INodeTypeBaseDescription, IVersionedNodeType } from 'n8n-workflow';
|
||||||
IHookFunctions,
|
import { VersionedNodeType } from 'n8n-workflow';
|
||||||
IWebhookFunctions,
|
|
||||||
IDataObject,
|
|
||||||
INodeType,
|
|
||||||
INodeTypeDescription,
|
|
||||||
IWebhookResponseData,
|
|
||||||
} from 'n8n-workflow';
|
|
||||||
import { NodeConnectionType } from 'n8n-workflow';
|
|
||||||
|
|
||||||
import { mailerliteApiRequest } from './GenericFunctions';
|
import { MailerLiteTriggerV1 } from './v1/MailerLiteTriggerV1.node';
|
||||||
|
import { MailerLiteTriggerV2 } from './v2/MailerLiteTriggerV2.node';
|
||||||
|
|
||||||
export class MailerLiteTrigger implements INodeType {
|
export class MailerLiteTrigger extends VersionedNodeType {
|
||||||
description: INodeTypeDescription = {
|
constructor() {
|
||||||
|
const baseDescription: INodeTypeBaseDescription = {
|
||||||
displayName: 'MailerLite Trigger',
|
displayName: 'MailerLite Trigger',
|
||||||
name: 'mailerLiteTrigger',
|
name: 'mailerLiteTrigger',
|
||||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
|
icon: 'file:MailerLite.svg',
|
||||||
icon: 'file:mailerLite.png',
|
|
||||||
group: ['trigger'],
|
group: ['trigger'],
|
||||||
version: 1,
|
|
||||||
description: 'Starts the workflow when MailerLite events occur',
|
description: 'Starts the workflow when MailerLite events occur',
|
||||||
defaults: {
|
defaultVersion: 2,
|
||||||
name: 'MailerLite Trigger',
|
|
||||||
},
|
|
||||||
inputs: [],
|
|
||||||
outputs: [NodeConnectionType.Main],
|
|
||||||
credentials: [
|
|
||||||
{
|
|
||||||
name: 'mailerLiteApi',
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
webhooks: [
|
|
||||||
{
|
|
||||||
name: 'default',
|
|
||||||
httpMethod: 'POST',
|
|
||||||
responseMode: 'onReceived',
|
|
||||||
path: 'webhook',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
properties: [
|
|
||||||
{
|
|
||||||
displayName: 'Event',
|
|
||||||
name: 'event',
|
|
||||||
type: 'options',
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Campaign Sent',
|
|
||||||
value: 'campaign.sent',
|
|
||||||
description: 'Fired when campaign is sent',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subscriber Added Throught Webform',
|
|
||||||
value: 'subscriber.added_through_webform',
|
|
||||||
description: 'Fired when a subscriber is added though a form',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subscriber Added to Group',
|
|
||||||
value: 'subscriber.add_to_group',
|
|
||||||
description: 'Fired when a subscriber is added to a group',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subscriber Autonomation Completed',
|
|
||||||
value: 'subscriber.automation_complete',
|
|
||||||
description: 'Fired when subscriber finishes automation',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subscriber Autonomation Triggered',
|
|
||||||
value: 'subscriber.automation_triggered',
|
|
||||||
description: 'Fired when subscriber starts automation',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subscriber Bounced',
|
|
||||||
value: 'subscriber.bounced',
|
|
||||||
description: 'Fired when an email address bounces',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subscriber Complained',
|
|
||||||
value: 'subscriber.complaint',
|
|
||||||
description: 'Fired when subscriber marks a campaign as a spam',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subscriber Created',
|
|
||||||
value: 'subscriber.create',
|
|
||||||
description: 'Fired when a new subscriber is added to an account',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subscriber Removed From Group',
|
|
||||||
value: 'subscriber.remove_from_group',
|
|
||||||
description: 'Fired when a subscriber is removed from a group',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subscriber Unsubscribe',
|
|
||||||
value: 'subscriber.unsubscribe',
|
|
||||||
description: 'Fired when a subscriber becomes unsubscribed',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subscriber Updated',
|
|
||||||
value: 'subscriber.update',
|
|
||||||
description: "Fired when any of the subscriber's custom fields are updated",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
required: true,
|
|
||||||
default: [],
|
|
||||||
description: 'The events to listen to',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
webhookMethods = {
|
const nodeVersions: IVersionedNodeType['nodeVersions'] = {
|
||||||
default: {
|
1: new MailerLiteTriggerV1(baseDescription),
|
||||||
async checkExists(this: IHookFunctions): Promise<boolean> {
|
2: new MailerLiteTriggerV2(baseDescription),
|
||||||
const webhookUrl = this.getNodeWebhookUrl('default');
|
|
||||||
const webhookData = this.getWorkflowStaticData('node');
|
|
||||||
const event = this.getNodeParameter('event') as string;
|
|
||||||
// Check all the webhooks which exist already if it is identical to the
|
|
||||||
// one that is supposed to get created.
|
|
||||||
const endpoint = '/webhooks';
|
|
||||||
const { webhooks } = await mailerliteApiRequest.call(this, 'GET', endpoint, {});
|
|
||||||
for (const webhook of webhooks) {
|
|
||||||
if (webhook.url === webhookUrl && webhook.event === event) {
|
|
||||||
// Set webhook-id to be sure that it can be deleted
|
|
||||||
webhookData.webhookId = webhook.id as string;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
async create(this: IHookFunctions): Promise<boolean> {
|
|
||||||
const webhookData = this.getWorkflowStaticData('node');
|
|
||||||
const webhookUrl = this.getNodeWebhookUrl('default');
|
|
||||||
const event = this.getNodeParameter('event') as string;
|
|
||||||
|
|
||||||
const endpoint = '/webhooks';
|
|
||||||
|
|
||||||
const body = {
|
|
||||||
url: webhookUrl,
|
|
||||||
event,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const responseData = await mailerliteApiRequest.call(this, 'POST', endpoint, body);
|
super(nodeVersions, baseDescription);
|
||||||
|
|
||||||
if (responseData.id === undefined) {
|
|
||||||
// Required data is missing so was not successful
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
webhookData.webhookId = responseData.id as string;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
async delete(this: IHookFunctions): Promise<boolean> {
|
|
||||||
const webhookData = this.getWorkflowStaticData('node');
|
|
||||||
if (webhookData.webhookId !== undefined) {
|
|
||||||
const endpoint = `/webhooks/${webhookData.webhookId}`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await mailerliteApiRequest.call(this, 'DELETE', endpoint);
|
|
||||||
} catch (error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove from the static workflow data so that it is clear
|
|
||||||
// that no webhooks are registered anymore
|
|
||||||
delete webhookData.webhookId;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
|
||||||
const body = this.getBodyData();
|
|
||||||
|
|
||||||
const events = body.events as IDataObject[];
|
|
||||||
|
|
||||||
return {
|
|
||||||
workflowData: [this.helpers.returnJsonArray(events)],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 893 B |
|
@ -0,0 +1,253 @@
|
||||||
|
/* eslint-disable n8n-nodes-base/node-param-display-name-miscased */
|
||||||
|
import {
|
||||||
|
type IExecuteFunctions,
|
||||||
|
type ILoadOptionsFunctions,
|
||||||
|
type IHookFunctions,
|
||||||
|
NodeApiError,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
import {
|
||||||
|
getCustomFields,
|
||||||
|
mailerliteApiRequest,
|
||||||
|
mailerliteApiRequestAllItems,
|
||||||
|
} from '../GenericFunctions';
|
||||||
|
|
||||||
|
describe('MailerLite -> mailerliteApiRequest', () => {
|
||||||
|
let mockExecuteFunctions: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions;
|
||||||
|
|
||||||
|
const setupMockFunctions = (typeVersion: number) => {
|
||||||
|
mockExecuteFunctions = {
|
||||||
|
getNode: jest.fn().mockReturnValue({ typeVersion }),
|
||||||
|
helpers: {
|
||||||
|
httpRequestWithAuthentication: jest.fn(),
|
||||||
|
},
|
||||||
|
} as unknown as IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions;
|
||||||
|
jest.clearAllMocks();
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
setupMockFunctions(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make a successful API request for type version 1', async () => {
|
||||||
|
const method = 'GET';
|
||||||
|
const path = '/test';
|
||||||
|
const body = {};
|
||||||
|
const qs = {};
|
||||||
|
|
||||||
|
const responseData = { success: true };
|
||||||
|
|
||||||
|
(mockExecuteFunctions.helpers.httpRequestWithAuthentication as jest.Mock).mockResolvedValue(
|
||||||
|
responseData,
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await mailerliteApiRequest.call(mockExecuteFunctions, method, path, body, qs);
|
||||||
|
|
||||||
|
expect(result).toEqual(responseData);
|
||||||
|
expect(mockExecuteFunctions.helpers.httpRequestWithAuthentication).toHaveBeenCalledWith(
|
||||||
|
'mailerLiteApi',
|
||||||
|
{
|
||||||
|
method,
|
||||||
|
qs,
|
||||||
|
url: 'https://api.mailerlite.com/api/v2/test',
|
||||||
|
json: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make a successful API request for type version 2', async () => {
|
||||||
|
setupMockFunctions(2);
|
||||||
|
|
||||||
|
const method = 'GET';
|
||||||
|
const path = '/test';
|
||||||
|
const body = {};
|
||||||
|
const qs = {};
|
||||||
|
|
||||||
|
const responseData = { success: true };
|
||||||
|
|
||||||
|
(mockExecuteFunctions.helpers.httpRequestWithAuthentication as jest.Mock).mockResolvedValue(
|
||||||
|
responseData,
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await mailerliteApiRequest.call(mockExecuteFunctions, method, path, body, qs);
|
||||||
|
|
||||||
|
expect(result).toEqual(responseData);
|
||||||
|
expect(mockExecuteFunctions.helpers.httpRequestWithAuthentication).toHaveBeenCalledWith(
|
||||||
|
'mailerLiteApi',
|
||||||
|
{
|
||||||
|
method,
|
||||||
|
qs,
|
||||||
|
url: 'https://connect.mailerlite.com/api/test',
|
||||||
|
json: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make an API request with an empty body', async () => {
|
||||||
|
const method = 'GET';
|
||||||
|
const path = '/test';
|
||||||
|
const body = {};
|
||||||
|
const qs = {};
|
||||||
|
|
||||||
|
const responseData = { success: true };
|
||||||
|
|
||||||
|
(mockExecuteFunctions.helpers.httpRequestWithAuthentication as jest.Mock).mockResolvedValue(
|
||||||
|
responseData,
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await mailerliteApiRequest.call(mockExecuteFunctions, method, path, body, qs);
|
||||||
|
|
||||||
|
expect(result).toEqual(responseData);
|
||||||
|
expect(mockExecuteFunctions.helpers.httpRequestWithAuthentication).toHaveBeenCalledWith(
|
||||||
|
'mailerLiteApi',
|
||||||
|
{
|
||||||
|
method,
|
||||||
|
qs,
|
||||||
|
url: 'https://api.mailerlite.com/api/v2/test',
|
||||||
|
json: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if the API request fails', async () => {
|
||||||
|
const method = 'GET';
|
||||||
|
const path = '/test';
|
||||||
|
const body = {};
|
||||||
|
const qs = {};
|
||||||
|
|
||||||
|
const errorResponse = { message: 'Error' };
|
||||||
|
|
||||||
|
(mockExecuteFunctions.helpers.httpRequestWithAuthentication as jest.Mock).mockRejectedValue(
|
||||||
|
errorResponse,
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
mailerliteApiRequest.call(mockExecuteFunctions, method, path, body, qs),
|
||||||
|
).rejects.toThrow(NodeApiError);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('MailerLite -> mailerliteApiRequestAllItems', () => {
|
||||||
|
let mockExecuteFunctions: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions;
|
||||||
|
|
||||||
|
const setupMockFunctions = (typeVersion: number) => {
|
||||||
|
mockExecuteFunctions = {
|
||||||
|
getNode: jest.fn().mockReturnValue({ typeVersion }),
|
||||||
|
helpers: {
|
||||||
|
httpRequestWithAuthentication: jest.fn(),
|
||||||
|
},
|
||||||
|
} as unknown as IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions;
|
||||||
|
jest.clearAllMocks();
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
setupMockFunctions(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle pagination for type version 1', async () => {
|
||||||
|
const method = 'GET';
|
||||||
|
const endpoint = '/test';
|
||||||
|
const body = {};
|
||||||
|
const query = {};
|
||||||
|
|
||||||
|
const responseDataPage1 = [{ id: 1 }, { id: 2 }];
|
||||||
|
const responseDataPage2 = [{ id: 3 }, { id: 4 }];
|
||||||
|
|
||||||
|
(mockExecuteFunctions.helpers.httpRequestWithAuthentication as jest.Mock)
|
||||||
|
.mockResolvedValueOnce(responseDataPage1)
|
||||||
|
.mockResolvedValueOnce(responseDataPage2)
|
||||||
|
.mockResolvedValueOnce([]);
|
||||||
|
|
||||||
|
const result = await mailerliteApiRequestAllItems.call(
|
||||||
|
mockExecuteFunctions,
|
||||||
|
method,
|
||||||
|
endpoint,
|
||||||
|
body,
|
||||||
|
query,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual([...responseDataPage1, ...responseDataPage2]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle pagination for type version 2', async () => {
|
||||||
|
setupMockFunctions(2);
|
||||||
|
|
||||||
|
const method = 'GET';
|
||||||
|
const endpoint = '/test';
|
||||||
|
const body = {};
|
||||||
|
const query = {};
|
||||||
|
|
||||||
|
const responseDataPage1 = {
|
||||||
|
data: [{ id: 1 }, { id: 2 }],
|
||||||
|
meta: { next_cursor: 'cursor1' },
|
||||||
|
links: { next: 'nextLink1' },
|
||||||
|
};
|
||||||
|
const responseDataPage2 = {
|
||||||
|
data: [{ id: 3 }, { id: 4 }],
|
||||||
|
meta: { next_cursor: null },
|
||||||
|
links: { next: null },
|
||||||
|
};
|
||||||
|
|
||||||
|
(mockExecuteFunctions.helpers.httpRequestWithAuthentication as jest.Mock)
|
||||||
|
.mockResolvedValueOnce(responseDataPage1)
|
||||||
|
.mockResolvedValueOnce(responseDataPage2);
|
||||||
|
|
||||||
|
const result = await mailerliteApiRequestAllItems.call(
|
||||||
|
mockExecuteFunctions,
|
||||||
|
method,
|
||||||
|
endpoint,
|
||||||
|
body,
|
||||||
|
query,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual([...responseDataPage1.data, ...responseDataPage2.data]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('MailerLite -> getCustomFields', () => {
|
||||||
|
let mockExecuteFunctions: ILoadOptionsFunctions;
|
||||||
|
|
||||||
|
const v1FieldResponse = [
|
||||||
|
{ name: 'Field1', key: 'field1' },
|
||||||
|
{ name: 'Field2', key: 'field2' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const v2FieldResponse = {
|
||||||
|
data: v1FieldResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
const setupMockFunctions = (typeVersion: number) => {
|
||||||
|
mockExecuteFunctions = {
|
||||||
|
getNode: jest.fn().mockReturnValue({ typeVersion }),
|
||||||
|
helpers: {
|
||||||
|
httpRequestWithAuthentication: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(typeVersion === 1 ? v1FieldResponse : v2FieldResponse),
|
||||||
|
},
|
||||||
|
} as unknown as ILoadOptionsFunctions;
|
||||||
|
jest.clearAllMocks();
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
setupMockFunctions(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return custom fields for type version 1', async () => {
|
||||||
|
const result = await getCustomFields.call(mockExecuteFunctions);
|
||||||
|
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'field1', value: 'field1' },
|
||||||
|
{ name: 'field2', value: 'field2' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return custom fields for type version 2', async () => {
|
||||||
|
setupMockFunctions(2);
|
||||||
|
const result = await getCustomFields.call(mockExecuteFunctions);
|
||||||
|
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'Field1', value: 'field1' },
|
||||||
|
{ name: 'Field2', value: 'field2' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
411
packages/nodes-base/nodes/MailerLite/tests/apiResponses.ts
Normal file
411
packages/nodes-base/nodes/MailerLite/tests/apiResponses.ts
Normal file
|
@ -0,0 +1,411 @@
|
||||||
|
export const getUpdateSubscriberResponseClassic = {
|
||||||
|
id: 1343965485,
|
||||||
|
email: 'demo@mailerlite.com',
|
||||||
|
sent: 0,
|
||||||
|
opened: 0,
|
||||||
|
clicked: 0,
|
||||||
|
type: 'unsubscribed',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'email',
|
||||||
|
value: 'demo@mailerlite.com',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
value: 'Demo',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'last_name',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'company',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'country',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'city',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'phone',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'state',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'zip',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
date_subscribe: null,
|
||||||
|
date_unsubscribe: '2016-04-04 12:07:26',
|
||||||
|
date_created: '2016-04-04',
|
||||||
|
date_updated: null,
|
||||||
|
};
|
||||||
|
export const getSubscriberResponseClassic = {
|
||||||
|
id: 1343965485,
|
||||||
|
name: 'John',
|
||||||
|
email: 'demo@mailerlite.com',
|
||||||
|
sent: 0,
|
||||||
|
opened: 0,
|
||||||
|
clicked: 0,
|
||||||
|
type: 'active',
|
||||||
|
signup_ip: '127.0.0.1',
|
||||||
|
signup_timestamp: '2018-01-01 01:01:01',
|
||||||
|
confirmation_ip: '127.0.0.2',
|
||||||
|
confirmation_timestamp: '2018-01-01 01:01:02',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'email',
|
||||||
|
value: 'demo@mailerlite.com',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
value: 'John',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'last_name',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'company',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'country',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'city',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'phone',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'state',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'zip',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
date_subscribe: null,
|
||||||
|
date_unsubscribe: null,
|
||||||
|
date_created: '2016-04-04',
|
||||||
|
date_updated: null,
|
||||||
|
};
|
||||||
|
export const getCreateResponseClassic = {
|
||||||
|
id: 1343965485,
|
||||||
|
name: 'John',
|
||||||
|
email: 'demo@mailerlite.com',
|
||||||
|
sent: 0,
|
||||||
|
opened: 0,
|
||||||
|
clicked: 0,
|
||||||
|
type: 'active',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'email',
|
||||||
|
value: 'demo@mailerlite.com',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
value: 'John',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'last_name',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'company',
|
||||||
|
value: 'MailerLite',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'country',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'city',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'phone',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'state',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'zip',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
date_subscribe: null,
|
||||||
|
date_unsubscribe: null,
|
||||||
|
date_created: '2016-04-04 12:00:00',
|
||||||
|
date_updated: '2016-04-04 12:00:00',
|
||||||
|
};
|
||||||
|
export const getAllSubscribersResponseClassic = [
|
||||||
|
{
|
||||||
|
id: 1343965485,
|
||||||
|
name: 'John',
|
||||||
|
email: 'demo@mailerlite.com',
|
||||||
|
sent: 0,
|
||||||
|
opened: 0,
|
||||||
|
clicked: 0,
|
||||||
|
type: 'active',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'email',
|
||||||
|
value: 'demo@mailerlite.com',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
value: 'John',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'last_name',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'company',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'country',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'city',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'phone',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'state',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'zip',
|
||||||
|
value: '',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
date_subscribe: null,
|
||||||
|
date_unsubscribe: null,
|
||||||
|
date_created: '2016-04-04',
|
||||||
|
date_updated: null,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const getUpdateSubscriberResponseV2 = {
|
||||||
|
data: {
|
||||||
|
id: '139872142007207563',
|
||||||
|
email: 'user@n8n.io',
|
||||||
|
status: 'junk',
|
||||||
|
source: 'api',
|
||||||
|
sent: 0,
|
||||||
|
opens_count: 0,
|
||||||
|
clicks_count: 0,
|
||||||
|
open_rate: 0,
|
||||||
|
click_rate: 0,
|
||||||
|
ip_address: null,
|
||||||
|
subscribed_at: '2024-12-05 09:54:29',
|
||||||
|
unsubscribed_at: null,
|
||||||
|
created_at: '2024-12-05 09:54:29',
|
||||||
|
updated_at: '2024-12-05 10:20:32',
|
||||||
|
fields: {
|
||||||
|
name: null,
|
||||||
|
last_name: null,
|
||||||
|
company: null,
|
||||||
|
country: null,
|
||||||
|
city: null,
|
||||||
|
phone: null,
|
||||||
|
state: null,
|
||||||
|
z_i_p: null,
|
||||||
|
},
|
||||||
|
groups: [],
|
||||||
|
opted_in_at: null,
|
||||||
|
optin_ip: '8.8.8.8',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export const getCreateResponseV2 = {
|
||||||
|
data: {
|
||||||
|
id: '139872142007207563',
|
||||||
|
email: 'user@n8n.io',
|
||||||
|
status: 'junk',
|
||||||
|
source: 'api',
|
||||||
|
sent: 0,
|
||||||
|
opens_count: 0,
|
||||||
|
clicks_count: 0,
|
||||||
|
open_rate: 0,
|
||||||
|
click_rate: 0,
|
||||||
|
ip_address: null,
|
||||||
|
subscribed_at: '2024-12-05 09:54:29',
|
||||||
|
unsubscribed_at: null,
|
||||||
|
created_at: '2024-12-05 09:54:29',
|
||||||
|
updated_at: '2024-12-05 10:20:32',
|
||||||
|
fields: {
|
||||||
|
name: null,
|
||||||
|
last_name: null,
|
||||||
|
company: null,
|
||||||
|
country: null,
|
||||||
|
city: null,
|
||||||
|
phone: null,
|
||||||
|
state: null,
|
||||||
|
z_i_p: null,
|
||||||
|
},
|
||||||
|
groups: [],
|
||||||
|
opted_in_at: null,
|
||||||
|
optin_ip: '8.8.8.8',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export const getSubscriberResponseV2 = {
|
||||||
|
data: {
|
||||||
|
id: '139872142007207563',
|
||||||
|
email: 'user@n8n.io',
|
||||||
|
status: 'junk',
|
||||||
|
source: 'api',
|
||||||
|
sent: 0,
|
||||||
|
opens_count: 0,
|
||||||
|
clicks_count: 0,
|
||||||
|
open_rate: 0,
|
||||||
|
click_rate: 0,
|
||||||
|
ip_address: null,
|
||||||
|
subscribed_at: '2024-12-05 09:54:29',
|
||||||
|
unsubscribed_at: null,
|
||||||
|
created_at: '2024-12-05 09:54:29',
|
||||||
|
updated_at: '2024-12-05 10:20:32',
|
||||||
|
fields: {
|
||||||
|
name: null,
|
||||||
|
last_name: null,
|
||||||
|
company: null,
|
||||||
|
country: null,
|
||||||
|
city: null,
|
||||||
|
phone: null,
|
||||||
|
state: null,
|
||||||
|
z_i_p: null,
|
||||||
|
},
|
||||||
|
groups: [],
|
||||||
|
opted_in_at: null,
|
||||||
|
optin_ip: '8.8.8.8',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export const getAllSubscribersResponseV2 = {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: '139872142007207563',
|
||||||
|
email: 'user@n8n.io',
|
||||||
|
status: 'junk',
|
||||||
|
source: 'api',
|
||||||
|
sent: 0,
|
||||||
|
opens_count: 0,
|
||||||
|
clicks_count: 0,
|
||||||
|
open_rate: 0,
|
||||||
|
click_rate: 0,
|
||||||
|
ip_address: null,
|
||||||
|
subscribed_at: '2024-12-05 09:54:29',
|
||||||
|
unsubscribed_at: null,
|
||||||
|
created_at: '2024-12-05 09:54:29',
|
||||||
|
updated_at: '2024-12-05 10:20:32',
|
||||||
|
fields: {
|
||||||
|
name: null,
|
||||||
|
last_name: null,
|
||||||
|
company: null,
|
||||||
|
country: null,
|
||||||
|
city: null,
|
||||||
|
phone: null,
|
||||||
|
state: null,
|
||||||
|
z_i_p: null,
|
||||||
|
},
|
||||||
|
opted_in_at: null,
|
||||||
|
optin_ip: '8.8.8.8',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '139059851540038710',
|
||||||
|
email: 'nathan@n8n.io',
|
||||||
|
status: 'junk',
|
||||||
|
source: 'api',
|
||||||
|
sent: 0,
|
||||||
|
opens_count: 0,
|
||||||
|
clicks_count: 0,
|
||||||
|
open_rate: 0,
|
||||||
|
click_rate: 0,
|
||||||
|
ip_address: null,
|
||||||
|
subscribed_at: null,
|
||||||
|
unsubscribed_at: null,
|
||||||
|
created_at: '2024-11-26 10:43:28',
|
||||||
|
updated_at: '2024-11-27 10:09:34',
|
||||||
|
fields: {
|
||||||
|
name: 'Nathan',
|
||||||
|
last_name: 'Workflow',
|
||||||
|
company: null,
|
||||||
|
country: null,
|
||||||
|
city: null,
|
||||||
|
phone: null,
|
||||||
|
state: null,
|
||||||
|
z_i_p: null,
|
||||||
|
},
|
||||||
|
opted_in_at: null,
|
||||||
|
optin_ip: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
links: {
|
||||||
|
first: null,
|
||||||
|
last: null,
|
||||||
|
prev: null,
|
||||||
|
next: null,
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
path: 'https://connect.mailerlite.com/api/subscribers',
|
||||||
|
per_page: 2,
|
||||||
|
next_cursor: null,
|
||||||
|
prev_cursor: null,
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,460 @@
|
||||||
|
{
|
||||||
|
"name": "[TEST] MailerLite v1 Node",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"id": "be5a39ea-04bf-49a3-969f-47d4a9496f08",
|
||||||
|
"name": "When clicking ‘Test workflow’",
|
||||||
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [-340, 280]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"email": "demo@mailerlite.com",
|
||||||
|
"additionalFields": {}
|
||||||
|
},
|
||||||
|
"id": "98d30bbe-cbdd-4313-933e-804cdf322860",
|
||||||
|
"name": "Create Subscriber",
|
||||||
|
"type": "n8n-nodes-base.mailerLite",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [-140, 40],
|
||||||
|
"credentials": {
|
||||||
|
"mailerLiteApi": {
|
||||||
|
"id": "bm7VHS2C7lRgVOhb",
|
||||||
|
"name": "Mailer Lite account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"type": "n8n-nodes-base.noOp",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [80, 40],
|
||||||
|
"id": "93aa764f-5101-4961-9b51-9fa92f746337",
|
||||||
|
"name": "No Operation, do nothing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"type": "n8n-nodes-base.noOp",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [80, 220],
|
||||||
|
"id": "4dccb059-c4f6-4eae-b68a-5c5c36d0b8d4",
|
||||||
|
"name": "No Operation, do nothing1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"operation": "get",
|
||||||
|
"subscriberId": "demo@mailerlite.com"
|
||||||
|
},
|
||||||
|
"type": "n8n-nodes-base.mailerLite",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [-140, 220],
|
||||||
|
"id": "82115adf-edf4-4ce4-9109-3ade129294d1",
|
||||||
|
"name": "Get Subscriber",
|
||||||
|
"credentials": {
|
||||||
|
"mailerLiteApi": {
|
||||||
|
"id": "bm7VHS2C7lRgVOhb",
|
||||||
|
"name": "Mailer Lite account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"operation": "update",
|
||||||
|
"subscriberId": "demo@mailerlite.com",
|
||||||
|
"updateFields": {
|
||||||
|
"type": "active"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "n8n-nodes-base.mailerLite",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [-140, 420],
|
||||||
|
"id": "fae9c6bd-1bd1-4ee8-865d-283b7edb6004",
|
||||||
|
"name": "Update Subscriber",
|
||||||
|
"credentials": {
|
||||||
|
"mailerLiteApi": {
|
||||||
|
"id": "bm7VHS2C7lRgVOhb",
|
||||||
|
"name": "Mailer Lite account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"type": "n8n-nodes-base.noOp",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [80, 420],
|
||||||
|
"id": "45937d69-3956-434d-b955-a67d77d43d57",
|
||||||
|
"name": "No Operation, do nothing2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"operation": "getAll",
|
||||||
|
"limit": 1,
|
||||||
|
"filters": {}
|
||||||
|
},
|
||||||
|
"type": "n8n-nodes-base.mailerLite",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [-180, 680],
|
||||||
|
"id": "6491d933-0929-44bd-89cf-977823dde650",
|
||||||
|
"name": "Get Many Subscrbers",
|
||||||
|
"credentials": {
|
||||||
|
"mailerLiteApi": {
|
||||||
|
"id": "bm7VHS2C7lRgVOhb",
|
||||||
|
"name": "Mailer Lite account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"type": "n8n-nodes-base.noOp",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [40, 680],
|
||||||
|
"id": "6e35d6e1-1ce3-4410-8558-a5d573676d8a",
|
||||||
|
"name": "No Operation, do nothing3"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pinData": {
|
||||||
|
"No Operation, do nothing": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 1343965485,
|
||||||
|
"name": "John",
|
||||||
|
"email": "demo@mailerlite.com",
|
||||||
|
"sent": 0,
|
||||||
|
"opened": 0,
|
||||||
|
"clicked": 0,
|
||||||
|
"type": "active",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"key": "email",
|
||||||
|
"value": "demo@mailerlite.com",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "name",
|
||||||
|
"value": "John",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "last_name",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "company",
|
||||||
|
"value": "MailerLite",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "country",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "city",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "phone",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "state",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "zip",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"date_subscribe": null,
|
||||||
|
"date_unsubscribe": null,
|
||||||
|
"date_created": "2016-04-04 12:00:00",
|
||||||
|
"date_updated": "2016-04-04 12:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"No Operation, do nothing1": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 1343965485,
|
||||||
|
"name": "John",
|
||||||
|
"email": "demo@mailerlite.com",
|
||||||
|
"sent": 0,
|
||||||
|
"opened": 0,
|
||||||
|
"clicked": 0,
|
||||||
|
"type": "active",
|
||||||
|
"signup_ip": "127.0.0.1",
|
||||||
|
"signup_timestamp": "2018-01-01 01:01:01",
|
||||||
|
"confirmation_ip": "127.0.0.2",
|
||||||
|
"confirmation_timestamp": "2018-01-01 01:01:02",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"key": "email",
|
||||||
|
"value": "demo@mailerlite.com",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "name",
|
||||||
|
"value": "John",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "last_name",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "company",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "country",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "city",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "phone",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "state",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "zip",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"date_subscribe": null,
|
||||||
|
"date_unsubscribe": null,
|
||||||
|
"date_created": "2016-04-04",
|
||||||
|
"date_updated": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"No Operation, do nothing2": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 1343965485,
|
||||||
|
"email": "demo@mailerlite.com",
|
||||||
|
"sent": 0,
|
||||||
|
"opened": 0,
|
||||||
|
"clicked": 0,
|
||||||
|
"type": "unsubscribed",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"key": "email",
|
||||||
|
"value": "demo@mailerlite.com",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "name",
|
||||||
|
"value": "Demo",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "last_name",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "company",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "country",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "city",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "phone",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "state",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "zip",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"date_subscribe": null,
|
||||||
|
"date_unsubscribe": "2016-04-04 12:07:26",
|
||||||
|
"date_created": "2016-04-04",
|
||||||
|
"date_updated": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"No Operation, do nothing3": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": 1343965485,
|
||||||
|
"name": "John",
|
||||||
|
"email": "demo@mailerlite.com",
|
||||||
|
"sent": 0,
|
||||||
|
"opened": 0,
|
||||||
|
"clicked": 0,
|
||||||
|
"type": "active",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"key": "email",
|
||||||
|
"value": "demo@mailerlite.com",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "name",
|
||||||
|
"value": "John",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "last_name",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "company",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "country",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "city",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "phone",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "state",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "zip",
|
||||||
|
"value": "",
|
||||||
|
"type": "TEXT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"date_subscribe": null,
|
||||||
|
"date_unsubscribe": null,
|
||||||
|
"date_created": "2016-04-04",
|
||||||
|
"date_updated": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"connections": {
|
||||||
|
"When clicking ‘Test workflow’": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "Create Subscriber",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Get Subscriber",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Update Subscriber",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Get Many Subscrbers",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Create Subscriber": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "No Operation, do nothing",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Get Subscriber": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "No Operation, do nothing1",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Update Subscriber": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "No Operation, do nothing2",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Get Many Subscrbers": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "No Operation, do nothing3",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": false,
|
||||||
|
"settings": {
|
||||||
|
"executionOrder": "v1"
|
||||||
|
},
|
||||||
|
"versionId": "826c1711-fcea-4564-809b-0258dbdd72f4",
|
||||||
|
"meta": {
|
||||||
|
"instanceId": "8c8c5237b8e37b006a7adce87f4369350c58e41f3ca9de16196d3197f69eabcd"
|
||||||
|
},
|
||||||
|
"id": "I0absgO5t7xV2f2V",
|
||||||
|
"tags": []
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
import nock from 'nock';
|
||||||
|
|
||||||
|
import { getWorkflowFilenames, testWorkflows } from '../../../../test/nodes/Helpers';
|
||||||
|
import {
|
||||||
|
getCreateResponseClassic,
|
||||||
|
getSubscriberResponseClassic,
|
||||||
|
getAllSubscribersResponseClassic,
|
||||||
|
getUpdateSubscriberResponseClassic,
|
||||||
|
} from '../apiResponses';
|
||||||
|
|
||||||
|
describe('MailerLite', () => {
|
||||||
|
describe('Run v1 workflow', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
nock.disableNetConnect();
|
||||||
|
|
||||||
|
const mock = nock('https://api.mailerlite.com/api/v2');
|
||||||
|
|
||||||
|
mock.post('/subscribers').reply(200, getCreateResponseClassic);
|
||||||
|
mock.get('/subscribers/demo@mailerlite.com').reply(200, getSubscriberResponseClassic);
|
||||||
|
mock.get('/subscribers').query({ limit: 1 }).reply(200, getAllSubscribersResponseClassic);
|
||||||
|
mock.put('/subscribers/demo@mailerlite.com').reply(200, getUpdateSubscriberResponseClassic);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
nock.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
const workflows = getWorkflowFilenames(__dirname);
|
||||||
|
testWorkflows(workflows);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,370 @@
|
||||||
|
{
|
||||||
|
"name": "[TEST] MailerLite v2 Node",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"id": "3c72284b-2b88-4d5f-81bc-b1970b14f2af",
|
||||||
|
"name": "When clicking ‘Test workflow’",
|
||||||
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [800, 240]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"email": "user@n8n.io",
|
||||||
|
"additionalFields": {
|
||||||
|
"status": "active"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "702c6598-cbe8-403e-962e-56621ec727a4",
|
||||||
|
"name": "Create Subscriber",
|
||||||
|
"type": "n8n-nodes-base.mailerLite",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [1000, 0],
|
||||||
|
"credentials": {
|
||||||
|
"mailerLiteApi": {
|
||||||
|
"id": "bm7VHS2C7lRgVOhb",
|
||||||
|
"name": "Mailer Lite account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"type": "n8n-nodes-base.noOp",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1220, 0],
|
||||||
|
"id": "540b98b5-b3bf-49a1-a406-acc6872f4b50",
|
||||||
|
"name": "No Operation, do nothing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"type": "n8n-nodes-base.noOp",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1220, 180],
|
||||||
|
"id": "17c0b8e7-a9d7-4a4f-882f-c3fb3f6bc289",
|
||||||
|
"name": "No Operation, do nothing1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"operation": "get",
|
||||||
|
"subscriberId": "user@n8n.io"
|
||||||
|
},
|
||||||
|
"type": "n8n-nodes-base.mailerLite",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [1000, 180],
|
||||||
|
"id": "5598f2b9-4d67-4ad7-a8e4-7b7bf723cd5a",
|
||||||
|
"name": "Get Subscriber",
|
||||||
|
"credentials": {
|
||||||
|
"mailerLiteApi": {
|
||||||
|
"id": "bm7VHS2C7lRgVOhb",
|
||||||
|
"name": "Mailer Lite account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"operation": "update",
|
||||||
|
"subscriberId": "user@n8n.io",
|
||||||
|
"additionalFields": {
|
||||||
|
"status": "junk",
|
||||||
|
"optin_ip": "8.8.8.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "n8n-nodes-base.mailerLite",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [1000, 380],
|
||||||
|
"id": "223e4507-c88e-4066-a122-ccaf9cea7b49",
|
||||||
|
"name": "Update Subscriber",
|
||||||
|
"credentials": {
|
||||||
|
"mailerLiteApi": {
|
||||||
|
"id": "bm7VHS2C7lRgVOhb",
|
||||||
|
"name": "Mailer Lite account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"type": "n8n-nodes-base.noOp",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1220, 380],
|
||||||
|
"id": "94d04b52-8809-4670-a8ca-135921139fc9",
|
||||||
|
"name": "No Operation, do nothing2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"operation": "getAll",
|
||||||
|
"limit": 2,
|
||||||
|
"filters": {
|
||||||
|
"status": "junk"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "n8n-nodes-base.mailerLite",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [960, 640],
|
||||||
|
"id": "30c6e797-ceda-4c84-8f34-b61200ffd9e9",
|
||||||
|
"name": "Get Many Subscrbers",
|
||||||
|
"credentials": {
|
||||||
|
"mailerLiteApi": {
|
||||||
|
"id": "bm7VHS2C7lRgVOhb",
|
||||||
|
"name": "Mailer Lite account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"type": "n8n-nodes-base.noOp",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1180, 640],
|
||||||
|
"id": "c8529a30-889b-4ac9-a509-73f5dd8eef4a",
|
||||||
|
"name": "No Operation, do nothing3"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pinData": {
|
||||||
|
"No Operation, do nothing": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": "139872142007207563",
|
||||||
|
"email": "user@n8n.io",
|
||||||
|
"status": "junk",
|
||||||
|
"source": "api",
|
||||||
|
"sent": 0,
|
||||||
|
"opens_count": 0,
|
||||||
|
"clicks_count": 0,
|
||||||
|
"open_rate": 0,
|
||||||
|
"click_rate": 0,
|
||||||
|
"ip_address": null,
|
||||||
|
"subscribed_at": "2024-12-05 09:54:29",
|
||||||
|
"unsubscribed_at": null,
|
||||||
|
"created_at": "2024-12-05 09:54:29",
|
||||||
|
"updated_at": "2024-12-05 10:20:32",
|
||||||
|
"fields": {
|
||||||
|
"name": null,
|
||||||
|
"last_name": null,
|
||||||
|
"company": null,
|
||||||
|
"country": null,
|
||||||
|
"city": null,
|
||||||
|
"phone": null,
|
||||||
|
"state": null,
|
||||||
|
"z_i_p": null
|
||||||
|
},
|
||||||
|
"groups": [],
|
||||||
|
"opted_in_at": null,
|
||||||
|
"optin_ip": "8.8.8.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"No Operation, do nothing1": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": "139872142007207563",
|
||||||
|
"email": "user@n8n.io",
|
||||||
|
"status": "junk",
|
||||||
|
"source": "api",
|
||||||
|
"sent": 0,
|
||||||
|
"opens_count": 0,
|
||||||
|
"clicks_count": 0,
|
||||||
|
"open_rate": 0,
|
||||||
|
"click_rate": 0,
|
||||||
|
"ip_address": null,
|
||||||
|
"subscribed_at": "2024-12-05 09:54:29",
|
||||||
|
"unsubscribed_at": null,
|
||||||
|
"created_at": "2024-12-05 09:54:29",
|
||||||
|
"updated_at": "2024-12-05 10:20:32",
|
||||||
|
"fields": {
|
||||||
|
"name": null,
|
||||||
|
"last_name": null,
|
||||||
|
"company": null,
|
||||||
|
"country": null,
|
||||||
|
"city": null,
|
||||||
|
"phone": null,
|
||||||
|
"state": null,
|
||||||
|
"z_i_p": null
|
||||||
|
},
|
||||||
|
"groups": [],
|
||||||
|
"opted_in_at": null,
|
||||||
|
"optin_ip": "8.8.8.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"No Operation, do nothing2": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"data": {
|
||||||
|
"id": "139872142007207563",
|
||||||
|
"email": "user@n8n.io",
|
||||||
|
"status": "junk",
|
||||||
|
"source": "api",
|
||||||
|
"sent": 0,
|
||||||
|
"opens_count": 0,
|
||||||
|
"clicks_count": 0,
|
||||||
|
"open_rate": 0,
|
||||||
|
"click_rate": 0,
|
||||||
|
"ip_address": null,
|
||||||
|
"subscribed_at": "2024-12-05 09:54:29",
|
||||||
|
"unsubscribed_at": null,
|
||||||
|
"created_at": "2024-12-05 09:54:29",
|
||||||
|
"updated_at": "2024-12-05 10:20:32",
|
||||||
|
"fields": {
|
||||||
|
"name": null,
|
||||||
|
"last_name": null,
|
||||||
|
"company": null,
|
||||||
|
"country": null,
|
||||||
|
"city": null,
|
||||||
|
"phone": null,
|
||||||
|
"state": null,
|
||||||
|
"z_i_p": null
|
||||||
|
},
|
||||||
|
"groups": [],
|
||||||
|
"opted_in_at": null,
|
||||||
|
"optin_ip": "8.8.8.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"No Operation, do nothing3": [
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": "139872142007207563",
|
||||||
|
"email": "user@n8n.io",
|
||||||
|
"status": "junk",
|
||||||
|
"source": "api",
|
||||||
|
"sent": 0,
|
||||||
|
"opens_count": 0,
|
||||||
|
"clicks_count": 0,
|
||||||
|
"open_rate": 0,
|
||||||
|
"click_rate": 0,
|
||||||
|
"ip_address": null,
|
||||||
|
"subscribed_at": "2024-12-05 09:54:29",
|
||||||
|
"unsubscribed_at": null,
|
||||||
|
"created_at": "2024-12-05 09:54:29",
|
||||||
|
"updated_at": "2024-12-05 10:20:32",
|
||||||
|
"fields": {
|
||||||
|
"name": null,
|
||||||
|
"last_name": null,
|
||||||
|
"company": null,
|
||||||
|
"country": null,
|
||||||
|
"city": null,
|
||||||
|
"phone": null,
|
||||||
|
"state": null,
|
||||||
|
"z_i_p": null
|
||||||
|
},
|
||||||
|
"opted_in_at": null,
|
||||||
|
"optin_ip": "8.8.8.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"json": {
|
||||||
|
"id": "139059851540038710",
|
||||||
|
"email": "nathan@n8n.io",
|
||||||
|
"status": "junk",
|
||||||
|
"source": "api",
|
||||||
|
"sent": 0,
|
||||||
|
"opens_count": 0,
|
||||||
|
"clicks_count": 0,
|
||||||
|
"open_rate": 0,
|
||||||
|
"click_rate": 0,
|
||||||
|
"ip_address": null,
|
||||||
|
"subscribed_at": null,
|
||||||
|
"unsubscribed_at": null,
|
||||||
|
"created_at": "2024-11-26 10:43:28",
|
||||||
|
"updated_at": "2024-11-27 10:09:34",
|
||||||
|
"fields": {
|
||||||
|
"name": "Nathan",
|
||||||
|
"last_name": "Workflow",
|
||||||
|
"company": null,
|
||||||
|
"country": null,
|
||||||
|
"city": null,
|
||||||
|
"phone": null,
|
||||||
|
"state": null,
|
||||||
|
"z_i_p": null
|
||||||
|
},
|
||||||
|
"opted_in_at": null,
|
||||||
|
"optin_ip": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"connections": {
|
||||||
|
"When clicking ‘Test workflow’": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "Create Subscriber",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Get Subscriber",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Update Subscriber",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "Get Many Subscrbers",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Create Subscriber": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "No Operation, do nothing",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Get Subscriber": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "No Operation, do nothing1",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Update Subscriber": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "No Operation, do nothing2",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Get Many Subscrbers": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "No Operation, do nothing3",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": false,
|
||||||
|
"settings": {
|
||||||
|
"executionOrder": "v1"
|
||||||
|
},
|
||||||
|
"versionId": "338331ef-1b38-47dc-9e2b-45340ea3fe3b",
|
||||||
|
"meta": {
|
||||||
|
"templateCredsSetupCompleted": true,
|
||||||
|
"instanceId": "8c8c5237b8e37b006a7adce87f4369350c58e41f3ca9de16196d3197f69eabcd"
|
||||||
|
},
|
||||||
|
"id": "0Ov6Vd62DUXrWWQH",
|
||||||
|
"tags": []
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import nock from 'nock';
|
||||||
|
|
||||||
|
import { getWorkflowFilenames, testWorkflows } from '../../../../test/nodes/Helpers';
|
||||||
|
import {
|
||||||
|
getCreateResponseV2,
|
||||||
|
getSubscriberResponseV2,
|
||||||
|
getAllSubscribersResponseV2,
|
||||||
|
getUpdateSubscriberResponseV2,
|
||||||
|
} from '../apiResponses';
|
||||||
|
|
||||||
|
describe('MailerLite', () => {
|
||||||
|
describe('Run v2 workflow', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
nock.disableNetConnect();
|
||||||
|
|
||||||
|
const mock = nock('https://connect.mailerlite.com/api');
|
||||||
|
|
||||||
|
mock.post('/subscribers').reply(200, getCreateResponseV2);
|
||||||
|
mock.get('/subscribers/user@n8n.io').reply(200, getSubscriberResponseV2);
|
||||||
|
mock
|
||||||
|
.get('/subscribers')
|
||||||
|
.query({ 'filter[status]': 'junk', limit: 2 })
|
||||||
|
.reply(200, getAllSubscribersResponseV2);
|
||||||
|
mock.put('/subscribers/user@n8n.io').reply(200, getUpdateSubscriberResponseV2);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
nock.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
const workflows = getWorkflowFilenames(__dirname);
|
||||||
|
testWorkflows(workflows);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,184 @@
|
||||||
|
import {
|
||||||
|
type IHookFunctions,
|
||||||
|
type IWebhookFunctions,
|
||||||
|
type IDataObject,
|
||||||
|
type INodeType,
|
||||||
|
type INodeTypeDescription,
|
||||||
|
type IWebhookResponseData,
|
||||||
|
type INodeTypeBaseDescription,
|
||||||
|
NodeConnectionType,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
import { mailerliteApiRequest } from '../GenericFunctions';
|
||||||
|
|
||||||
|
export class MailerLiteTriggerV1 implements INodeType {
|
||||||
|
description: INodeTypeDescription;
|
||||||
|
|
||||||
|
constructor(baseDescription: INodeTypeBaseDescription) {
|
||||||
|
this.description = {
|
||||||
|
...baseDescription,
|
||||||
|
displayName: 'MailerLite Trigger',
|
||||||
|
name: 'mailerLiteTrigger',
|
||||||
|
group: ['trigger'],
|
||||||
|
version: 1,
|
||||||
|
description: 'Starts the workflow when MailerLite events occur',
|
||||||
|
defaults: {
|
||||||
|
name: 'MailerLite Trigger',
|
||||||
|
},
|
||||||
|
inputs: [],
|
||||||
|
outputs: [NodeConnectionType.Main],
|
||||||
|
credentials: [
|
||||||
|
{
|
||||||
|
name: 'mailerLiteApi',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
webhooks: [
|
||||||
|
{
|
||||||
|
name: 'default',
|
||||||
|
httpMethod: 'POST',
|
||||||
|
responseMode: 'onReceived',
|
||||||
|
path: 'webhook',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
displayName: 'Event',
|
||||||
|
name: 'event',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Campaign Sent',
|
||||||
|
value: 'campaign.sent',
|
||||||
|
description: 'Fired when campaign is sent',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Added Through Webform',
|
||||||
|
value: 'subscriber.added_through_webform',
|
||||||
|
description: 'Fired when a subscriber is added though a form',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Added to Group',
|
||||||
|
value: 'subscriber.add_to_group',
|
||||||
|
description: 'Fired when a subscriber is added to a group',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Automation Completed',
|
||||||
|
value: 'subscriber.automation_complete',
|
||||||
|
description: 'Fired when subscriber finishes automation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Automation Triggered',
|
||||||
|
value: 'subscriber.automation_triggered',
|
||||||
|
description: 'Fired when subscriber starts automation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Bounced',
|
||||||
|
value: 'subscriber.bounced',
|
||||||
|
description: 'Fired when an email address bounces',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Complained',
|
||||||
|
value: 'subscriber.complaint',
|
||||||
|
description: 'Fired when subscriber marks a campaign as a spam',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Created',
|
||||||
|
value: 'subscriber.create',
|
||||||
|
description: 'Fired when a new subscriber is added to an account',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Removed From Group',
|
||||||
|
value: 'subscriber.remove_from_group',
|
||||||
|
description: 'Fired when a subscriber is removed from a group',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Unsubscribe',
|
||||||
|
value: 'subscriber.unsubscribe',
|
||||||
|
description: 'Fired when a subscriber becomes unsubscribed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Updated',
|
||||||
|
value: 'subscriber.update',
|
||||||
|
description: "Fired when any of the subscriber's custom fields are updated",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
required: true,
|
||||||
|
default: [],
|
||||||
|
description: 'The events to listen to',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
webhookMethods = {
|
||||||
|
default: {
|
||||||
|
async checkExists(this: IHookFunctions): Promise<boolean> {
|
||||||
|
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||||
|
const webhookData = this.getWorkflowStaticData('node');
|
||||||
|
const event = this.getNodeParameter('event') as string;
|
||||||
|
// Check all the webhooks which exist already if it is identical to the
|
||||||
|
// one that is supposed to get created.
|
||||||
|
const endpoint = '/webhooks';
|
||||||
|
const { webhooks } = await mailerliteApiRequest.call(this, 'GET', endpoint, {});
|
||||||
|
for (const webhook of webhooks) {
|
||||||
|
if (webhook.url === webhookUrl && webhook.event === event) {
|
||||||
|
// Set webhook-id to be sure that it can be deleted
|
||||||
|
webhookData.webhookId = webhook.id as string;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
async create(this: IHookFunctions): Promise<boolean> {
|
||||||
|
const webhookData = this.getWorkflowStaticData('node');
|
||||||
|
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||||
|
const event = this.getNodeParameter('event') as string;
|
||||||
|
|
||||||
|
const endpoint = '/webhooks';
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
url: webhookUrl,
|
||||||
|
event,
|
||||||
|
};
|
||||||
|
|
||||||
|
const responseData = await mailerliteApiRequest.call(this, 'POST', endpoint, body);
|
||||||
|
|
||||||
|
if (responseData.id === undefined) {
|
||||||
|
// Required data is missing so was not successful
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
webhookData.webhookId = responseData.id as string;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
async delete(this: IHookFunctions): Promise<boolean> {
|
||||||
|
const webhookData = this.getWorkflowStaticData('node');
|
||||||
|
if (webhookData.webhookId !== undefined) {
|
||||||
|
const endpoint = `/webhooks/${webhookData.webhookId}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await mailerliteApiRequest.call(this, 'DELETE', endpoint);
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from the static workflow data so that it is clear
|
||||||
|
// that no webhooks are registered anymore
|
||||||
|
delete webhookData.webhookId;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||||
|
const body = this.getBodyData();
|
||||||
|
|
||||||
|
const events = body.events as IDataObject[];
|
||||||
|
|
||||||
|
return {
|
||||||
|
workflowData: [this.helpers.returnJsonArray(events)],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
199
packages/nodes-base/nodes/MailerLite/v1/MailerLiteV1.node.ts
Normal file
199
packages/nodes-base/nodes/MailerLite/v1/MailerLiteV1.node.ts
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
import type {
|
||||||
|
IExecuteFunctions,
|
||||||
|
IDataObject,
|
||||||
|
INodeExecutionData,
|
||||||
|
INodeType,
|
||||||
|
INodeTypeDescription,
|
||||||
|
INodeTypeBaseDescription,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
import { NodeConnectionType } from 'n8n-workflow';
|
||||||
|
|
||||||
|
import { subscriberFields, subscriberOperations } from './SubscriberDescription';
|
||||||
|
import {
|
||||||
|
getCustomFields,
|
||||||
|
mailerliteApiRequest,
|
||||||
|
mailerliteApiRequestAllItems,
|
||||||
|
} from '../GenericFunctions';
|
||||||
|
|
||||||
|
export class MailerLiteV1 implements INodeType {
|
||||||
|
description: INodeTypeDescription;
|
||||||
|
|
||||||
|
constructor(baseDescription: INodeTypeBaseDescription) {
|
||||||
|
this.description = {
|
||||||
|
...baseDescription,
|
||||||
|
displayName: 'MailerLite',
|
||||||
|
name: 'mailerLite',
|
||||||
|
group: ['input'],
|
||||||
|
version: 1,
|
||||||
|
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||||
|
description: 'Consume Mailer Lite API',
|
||||||
|
defaults: {
|
||||||
|
name: 'MailerLite',
|
||||||
|
},
|
||||||
|
inputs: [NodeConnectionType.Main],
|
||||||
|
outputs: [NodeConnectionType.Main],
|
||||||
|
credentials: [
|
||||||
|
{
|
||||||
|
name: 'mailerLiteApi',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
displayName: 'Resource',
|
||||||
|
name: 'resource',
|
||||||
|
type: 'options',
|
||||||
|
noDataExpression: true,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Subscriber',
|
||||||
|
value: 'subscriber',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'subscriber',
|
||||||
|
},
|
||||||
|
...subscriberOperations,
|
||||||
|
...subscriberFields,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
methods = {
|
||||||
|
loadOptions: {
|
||||||
|
getCustomFields,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||||
|
const items = this.getInputData();
|
||||||
|
const returnData: INodeExecutionData[] = [];
|
||||||
|
const length = items.length;
|
||||||
|
const qs: IDataObject = {};
|
||||||
|
let responseData;
|
||||||
|
const resource = this.getNodeParameter('resource', 0);
|
||||||
|
const operation = this.getNodeParameter('operation', 0);
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
try {
|
||||||
|
if (resource === 'subscriber') {
|
||||||
|
//https://developers.mailerlite.com/reference#create-a-subscriber
|
||||||
|
if (operation === 'create') {
|
||||||
|
const email = this.getNodeParameter('email', i) as string;
|
||||||
|
|
||||||
|
const additionalFields = this.getNodeParameter('additionalFields', i);
|
||||||
|
|
||||||
|
const body: IDataObject = {
|
||||||
|
email,
|
||||||
|
fields: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(body, additionalFields);
|
||||||
|
|
||||||
|
if (additionalFields.customFieldsUi) {
|
||||||
|
const customFieldsValues = (additionalFields.customFieldsUi as IDataObject)
|
||||||
|
.customFieldsValues as IDataObject[];
|
||||||
|
|
||||||
|
if (customFieldsValues) {
|
||||||
|
const fields = {};
|
||||||
|
|
||||||
|
for (const customFieldValue of customFieldsValues) {
|
||||||
|
//@ts-ignore
|
||||||
|
fields[customFieldValue.fieldId] = customFieldValue.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.fields = fields;
|
||||||
|
delete body.customFieldsUi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData = await mailerliteApiRequest.call(this, 'POST', '/subscribers', body);
|
||||||
|
}
|
||||||
|
//https://developers.mailerlite.com/reference#single-subscriber
|
||||||
|
if (operation === 'get') {
|
||||||
|
const subscriberId = this.getNodeParameter('subscriberId', i) as string;
|
||||||
|
|
||||||
|
responseData = await mailerliteApiRequest.call(
|
||||||
|
this,
|
||||||
|
'GET',
|
||||||
|
`/subscribers/${subscriberId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//https://developers.mailerlite.com/reference#subscribers
|
||||||
|
if (operation === 'getAll') {
|
||||||
|
const returnAll = this.getNodeParameter('returnAll', i);
|
||||||
|
|
||||||
|
const filters = this.getNodeParameter('filters', i);
|
||||||
|
|
||||||
|
Object.assign(qs, filters);
|
||||||
|
|
||||||
|
if (returnAll) {
|
||||||
|
responseData = await mailerliteApiRequestAllItems.call(
|
||||||
|
this,
|
||||||
|
'GET',
|
||||||
|
'/subscribers',
|
||||||
|
{},
|
||||||
|
qs,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
qs.limit = this.getNodeParameter('limit', i);
|
||||||
|
|
||||||
|
responseData = await mailerliteApiRequest.call(this, 'GET', '/subscribers', {}, qs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//https://developers.mailerlite.com/reference#update-subscriber
|
||||||
|
if (operation === 'update') {
|
||||||
|
const subscriberId = this.getNodeParameter('subscriberId', i) as string;
|
||||||
|
|
||||||
|
const updateFields = this.getNodeParameter('updateFields', i);
|
||||||
|
|
||||||
|
const body: IDataObject = {};
|
||||||
|
|
||||||
|
Object.assign(body, updateFields);
|
||||||
|
|
||||||
|
if (updateFields.customFieldsUi) {
|
||||||
|
const customFieldsValues = (updateFields.customFieldsUi as IDataObject)
|
||||||
|
.customFieldsValues as IDataObject[];
|
||||||
|
|
||||||
|
if (customFieldsValues) {
|
||||||
|
const fields = {};
|
||||||
|
|
||||||
|
for (const customFieldValue of customFieldsValues) {
|
||||||
|
//@ts-ignore
|
||||||
|
fields[customFieldValue.fieldId] = customFieldValue.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.fields = fields;
|
||||||
|
delete body.customFieldsUi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData = await mailerliteApiRequest.call(
|
||||||
|
this,
|
||||||
|
'PUT',
|
||||||
|
`/subscribers/${subscriberId}`,
|
||||||
|
body,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
const executionErrorData = this.helpers.constructExecutionMetaData(
|
||||||
|
this.helpers.returnJsonArray({ error: error.message }),
|
||||||
|
{ itemData: { item: i } },
|
||||||
|
);
|
||||||
|
returnData.push(...executionErrorData);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const executionData = this.helpers.constructExecutionMetaData(
|
||||||
|
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||||
|
{ itemData: { item: i } },
|
||||||
|
);
|
||||||
|
|
||||||
|
returnData.push(...executionData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [returnData];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
export interface CustomField {
|
||||||
|
name: string;
|
||||||
|
key: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SubscriberFields {
|
||||||
|
city: string | null;
|
||||||
|
company: string | null;
|
||||||
|
country: string | null;
|
||||||
|
last_name: string | null;
|
||||||
|
name: string | null;
|
||||||
|
phone: string | null;
|
||||||
|
state: string | null;
|
||||||
|
z_i_p: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Subscriber {
|
||||||
|
id: string;
|
||||||
|
email: string;
|
||||||
|
status: string;
|
||||||
|
source: string;
|
||||||
|
sent: number;
|
||||||
|
opens_count: number;
|
||||||
|
clicks_count: number;
|
||||||
|
open_rate: number;
|
||||||
|
click_rate: number;
|
||||||
|
ip_address: string | null;
|
||||||
|
subscribed_at: string;
|
||||||
|
unsubscribed_at: string | null;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
fields: SubscriberFields;
|
||||||
|
opted_in_at: string | null;
|
||||||
|
optin_ip: string | null;
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
import {
|
||||||
|
type IHookFunctions,
|
||||||
|
type IWebhookFunctions,
|
||||||
|
type IDataObject,
|
||||||
|
type INodeType,
|
||||||
|
type INodeTypeDescription,
|
||||||
|
type IWebhookResponseData,
|
||||||
|
type INodeTypeBaseDescription,
|
||||||
|
NodeConnectionType,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
import { mailerliteApiRequest } from '../GenericFunctions';
|
||||||
|
|
||||||
|
export class MailerLiteTriggerV2 implements INodeType {
|
||||||
|
description: INodeTypeDescription;
|
||||||
|
|
||||||
|
constructor(baseDescription: INodeTypeBaseDescription) {
|
||||||
|
this.description = {
|
||||||
|
...baseDescription,
|
||||||
|
displayName: 'MailerLite Trigger',
|
||||||
|
name: 'mailerLiteTrigger',
|
||||||
|
group: ['trigger'],
|
||||||
|
version: [2],
|
||||||
|
description: 'Starts the workflow when MailerLite events occur',
|
||||||
|
defaults: {
|
||||||
|
name: 'MailerLite Trigger',
|
||||||
|
},
|
||||||
|
inputs: [],
|
||||||
|
outputs: [NodeConnectionType.Main],
|
||||||
|
credentials: [
|
||||||
|
{
|
||||||
|
name: 'mailerLiteApi',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
webhooks: [
|
||||||
|
{
|
||||||
|
name: 'default',
|
||||||
|
httpMethod: 'POST',
|
||||||
|
responseMode: 'onReceived',
|
||||||
|
path: 'webhook',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
displayName: 'Events',
|
||||||
|
name: 'events',
|
||||||
|
type: 'multiOptions',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Campaign Sent',
|
||||||
|
value: 'campaign.sent',
|
||||||
|
description: 'Fired when campaign is sent',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Added to Group',
|
||||||
|
value: 'subscriber.added_to_group',
|
||||||
|
description: 'Fired when a subscriber is added to a group',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Automation Completed',
|
||||||
|
value: 'subscriber.automation_completed',
|
||||||
|
description: 'Fired when subscriber finishes automation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Automation Triggered',
|
||||||
|
value: 'subscriber.automation_triggered',
|
||||||
|
description: 'Fired when subscriber starts automation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Bounced',
|
||||||
|
value: 'subscriber.bounced',
|
||||||
|
description: 'Fired when an email address bounces',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Created',
|
||||||
|
value: 'subscriber.created',
|
||||||
|
description: 'Fired when a new subscriber is added to an account',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Removed From Group',
|
||||||
|
value: 'subscriber.removed_from_group',
|
||||||
|
description: 'Fired when a subscriber is removed from a group',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Spam Reported',
|
||||||
|
value: 'subscriber.spam_reported',
|
||||||
|
description: 'Fired when subscriber marks a campaign as a spam',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Unsubscribe',
|
||||||
|
value: 'subscriber.unsubscribed',
|
||||||
|
description: 'Fired when a subscriber becomes unsubscribed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Subscriber Updated',
|
||||||
|
value: 'subscriber.updated',
|
||||||
|
description: "Fired when any of the subscriber's custom fields are updated",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
required: true,
|
||||||
|
default: [],
|
||||||
|
description: 'The events to listen to',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
webhookMethods = {
|
||||||
|
default: {
|
||||||
|
async checkExists(this: IHookFunctions): Promise<boolean> {
|
||||||
|
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||||
|
const webhookData = this.getWorkflowStaticData('node');
|
||||||
|
const events = this.getNodeParameter('events') as string[];
|
||||||
|
// Check all the webhooks which exist already if it is identical to the
|
||||||
|
// one that is supposed to get created.
|
||||||
|
const endpoint = '/webhooks';
|
||||||
|
const { data } = await mailerliteApiRequest.call(this, 'GET', endpoint, {});
|
||||||
|
for (const webhook of data) {
|
||||||
|
if (webhook.url === webhookUrl && webhook.events === events) {
|
||||||
|
// Set webhook-id to be sure that it can be deleted
|
||||||
|
webhookData.webhookId = webhook.id as string;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
async create(this: IHookFunctions): Promise<boolean> {
|
||||||
|
const webhookData = this.getWorkflowStaticData('node');
|
||||||
|
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||||
|
const events = this.getNodeParameter('events') as string[];
|
||||||
|
|
||||||
|
const endpoint = '/webhooks';
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
url: webhookUrl,
|
||||||
|
events,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data } = await mailerliteApiRequest.call(this, 'POST', endpoint, body);
|
||||||
|
|
||||||
|
if (data.id === undefined) {
|
||||||
|
// Required data is missing so was not successful
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
webhookData.webhookId = data.id as string;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
async delete(this: IHookFunctions): Promise<boolean> {
|
||||||
|
const webhookData = this.getWorkflowStaticData('node');
|
||||||
|
if (webhookData.webhookId !== undefined) {
|
||||||
|
const endpoint = `/webhooks/${webhookData.webhookId}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await mailerliteApiRequest.call(this, 'DELETE', endpoint);
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from the static workflow data so that it is clear
|
||||||
|
// that no webhooks are registered anymore
|
||||||
|
delete webhookData.webhookId;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||||
|
const body = this.getBodyData();
|
||||||
|
|
||||||
|
const data = body.fields as IDataObject[];
|
||||||
|
|
||||||
|
return {
|
||||||
|
workflowData: [this.helpers.returnJsonArray(data)],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
206
packages/nodes-base/nodes/MailerLite/v2/MailerLiteV2.node.ts
Normal file
206
packages/nodes-base/nodes/MailerLite/v2/MailerLiteV2.node.ts
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
import type {
|
||||||
|
IExecuteFunctions,
|
||||||
|
IDataObject,
|
||||||
|
INodeExecutionData,
|
||||||
|
INodeType,
|
||||||
|
INodeTypeDescription,
|
||||||
|
INodeTypeBaseDescription,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
import { NodeConnectionType } from 'n8n-workflow';
|
||||||
|
|
||||||
|
import type { Subscriber } from './MailerLite.Interface';
|
||||||
|
import { subscriberFields, subscriberOperations } from './SubscriberDescription';
|
||||||
|
import {
|
||||||
|
getCustomFields,
|
||||||
|
mailerliteApiRequest,
|
||||||
|
mailerliteApiRequestAllItems,
|
||||||
|
} from '../GenericFunctions';
|
||||||
|
|
||||||
|
export class MailerLiteV2 implements INodeType {
|
||||||
|
description: INodeTypeDescription;
|
||||||
|
|
||||||
|
constructor(baseDescription: INodeTypeBaseDescription) {
|
||||||
|
this.description = {
|
||||||
|
...baseDescription,
|
||||||
|
displayName: 'MailerLite',
|
||||||
|
name: 'mailerLite',
|
||||||
|
group: ['input'],
|
||||||
|
version: [2],
|
||||||
|
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||||
|
description: 'Consume Mailer Lite API',
|
||||||
|
defaults: {
|
||||||
|
name: 'MailerLite',
|
||||||
|
},
|
||||||
|
inputs: [NodeConnectionType.Main],
|
||||||
|
outputs: [NodeConnectionType.Main],
|
||||||
|
credentials: [
|
||||||
|
{
|
||||||
|
name: 'mailerLiteApi',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
displayName: 'Resource',
|
||||||
|
name: 'resource',
|
||||||
|
type: 'options',
|
||||||
|
noDataExpression: true,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Subscriber',
|
||||||
|
value: 'subscriber',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'subscriber',
|
||||||
|
},
|
||||||
|
...subscriberOperations,
|
||||||
|
...subscriberFields,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
methods = {
|
||||||
|
loadOptions: {
|
||||||
|
getCustomFields,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||||
|
const items = this.getInputData();
|
||||||
|
const returnData: INodeExecutionData[] = [];
|
||||||
|
const length = items.length;
|
||||||
|
const qs: IDataObject = {};
|
||||||
|
let responseData;
|
||||||
|
const resource = this.getNodeParameter('resource', 0);
|
||||||
|
const operation = this.getNodeParameter('operation', 0);
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
try {
|
||||||
|
if (resource === 'subscriber') {
|
||||||
|
//https://developers.mailerlite.com/reference#create-a-subscriber
|
||||||
|
if (operation === 'create') {
|
||||||
|
const email = this.getNodeParameter('email', i) as string;
|
||||||
|
|
||||||
|
const additionalFields = this.getNodeParameter('additionalFields', i);
|
||||||
|
|
||||||
|
const body: IDataObject = {
|
||||||
|
email,
|
||||||
|
fields: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(body, additionalFields);
|
||||||
|
|
||||||
|
if (additionalFields.customFieldsUi) {
|
||||||
|
const customFieldsValues = (additionalFields.customFieldsUi as IDataObject)
|
||||||
|
.customFieldsValues as IDataObject[];
|
||||||
|
|
||||||
|
if (customFieldsValues) {
|
||||||
|
const fields = {};
|
||||||
|
|
||||||
|
for (const customFieldValue of customFieldsValues) {
|
||||||
|
//@ts-ignore
|
||||||
|
fields[customFieldValue.fieldId] = customFieldValue.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.fields = fields;
|
||||||
|
delete body.customFieldsUi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData = await mailerliteApiRequest.call(this, 'POST', '/subscribers', body);
|
||||||
|
responseData = responseData.data;
|
||||||
|
}
|
||||||
|
//https://developers.mailerlite.com/reference#single-subscriber
|
||||||
|
if (operation === 'get') {
|
||||||
|
const subscriberId = this.getNodeParameter('subscriberId', i) as string;
|
||||||
|
|
||||||
|
responseData = await mailerliteApiRequest.call(
|
||||||
|
this,
|
||||||
|
'GET',
|
||||||
|
`/subscribers/${subscriberId}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
responseData = responseData.data as Subscriber[];
|
||||||
|
}
|
||||||
|
//https://developers.mailerlite.com/reference#subscribers
|
||||||
|
if (operation === 'getAll') {
|
||||||
|
const returnAll = this.getNodeParameter('returnAll', i);
|
||||||
|
|
||||||
|
const filters = this.getNodeParameter('filters', i);
|
||||||
|
|
||||||
|
if (filters.status) {
|
||||||
|
qs['filter[status]'] = filters.status as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnAll) {
|
||||||
|
responseData = await mailerliteApiRequestAllItems.call(
|
||||||
|
this,
|
||||||
|
'GET',
|
||||||
|
'/subscribers',
|
||||||
|
{},
|
||||||
|
qs,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
qs.limit = this.getNodeParameter('limit', i);
|
||||||
|
|
||||||
|
responseData = await mailerliteApiRequest.call(this, 'GET', '/subscribers', {}, qs);
|
||||||
|
responseData = responseData.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//https://developers.mailerlite.com/reference#update-subscriber
|
||||||
|
if (operation === 'update') {
|
||||||
|
const subscriberId = this.getNodeParameter('subscriberId', i) as string;
|
||||||
|
|
||||||
|
const additionalFields = this.getNodeParameter('additionalFields', i);
|
||||||
|
|
||||||
|
const body: IDataObject = {};
|
||||||
|
|
||||||
|
Object.assign(body, additionalFields);
|
||||||
|
|
||||||
|
if (additionalFields.customFieldsUi) {
|
||||||
|
const customFieldsValues = (additionalFields.customFieldsUi as IDataObject)
|
||||||
|
.customFieldsValues as IDataObject[];
|
||||||
|
|
||||||
|
if (customFieldsValues) {
|
||||||
|
const fields = {};
|
||||||
|
|
||||||
|
for (const customFieldValue of customFieldsValues) {
|
||||||
|
//@ts-ignore
|
||||||
|
fields[customFieldValue.fieldId] = customFieldValue.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.fields = fields;
|
||||||
|
delete body.customFieldsUi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData = await mailerliteApiRequest.call(
|
||||||
|
this,
|
||||||
|
'PUT',
|
||||||
|
`/subscribers/${subscriberId}`,
|
||||||
|
body,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
const executionErrorData = this.helpers.constructExecutionMetaData(
|
||||||
|
this.helpers.returnJsonArray({ error: error.message }),
|
||||||
|
{ itemData: { item: i } },
|
||||||
|
);
|
||||||
|
returnData.push(...executionErrorData);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const executionData = this.helpers.constructExecutionMetaData(
|
||||||
|
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||||
|
{ itemData: { item: i } },
|
||||||
|
);
|
||||||
|
|
||||||
|
returnData.push(...executionData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [returnData];
|
||||||
|
}
|
||||||
|
}
|
304
packages/nodes-base/nodes/MailerLite/v2/SubscriberDescription.ts
Normal file
304
packages/nodes-base/nodes/MailerLite/v2/SubscriberDescription.ts
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
import type { INodeProperties } from 'n8n-workflow';
|
||||||
|
|
||||||
|
export const subscriberOperations: INodeProperties[] = [
|
||||||
|
{
|
||||||
|
displayName: 'Operation',
|
||||||
|
name: 'operation',
|
||||||
|
type: 'options',
|
||||||
|
noDataExpression: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: ['subscriber'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Create',
|
||||||
|
value: 'create',
|
||||||
|
description: 'Create a new subscriber',
|
||||||
|
action: 'Create a subscriber',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Get',
|
||||||
|
value: 'get',
|
||||||
|
description: 'Get an subscriber',
|
||||||
|
action: 'Get a subscriber',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Get Many',
|
||||||
|
value: 'getAll',
|
||||||
|
description: 'Get many subscribers',
|
||||||
|
action: 'Get many subscribers',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Update',
|
||||||
|
value: 'update',
|
||||||
|
description: 'Update an subscriber',
|
||||||
|
action: 'Update a subscriber',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'create',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const subscriberFields: INodeProperties[] = [
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* subscriber:create */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
displayName: 'Email',
|
||||||
|
name: 'email',
|
||||||
|
type: 'string',
|
||||||
|
placeholder: 'name@email.com',
|
||||||
|
required: true,
|
||||||
|
default: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: ['subscriber'],
|
||||||
|
operation: ['create'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'Email of new subscriber',
|
||||||
|
},
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* subscriber:update */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
displayName: 'Subscriber Email',
|
||||||
|
name: 'subscriberId',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: ['subscriber'],
|
||||||
|
operation: ['update'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'Email of subscriber',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Additional Fields',
|
||||||
|
name: 'additionalFields',
|
||||||
|
type: 'collection',
|
||||||
|
placeholder: 'Add Field',
|
||||||
|
default: {},
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: ['subscriber'],
|
||||||
|
operation: ['update', 'create'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Custom Fields',
|
||||||
|
name: 'customFieldsUi',
|
||||||
|
placeholder: 'Add Custom Field',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: true,
|
||||||
|
},
|
||||||
|
description: 'Filter by custom fields',
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'customFieldsValues',
|
||||||
|
displayName: 'Custom Field',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'Field Name or ID',
|
||||||
|
name: 'fieldId',
|
||||||
|
type: 'options',
|
||||||
|
typeOptions: {
|
||||||
|
loadOptionsMethod: 'getCustomFields',
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description:
|
||||||
|
'The ID of the field to add custom field to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Value',
|
||||||
|
name: 'value',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'The value to set on custom field',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Status',
|
||||||
|
name: 'status',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Active',
|
||||||
|
value: 'active',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bounced',
|
||||||
|
value: 'bounced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Junk',
|
||||||
|
value: 'junk',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Unconfirmed',
|
||||||
|
value: 'unconfirmed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Unsubscribed',
|
||||||
|
value: 'unsubscribed',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Subscribed At',
|
||||||
|
name: 'subscribed_at',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'IP Address',
|
||||||
|
name: 'ip_address',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Opted In At',
|
||||||
|
name: 'opted_in_at',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Opt In IP',
|
||||||
|
name: 'optin_ip',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Unsubscribed At',
|
||||||
|
name: 'unsubscribed_at',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* subscriber:delete */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
displayName: 'Subscriber Email',
|
||||||
|
name: 'subscriberId',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: ['subscriber'],
|
||||||
|
operation: ['delete'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'Email of subscriber to delete',
|
||||||
|
},
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* subscriber:get */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
displayName: 'Subscriber Email',
|
||||||
|
name: 'subscriberId',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: ['subscriber'],
|
||||||
|
operation: ['get'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'Email of subscriber to get',
|
||||||
|
},
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* subscriber:getAll */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
displayName: 'Return All',
|
||||||
|
name: 'returnAll',
|
||||||
|
type: 'boolean',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: ['subscriber'],
|
||||||
|
operation: ['getAll'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: false,
|
||||||
|
description: 'Whether to return all results or only up to a given limit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Limit',
|
||||||
|
name: 'limit',
|
||||||
|
type: 'number',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: ['subscriber'],
|
||||||
|
operation: ['getAll'],
|
||||||
|
returnAll: [false],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typeOptions: {
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 100,
|
||||||
|
},
|
||||||
|
default: 50,
|
||||||
|
description: 'Max number of results to return',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Filters',
|
||||||
|
name: 'filters',
|
||||||
|
type: 'collection',
|
||||||
|
placeholder: 'Add Filter',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: ['getAll'],
|
||||||
|
resource: ['subscriber'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Status',
|
||||||
|
name: 'status',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Active',
|
||||||
|
value: 'active',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bounced',
|
||||||
|
value: 'bounced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Junk',
|
||||||
|
value: 'junk',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Unconfirmed',
|
||||||
|
value: 'unconfirmed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Unsubscribed',
|
||||||
|
value: 'unsubscribed',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
Loading…
Reference in a new issue