From 68cb8384f7dfdbcaf2932293ec5a2f1ec0a1554e Mon Sep 17 00:00:00 2001 From: Raphael Hittich Date: Wed, 1 Aug 2018 10:46:34 +0200 Subject: [PATCH 1/3] Add custom unsubscribe option in a campaign --- lib/models/campaigns.js | 2 +- lib/tools.js | 26 +++++++++++++++----------- routes/campaigns.js | 3 ++- routes/settings.js | 2 +- services/sender.js | 2 +- setup/sql/upgrade-00032.sql | 13 +++++++++++++ views/campaigns/create.hbs | 6 ++++++ views/campaigns/edit.hbs | 6 ++++++ views/settings.hbs | 7 +++++++ 9 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 setup/sql/upgrade-00032.sql diff --git a/lib/models/campaigns.js b/lib/models/campaigns.js index 8d7bc899..e9b178ea 100644 --- a/lib/models/campaigns.js +++ b/lib/models/campaigns.js @@ -16,7 +16,7 @@ let _ = require('../translate')._; let util = require('util'); let tableHelpers = require('../table-helpers'); -let allowedKeys = ['description', 'from', 'address', 'reply_to', 'subject', 'editor_name', 'editor_data', 'template', 'source_url', 'list', 'segment', 'html', 'text', 'click_tracking_disabled', 'open_tracking_disabled']; +let allowedKeys = ['description', 'from', 'address', 'reply_to', 'subject', 'editor_name', 'editor_data', 'template', 'source_url', 'list', 'segment', 'html', 'text', 'click_tracking_disabled', 'open_tracking_disabled', 'unsubscribe']; module.exports.list = (start, limit, callback) => { tableHelpers.list('campaigns', ['*'], 'scheduled', null, start, limit, callback); diff --git a/lib/tools.js b/lib/tools.js index ad62a45a..ea113acc 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -181,7 +181,7 @@ function validateEmail(address, checkBlocked, callback) { function getMessageLinks(serviceUrl, campaign, list, subscription) { return { - LINK_UNSUBSCRIBE: urllib.resolve(serviceUrl, '/subscription/' + list.cid + '/unsubscribe/' + subscription.cid + '?c=' + campaign.cid), + LINK_UNSUBSCRIBE: campaign.unsubscribe ? campaign.unsubscribe : urllib.resolve(serviceUrl, '/subscription/' + list.cid + '/unsubscribe/' + subscription.cid + '?c=' + campaign.cid), LINK_PREFERENCES: urllib.resolve(serviceUrl, '/subscription/' + list.cid + '/manage/' + subscription.cid), LINK_BROWSER: urllib.resolve(serviceUrl, '/archive/' + campaign.cid + '/' + list.cid + '/' + subscription.cid), CAMPAIGN_ID: campaign.cid, @@ -195,7 +195,7 @@ function formatMessage(serviceUrl, campaign, list, subscription, message, filter let links = getMessageLinks(serviceUrl, campaign, list, subscription); - let getValue = key => { + let getTagValue = key => { key = (key || '').toString().toUpperCase().trim(); if (links.hasOwnProperty(key)) { return links[key]; @@ -211,15 +211,19 @@ function formatMessage(serviceUrl, campaign, list, subscription, message, filter return false; }; - return message.replace(/\[([a-z0-9_]+)(?:\/([^\]]+))?\]/ig, (match, identifier, fallback) => { - identifier = identifier.toUpperCase(); - let value = getValue(identifier); - if (value === false) { - return match; - } - value = (value || fallback || '').trim(); - return filter(value); - }); + let tagReplace = message => { + return message.replace(/\[([a-z0-9_]+)(?:\/([^\]]+))?\]/ig, (match, identifier, fallback) => { + identifier = identifier.toUpperCase(); + let value = getTagValue(identifier); + if (value === false) { + return match; + } + value = (value || fallback || '').trim(); + return filter(value); + }); + }; + + return tagReplace(tagReplace(message)); } function prepareHtml(html, callback) { diff --git a/routes/campaigns.js b/routes/campaigns.js index 9f721db0..d9c3cd49 100644 --- a/routes/campaigns.js +++ b/routes/campaigns.js @@ -46,7 +46,7 @@ router.get('/create', passport.csrfProtection, (req, res) => { data.list = Number(data.list.split(':').shift()); } - settings.list(['defaultFrom', 'defaultAddress', 'defaultSubject'], (err, configItems) => { + settings.list(['defaultFrom', 'defaultAddress', 'defaultSubject', 'defaultUnsubscribe'], (err, configItems) => { if (err) { req.flash('danger', err.message || err); return res.redirect('/'); @@ -93,6 +93,7 @@ router.get('/create', passport.csrfProtection, (req, res) => { data.address = data.address || configItems.defaultAddress; data.replyTo = data.replyTo || ''; data.subject = data.subject || configItems.defaultSubject; + data.unsubscribe = data.unsubscribe || configItems.defaultUnsubscribe; let view; switch (req.query.type) { diff --git a/routes/settings.js b/routes/settings.js index e3fdb6d6..819b498f 100644 --- a/routes/settings.js +++ b/routes/settings.js @@ -16,7 +16,7 @@ let _ = require('../lib/translate')._; let settings = require('../lib/models/settings'); -let allowedKeys = ['service_url', 'smtp_hostname', 'smtp_port', 'smtp_encryption', 'smtp_disable_auth', 'smtp_user', 'smtp_pass', 'admin_email', 'smtp_log', 'smtp_max_connections', 'smtp_max_messages', 'smtp_self_signed', 'default_from', 'default_address', 'default_subject', 'default_homepage', 'default_postaddress', 'default_sender', 'verp_hostname', 'verp_use', 'disable_wysiwyg', 'pgp_private_key', 'pgp_passphrase', 'ua_code', 'shoutout', 'disable_confirmations', 'smtp_throttling', 'dkim_api_key', 'dkim_private_key', 'dkim_selector', 'dkim_domain', 'mail_transport', 'ses_key', 'ses_secret', 'ses_region', 'x_mailer']; +let allowedKeys = ['service_url', 'smtp_hostname', 'smtp_port', 'smtp_encryption', 'smtp_disable_auth', 'smtp_user', 'smtp_pass', 'admin_email', 'smtp_log', 'smtp_max_connections', 'smtp_max_messages', 'smtp_self_signed', 'default_from', 'default_address', 'default_subject', 'default_homepage', 'default_postaddress', 'default_sender', 'verp_hostname', 'verp_use', 'disable_wysiwyg', 'pgp_private_key', 'pgp_passphrase', 'ua_code', 'shoutout', 'disable_confirmations', 'smtp_throttling', 'dkim_api_key', 'dkim_private_key', 'dkim_selector', 'dkim_domain', 'mail_transport', 'ses_key', 'ses_secret', 'ses_region', 'x_mailer', 'default_unsubscribe']; router.all('/*', (req, res, next) => { if (!req.user) { diff --git a/services/sender.js b/services/sender.js index 3c2293ff..3a7709a2 100644 --- a/services/sender.js +++ b/services/sender.js @@ -381,7 +381,7 @@ function formatMessage(message, callback) { let listUnsubscribe = null; if (!list.listunsubscribeDisabled) { - listUnsubscribe = url.resolve(configItems.serviceUrl, '/subscription/' + list.cid + '/unsubscribe/' + message.subscription.cid); + listUnsubscribe = campaign.unsubscribe ? tools.formatMessage(configItems.serviceUrl, campaign, list, message.subscription, campaign.unsubscribe) : url.resolve(configItems.serviceUrl, '/subscription/' + list.cid + '/unsubscribe/' + message.subscription.cid); } return callback(null, { diff --git a/setup/sql/upgrade-00032.sql b/setup/sql/upgrade-00032.sql new file mode 100644 index 00000000..5e17c70c --- /dev/null +++ b/setup/sql/upgrade-00032.sql @@ -0,0 +1,13 @@ +# Header section +# Define incrementing schema version number +SET @schema_version = '32'; + +# Adds new column 'unsubscribe' to campaign table. +ALTER TABLE campaigns ADD COLUMN `unsubscribe` VARCHAR(255) NOT NULL DEFAULT '' AFTER `subject`; + +# Footer section. Updates schema version in settings +LOCK TABLES `settings` WRITE; +/*!40000 ALTER TABLE `settings` DISABLE KEYS */; +INSERT INTO `settings` (`key`, `value`) VALUES('db_schema_version', @schema_version) ON DUPLICATE KEY UPDATE `value`=@schema_version; +/*!40000 ALTER TABLE `settings` ENABLE KEYS */; +UNLOCK TABLES; diff --git a/views/campaigns/create.hbs b/views/campaigns/create.hbs index 24c74fc1..dda4d827 100644 --- a/views/campaigns/create.hbs +++ b/views/campaigns/create.hbs @@ -106,6 +106,12 @@ +
+ +
+ +
+
diff --git a/views/campaigns/edit.hbs b/views/campaigns/edit.hbs index faa0053c..759672f1 100644 --- a/views/campaigns/edit.hbs +++ b/views/campaigns/edit.hbs @@ -117,6 +117,12 @@
+
+ +
+ +
+
diff --git a/views/settings.hbs b/views/settings.hbs index ab232a4f..9314bc45 100644 --- a/views/settings.hbs +++ b/views/settings.hbs @@ -130,6 +130,13 @@  
+
+ +
+ + {{#translate}}Set a custom unsubscribe url.{{/translate}} +
+
From a26c75e26c3aeef5e4f87dc4f38488e4b966258d Mon Sep 17 00:00:00 2001 From: Raphael Hittich Date: Wed, 1 Aug 2018 11:09:16 +0200 Subject: [PATCH 2/3] Fix linter error --- lib/tools.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/tools.js b/lib/tools.js index ea113acc..1530e572 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -211,8 +211,8 @@ function formatMessage(serviceUrl, campaign, list, subscription, message, filter return false; }; - let tagReplace = message => { - return message.replace(/\[([a-z0-9_]+)(?:\/([^\]]+))?\]/ig, (match, identifier, fallback) => { + let tagReplace = message => + message.replace(/\[([a-z0-9_]+)(?:\/([^\]]+))?\]/ig, (match, identifier, fallback) => { identifier = identifier.toUpperCase(); let value = getTagValue(identifier); if (value === false) { @@ -221,7 +221,7 @@ function formatMessage(serviceUrl, campaign, list, subscription, message, filter value = (value || fallback || '').trim(); return filter(value); }); - }; + ; return tagReplace(tagReplace(message)); } From 0f20c5f6f7503b5208e047424ab70890fc4588ab Mon Sep 17 00:00:00 2001 From: Raphael Hittich Date: Wed, 1 Aug 2018 11:12:44 +0200 Subject: [PATCH 3/3] Fix another linter error --- lib/tools.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/tools.js b/lib/tools.js index 1530e572..b0d16822 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -221,7 +221,6 @@ function formatMessage(serviceUrl, campaign, list, subscription, message, filter value = (value || fallback || '').trim(); return filter(value); }); - ; return tagReplace(tagReplace(message)); }