From f4016d4ba6a5039c709e83fb0a4492b96e9d09bd Mon Sep 17 00:00:00 2001 From: cel Date: Sun, 18 Nov 2018 18:50:13 -1000 Subject: Link to contact messages from contact pages --- lib/app.js | 2 +- lib/contacts.js | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/render.js | 12 +++-- lib/serve.js | 2 +- 4 files changed, 170 insertions(+), 5 deletions(-) create mode 100644 lib/contacts.js (limited to 'lib') diff --git a/lib/app.js b/lib/app.js index d895fa7..b49b378 100644 --- a/lib/app.js +++ b/lib/app.js @@ -6,7 +6,7 @@ var u = require('./util') var pull = require('pull-stream') var multicb = require('multicb') var paramap = require('pull-paramap') -var Contacts = require('ssb-contact') +var Contacts = require('./contacts') var PrivateBox = require('private-box') var About = require('./about') var Follows = require('./follows') diff --git a/lib/contacts.js b/lib/contacts.js new file mode 100644 index 0000000..846cdf9 --- /dev/null +++ b/lib/contacts.js @@ -0,0 +1,159 @@ +var pull = require('pull-stream') +var defer = require('pull-defer') +var many = require('pull-many') + +module.exports = Contacts + +function Contacts(sbot) { + if (!(this instanceof Contacts)) return new Contacts(sbot) + this.sbot = sbot +} + +Contacts.prototype._createContactStream = function (source, dest) { + return pull( + this.sbot.links({ + source: source, + dest: dest, + rel: 'contact', + values: true, + reverse: true + }), + pull.filter(function (msg) { + var c = msg && msg.value && msg.value.content + return c && c.type === 'contact' && (!dest || c.contact === dest) + }), + pull.map(function (msg) { + var c = msg && msg.value && msg.value.content + return { + source: msg.value.author, + dest: c.contact, + msg: msg, + value: c.following ? true : c.flagged || c.blocking ? false : null + } + }), + pull.unique(function (edge) { + return edge.source + '-' + edge.dest + }) + ) +} + +Contacts.prototype.createFollowsStream = function (id) { + return pull( + this._createContactStream(id, null), + pull.filter('value'), + pull.map('dest') + ) +} + +Contacts.prototype.createFollowersStream = function (id) { + return pull( + this._createContactStream(null, id), + pull.filter('value'), + pull.map('source') + ) +} + +Contacts.prototype.createFollowedFollowersStream = function (source, dest) { + var follows = {}, followers = {} + return pull( + many([ + this._createContactStream(source, null), + this._createContactStream(null, dest) + ]), + pull.filter('value'), + pull.map(function (edge) { + if (edge.source === source) { + if (followers[edge.dest]) { + delete followers[edge.dest] + return edge.dest + } else { + follows[edge.dest] = true + } + } else if (edge.dest === dest) { + if (follows[edge.source]) { + delete follows[edge.source] + return edge.source + } else { + followers[edge.source] = true + } + } + }), + pull.filter() + ) +} + +Contacts.prototype.createFriendsStream = function (opts, endCb) { + if (typeof opts === 'string') opts = {id: opts} + var id = opts.id + var msgIds = opts.msgIds + var follows = {}, followers = {} + var blocks = {}, blockers = {} + return pull( + many([ + this._createContactStream(id, null), + this._createContactStream(null, id) + ]), + pull.map(function (edge) { + if (edge.value) { + if (edge.source === id) { + if (followers[edge.dest]) { + var item2 = followers[edge.dest] + delete followers[edge.dest] + return msgIds ? {feed: edge.dest, msg: edge.msg, msg2: item2.msg} : edge.dest + } else { + follows[edge.dest] = msgIds ? {feed: edge.dest, msg: edge.msg} : edge.dest + } + } else if (edge.dest === id) { + if (follows[edge.source]) { + var item2 = follows[edge.source] + delete follows[edge.source] + return msgIds ? {feed: edge.source, msg: edge.msg, msg2: item2.msg} : edge.source + } else { + followers[edge.source] = msgIds ? {feed: edge.source, msg: edge.msg} : edge.source + } + } + } else if (edge.value === false) { + if (edge.source === id) { + blocks[edge.dest] = msgIds ? {feed: edge.dest, msg: edge.msg} : edge.dest + } else if (edge.dest === id) { + blockers[edge.source] = msgIds ? {feed: edge.source, msg: edge.msg} : edge.source + } + } + }), + pull.filter(), + endCb && function (read) { + return function (abort, cb) { + read(abort, function (end, data) { + cb(end, data) + if (end) endCb(end === true ? null : end, { + followers: Object.values(followers), + follows: Object.values(follows), + blocks: Object.values(blocks), + blockers: Object.values(blockers), + }) + }) + } + } + ) +} + +Contacts.prototype.createContactStreams = function (opts) { + var msgIds = opts.msgIds + var follows = defer.source() + var followers = defer.source() + var blocks = defer.source() + var blockers = defer.source() + var friends = this.createFriendsStream(opts, function (err, more) { + follows.resolve(err ? pull.error(err) : pull.values(more.follows)) + followers.resolve(err ? pull.error(err) : pull.values(more.followers)) + blocks.resolve(err ? pull.error(err) : pull.values(more.blocks)) + blockers.resolve(err ? pull.error(err) : pull.values(more.blockers)) + }) + return { + friends: friends, + follows: follows, + followers: followers, + blocks: blocks, + blockers: blockers, + } +} diff --git a/lib/render.js b/lib/render.js index 862cfd9..deaf061 100644 --- a/lib/render.js +++ b/lib/render.js @@ -612,10 +612,16 @@ Render.prototype.friendsList = function (prefix) { prefix = prefix || '/' var self = this return pull( - paramap(function (id, cb) { - self.app.getAbout(id, function (err, about) { + paramap(function (item, cb) { + if (typeof item === 'string') item = {feed: item} + var id = item.feed + self.app.getAbout(item.feed, function (err, about) { var name = about && about.name || id.substr(0, 8) + '…' - cb(null, h('a', {href: self.toUrl(prefix + id)}, name)) + cb(null, [ + h('a', {href: self.toUrl(prefix + id)}, name), + item.msg ? h('a', {href: self.toUrl(item.msg.key)}, '₁') : '', + item.msg2 ? h('a', {href: self.toUrl(item.msg2.key)}, '₂') : '' + ]) }) }, 8), function (read) { diff --git a/lib/serve.js b/lib/serve.js index a58fb1a..0ca35a6 100644 --- a/lib/serve.js +++ b/lib/serve.js @@ -879,7 +879,7 @@ Serve.prototype.tags = function (path) { Serve.prototype.contacts = function (path) { var self = this var id = String(path).substr(1) - var contacts = self.app.contacts.createContactStreams(id) + var contacts = self.app.contacts.createContactStreams({id: id, msgIds: true}) var render = self.app.render pull( -- cgit v1.2.3