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 @@ + + + +
+ ++ If you want to modify your subscription then you can: +
+ ++ manage your preferences + or + unsubscribe here +
+ +For questions about this list, please contact:
+
{{contactAddress}}
+ If you unsubscribed by mistake, you can re-subscribe at: +
+ + + +For questions about this list, please contact:
+
{{contactAddress}}