diff --git a/lib/emailservice.js b/lib/emailservice.js index 93e8bc4..9d10c68 100644 --- a/lib/emailservice.js +++ b/lib/emailservice.js @@ -155,8 +155,17 @@ EmailService.prototype._getDataForTemplate = function(notification, cb) { id: notification.creatorId }); if (copayer) { - data.creatorId = copayer.id; - data.creatorName = copayer.name; + data.copayerId = copayer.id; + 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); }); diff --git a/lib/server.js b/lib/server.js index bfa38a2..a0a3a0d 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1072,8 +1072,13 @@ WalletService.prototype.rejectTx = function(opts, cb) { }, function(next) { if (txp.status == 'rejected') { + var rejectedBy = _.pluck(_.filter(txp.actions, { + type: 'reject' + }), 'copayerId'); + self._notify('TxProposalFinallyRejected', { txProposalId: opts.txProposalId, + rejectedBy: rejectedBy, }, next); } else { next(); diff --git a/lib/templates/new_tx_proposal.plain b/lib/templates/new_tx_proposal.plain index fee4cc8..56f2313 100644 --- a/lib/templates/new_tx_proposal.plain +++ b/lib/templates/new_tx_proposal.plain @@ -1,2 +1,2 @@ {{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}}. diff --git a/lib/templates/txp_finally_rejected.plain b/lib/templates/txp_finally_rejected.plain index 8c765e1..72db5e9 100644 --- a/lib/templates/txp_finally_rejected.plain +++ b/lib/templates/txp_finally_rejected.plain @@ -1,2 +1,2 @@ {{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}}. diff --git a/test/integration/server.js b/test/integration/server.js index d8924cc..7fb3695 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -274,7 +274,7 @@ describe('Wallet service', function() { async.eachSeries(w.copayers, function(copayer, next) { helpers.getAuthServer(copayer.id, function(server) { server.savePreferences({ - email: 'copayer' + (i++) + '@domain.com', + email: 'copayer' + (++i) + '@domain.com', }, next); }); }, function(err) { @@ -313,7 +313,7 @@ describe('Wallet service', function() { var emails = _.map(calls, function(c) { 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]; one.from.should.equal('bws@dummy.net'); one.subject.should.contain('New payment proposal'); @@ -366,7 +366,7 @@ describe('Wallet service', function() { var emails = _.map(_.takeRight(calls, 3), function(c) { 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]; one.from.should.equal('bws@dummy.net'); 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) { server.createAddress({}, function(err, address) { should.not.exist(err); @@ -398,7 +444,7 @@ describe('Wallet service', function() { var emails = _.map(calls, function(c) { 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]; one.from.should.equal('bws@dummy.net'); one.subject.should.contain('New payment received');