From 9e3b42e11c6cfb3587d1d0baa632228370cbc816 Mon Sep 17 00:00:00 2001 From: Andris Reinman Date: Thu, 21 Apr 2016 20:17:19 +0300 Subject: [PATCH] Send welcome and unsubscribe confirmation emails --- config/default.toml | 2 - index.js | 16 +--- lib/models/subscriptions.js | 25 +++--- package.json | 2 +- routes/subscription.js | 87 +++++++++++++++++++- setup/mailtrain.conf | 2 +- setup/sql/sql.js | 2 +- views/emails/subscription-confirmed-html.hbs | 30 +++++++ views/emails/subscription-confirmed-text.hbs | 16 ++++ views/emails/unsubscribe-confirmed-html.hbs | 26 ++++++ views/emails/unsubscribe-confirmed-text.hbs | 12 +++ views/subscription/subscribed.hbs | 2 +- 12 files changed, 189 insertions(+), 33 deletions(-) create mode 100644 views/emails/subscription-confirmed-html.hbs create mode 100644 views/emails/subscription-confirmed-text.hbs create mode 100644 views/emails/unsubscribe-confirmed-html.hbs create mode 100644 views/emails/unsubscribe-confirmed-text.hbs diff --git a/config/default.toml b/config/default.toml index ba2828f5..3c6f8af8 100644 --- a/config/default.toml +++ b/config/default.toml @@ -34,8 +34,6 @@ database="mailtrain" charset="utf8mb4" # enter path for mysql command line application command="mysql" -# required database schema version -schema_version=1 [redis] # enable to use Redis session cache or disable if Redis is not installed diff --git a/index.js b/index.js index 65d07f93..ac13fec3 100644 --- a/index.js +++ b/index.js @@ -12,7 +12,6 @@ let sender = require('./services/sender'); let importer = require('./services/importer'); // eslint-disable-line global-require let verpServer = require('./services/verp-server'); // eslint-disable-line global-require let testServer = require('./services/test-server'); // eslint-disable-line global-require -let settings = require('./lib/models/settings'); let port = config.www.port; let host = config.www.host; @@ -34,20 +33,7 @@ let server = http.createServer(app); * Listen on provided port, on all network interfaces. */ -settings.list(['db_schema_version'], (err, configItems) => { - if (err) { - throw err; - } - let dbSchemaVersion = Number(configItems.dbSchemaVersion) || 0; - - if (dbSchemaVersion < config.mysql.schema_version) { - log.error('Database', 'Database schema outdated. Run `npm run sql` to upgrade'); - return process.exit(1); - } - - server.listen(port, host); - -}); +server.listen(port, host); server.on('error', err => { if (err.syscall !== 'listen') { diff --git a/lib/models/subscriptions.js b/lib/models/subscriptions.js index eef3d8a0..9bb6ef3c 100644 --- a/lib/models/subscriptions.js +++ b/lib/models/subscriptions.js @@ -182,6 +182,10 @@ module.exports.subscribe = (cid, optInIp, callback) => { subscription = {}; } + subscription.cid = cid; + subscription.list = listId; + subscription.email = email; + let optInCountry = geoip.lookupCountry(optInIp) || null; module.exports.insert(listId, { email, @@ -200,11 +204,7 @@ module.exports.subscribe = (cid, optInIp, callback) => { } connection.query('DELETE FROM confirmations WHERE `cid`=? LIMIT 1', [cid], () => { connection.release(); - callback(null, { - list: listId, - cid, - email - }); + callback(null, subscription); }); }); }); @@ -361,8 +361,8 @@ module.exports.get = (listId, cid, callback) => { return callback(null, false); } - let list = tools.convertKeys(rows[0]); - return callback(null, list); + let subscription = tools.convertKeys(rows[0]); + return callback(null, subscription); }); }); }; @@ -448,7 +448,7 @@ module.exports.unsubscribe = (listId, email, campaignId, callback) => { return callback(err); } - connection.query('SELECT id, status FROM `subscription__' + listId + '` WHERE `email`=?', [email], (err, rows) => { + connection.query('SELECT * FROM `subscription__' + listId + '` WHERE `email`=?', [email], (err, rows) => { connection.release(); if (err) { return callback(err); @@ -457,8 +457,13 @@ module.exports.unsubscribe = (listId, email, campaignId, callback) => { return callback(null, false); } - let id = rows[0].id; - module.exports.changeStatus(id, listId, campaignId, 2, callback); + let subscription = tools.convertKeys(rows[0]); + module.exports.changeStatus(subscription.id, listId, campaignId, 2, err => { + if (err) { + return callback(err); + } + return callback(null, subscription); + }); }); }); }; diff --git a/package.json b/package.json index db424d7b..a5252cfc 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "main": "index.js", "scripts": { "test": "grunt", - "start": "node index.js", + "start": "node setup/sql/sql.js && node index.js", "sql": "node setup/sql/sql.js", "sqldump": "node setup/sql/dump.js | sed -e '/^--.*$/d' > setup/sql/mailtrain.sql", "sqldrop": "node setup/sql/drop.js" diff --git a/routes/subscription.js b/routes/subscription.js index 22d1be9c..60f909f8 100644 --- a/routes/subscription.js +++ b/routes/subscription.js @@ -35,7 +35,7 @@ router.get('/subscribe/:cid', (req, res, next) => { return next(err); } - settings.list(['defaultHomepage', 'serviceUrl', 'pgpPrivateKey'], (err, configItems) => { + settings.list(['defaultHomepage', 'serviceUrl', 'pgpPrivateKey', 'defaultAddress', 'defaultFrom'], (err, configItems) => { if (err) { return next(err); } @@ -47,6 +47,45 @@ router.get('/subscribe/:cid', (req, res, next) => { preferences: '/subscription/' + list.cid + '/manage/' + subscription.cid, hasPubkey: !!configItems.pgpPrivateKey }); + + fields.list(list.id, (err, fieldList) => { + if (err) { + return log.error('Fields', err); + } + + let encryptionKeys = []; + fields.getRow(fieldList, subscription).forEach(field => { + if (field.type === 'gpg' && field.value) { + encryptionKeys.push(field.value.trim()); + } + }); + + mailer.sendMail({ + from: { + name: configItems.defaultFrom, + address: configItems.defaultAddress + }, + to: { + name: [].concat(subscription.firstName || []).concat(subscription.lastName || []).join(' '), + address: subscription.email + }, + subject: list.name + ': Subscription Confirmed', + encryptionKeys + }, { + html: 'emails/subscription-confirmed-html.hbs', + text: 'emails/subscription-confirmed-text.hbs', + data: { + title: list.name, + contactAddress: configItems.defaultAddress, + preferencesUrl: urllib.resolve(configItems.serviceUrl, '/subscription/' + list.cid + '/manage/' + subscription.cid), + unsubscribeUrl: urllib.resolve(configItems.serviceUrl, '/subscription/' + list.cid + '/unsubscribe/' + subscription.cid) + } + }, err => { + if (err) { + log.error('Subscription', err.stack); + } + }); + }); }); }); }); @@ -362,12 +401,56 @@ router.post('/:lcid/unsubscribe', passport.parseForm, passport.csrfProtection, ( let email = req.body.email; - subscriptions.unsubscribe(list.id, email, req.body.campaign, err => { + subscriptions.unsubscribe(list.id, email, req.body.campaign, (err, subscription) => { if (err) { req.flash('danger', err.message || err); return res.redirect('/subscription/' + encodeURIComponent(req.params.lcid) + '/unsubscribe/' + encodeURIComponent(req.body.cid) + '?' + tools.queryParams(req.body)); } res.redirect('/subscription/' + req.params.lcid + '/unsubscribe-notice'); + + fields.list(list.id, (err, fieldList) => { + if (err) { + return log.error('Fields', err); + } + + let encryptionKeys = []; + fields.getRow(fieldList, subscription).forEach(field => { + if (field.type === 'gpg' && field.value) { + encryptionKeys.push(field.value.trim()); + } + }); + + settings.list(['defaultHomepage', 'defaultFrom', 'defaultAddress', 'serviceUrl'], (err, configItems) => { + if (err) { + return next(err); + } + + mailer.sendMail({ + from: { + name: configItems.defaultFrom, + address: configItems.defaultAddress + }, + to: { + name: [].concat(subscription.firstName || []).concat(subscription.lastName || []).join(' '), + address: subscription.email + }, + subject: list.name + ': Subscription Confirmed', + encryptionKeys + }, { + html: 'emails/unsubscribe-confirmed-html.hbs', + text: 'emails/unsubscribe-confirmed-text.hbs', + data: { + title: list.name, + contactAddress: configItems.defaultAddress, + subscribeUrl: urllib.resolve(configItems.serviceUrl, '/subscription/' + list.cid + '?cid=' + subscription.cid) + } + }, err => { + if (err) { + log.error('Subscription', err.stack); + } + }); + }); + }); }); }); }); diff --git a/setup/mailtrain.conf b/setup/mailtrain.conf index 75826c26..0d00ff57 100644 --- a/setup/mailtrain.conf +++ b/setup/mailtrain.conf @@ -13,5 +13,5 @@ respawn limit 10 0 script cd /opt/mailtrain - exec node index.js >> /var/log/mailtrain.log 2>&1 + exec npm start >> /var/log/mailtrain.log 2>&1 end script diff --git a/setup/sql/sql.js b/setup/sql/sql.js index f570fec8..b04a2943 100644 --- a/setup/sql/sql.js +++ b/setup/sql/sql.js @@ -178,6 +178,6 @@ runUpdates(err => { log.error('sql', err); process.exit(1); } - log.info('sql', 'Database update completed'); + log.info('sql', 'Database check completed'); process.exit(0); }); diff --git a/views/emails/subscription-confirmed-html.hbs b/views/emails/subscription-confirmed-html.hbs new file mode 100644 index 00000000..e24f9166 --- /dev/null +++ b/views/emails/subscription-confirmed-html.hbs @@ -0,0 +1,30 @@ + + + + + + {{title}}: Subscription Confirmed + + + + +

