diff options
author | cel <cel@f/6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU=.ed25519> | 2017-06-06 23:25:30 -1000 |
---|---|---|
committer | cel <cel@f/6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU=.ed25519> | 2017-06-06 23:25:30 -1000 |
commit | a3dca9e424477c2745c59f482342a1580ed807f0 (patch) | |
tree | 14712ccb963a037ae9ceec1f6e9a8f4246d58592 /lib | |
parent | e9b1ee71a12fcd6c15a2f0b06671bc819da98303 (diff) | |
parent | 0e9903642e2e2c9cfb6f89f80a0256fa6f53ef5c (diff) | |
download | patchfoo-a3dca9e424477c2745c59f482342a1580ed807f0.tar.gz patchfoo-a3dca9e424477c2745c59f482342a1580ed807f0.zip |
Merge branch 'votes'
Diffstat (limited to 'lib')
-rw-r--r-- | lib/app.js | 60 | ||||
-rw-r--r-- | lib/render.js | 33 | ||||
-rw-r--r-- | lib/serve.js | 130 |
3 files changed, 195 insertions, 28 deletions
@@ -389,6 +389,66 @@ App.prototype.createContactStreams = function (id) { return new Contacts(this.sbot).createContactStreams(id) } +function compareVoted(a, b) { + return b.value - a.value +} + +App.prototype.getVoted = function (_opts, cb) { + if (isNaN(_opts.limit)) return pull.error(new Error('missing limit')) + var self = this + var opts = { + type: 'vote', + limit: _opts.limit * 100, + reverse: !!_opts.reverse, + gt: _opts.gt || undefined, + lt: _opts.lt || undefined, + } + + var votedObj = {} + var votedArray = [] + var numItems = 0 + var firstTimestamp, lastTimestamp + pull( + self.sbot.messagesByType(opts), + self.unboxMessages(), + pull.take(function () { + return numItems < _opts.limit + }), + pull.drain(function (msg) { + if (!firstTimestamp) firstTimestamp = msg.timestamp + lastTimestamp = msg.timestamp + var vote = msg.value.content.vote + if (!vote) return + var target = u.linkDest(vote) + var votes = votedObj[target] + if (!votes) { + numItems++ + votes = {id: target, value: 0, feedsObj: {}, feeds: []} + votedObj[target] = votes + votedArray.push(votes) + } + if (msg.value.author in votes.feedsObj) { + if (!opts.reverse) return // leave latest vote value as-is + // remove old vote value + votes.value -= votes.feedsObj[msg.value.author] + } else { + votes.feeds.push(msg.value.author) + } + var value = vote.value > 0 ? 1 : vote.value < 0 ? -1 : 0 + votes.feedsObj[msg.value.author] = value + votes.value += value + }, function (err) { + if (err) return cb(err) + var items = votedArray + if (opts.reverse) items.reverse() + items.sort(compareVoted) + cb(null, {items: items, + firstTimestamp: firstTimestamp, + lastTimestamp: lastTimestamp}) + }) + ) +} + App.prototype.createAboutStreams = function (id) { return this.about.createAboutStreams(id) } diff --git a/lib/render.js b/lib/render.js index 880470a..c1c7edf 100644 --- a/lib/render.js +++ b/lib/render.js @@ -313,3 +313,36 @@ Render.prototype.gitCommitBody = function (body) { ? h('div', {innerHTML: this.markdown('\n' + body)}) : h('pre', this.linkify('\n' + body)) } + +Render.prototype.getName = function (id, cb) { + // TODO: consolidate the get name/link functions + var self = this + switch (id && id[0]) { + case '%': + return self.app.getMsgDecrypted(id, function (err, msg) { + if (err && err.name == 'NotFoundError') + return cb(null, String(id).substring(0, 8) + '…(missing)') + if (err) return fallback() + new RenderMsg(self, self.app, msg, {wrap: false}).title(cb) + }) + case '@': // fallthrough + case '&': + return self.app.getAbout(id, function (err, about) { + if (err || !about || !about.name) return fallback() + cb(null, about.name) + }) + default: + return cb(null, String(id)) + } + function fallback() { + cb(null, String(id).substr(0, 8) + '…') + } +} + +Render.prototype.getNameLink = function (id, cb) { + var self = this + self.getName(id, function (err, name) { + if (err) return cb(err) + cb(null, h('a', {href: self.toUrl(id)}, name)) + }) +} diff --git a/lib/serve.js b/lib/serve.js index 1fe9b37..4f2ed42 100644 --- a/lib/serve.js +++ b/lib/serve.js @@ -284,6 +284,7 @@ Serve.prototype.path = function (url) { case '/live': return this.live(m[2]) case '/compose': return this.compose(m[2]) case '/emojis': return this.emojis(m[2]) + case '/votes': return this.votes(m[2]) } m = /^(\/?[^\/]*)(\/.*)?$/.exec(url) switch (m[1]) { @@ -526,6 +527,90 @@ Serve.prototype.compose = function (ext) { }) } +Serve.prototype.votes = function (path) { + if (path) return pull( + pull.once(u.renderError(new Error('Not implemented')).outerHTML), + this.wrapPage('#' + channel), + this.respondSink(404, {'Content-Type': ctype('html')}) + ) + + var self = this + var q = self.query + var opts = { + reverse: !q.forwards, + limit: Number(q.limit) || 50, + } + var gt = Number(q.gt) + if (gt) opts.gt = gt + var lt = Number(q.lt) + if (lt) opts.lt = lt + + self.app.getVoted(opts, function (err, voted) { + if (err) return pull( + pull.once(u.renderError(err).outerHTML), + self.wrapPage('#' + channel), + self.respondSink(500, {'Content-Type': ctype('html')}) + ) + + pull( + ph('table', [ + ph('thead', [ + ph('tr', [ + ph('td', {colspan: 2}, self.syncPager({ + first: voted.firstTimestamp, + last: voted.lastTimestamp, + })) + ]) + ]), + ph('tbody', pull( + pull.values(voted.items), + paramap(function (item, cb) { + cb(null, ph('tr', [ + ph('td', [String(item.value)]), + ph('td', [ + self.phIdLink(item.id), + pull.once(' dug by '), + self.renderIdsList()(pull.values(item.feeds)) + ]) + ])) + }, 8) + )), + ph('tfoot', {}, []), + ]), + self.wrapPage('votes'), + self.respondSink(200, { + 'Content-Type': ctype('html') + }) + ) + }) +} + +Serve.prototype.syncPager = function (opts) { + var q = this.query + var reverse = !q.forwards + var min = (reverse ? opts.last : opts.first) || Number(q.gt) + var max = (reverse ? opts.first : opts.last) || Number(q.lt) + var minDate = new Date(min) + var maxDate = new Date(max) + var qOlder = mergeOpts(q, {lt: min, gt: undefined, forwards: undefined}) + var qNewer = mergeOpts(q, {gt: max, lt: undefined, forwards: 1}) + var atNewest = reverse ? !q.lt : !max + var atOldest = reverse ? !min : !q.gt + if (atNewest && !reverse) qOlder.lt++ + if (atOldest && reverse) qNewer.gt-- + return h('div', + atOldest ? 'oldest' : [ + h('a', {href: '?' + qs.stringify(qOlder)}, '<<'), ' ', + h('span', {title: minDate.toString()}, htime(minDate)), ' ', + ], + ' - ', + atNewest ? 'now' : [ + h('span', {title: maxDate.toString()}, htime(maxDate)), ' ', + h('a', {href: '?' + qs.stringify(qNewer)}, '>>') + ] + ).outerHTML +} + Serve.prototype.peers = function (ext) { var self = this if (self.data.action === 'connect') { @@ -620,14 +705,6 @@ Serve.prototype.channels = function (ext) { ) } -Serve.prototype.phIdLink = function (id) { - return pull( - pull.once(id), - pull.asyncMap(this.renderIdLink.bind(this)), - pull.map(u.toHTML) - ) -} - Serve.prototype.contacts = function (path) { var self = this var id = String(path).substr(1) @@ -1159,6 +1236,7 @@ Serve.prototype.wrapPage = function (title, searchQ) { h('a', {href: render.toUrl('/advsearch')}, 'search'), ' ', h('a', {href: render.toUrl('/live')}, 'live'), ' ', h('a', {href: render.toUrl('/compose')}, 'compose'), ' ', + h('a', {href: render.toUrl('/votes')}, 'votes'), ' ', h('a', {href: render.toUrl('/emojis')}, 'emojis'), ' ', render.idLink(self.app.sbot.id, done()), ' ', h('input.search-input', {name: 'q', value: searchQ, @@ -1179,25 +1257,18 @@ Serve.prototype.wrapPage = function (title, searchQ) { ) } -Serve.prototype.renderIdLink = function (id, cb) { - var render = this.app.render - var el = render.idLink(id, function (err) { - if (err || !el) { - el = h('a', {href: render.toUrl(id)}, id) - } - cb(null, el) - }) +Serve.prototype.phIdLink = function (id) { + return pull( + pull.once(id), + this.renderIdsList() + ) } Serve.prototype.friends = function (path) { var self = this pull( self.app.sbot.friends.createFriendStream({hops: 1}), - self.renderFriends(), - pull.map(function (el) { - return [el, ' '] - }), - pull.map(u.toHTML), + self.renderIdsList(), u.hyperwrap(function (items, cb) { cb(null, [ h('section', @@ -1213,14 +1284,17 @@ Serve.prototype.friends = function (path) { ) } -Serve.prototype.renderFriends = function () { +Serve.prototype.renderIdsList = function () { var self = this - return paramap(function (id, cb) { - self.renderIdLink(id, function (err, el) { - if (err) el = u.renderError(err, ext) - cb(null, el) - }) - }, 8) + return pull( + paramap(function (id, cb) { + self.app.render.getNameLink(id, cb) + }, 8), + pull.map(function (el) { + return [el, ' '] + }), + pull.map(u.toHTML) + ) } var relationships = [ |