Browse Source

Merge pull request #240 from isocolsky/improve_rejection_email

Improve rejection email
activeAddress
Matias Alejo Garcia 10 years ago
parent
commit
6403692362
  1. 20
      lib/emailservice.js
  2. 5
      lib/server.js
  3. 4
      lib/templates/new_copayer.plain
  4. 4
      lib/templates/new_incoming_tx.plain
  5. 4
      lib/templates/new_outgoing_tx.plain
  6. 4
      lib/templates/new_tx_proposal.plain
  7. 4
      lib/templates/txp_finally_rejected.plain
  8. 4
      lib/templates/wallet_complete.plain
  9. 18
      package.json
  10. 54
      test/integration/server.js

20
lib/emailservice.js

@ -3,6 +3,7 @@
var _ = require('lodash'); var _ = require('lodash');
var $ = require('preconditions').singleton(); var $ = require('preconditions').singleton();
var async = require('async'); var async = require('async');
var Mustache = require('mustache');
var log = require('npmlog'); var log = require('npmlog');
log.debug = log.verbose; log.debug = log.verbose;
var fs = require('fs'); var fs = require('fs');
@ -98,8 +99,8 @@ EmailService.prototype._readTemplate = function(filename, cb) {
} }
var lines = template.split('\n'); var lines = template.split('\n');
return cb(null, { return cb(null, {
subject: _.template(lines[0]), subject: lines[0],
body: _.template(_.rest(lines).join('\n')), body: _.rest(lines).join('\n'),
}); });
}); });
}; };
@ -107,7 +108,7 @@ EmailService.prototype._readTemplate = function(filename, cb) {
EmailService.prototype._applyTemplate = function(template, data, cb) { EmailService.prototype._applyTemplate = function(template, data, cb) {
var result = _.mapValues(template, function(t) { var result = _.mapValues(template, function(t) {
try { try {
return t(data); return Mustache.render(t, data);
} catch (e) { } catch (e) {
log.error('Could not apply data to template', e); log.error('Could not apply data to template', e);
return cb(e); return cb(e);
@ -154,8 +155,17 @@ EmailService.prototype._getDataForTemplate = function(notification, cb) {
id: notification.creatorId id: notification.creatorId
}); });
if (copayer) { if (copayer) {
data.creatorId = copayer.id; data.copayerId = copayer.id;
data.creatorName = copayer.name; data.copayerName = copayer.name;
}
if (notification.type == 'TxProposalFinallyRejected' && data.rejectedBy) {
var rejectors = _.map(data.rejectedBy, function(copayerId) {
return _.find(wallet.copayers, {
id: copayerId
}).name
});
data.rejectorsNames = rejectors.join(', ');
} }
return cb(null, data); return cb(null, data);
}); });

5
lib/server.js

@ -1072,8 +1072,13 @@ WalletService.prototype.rejectTx = function(opts, cb) {
}, },
function(next) { function(next) {
if (txp.status == 'rejected') { if (txp.status == 'rejected') {
var rejectedBy = _.pluck(_.filter(txp.actions, {
type: 'reject'
}), 'copayerId');
self._notify('TxProposalFinallyRejected', { self._notify('TxProposalFinallyRejected', {
txProposalId: opts.txProposalId, txProposalId: opts.txProposalId,
rejectedBy: rejectedBy,
}, next); }, next);
} else { } else {
next(); next();

4
lib/templates/new_copayer.plain

@ -1,2 +1,2 @@
<%= subjectPrefix %>New copayer {{subjectPrefix}}New copayer
A new copayer just joined your wallet <%= walletName %>. A new copayer just joined your wallet {{walletName}}.

4
lib/templates/new_incoming_tx.plain

@ -1,2 +1,2 @@
<%= subjectPrefix %>New payment received {{subjectPrefix}}New payment received
A payment of <%= amount %> has been received into your wallet <%= walletName %>. A payment of {{amount}} has been received into your wallet {{walletName}}.

4
lib/templates/new_outgoing_tx.plain

@ -1,2 +1,2 @@
<%= subjectPrefix %>Payment sent {{subjectPrefix}}Payment sent
A Payment of <%= amount %> has been sent from your wallet <%= walletName %>. A Payment of {{amount}} has been sent from your wallet {{walletName}}.

4
lib/templates/new_tx_proposal.plain

@ -1,2 +1,2 @@
<%= subjectPrefix %>New payment proposal {{subjectPrefix}}New payment proposal
A new payment proposal has been created in your wallet <%= walletName %> by <%= creatorName %>. A new payment proposal has been created in your wallet {{walletName}} by {{copayerName}}.

4
lib/templates/txp_finally_rejected.plain

@ -1,2 +1,2 @@
<%= subjectPrefix %>Payment proposal rejected {{subjectPrefix}}Payment proposal rejected
A payment proposal in your wallet <%= walletName %> has been rejected by <%= creatorName %>. A payment proposal in your wallet {{walletName}} has been rejected by {{rejectorsNames}}.

4
lib/templates/wallet_complete.plain

@ -1,2 +1,2 @@
<%= subjectPrefix %>Wallet complete {{subjectPrefix}}Wallet complete
Your wallet <%= walletName %> is complete. Your wallet {{walletName}} is complete.

18
package.json

@ -34,6 +34,7 @@
"moment": "^2.10.3", "moment": "^2.10.3",
"mongodb": "^2.0.27", "mongodb": "^2.0.27",
"morgan": "*", "morgan": "*",
"mustache": "^2.1.0",
"nodemailer": "^1.3.4", "nodemailer": "^1.3.4",
"npmlog": "^0.1.1", "npmlog": "^0.1.1",
"preconditions": "^1.0.7", "preconditions": "^1.0.7",
@ -61,11 +62,14 @@
"test": "./node_modules/.bin/mocha", "test": "./node_modules/.bin/mocha",
"coveralls": "./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage" "coveralls": "./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
}, },
"contributors": [{ "contributors": [
"name": "Ivan Socolsky", {
"email": "ivan@bitpay.com" "name": "Ivan Socolsky",
}, { "email": "ivan@bitpay.com"
"name": "Matias Alejo Garcia", },
"email": "ematiu@gmail.com" {
}] "name": "Matias Alejo Garcia",
"email": "ematiu@gmail.com"
}
]
} }

54
test/integration/server.js

@ -274,7 +274,7 @@ describe('Wallet service', function() {
async.eachSeries(w.copayers, function(copayer, next) { async.eachSeries(w.copayers, function(copayer, next) {
helpers.getAuthServer(copayer.id, function(server) { helpers.getAuthServer(copayer.id, function(server) {
server.savePreferences({ server.savePreferences({
email: 'copayer' + (i++) + '@domain.com', email: 'copayer' + (++i) + '@domain.com',
}, next); }, next);
}); });
}, function(err) { }, function(err) {
@ -313,7 +313,7 @@ describe('Wallet service', function() {
var emails = _.map(calls, function(c) { var emails = _.map(calls, function(c) {
return c.args[0]; return c.args[0];
}); });
_.difference(['copayer1@domain.com', 'copayer2@domain.com'], _.pluck(emails, 'to')).should.be.empty; _.difference(['copayer2@domain.com', 'copayer3@domain.com'], _.pluck(emails, 'to')).should.be.empty;
var one = emails[0]; var one = emails[0];
one.from.should.equal('bws@dummy.net'); one.from.should.equal('bws@dummy.net');
one.subject.should.contain('New payment proposal'); one.subject.should.contain('New payment proposal');
@ -366,7 +366,7 @@ describe('Wallet service', function() {
var emails = _.map(_.takeRight(calls, 3), function(c) { var emails = _.map(_.takeRight(calls, 3), function(c) {
return c.args[0]; return c.args[0];
}); });
_.difference(['copayer0@domain.com', 'copayer1@domain.com', 'copayer2@domain.com'], _.pluck(emails, 'to')).should.be.empty; _.difference(['copayer1@domain.com', 'copayer2@domain.com', 'copayer3@domain.com'], _.pluck(emails, 'to')).should.be.empty;
var one = emails[0]; var one = emails[0];
one.from.should.equal('bws@dummy.net'); one.from.should.equal('bws@dummy.net');
one.subject.should.contain('Payment sent'); one.subject.should.contain('Payment sent');
@ -382,6 +382,52 @@ describe('Wallet service', function() {
}); });
}); });
it('should notify copayers a tx has been finally rejected', function(done) {
helpers.stubUtxos(server, wallet, 1, function() {
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.8, 'some message', TestData.copayers[0].privKey_1H_0);
var txpId;
async.waterfall([
function(next) {
server.createTx(txOpts, next);
},
function(txp, next) {
txpId = txp.id;
async.eachSeries(_.range(1, 3), function(i, next) {
var copayer = TestData.copayers[i];
helpers.getAuthServer(copayer.id, function(server) {
server.rejectTx({
txProposalId: txp.id,
}, next);
});
}, next);
},
], function(err) {
should.not.exist(err);
setTimeout(function() {
var calls = mailerStub.sendMail.getCalls();
var emails = _.map(_.takeRight(calls, 2), function(c) {
return c.args[0];
});
_.difference(['copayer1@domain.com', 'copayer2@domain.com'], _.pluck(emails, 'to')).should.be.empty;
var one = emails[0];
one.from.should.equal('bws@dummy.net');
one.subject.should.contain('Payment proposal rejected');
one.text.should.contain(wallet.name);
one.text.should.contain('copayer 2, copayer 3');
one.text.should.not.contain('copayer 1');
server.storage.fetchUnsentEmails(function(err, unsent) {
should.not.exist(err);
unsent.should.be.empty;
done();
});
}, 100);
});
});
});
it('should notify copayers of incoming txs', function(done) { it('should notify copayers of incoming txs', function(done) {
server.createAddress({}, function(err, address) { server.createAddress({}, function(err, address) {
should.not.exist(err); should.not.exist(err);
@ -398,7 +444,7 @@ describe('Wallet service', function() {
var emails = _.map(calls, function(c) { var emails = _.map(calls, function(c) {
return c.args[0]; return c.args[0];
}); });
_.difference(['copayer0@domain.com', 'copayer1@domain.com', 'copayer2@domain.com'], _.pluck(emails, 'to')).should.be.empty; _.difference(['copayer1@domain.com', 'copayer2@domain.com', 'copayer3@domain.com'], _.pluck(emails, 'to')).should.be.empty;
var one = emails[0]; var one = emails[0];
one.from.should.equal('bws@dummy.net'); one.from.should.equal('bws@dummy.net');
one.subject.should.contain('New payment received'); one.subject.should.contain('New payment received');

Loading…
Cancel
Save