{{title}}

+ +

Your subscription to our list has been confirmed.

+ +

+ If you want to modify your subscription then you can: +

+ +

+ manage your preferences + or + unsubscribe here +

+ +

For questions about this list, please contact: +
{{contactAddress}}

+ + + + diff --git a/views/emails/subscription-confirmed-text.hbs b/views/emails/subscription-confirmed-text.hbs new file mode 100644 index 00000000..07d4e614 --- /dev/null +++ b/views/emails/subscription-confirmed-text.hbs @@ -0,0 +1,16 @@ +{{{title}}} +Subscription Confirmed +====================== + +Your subscription to our list has been confirmed. + +If you want to modify your subscription then you can: + +manage your preferences: {{preferencesUrl}} + +- or - + +unsubscribe here: {{unsubscribeUrl}} + +For questions about this list, please contact: +{{{contactAddress}}} diff --git a/views/emails/unsubscribe-confirmed-html.hbs b/views/emails/unsubscribe-confirmed-html.hbs new file mode 100644 index 00000000..cba3118d --- /dev/null +++ b/views/emails/unsubscribe-confirmed-html.hbs @@ -0,0 +1,26 @@ + + + + + + {{title}}: You are now unsubscribed + + + + +

{{title}}

+ +

We have removed your email address from our list.

+ +

+ If you unsubscribed by mistake, you can re-subscribe at: +

+ +

+ +

For questions about this list, please contact: +
{{contactAddress}}

+ + + + diff --git a/views/emails/unsubscribe-confirmed-text.hbs b/views/emails/unsubscribe-confirmed-text.hbs new file mode 100644 index 00000000..5186f8e4 --- /dev/null +++ b/views/emails/unsubscribe-confirmed-text.hbs @@ -0,0 +1,12 @@ +{{{title}}} +You are now unsubscribed +======================== + +We have removed your email address from our list. + +If you unsubscribed by mistake, you can re-subscribe at: + +Subscribe: {{subscribeUrl}} + +For questions about this list, please contact: +{{{contactAddress}}} diff --git a/views/subscription/subscribed.hbs b/views/subscription/subscribed.hbs index 5fe2f79b..416427b0 100644 --- a/views/subscription/subscribed.hbs +++ b/views/subscription/subscribed.hbs @@ -10,6 +10,6 @@ or - manage you preferences + manage your preferences