diff --git a/lib/emailservice.js b/lib/emailservice.js index 595a620..e5f8d43 100644 --- a/lib/emailservice.js +++ b/lib/emailservice.js @@ -15,6 +15,10 @@ var EMAIL_TYPES = { filename: 'new_copayer', notifyDoer: false, }, + 'WalletComplete': { + filename: 'wallet_complete', + notifyDoer: true, + }, 'NewTxProposal': { filename: 'new_tx_proposal', notifyDoer: false, diff --git a/lib/server.js b/lib/server.js index 3e191f4..b3d1878 100644 --- a/lib/server.js +++ b/lib/server.js @@ -423,11 +423,28 @@ WalletService.prototype.joinWallet = function(opts, cb) { self.storage.storeWalletAndUpdateCopayersLookup(wallet, function(err) { if (err) return cb(err); - self._notify('NewCopayer', { - walletId: opts.walletId, - copayerId: copayer.id, - copayerName: copayer.name, - }, function() { + + async.series([ + + function(next) { + self._notify('NewCopayer', { + walletId: opts.walletId, + copayerId: copayer.id, + copayerName: copayer.name, + }, next); + }, + function(next) { + if (wallet.isComplete() && wallet.isShared()) { + self._notify('WalletComplete', { + walletId: opts.walletId, + }, { + isGlobal: true + }, next); + } else { + next(); + } + }, + ], function() { return cb(null, { copayerId: copayer.id, wallet: wallet @@ -934,21 +951,21 @@ WalletService.prototype.signTx = function(opts, cb) { self.storage.storeTx(self.walletId, txp, function(err) { if (err) return cb(err); - async.parallel([ + async.series([ - function(done) { + function(next) { self._notify('TxProposalAcceptedBy', { txProposalId: opts.txProposalId, copayerId: self.copayerId, - }, done); + }, next); }, - function(done) { + function(next) { if (txp.isAccepted()) { self._notify('TxProposalFinallyAccepted', { txProposalId: opts.txProposalId, - }, done); + }, next); } else { - done(); + next(); } }, ], function() { @@ -1035,21 +1052,21 @@ WalletService.prototype.rejectTx = function(opts, cb) { self.storage.storeTx(self.walletId, txp, function(err) { if (err) return cb(err); - async.parallel([ + async.series([ - function(done) { + function(next) { self._notify('TxProposalRejectedBy', { txProposalId: opts.txProposalId, copayerId: self.copayerId, - }, done); + }, next); }, - function(done) { + function(next) { if (txp.status == 'rejected') { self._notify('TxProposalFinallyRejected', { txProposalId: opts.txProposalId, - }, done); + }, next); } else { - done(); + next(); } }, ], function() { diff --git a/lib/templates/wallet_complete.plain b/lib/templates/wallet_complete.plain new file mode 100644 index 0000000..ba52e3e --- /dev/null +++ b/lib/templates/wallet_complete.plain @@ -0,0 +1,2 @@ +<%= subjectPrefix %>Wallet complete +Your wallet <%= walletName %> is complete. diff --git a/package.json b/package.json index b5d4bd3..ca38461 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "locker-server": "^0.1.3", "lodash": "^3.3.1", "mocha-lcov-reporter": "0.0.1", + "moment": "^2.10.3", "mongodb": "^2.0.27", "morgan": "*", "nodemailer": "^1.3.4", diff --git a/test/integration/server.js b/test/integration/server.js index 4cf42a4..20d38df 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -478,7 +478,22 @@ describe('Wallet service', function() { var copayer = wallet.copayers[0]; copayer.name.should.equal('me'); copayer.id.should.equal(copayerId); - done(); + server.getNotifications({}, function(err, notifications) { + should.not.exist(err); + var notif = _.find(notifications, { + type: 'NewCopayer' + }); + should.exist(notif); + notif.data.walletId.should.equal(walletId); + notif.data.copayerId.should.equal(copayerId); + notif.data.copayerName.should.equal('me'); + + notif = _.find(notifications, { + type: 'WalletComplete' + }); + should.not.exist(notif); + done(); + }); }); }); }); @@ -548,7 +563,7 @@ describe('Wallet service', function() { }); }); - it('should fail two wallets with same xPubKey', function(done) { + it('should fail to join two wallets with same xPubKey', function(done) { var copayerOpts = helpers.getSignedCopayerOpts({ walletId: walletId, name: 'me', @@ -630,6 +645,27 @@ describe('Wallet service', function() { should.not.exist(err); wallet.status.should.equal('complete'); wallet.publicKeyRing.length.should.equal(3); + server.getNotifications({}, function(err, notifications) { + should.not.exist(err); + var notif = _.find(notifications, { + type: 'WalletComplete' + }); + should.exist(notif); + notif.data.walletId.should.equal(wallet.id); + done(); + }); + }); + }); + }); + + it('should not notify WalletComplete if 1-of-1', function(done) { + helpers.createAndJoinWallet(1, 1, function(server) { + server.getNotifications({}, function(err, notifications) { + should.not.exist(err); + var notif = _.find(notifications, { + type: 'WalletComplete' + }); + should.not.exist(notif); done(); }); });