From d9f7d5b1af062a349b14818a9b5257b91042a4c1 Mon Sep 17 00:00:00 2001 From: Andris Reinman Date: Mon, 25 Apr 2016 16:19:55 +0300 Subject: [PATCH] Rewrite merge tags in links --- lib/models/subscriptions.js | 39 ++++++++++++++++ lib/tools.js | 6 ++- routes/archive.js | 46 ++++++------------- routes/links.js | 52 +++++++++++++++++++++- views/lists/subscription/import-failed.hbs | 4 ++ 5 files changed, 111 insertions(+), 36 deletions(-) diff --git a/lib/models/subscriptions.js b/lib/models/subscriptions.js index 9d33df52..cae7cd8b 100644 --- a/lib/models/subscriptions.js +++ b/lib/models/subscriptions.js @@ -373,6 +373,45 @@ module.exports.get = (listId, cid, callback) => { }); }; +module.exports.getWithMergeTags = (listId, cid, callback) => { + module.exports.get(listId, cid, (err, subscription) => { + if (err) { + return callback(err); + } + + if (!subscription) { + return callback(null, false); + } + + fields.list(listId, (err, fieldList) => { + if (err || !fieldList) { + return fieldList = []; + } + + subscription.mergeTags = { + EMAIL: subscription.email, + FIRST_NAME: subscription.firstName, + LAST_NAME: subscription.lastName, + FULL_NAME: [].concat(subscription.firstName || []).concat(subscription.lastName || []).join(' ') + }; + + fields.getRow(fieldList, subscription, true, true).forEach(field => { + if (field.mergeTag) { + subscription.mergeTags[field.mergeTag] = field.mergeValue || ''; + } + if (field.options) { + field.options.forEach(subField => { + if (subField.mergeTag) { + subscription.mergeTags[subField.mergeTag] = subField.mergeValue || ''; + } + }); + } + }); + return callback(null, subscription); + }); + }); +}; + module.exports.update = (listId, cid, updates, allowEmail, callback) => { updates = tools.convertKeys(updates); listId = Number(listId) || 0; diff --git a/lib/tools.js b/lib/tools.js index a67791b6..79cde0a1 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -147,7 +147,8 @@ function validateEmail(address, checkBlocked, callback) { }); } -function formatMessage(serviceUrl, campaign, list, subscription, message) { +function formatMessage(serviceUrl, campaign, list, subscription, message, filter) { + filter = typeof filter === 'function' ? filter : (str => str); let getValue = key => { switch ((key || '').toString().toUpperCase().trim()) { @@ -166,6 +167,7 @@ function formatMessage(serviceUrl, campaign, list, subscription, message) { return message.replace(/\[([a-z0-9_]+)(?:\/([^\]]+))?\]/ig, (match, identifier, fallback) => { identifier = identifier.toUpperCase(); - return (getValue(identifier) || fallback || '').trim() || match; + let value = (getValue(identifier) || fallback || '').trim(); + return value ? filter(value) : match; }); } diff --git a/routes/archive.js b/routes/archive.js index 170feb94..8e08e844 100644 --- a/routes/archive.js +++ b/routes/archive.js @@ -2,9 +2,9 @@ let settings = require('../lib/models/settings'); let campaigns = require('../lib/models/campaigns'); +let links = require('../lib/models/links'); let lists = require('../lib/models/lists'); let subscriptions = require('../lib/models/subscriptions'); -let fields = require('../lib/models/fields'); let tools = require('../lib/tools'); let express = require('express'); let router = new express.Router(); @@ -40,7 +40,7 @@ router.get('/:campaign/:list/:subscription', (req, res, next) => { return next(err); } - subscriptions.get(list.id, req.params.subscription, (err, subscription) => { + subscriptions.getWithMergeTags(list.id, req.params.subscription, (err, subscription) => { if (err) { req.flash('danger', err.message || err); return res.redirect('/'); @@ -52,46 +52,28 @@ router.get('/:campaign/:list/:subscription', (req, res, next) => { return next(err); } - fields.list(list.id, (err, fieldList) => { - if (err || !fieldList) { - return fieldList = []; + campaigns.getMail(campaign.id, list.id, subscription.id, (err, mail) => { + if (err) { + req.flash('danger', err.message || err); + return res.redirect('/'); } - subscription.mergeTags = { - EMAIL: subscription.email, - FIRST_NAME: subscription.firstName, - LAST_NAME: subscription.lastName, - FULL_NAME: [].concat(subscription.firstName || []).concat(subscription.lastName || []).join(' ') - }; + if (!mail) { + err = new Error('Not Found'); + err.status = 404; + return next(err); + } - fields.getRow(fieldList, subscription, true, true).forEach(field => { - if (field.mergeTag) { - subscription.mergeTags[field.mergeTag] = field.mergeValue || ''; - } - if (field.options) { - field.options.forEach(subField => { - if (subField.mergeTag) { - subscription.mergeTags[subField.mergeTag] = subField.mergeValue || ''; - } - }); - } - }); - - campaigns.getMail(campaign.id, list.id, subscription.id, (err, mail) => { + // rewrite links to count clicks + links.updateLinks(campaign, list, subscription, serviceUrl, campaign.html, (err, html) => { if (err) { req.flash('danger', err.message || err); return res.redirect('/'); } - if (!mail) { - err = new Error('Not Found'); - err.status = 404; - return next(err); - } - res.render('archive/view', { layout: 'archive/layout', - message: tools.formatMessage(serviceUrl, campaign, list, subscription, campaign.html), + message: tools.formatMessage(serviceUrl, campaign, list, subscription, html), campaign, list, subscription diff --git a/routes/links.js b/routes/links.js index 25b8d3e0..fdbe867a 100644 --- a/routes/links.js +++ b/routes/links.js @@ -1,6 +1,10 @@ 'use strict'; let links = require('../lib/models/links'); +let settings = require('../lib/models/settings'); +let lists = require('../lib/models/lists'); +let subscriptions = require('../lib/models/subscriptions'); +let tools = require('../lib/tools'); let log = require('npmlog'); let express = require('express'); @@ -26,7 +30,7 @@ router.get('/:campaign/:list/:subscription', (req, res) => { res.end(trackImg); }); -router.get('/:campaign/:list/:subscription/:link', (req, res) => { +router.get('/:campaign/:list/:subscription/:link', (req, res, next) => { links.resolve(req.params.campaign, req.params.link, (err, linkId, url) => { if (err) { req.flash('danger', err.message || err); @@ -40,7 +44,51 @@ router.get('/:campaign/:list/:subscription/:link', (req, res) => { log.verbose('Redirect', 'First click for %s:%s:%s (%s)', req.params.campaign, req.params.list, req.params.subscription, url); } }); - res.redirect(url); + + if (!/\[[^\]]+\]/.test(url)) { + // no special tags, just pass on the link + return res.redirect(url); + } + + // url might include variables, need to rewrite those just as we do with message content + lists.getByCid(req.params.list, (err, list) => { + if (err) { + req.flash('danger', err.message || err); + return res.redirect('/'); + } + + if (!list) { + err = new Error('Not Found'); + err.status = 404; + return next(err); + } + + settings.get('serviceUrl', (err, serviceUrl) => { + if (err) { + // ignore + } + serviceUrl = (serviceUrl || '').toString().trim(); + + subscriptions.getWithMergeTags(list.id, req.params.subscription, (err, subscription) => { + if (err) { + req.flash('danger', err.message || err); + return res.redirect('/'); + } + + if (!subscription) { + err = new Error('Not Found'); + err.status = 404; + return next(err); + } + + url = tools.formatMessage(serviceUrl, { + cid: req.params.campaign + }, list, subscription, url, str => encodeURIComponent(str)); + + res.redirect(url); + }); + }); + }); }); }); diff --git a/views/lists/subscription/import-failed.hbs b/views/lists/subscription/import-failed.hbs index 18609659..d1f3093a 100644 --- a/views/lists/subscription/import-failed.hbs +++ b/views/lists/subscription/import-failed.hbs @@ -9,6 +9,10 @@
+
+ Role-based addresses like postmaster@example.com are blocked when importing. Subscribers with role-based email addresses can join your list using the subsription form. +
+