|
|
@ -7,6 +7,7 @@ var Mustache = require('mustache'); |
|
|
|
var log = require('npmlog'); |
|
|
|
log.debug = log.verbose; |
|
|
|
var fs = require('fs'); |
|
|
|
var path = require('path'); |
|
|
|
var nodemailer = require('nodemailer'); |
|
|
|
|
|
|
|
var WalletUtils = require('bitcore-wallet-utils'); |
|
|
@ -49,10 +50,32 @@ function EmailService() {}; |
|
|
|
EmailService.prototype.start = function(opts, cb) { |
|
|
|
opts = opts || {}; |
|
|
|
|
|
|
|
function _readDirectories(basePath, cb) { |
|
|
|
fs.readdir(basePath, function(err, files) { |
|
|
|
if (err) return cb(err); |
|
|
|
async.filter(files, function(file, next) { |
|
|
|
fs.stat(path.join(basePath, file), function(err, stats) { |
|
|
|
return next(!err && stats.isDirectory()); |
|
|
|
}); |
|
|
|
}, function(dirs) { |
|
|
|
return cb(null, dirs); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
self.defaultLanguage = opts.defaultLanguage || 'en'; |
|
|
|
self.templatePath = path.normalize((opts.templatePath || (__dirname + '/templates')) + '/'); |
|
|
|
|
|
|
|
async.parallel([ |
|
|
|
|
|
|
|
function(done) { |
|
|
|
_readDirectories(self.templatePath, function(err, res) { |
|
|
|
self.availableLanguages = res; |
|
|
|
done(err); |
|
|
|
}); |
|
|
|
}, |
|
|
|
function(done) { |
|
|
|
if (opts.storage) { |
|
|
|
self.storage = opts.storage; |
|
|
@ -87,10 +110,13 @@ EmailService.prototype.start = function(opts, cb) { |
|
|
|
|
|
|
|
|
|
|
|
// TODO: cache for X minutes
|
|
|
|
EmailService.prototype._readTemplate = function(filename, cb) { |
|
|
|
fs.readFile(__dirname + '/templates/' + filename + '.plain', 'utf8', function(err, template) { |
|
|
|
EmailService.prototype._readTemplate = function(filename, language, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
var fullFilename = path.join(self.templatePath, language, filename + '.plain'); |
|
|
|
fs.readFile(fullFilename, 'utf8', function(err, template) { |
|
|
|
if (err) { |
|
|
|
log.error('Could not read template file ' + filename, err); |
|
|
|
log.error('Could not read template file ' + fullFilename, err); |
|
|
|
return cb(err); |
|
|
|
} |
|
|
|
var lines = template.split('\n'); |
|
|
@ -126,9 +152,18 @@ EmailService.prototype._getRecipientsList = function(notification, emailType, cb |
|
|
|
|
|
|
|
usedEmails[p.email] = true; |
|
|
|
if (notification.creatorId == p.copayerId && !emailType.notifyDoer) return; |
|
|
|
if (!_.contains(self.availableLanguages, p.language)) { |
|
|
|
if (p.language) { |
|
|
|
log.warn('Language for email "' + p.language + '" not available.'); |
|
|
|
} |
|
|
|
p.language = self.defaultLanguage; |
|
|
|
} |
|
|
|
|
|
|
|
return { |
|
|
|
copayerId: p.copayerId, |
|
|
|
emailAddress: p.email |
|
|
|
emailAddress: p.email, |
|
|
|
language: p.language, |
|
|
|
unit: p.unit || 'btc', |
|
|
|
}; |
|
|
|
})); |
|
|
|
|
|
|
@ -189,6 +224,36 @@ EmailService.prototype._send = function(email, cb) { |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
EmailService.prototype._readAndApplyTemplates = function(notification, emailType, recipientsList, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
async.waterfall([ |
|
|
|
|
|
|
|
function(next) { |
|
|
|
self._getDataForTemplate(notification, next); |
|
|
|
}, |
|
|
|
function(data, next) { |
|
|
|
var languages = _.uniq(_.pluck(recipientsList, 'language')); |
|
|
|
async.map(languages, function(lang, next) { |
|
|
|
async.waterfall([ |
|
|
|
|
|
|
|
function(next) { |
|
|
|
self._readTemplate(emailType.filename, lang, next); |
|
|
|
}, |
|
|
|
function(template, next) { |
|
|
|
self._applyTemplate(template, data, next); |
|
|
|
}, |
|
|
|
], function(err, res) { |
|
|
|
next(err, [lang, res]); |
|
|
|
}); |
|
|
|
}, function(err, res) { |
|
|
|
return next(err, _.zipObject(res)); |
|
|
|
}); |
|
|
|
}, |
|
|
|
], cb); |
|
|
|
}; |
|
|
|
|
|
|
|
EmailService.prototype.sendEmail = function(notification, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
@ -211,23 +276,11 @@ EmailService.prototype.sendEmail = function(notification, cb) { |
|
|
|
async.waterfall([ |
|
|
|
|
|
|
|
function(next) { |
|
|
|
async.parallel([ |
|
|
|
|
|
|
|
function(next) { |
|
|
|
self._readTemplate(emailType.filename, next); |
|
|
|
}, |
|
|
|
function(next) { |
|
|
|
self._getDataForTemplate(notification, next); |
|
|
|
}, |
|
|
|
], function(err, res) { |
|
|
|
next(err, res[0], res[1]); |
|
|
|
}); |
|
|
|
}, |
|
|
|
function(template, data, next) { |
|
|
|
self._applyTemplate(template, data, next); |
|
|
|
self._readAndApplyTemplates(notification, emailType, recipientsList, next); |
|
|
|
}, |
|
|
|
function(content, next) { |
|
|
|
function(contents, next) { |
|
|
|
async.map(recipientsList, function(recipient, next) { |
|
|
|
var content = contents[recipient.language]; |
|
|
|
var email = Model.Email.create({ |
|
|
|
walletId: notification.walletId, |
|
|
|
copayerId: recipient.copayerId, |
|
|
|