UNPKG

@jaybirdgroup/data-hub-connector-mailchimp

Version:

Connector to interact with MailChimp API in score of Data Hub.

769 lines (642 loc) 20 kB
'use strict'; const _merge = require('lodash/merge'); const Moment = require('moment'); const MailChimpAPI = require('mailchimp-api-v3'); /** * Class representing a basic Mail Chimp API calls wrapping */ class MailChimp { /** * Init class and apply defaults. * @param {Object} config - MailChimp configuration. */ constructor(config) { // default params this.defaults = { apikey: '', fromEmail: '', fromName: '', listId: '' }; // TODO: check for missing parameters this.config = _merge({}, this.defaults, config); this.instance = new MailChimpAPI(this.config.apikey); } /** * Method to be called after getting Subscriber Lists or error occurred. * * @callback getSubscriberListsCallback * @param {Error} [err] - JS Error object or null. * @param {Object} subscriberListsResponse - An object with lists response */ /** * Get information about all subscriber lists in the account. * @param {number} [page=1] - A page of record to return * @param {number} [limit=10] - A number of records to return. * @param {string[]} [fields] - An array of fields to return. Reference parameters of sub-objects with dot notation. * @param {getSubscriberListsCallback} next - The callback that handles the response. * @return {Promise} */ getSubscriberLists(page = 1, limit = 10, fields = ['lists.id','lists.name','total_items'], next = null) { const offset = (page - 1) * limit; const fieldsStr = fields ? fields.join(',') : ''; return new Promise((resolve, reject) => { this.instance.request({ method: 'get', path: `/lists?offset=${offset}&count=${limit}&fields=${fieldsStr}` }, (err, response) => { if (err) { if (next) { next(err); } return reject(err); } if (next) { next(err, response); } return resolve(response); }); }); } /** * Create a Mail Chimp list * @param {Object} instance - Mail Chimp wrapper * @param {Object} options - Additional parameters to configure API call * @param {nextCallback} next - Callback function. */ createList (options, next) { this.instance.request({ method: 'post', path: '/lists/', body: { name: options.presentationName, email_type_option: true, campaign_defaults: { from_name: this.config.fromName, from_email: this.config.fromEmail, subject: options.subject, language: 'en' }, permission_reminder: 'You have been invited to the presentation', contact: { company: options.company.companyName, address1: options.company.address1, city: options.company.city, state: options.company.state, zip: options.company.zip.toString(), country: options.company.country } } }, (err, response) => { next(err, response); }); } /** * Get a Mail Chimp list * @param {Object} instance - Mail Chimp wrapper * @param {String} listId - List id to get * @param {nextCallback} next - Callback function. */ checkSubscriberList (listId, next) { if (!listId) { return next(new Error('List id is not provided')); } this.instance.request({ method: 'get', path: '/lists/' + listId }, (err, response) => { next(err, response); }); } /** * Assign a batch of subscribers to the list * @param {Object} instance - Mail Chimp wrapper * @param {Object} options - Additional parameters to configure API call * @param {nextCallback} next - Callback function. */ batchSubscribe (options, next) { if (!options.listId) { return next(new Error('List id is not provided')); } if (!Array.isArray(options.subscribers) || options.subscribers.length === 0) { return next(new Error('Subscriber list is not provided')); } const members = []; const ln = options.subscribers.length; for (let i = 0; i < ln; ++i) { members.push({ email_address: options.subscribers[i].email, email_type: 'html', merge_fields: { 'FNAME': options.subscribers[i].firstName, 'LNAME': options.subscribers[i].lastName }, status: 'subscribed' }); } const formData = { members, update_existing: true }; this.instance.request({ method: 'post', path: '/lists/' + options.listId, body: formData }, (err, response) => { next(err, response); }); } /** * Create a Mail Chimp campaign * @param {Object} type - A type of created campaign * @param {Object} options - Additional parameters to configure API call * @param {nextCallback} next - Callback function. */ createCampaign (type, options, next) { return new Promise((resolve, reject) => { let error = null; if (!options) { error = new Error('Options argument not provided to createCampaign'); } if (!options.listId && !error) { error = new Error('List Id is not provided'); } if (!options.subject && !error) { error = new Error('Subject is not provided'); } if (!options.templateId && !error) { error = new Error('Template Id is not provided'); } if (error) { if (next) { next(error); } return reject(error); } this.instance.request({ method: 'post', path: '/campaigns', body: { type, recipients: { list_id: options.listId }, settings: { subject_line: options.subject, from_name: this.config.companyName, reply_to: options.replyTo, title: options.title, template_id: options.templateId }, tracking: { opens: true, html_clicks: true, text_clicks: true }, rss_opts: { feed_url: options.feedUrl, frequency: 'daily', schedule: { hour: options.schedule.hour, daily_send: options.schedule.weekDays } } } }, (err, response) => { if (err) { if (next) { next(err); } return reject(err); } if (next) { next(null, response); } resolve(response); }); }); } /** * Update a Mail Chimp campaign * @param {string} id - Id of the campaign * @param {Object} options - Additional parameters to configure API call * @param {nextCallback} next - Callback function. */ updateCampaign (id, options, next) { return new Promise((resolve, reject) => { let error = null; if (!options) { error = new Error('Options argument not provided to createCampaign'); } if (!options.listId && !error) { error = new Error('List Id is not provided'); } if (!options.subject && !error) { error = new Error('Subject is not provided'); } if (!options.templateId && !error) { error = new Error('Template Id is not provided'); } if (error) { if (next) { next(error); } return reject(error); } this.instance.request({ method: 'patch', path: `/campaigns/${id}`, body: { recipients: { list_id: options.listId }, settings: { subject_line: options.subject, from_name: this.config.companyName, reply_to: options.replyTo, title: options.title, template_id: options.templateId }, tracking: { opens: true, html_clicks: true, text_clicks: true }, rss_opts: { feed_url: options.feedUrl, frequency: 'daily', schedule: { hour: options.schedule.hour, daily_send: options.schedule.weekDays } } } }, (err, response) => { if (err) { if (next) { next(err); } return reject(err); } if (next) { next(null, response); } resolve(response); }); }); } /** * Pause rss campaign * @param {string} id - The id of the campaign * @param next * @return {Promise} */ pauseCampaign(id, next) { return new Promise((resolve, reject) => { if (!id) { const error = new Error('Campaign ID is not provided'); if(next) { next(error); } return reject(error); } this.instance.request({ method: 'post', path: `/campaigns/${id}/actions/pause` }, (err, response) => { if (err) { if (next) { next(err); } return reject(err); } if (next) { next(null, response); } resolve(response); }); }); } /** * Send an email dispatch to the subscribers, provided in a campaign lists * @param {String} id - Id of the campaign * @param {nextCallback} next - Callback function. */ sendCampaign(id, next) { return new Promise((resolve, reject) => { if (!id) { const error = new Error('Campaign ID is not provided'); if(next) { next(error); } return reject(error); } this.instance.request({ method: 'post', path: `/campaigns/${id}/actions/send` }, (err, response) => { if (err) { if (next) { next(err); } return reject(err); } if (next) { next(null, response); } resolve(response); }); }); } /** * Resume rss campaign * @param id * @param next * @return {Promise} */ resumeCampaign(id, next) { return new Promise((resolve, reject) => { if (!id) { const error = new Error('Campaign ID is not provided'); if(next) { next(error); } return reject(error); } this.instance.request({ method: 'post', path: `/campaigns/${id}/actions/resume` }, (err, response) => { if (err) { if (next) { next(err); } return reject(err); } if (next) { next(null, response); } resolve(response); }); }); } /** * Delete rss campaign * @param {string} id - The id of the campaign * @param next * @return {Promise} */ deleteCampaign(id, next) { return new Promise((resolve, reject) => { if (!id) { const error = new Error('Campaign ID is not provided'); if(next) { next(error); } return reject(error); } this.instance.request({ method: 'delete', path: `/campaigns/${id}` }, (err, response) => { if (err) { if (next) { next(err); } return reject(err); } if (next) { next(null, response); } resolve(response); }); }); } /** * Create a Mail Chimp template * @param {Object} instance - Mail Chimp wrapper * @param {Object} options - Additional parameters to configure API call * @param {nextCallback} next - Callback function. */ createTemplate (instance, options, next) { if (!options.name) { return next(new Error('Template Name is not provided')); } if (!options.html) { return next(new Error('Html is not provided')); } if (!options.folder_id) { return next(new Error('Folder Id is not provided')); } instance.request({ method: 'post', path: '/templates', body: { name: options.name, folder_id: options.folder_id, html: options.html } }, (err, response) => { next(err, response); }); } /** * Edit a Mail Chimp template * @param {Object} instance - Mail Chimp wrapper * @param {Object} options - Additional parameters to configure API call * @param {nextCallback} next - Callback function. */ editTemplate (instance, options, next) { if (!options.id) { return next(new Error('Template ID is not provided')); } if (!options.html) { return next(new Error('Html is not provided')); } if (!options.folder_id) { return next(new Error('Folder Id is not provided')); } instance.request({ method: 'patch', path: '/templates/' + options.id, body: { folder_id: options.folder_id, html: options.html } }, (err, response) => { next(err, response); }); } /** * Delete a Mail Chimp template * @param {Object} instance - Mail Chimp wrapper * @param {Object} options - Additional parameters to configure API call * @param {nextCallback} next - Callback function. */ deleteTemplate (instance, options, next) { if (!options.id) { return next(new Error('Template ID is not provided')); } instance.request({ method: 'delete', path: '/templates/' + options.id }, (err, response) => { next(err, response); }); } /** * Get a Mail Chimp campaign by id * @param {String} campaignId - Campaign id to get via Mail Chimp API * @param {nextCallback} next - Callback function. */ getCampaign (campaignId, next) { return new Promise((resolve, reject) => { if (!campaignId) { const err = new Error('Campaign Id is not provided'); if (next) { next(err); } return reject(err) } this.instance.request({ method: 'get', path: '/campaigns/' + campaignId }, (err, response) => { if (err) { if (next) { next(err); } return reject(err); } if (next) { next(null, response); } resolve(response); }); }); } /** * Get a Mail Chimp campaigns under the specific folder * @param {Object} instance - Mail Chimp wrapper * @param {String} folderId - Folder id * @param {nextCallback} next - Callback function. */ getCampaigns (folderId, next) { this.instance.request({ method: 'get', path: `/campaigns?folder_id=${folderId}&count=100` }, (err, response) => { next(err, response); }); } /** * Get all campaign folders * @param {nextCallback} next - Callback function. */ getCampaignFolders (next) { return new Promise((resolve, reject) => { this.instance.request({ method: 'get', path: '/campaign-folders' }, (err, response) => { if (err) { return typeof next === 'function' ? next(err) : reject(err); } return typeof next === 'function' ? next(null, response) : resolve(response); }); }); } /** * Get all folders used to organize templates * @param {nextCallback} next - Callback function. */ getTemplateFolders (next) { return new Promise((resolve, reject) => { this.instance.request({ method: 'get', path: '/template-folders' }, (err, response) => { if (err) { return typeof next === 'function' ? next(err) : reject(err); } return typeof next === 'function' ? next(null, response) : resolve(response); }); }); } /** * Add a custom merge tags * @param {Object} instance - Mail Chimp wrapper * @param {Object} options - Additional parameters to configure API call * @param {nextCallback} next - Callback function. */ addCustomMergeTags (options, next) { if (!options.listId) { return next(new Error('List Id is not provided')); } if (!(options.tags instanceof Array) || options.tags.length === 0) { return next(new Error('Merge tags are not provided')); } const calls = options.tags.reduce((prev, nextCalls) => { prev.push({ method: 'post', path: '/lists/' + options.listId + '/merge-fields', body: { name: nextCalls.tagName, type: 'text' } }); return prev; }, []); this.instance.batch(calls, (err, response) => { next(err, response); }, { wait: true, interval: 2000, unpack: true }); } /** * Add a custom merge tag * @param {Object} instance - Mail Chimp wrapper * @param {Object} options - Additional parameters to configure API call * @param {nextCallback} next - Callback function. */ addCustomMergeTag (options, next) { if (!options.listId) { return next(new Error('List Id is not provided')); } if (!options.tagName) { return next(new Error('Merge tag is not provided')); } this.instance.request({ method: 'post', path: '/lists/' + options.listId + '/merge-fields', body: { name: options.tagName, type: 'text' } }, (err, response) => { next(err, response); }); } getAccount(next) { return new Promise((resolve, reject) => { this.instance.request({ method: 'get', path: '/' }, (err, response) => { if (err) { if (next) { next(err); } return reject(err); } if (next) { next(null, response); } resolve(response); }); }); } } module.exports = MailChimp;