Sending emails moved completely to controller. It felt strange to have some emails sent from the controller and some of them from the model. Confirmations refactored to an independent model that can be potentially used also for other actions that need an email confirmation.
268 lines
7.5 KiB
JavaScript
268 lines
7.5 KiB
JavaScript
'use strict';
|
|
|
|
let config = require('config');
|
|
let path = require('path');
|
|
let fs = require('fs');
|
|
let tools = require('./tools');
|
|
let settings = require('./models/settings');
|
|
let lists = require('./models/lists');
|
|
let fields = require('./models/fields');
|
|
let forms = require('./models/forms');
|
|
let _ = require('./translate')._;
|
|
let objectHash = require('object-hash');
|
|
let mjml = require('mjml');
|
|
let mjmlTemplates = new Map();
|
|
let hbs = require('hbs');
|
|
|
|
module.exports = {
|
|
getDefaultMergeTags,
|
|
getListMergeTags,
|
|
captureFlashMessages,
|
|
injectCustomFormData,
|
|
injectCustomFormTemplates,
|
|
filterCustomFields,
|
|
getMjmlTemplate,
|
|
rollbackAndReleaseConnection
|
|
};
|
|
|
|
function getDefaultMergeTags(callback) {
|
|
// Using a callback for the sake of future-proofness
|
|
callback(null, [{
|
|
key: 'LINK_UNSUBSCRIBE',
|
|
value: _('URL that points to the unsubscribe page')
|
|
}, {
|
|
key: 'LINK_PREFERENCES',
|
|
value: _('URL that points to the preferences page of the subscriber')
|
|
}, {
|
|
key: 'LINK_BROWSER',
|
|
value: _('URL to preview the message in a browser')
|
|
}, {
|
|
key: 'EMAIL',
|
|
value: _('Email address')
|
|
}, {
|
|
key: 'FIRST_NAME',
|
|
value: _('First name')
|
|
}, {
|
|
key: 'LAST_NAME',
|
|
value: _('Last name')
|
|
}, {
|
|
key: 'FULL_NAME',
|
|
value: _('Full name (first and last name combined)')
|
|
}, {
|
|
key: 'SUBSCRIPTION_ID',
|
|
value: _('Unique ID that identifies the recipient')
|
|
}, {
|
|
key: 'LIST_ID',
|
|
value: _('Unique ID that identifies the list used for this campaign')
|
|
}, {
|
|
key: 'CAMPAIGN_ID',
|
|
value: _('Unique ID that identifies current campaign')
|
|
}]);
|
|
}
|
|
|
|
function getListMergeTags(listId, callback) {
|
|
lists.get(listId, (err, list) => {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
if (!list) {
|
|
list = {
|
|
id: listId
|
|
};
|
|
}
|
|
|
|
fields.list(list.id, (err, fieldList) => {
|
|
if (err && !fieldList) {
|
|
fieldList = [];
|
|
}
|
|
|
|
let mergeTags = [];
|
|
|
|
fieldList.forEach(field => {
|
|
mergeTags.push({
|
|
key: field.key,
|
|
value: field.name
|
|
});
|
|
});
|
|
|
|
return callback(null, mergeTags);
|
|
});
|
|
});
|
|
}
|
|
|
|
function filterCustomFields(customFieldsIn = [], fieldIds = [], method = 'include') {
|
|
let customFields = customFieldsIn.slice();
|
|
fieldIds = typeof fieldIds === 'string' ? fieldIds.split(',') : fieldIds;
|
|
|
|
customFields.unshift({
|
|
id: 'email',
|
|
name: 'Email Address',
|
|
type: 'Email',
|
|
typeSubsciptionEmail: true
|
|
}, {
|
|
id: 'firstname',
|
|
name: 'First Name',
|
|
type: 'Text',
|
|
typeFirstName: true
|
|
}, {
|
|
id: 'lastname',
|
|
name: 'Last Name',
|
|
type: 'Text',
|
|
typeLastName: true
|
|
});
|
|
|
|
let filtered = [];
|
|
|
|
if (method === 'include') {
|
|
fieldIds.forEach(id => {
|
|
let field = customFields.find(f => f.id.toString() === id);
|
|
field && filtered.push(field);
|
|
});
|
|
} else {
|
|
customFields.forEach(field => {
|
|
!fieldIds.includes(field.id.toString()) && filtered.push(field);
|
|
});
|
|
}
|
|
|
|
return filtered;
|
|
}
|
|
|
|
function injectCustomFormData(customFormId, viewPath, data, callback) {
|
|
|
|
let injectDefaultData = data => {
|
|
data.customFields = filterCustomFields(data.customFields, [], 'exclude');
|
|
data.formInputStyle = '@import url(/subscription/form-input-style.css);';
|
|
return data;
|
|
};
|
|
|
|
if (Number(customFormId) < 1) {
|
|
return callback(null, injectDefaultData(data));
|
|
}
|
|
|
|
forms.get(customFormId, (err, form) => {
|
|
if (err) {
|
|
return callback(null, injectDefaultData(data));
|
|
}
|
|
|
|
let view = viewPath.split('/')[1];
|
|
|
|
if (view === 'web-subscribe') {
|
|
data.customFields = form.fieldsShownOnSubscribe
|
|
? filterCustomFields(data.customFields, form.fieldsShownOnSubscribe)
|
|
: filterCustomFields(data.customFields, [], 'exclude');
|
|
} else if (view === 'web-manage') {
|
|
data.customFields = form.fieldsShownOnManage
|
|
? filterCustomFields(data.customFields, form.fieldsShownOnManage)
|
|
: filterCustomFields(data.customFields, [], 'exclude');
|
|
}
|
|
|
|
let key = tools.fromDbKey(view);
|
|
data.template.template = form[key] || data.template.template;
|
|
data.template.layout = form.layout || data.template.layout;
|
|
data.formInputStyle = form.formInputStyle || '@import url(/subscription/form-input-style.css);';
|
|
|
|
settings.list(['ua_code'], (err, configItems) => {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
|
|
data.uaCode = configItems.uaCode;
|
|
data.customSubscriptionScripts = config.customsubscriptionscripts || [];
|
|
callback(null, data);
|
|
});
|
|
});
|
|
}
|
|
|
|
function injectCustomFormTemplates(customFormId, templates, callback) {
|
|
if (Number(customFormId) < 1) {
|
|
return callback(null, templates);
|
|
}
|
|
|
|
forms.get(customFormId, (err, form) => {
|
|
if (err) {
|
|
return callback(null, templates);
|
|
}
|
|
|
|
let lookUp = name => {
|
|
let key = tools.fromDbKey(
|
|
/subscription\/([^.]*)/.exec(name)[1]
|
|
);
|
|
return form[key] || name;
|
|
};
|
|
|
|
Object.keys(templates).forEach(key => {
|
|
let value = templates[key];
|
|
|
|
if (typeof value === 'string') {
|
|
templates[key] = lookUp(value);
|
|
}
|
|
if (typeof value === 'object' && value.template) {
|
|
templates[key].template = lookUp(value.template);
|
|
}
|
|
if (typeof value === 'object' && value.layout) {
|
|
templates[key].layout = lookUp(value.layout);
|
|
}
|
|
});
|
|
|
|
callback(null, templates);
|
|
});
|
|
}
|
|
|
|
function getMjmlTemplate(template, callback) {
|
|
if (!template) {
|
|
return callback(null, false);
|
|
}
|
|
|
|
let key = (typeof template === 'object') ? objectHash(template) : template;
|
|
|
|
if (mjmlTemplates.has(key)) {
|
|
return callback(null, mjmlTemplates.get(key));
|
|
}
|
|
|
|
let done = source => {
|
|
let compiled;
|
|
try {
|
|
compiled = mjml.mjml2html(source);
|
|
} catch (err) {
|
|
return callback(err);
|
|
}
|
|
if (compiled.errors.length) {
|
|
return callback(compiled.errors[0].message || compiled.errors[0]);
|
|
}
|
|
let renderer = hbs.handlebars.compile(compiled.html);
|
|
mjmlTemplates.set(key, renderer);
|
|
callback(null, renderer);
|
|
};
|
|
|
|
if (typeof template === 'object') {
|
|
tools.mergeTemplateIntoLayout(template.template, template.layout, (err, source) => {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
done(source);
|
|
});
|
|
} else {
|
|
fs.readFile(path.join(__dirname, '..', 'views', template), 'utf-8', (err, source) => {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
done(source);
|
|
});
|
|
}
|
|
}
|
|
|
|
function captureFlashMessages(req, res, callback) {
|
|
res.render('subscription/capture-flash-messages', { layout: null }, (err, flash) => {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
callback(null, flash);
|
|
});
|
|
}
|
|
|
|
function rollbackAndReleaseConnection(connection, callback) {
|
|
connection.rollback(() => {
|
|
connection.release();
|
|
return callback();
|
|
});
|
|
}
|