diff --git a/lib/model/txnote.js b/lib/model/txnote.js index bdf5490..2d33345 100644 --- a/lib/model/txnote.js +++ b/lib/model/txnote.js @@ -15,8 +15,8 @@ TxNote.create = function(opts) { x.walletId = opts.walletId; x.txid = opts.txid; x.body = opts.body; - x.lastEditedOn = now; - x.lastEditedBy = opts.copayerId; + x.editedOn = now; + x.editedBy = opts.copayerId; return x; }; @@ -29,16 +29,16 @@ TxNote.fromObj = function(obj) { x.walletId = obj.walletId; x.txid = obj.txid; x.body = obj.body; - x.lastEditedOn = obj.lastEditedOn; - x.lastEditedBy = obj.lastEditedBy; + x.editedOn = obj.editedOn; + x.editedBy = obj.editedBy; return x; }; TxNote.prototype.edit = function(body, copayerId) { this.body = body; - this.lastEditedBy = copayerId; - this.lastEditedOn = Math.floor(Date.now() / 1000); + this.editedBy = copayerId; + this.editedOn = Math.floor(Date.now() / 1000); }; TxNote.prototype.toObject = function() { diff --git a/lib/server.js b/lib/server.js index 42cb388..29fcf94 100644 --- a/lib/server.js +++ b/lib/server.js @@ -2033,6 +2033,8 @@ WalletService.prototype.getTx = function(opts, cb) { if (err) return cb(err); if (!txp) return cb(Errors.TX_NOT_FOUND); + if (!txp.txid) return cb(null, txp); + self.storage.fetchTxNote(self.walletId, txp.txid, function(err, note) { if (err) { log.warn('Error fetching tx note for ' + txp.txid); @@ -2542,10 +2544,11 @@ WalletService.prototype.getTxHistory = function(opts, cb) { if (opts.limit > Defaults.HISTORY_LIMIT) return cb(Errors.HISTORY_LIMIT_EXCEEDED); - function decorate(txs, addresses, proposals) { + function decorate(txs, addresses, proposals, notes) { var indexedAddresses = _.indexBy(addresses, 'address'); var indexedProposals = _.indexBy(proposals, 'txid'); + var indexedNotes = _.indexBy(notes, 'txid'); function sum(items, isMine, isChange) { var filter = {}; @@ -2659,6 +2662,11 @@ WalletService.prototype.getTxHistory = function(opts, cb) { //newTx.paymentAckMemo = proposal.paymentAckMemo; } + var note = indexedNotes[tx.txid]; + if (note) { + newTx.note = _.pick(note, ['body', 'editedBy', 'editedByName', 'editedOn']); + } + return newTx; }); }; @@ -2675,10 +2683,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) { async.parallel([ function(next) { - self.storage.fetchTxs(self.walletId, {}, function(err, txps) { - if (err) return next(err); - next(null, txps); - }); + self.storage.fetchTxs(self.walletId, {}, next); }, function(next) { var from = opts.skip || 0; @@ -2688,13 +2693,17 @@ WalletService.prototype.getTxHistory = function(opts, cb) { next(null, self._normalizeTxHistory(txs)); }); }, + function(next) { + self.storage.fetchTxNotes(self.walletId, next); + }, ], function(err, res) { if (err) return cb(err); var proposals = res[0]; var txs = res[1]; + var notes = res[2]; - txs = decorate(txs, addresses, proposals); + txs = decorate(txs, addresses, proposals, notes); return cb(null, txs); }); diff --git a/lib/storage.js b/lib/storage.js index fd0bfa5..4dd1c53 100644 --- a/lib/storage.js +++ b/lib/storage.js @@ -630,6 +630,33 @@ Storage.prototype.fetchTxNote = function(walletId, txid, cb) { }); }; +// TODO: should be done client-side +Storage.prototype._completeTxNotesData = function(walletId, notes, cb) { + var notesList = [].concat(notes); + this.fetchWallet(walletId, function(err, wallet) { + if (err) return cb(err); + _.each(notesList, function(note) { + note.editedByName = wallet.getCopayer(note.editedBy).name; + }); + return cb(null, notes); + }); +}; + +Storage.prototype.fetchTxNotes = function(walletId, cb) { + var self = this; + + this.db.collection(collections.TX_NOTES).find({ + walletId: walletId, + }).toArray(function(err, result) { + if (err) return cb(err); + var notes = _.compact(_.map(result, function(note) { + if (!note.body) return; + return Model.TxNote.fromObj(note); + })); + return self._completeTxNotesData(walletId, notes, cb); + }); +}; + Storage.prototype.storeTxNote = function(txNote, cb) { this.db.collection(collections.TX_NOTES).update({ txid: txNote.txid, diff --git a/test/integration/server.js b/test/integration/server.js index 5ea093c..9d6ea64 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -3858,8 +3858,8 @@ describe('Wallet service', function() { note.txid.should.equal('123'); note.walletId.should.equal(wallet.id); note.body.should.equal('note body'); - note.lastEditedBy.should.equal(server.copayerId); - note.createdOn.should.equal(note.lastEditedOn); + note.editedBy.should.equal(server.copayerId); + note.createdOn.should.equal(note.editedOn); done(); }); }); @@ -3876,9 +3876,9 @@ describe('Wallet service', function() { }, function(err, note) { should.not.exist(err); should.exist(note); - note.lastEditedBy.should.equal(server.copayerId); - note.createdOn.should.equal(note.lastEditedOn); - var creator = note.lastEditedBy; + note.editedBy.should.equal(server.copayerId); + note.createdOn.should.equal(note.editedOn); + var creator = note.editedBy; helpers.getAuthServer(wallet.copayers[1].id, function(server) { clock.tick(60 * 1000); server.editTxNote({ @@ -3891,9 +3891,9 @@ describe('Wallet service', function() { }, function(err, note) { should.not.exist(err); should.exist(note); - note.lastEditedBy.should.equal(server.copayerId); - note.createdOn.should.be.below(note.lastEditedOn); - creator.should.not.equal(note.lastEditedBy); + note.editedBy.should.equal(server.copayerId); + note.createdOn.should.be.below(note.editedOn); + creator.should.not.equal(note.editedBy); clock.restore(); done(); }); @@ -3935,7 +3935,7 @@ describe('Wallet service', function() { txp.note.txid.should.equal(txp.txid); txp.note.walletId.should.equal(wallet.id); txp.note.body.should.equal('note body'); - txp.note.lastEditedBy.should.equal(server.copayerId); + txp.note.editedBy.should.equal(server.copayerId); done(); }); }); @@ -3954,8 +3954,8 @@ describe('Wallet service', function() { }, function(err, note) { should.not.exist(err); should.exist(note); - note.lastEditedBy.should.equal(server.copayerId); - var creator = note.lastEditedBy; + note.editedBy.should.equal(server.copayerId); + var creator = note.editedBy; helpers.getAuthServer(wallet.copayers[1].id, function(server) { server.getTxNote({ txid: '123', @@ -3963,7 +3963,7 @@ describe('Wallet service', function() { should.not.exist(err); should.exist(note); note.body.should.equal('note body'); - note.lastEditedBy.should.equal(creator); + note.editedBy.should.equal(creator); done(); }); }); @@ -3997,6 +3997,43 @@ describe('Wallet service', function() { }); }); }); + it('should include the note in tx history listing', function(done) { + helpers.createAddresses(server, wallet, 1, 1, function(mainAddresses, changeAddress) { + server._normalizeTxHistory = sinon.stub().returnsArg(0); + var txs = [{ + txid: '123', + confirmations: 1, + fees: 100, + time: 20, + inputs: [{ + address: 'external', + amount: 500, + }], + outputs: [{ + address: mainAddresses[0].address, + amount: 200, + }], + }]; + helpers.stubHistory(txs); + server.editTxNote({ + txid: '123', + body: 'just some note' + }, function(err) { + should.not.exist(err); + server.getTxHistory({}, function(err, txs) { + should.not.exist(err); + should.exist(txs); + txs.length.should.equal(1); + var tx = txs[0]; + should.exist(tx.note); + tx.note.body.should.equal('just some note'); + tx.note.editedBy.should.equal(server.copayerId); + should.exist(tx.note.editedOn); + done(); + }); + }); + }); + }); }); });