diff --git a/lib/emailservice.js b/lib/emailservice.js index ee4d623..f82c78c 100644 --- a/lib/emailservice.js +++ b/lib/emailservice.js @@ -109,22 +109,33 @@ EmailService.prototype.start = function(opts, cb) { }); }; +EmailService.prototype._compileTemplate = function(template) { + var lines = template.split('\n'); + return { + subject: lines[0], + body: _.rest(lines).join('\n'), + }; +}; -// TODO: cache for X minutes -EmailService.prototype._readTemplate = function(filename, language, cb) { +EmailService.prototype._readTemplateFile = function(language, filename, cb) { var self = this; - var fullFilename = path.join(self.templatePath, language, filename + '.plain'); + var fullFilename = path.join(self.templatePath, language, filename); fs.readFile(fullFilename, 'utf8', function(err, template) { if (err) { - log.error('Could not read template file ' + fullFilename, err); - return cb(err); + return cb(new Error('Could not read template file ' + fullFilename, err)); } - var lines = template.split('\n'); - return cb(null, { - subject: lines[0], - body: _.rest(lines).join('\n'), - }); + return cb(null, template); + }); +}; + +// TODO: cache for X minutes +EmailService.prototype._loadTemplate = function(emailType, recipient, extension, cb) { + var self = this; + + self._readTemplateFile(recipient.language, emailType.filename + extension, function(err, template) { + if (err) return cb(err); + return cb(null, self._compileTemplate(template)); }); }; @@ -213,8 +224,11 @@ EmailService.prototype._send = function(email, cb) { from: email.from, to: email.to, subject: email.subject, - text: email.body, + text: email.bodyPlain, }; + if (email.bodyHtml) { + mailOptions.html = email.bodyHtml; + } self.mailer.sendMail(mailOptions, function(err, result) { if (err) { log.error('An error occurred when trying to send email to ' + email.to, err); @@ -233,20 +247,23 @@ EmailService.prototype._readAndApplyTemplates = function(notification, emailType async.waterfall([ function(next) { - async.parallel([ - - function(next) { - self._readTemplate(emailType.filename, recipient.language, next); - }, - function(next) { - self._getDataForTemplate(notification, recipient, next); - }, - ], next); + self._getDataForTemplate(notification, recipient, next); + }, + function(data, next) { + async.map(['plain', 'html'], function(type, next) { + self._loadTemplate(emailType, recipient, '.' + type, function(err, template) { + if (err && type == 'html') return next(); + if (err) return next(err); + self._applyTemplate(template, data, function(err, res) { + return next(err, [type, res]); + }); + }); + }, function(err, res) { + return next(err, _.zipObject(res)); + }); }, function(result, next) { - var template = result[0]; - var data = result[1]; - self._applyTemplate(template, data, next); + next(null, result); }, ], function(err, res) { next(err, [recipient.language, res]); @@ -288,8 +305,9 @@ EmailService.prototype.sendEmail = function(notification, cb) { copayerId: recipient.copayerId, from: self.from, to: recipient.emailAddress, - subject: content.subject, - body: content.body, + subject: content.plain.subject, + bodyPlain: content.plain.body, + bodyHtml: content.html ? content.html.body : null, notificationId: notification.id, }); self.storage.storeEmail(email, function(err) { diff --git a/lib/model/email.js b/lib/model/email.js index f6ebca6..5b169b9 100644 --- a/lib/model/email.js +++ b/lib/model/email.js @@ -4,7 +4,7 @@ var _ = require('lodash'); var Uuid = require('uuid'); function Email() { - this.version = '1.0.0'; + this.version = '1.0.1'; }; Email.create = function(opts) { @@ -20,7 +20,8 @@ Email.create = function(opts) { x.from = opts.from; x.to = opts.to; x.subject = opts.subject; - x.body = opts.body; + x.bodyPlain = opts.bodyPlain; + x.bodyHtml = opts.bodyHtml; x.status = 'pending'; x.attempts = 0; x.lastAttemptOn = null; @@ -39,7 +40,12 @@ Email.fromObj = function(obj) { x.from = obj.from; x.to = obj.to; x.subject = obj.subject; - x.body = obj.body; + if (obj.version == '1.0.0') { + x.bodyPlain = obj.body; + } else { + x.bodyPlain = obj.bodyPlain; + } + x.bodyHtml = obj.bodyHtml; x.status = obj.status; x.attempts = obj.attempts; x.lastAttemptOn = obj.lastAttemptOn; diff --git a/test/integration/server.js b/test/integration/server.js index e3a22a4..8dbc84b 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -350,6 +350,14 @@ describe('Wallet service', function() { }); it('should notify copayers a new tx proposal has been created', function(done) { + var _readTemplateFile_old = emailService._readTemplateFile; + emailService._readTemplateFile = function(language, filename, cb) { + if (_.endsWith(filename, '.html')) { + return cb(null, 'Subject\n{{walletName}}'); + } else { + _readTemplateFile_old.call(emailService, language, filename, cb); + } + }; helpers.stubUtxos(server, wallet, [1, 1], function() { var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.8, 'some message', TestData.copayers[0].privKey_1H_0); server.createTx(txOpts, function(err, tx) { @@ -366,9 +374,13 @@ describe('Wallet service', function() { one.subject.should.contain('New payment proposal'); one.text.should.contain(wallet.name); one.text.should.contain(wallet.copayers[0].name); + should.exist(one.html); + one.html.should.contain(''); + one.html.should.contain(wallet.name); server.storage.fetchUnsentEmails(function(err, unsent) { should.not.exist(err); unsent.should.be.empty; + emailService._readTemplateFile = _readTemplateFile_old; done(); }); }, 100);