move ssb-patchwork-api and ssb-patchwork-ui into this repo

This commit is contained in:
Paul Frazee
2015-09-22 13:44:28 -05:00
parent ca4830cec8
commit 0f60126e9d
1094 changed files with 22959 additions and 8 deletions

389
api/test/indexes.js Normal file
View File

@@ -0,0 +1,389 @@
var multicb = require('multicb')
var tape = require('tape')
var ssbkeys = require('ssb-keys')
var pull = require('pull-stream')
var u = require('./util')
tape('inbox index includes encrypted messages from followeds', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob'] }, // Note, does not follow charlie
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
var done = multicb()
users.bob.add(ssbkeys.box({ type: 'post', text: 'hello from bob' }, [users.alice.keys, users.bob.keys]), done())
users.charlie.add(ssbkeys.box({ type: 'post', text: 'hello from charlie' }, [users.alice.keys, users.charlie.keys]), done())
done(function (err) {
if (err) throw err
pull(sbot.patchwork.createInboxStream(), pull.collect(function (err, msgs) {
if (err) throw err
t.equal(msgs.length, 1)
t.equal(msgs[0].value.author, users.bob.id)
t.end()
sbot.close()
}))
})
})
})
tape('inbox index includes replies to the users posts from followeds', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob'] }, // Note, does not follow charlie
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
users.alice.add({ type: 'post', text: 'hello from alice' }, function (err, msg) {
if (err) throw err
var done = multicb()
users.bob.add({ type: 'post', text: 'hello from bob', root: msg.key, branch: msg.key }, done())
users.charlie.add({ type: 'post', text: 'hello from charlie', root: msg.key, branch: msg.key }, done())
done(function (err) {
if (err) throw err
pull(sbot.patchwork.createInboxStream(), pull.collect(function (err, msgs) {
if (err) throw err
t.equal(msgs.length, 1)
t.equal(msgs[0].value.author, users.bob.id)
t.end()
sbot.close()
}))
})
})
})
})
tape('inbox index includes mentions of the user from followeds', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob'] }, // Note, does not follow charlie
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
var done = multicb()
users.bob.add({ type: 'post', text: 'hello from bob', mentions: [users.alice.id] }, done())
users.charlie.add({ type: 'post', text: 'hello from charlie', mentions: [users.alice.id] }, done())
done(function (err) {
if (err) throw err
pull(sbot.patchwork.createInboxStream(), pull.collect(function (err, msgs) {
if (err) throw err
t.equal(msgs.length, 1)
t.equal(msgs[0].value.author, users.bob.id)
t.end()
sbot.close()
}))
})
})
})
tape('inbox index counts correctly track read/unread', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob'] }, // Note, does not follow charlie
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
var done = multicb()
users.bob.add({ type: 'post', text: 'hello from bob', mentions: [users.alice.id] }, done())
users.charlie.add({ type: 'post', text: 'hello from charlie', mentions: [users.alice.id] }, done())
done(function (err, msgs) {
if (err) throw err
var inboxedMsg = msgs[0][1]
sbot.patchwork.getIndexCounts(function (err, counts) {
if (err) throw err
t.equal(counts.inbox, 1)
t.equal(counts.inboxUnread, 1)
sbot.patchwork.markRead(inboxedMsg.key, function (err) {
if (err) throw err
sbot.patchwork.getIndexCounts(function (err, counts) {
if (err) throw err
t.equal(counts.inbox, 1)
t.equal(counts.inboxUnread, 0)
sbot.patchwork.markUnread(inboxedMsg.key, function (err) {
if (err) throw err
sbot.patchwork.getIndexCounts(function (err, counts) {
if (err) throw err
t.equal(counts.inbox, 1)
t.equal(counts.inboxUnread, 1)
t.end()
sbot.close()
})
})
})
})
})
})
})
})
tape('vote index includes upvotes on the users posts', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob'] }, // Note, does not follow charlie
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
users.alice.add({ type: 'post', text: 'hello from alice' }, function (err, msg) {
if (err) throw err
var done = multicb()
users.bob.add({ type: 'vote', vote: { link: msg.key, value: 1 } }, done())
users.charlie.add({ type: 'vote', vote: { link: msg.key, value: 1 } }, done())
done(function (err) {
if (err) throw err
pull(sbot.patchwork.createVoteStream(), pull.collect(function (err, msgs) {
if (err) throw err
t.equal(msgs.length, 2)
t.end()
sbot.close()
}))
})
})
})
})
tape('vote index does not include downvotes, and removes unvotes', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob'] }, // Note, does not follow charlie
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
users.alice.add({ type: 'post', text: 'hello from alice' }, function (err, msg) {
if (err) throw err
var done = multicb()
users.bob.add({ type: 'vote', vote: { link: msg.key, value: -1 } }, done())
users.charlie.add({ type: 'vote', vote: { link: msg.key, value: 1 } }, done())
users.charlie.add({ type: 'vote', vote: { link: msg.key, value: 0 } }, done())
done(function (err) {
if (err) throw err
pull(sbot.patchwork.createVoteStream(), pull.collect(function (err, msgs) {
if (err) throw err
t.equal(msgs.length, 0)
t.end()
sbot.close()
}))
})
})
})
})
tape('vote index counts correctly track read/unread', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob'] }, // Note, does not follow charlie
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
users.alice.add({ type: 'post', text: 'hello from alice' }, function (err, msg) {
if (err) throw err
var done = multicb()
users.bob.add({ type: 'vote', vote: { link: msg.key, value: 1 } }, done())
users.charlie.add({ type: 'vote', vote: { link: msg.key, value: 1 } }, done())
done(function (err, msgs) {
if (err) throw err
var voteMsg = msgs[0][1]
sbot.patchwork.getIndexCounts(function (err, counts) {
if (err) throw err
t.equal(counts.votes, 2)
t.equal(counts.votesUnread, 2)
sbot.patchwork.markRead(voteMsg.key, function (err) {
if (err) throw err
sbot.patchwork.getIndexCounts(function (err, counts) {
if (err) throw err
t.equal(counts.votes, 2)
t.equal(counts.votesUnread, 1)
sbot.patchwork.markUnread(voteMsg.key, function (err) {
if (err) throw err
sbot.patchwork.getIndexCounts(function (err, counts) {
if (err) throw err
t.equal(counts.votes, 2)
t.equal(counts.votesUnread, 2)
t.end()
sbot.close()
})
})
})
})
})
})
})
})
})
tape('follow index includes all new followers', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: {},
bob: { follows: ['alice'] },
charlie: { follows: ['alice'] }
}, function (err, users) {
if (err) throw err
pull(sbot.patchwork.createFollowStream(), pull.collect(function (err, msgs) {
if (err) throw err
t.equal(msgs.length, 2)
t.end()
sbot.close()
}))
})
})
tape('follow index includes unfollows', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: {},
bob: { follows: ['alice'] },
charlie: { follows: ['alice'] }
}, function (err, users) {
if (err) throw err
users.charlie.add({ type: 'contact', contact: users.alice.id, following: false }, function (err) {
if (err) throw err
pull(sbot.patchwork.createFollowStream(), pull.collect(function (err, msgs) {
if (err) throw err
t.equal(msgs.length, 3)
t.end()
sbot.close()
}))
})
})
})
tape('follow index counts correctly track read/unread', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: {},
bob: { follows: ['alice'] },
charlie: { follows: ['alice'] }
}, function (err, users, msgs) {
if (err) throw err
var followMsg = msgs[1][1]
console.log('getting indexes 1')
sbot.patchwork.getIndexCounts(function (err, counts) {
if (err) throw err
t.equal(counts.follows, 2)
t.equal(counts.followsUnread, 2)
console.log('marking read')
sbot.patchwork.markRead(followMsg.key, function (err) {
if (err) throw err
console.log('getting indexes 2')
sbot.patchwork.getIndexCounts(function (err, counts) {
if (err) throw err
t.equal(counts.follows, 2)
t.equal(counts.followsUnread, 1)
sbot.patchwork.markUnread(followMsg.key, function (err) {
if (err) throw err
sbot.patchwork.getIndexCounts(function (err, counts) {
if (err) throw err
t.equal(counts.follows, 2)
t.equal(counts.followsUnread, 2)
t.end()
sbot.close()
})
})
})
})
})
})
})
tape('home index includes all posts', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob'] }, // Note, does not follow charlie
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
users.alice.add({ type: 'post', text: 'hello from alice' }, function (err, msg) {
if (err) throw err
var done = multicb()
users.bob.add({ type: 'post', text: 'hello from bob' }, done())
users.charlie.add({ type: 'post', text: 'hello from charlie', root: msg.key, branch: msg.key }, done())
done(function (err) {
if (err) throw err
pull(sbot.patchwork.createHomeStream(), pull.collect(function (err, msgs) {
if (err) throw err
t.equal(msgs.length, 3)
t.end()
sbot.close()
}))
})
})
})
})
tape('home index includes non-posts with post replies on them', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob'] }, // Note, does not follow charlie
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
users.alice.add({ type: 'nonpost', text: 'hello from alice' }, function (err, msg) {
if (err) throw err
var done = multicb()
users.bob.add({ type: 'nonpost', text: 'hello from bob' }, done())
users.charlie.add({ type: 'post', text: 'hello from charlie', root: msg.key, branch: msg.key }, done())
done(function (err) {
if (err) throw err
pull(sbot.patchwork.createHomeStream(), pull.collect(function (err, msgs) {
if (err) throw err
t.equal(msgs.length, 2)
t.equal(msgs[0].value.author, users.charlie.id)
t.equal(msgs[1].value.author, users.alice.id)
t.end()
sbot.close()
}))
})
})
})
})

220
api/test/names.js Normal file
View File

@@ -0,0 +1,220 @@
var multicb = require('multicb')
var tape = require('tape')
var u = require('./util')
tape('names default to self-assigned', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob', 'charlie'] },
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
sbot.patchwork.getNamesById(function (err, names) {
if (err) throw err
t.equal(names[users.alice.id], 'alice')
t.equal(names[users.bob.id], 'bob')
t.equal(names[users.charlie.id], 'charlie')
sbot.patchwork.getIdsByName(function (err, ids) {
if (err) throw err
t.equal(ids.alice, users.alice.id)
t.equal(ids.bob, users.bob.id)
t.equal(ids.charlie, users.charlie.id)
t.end()
sbot.close()
})
})
})
})
tape('the local users name assignments take precedence', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob', 'charlie'] },
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
var done = multicb()
users.alice.add({ type: 'about', about: users.bob.id, name: 'robert' }, done())
users.alice.add({ type: 'about', about: users.charlie.id, name: 'chuck' }, done())
done(function (err) {
if (err) throw err
sbot.patchwork.getNamesById(function (err, names) {
if (err) throw err
t.equal(names[users.alice.id], 'alice')
t.equal(names[users.bob.id], 'robert')
t.equal(names[users.charlie.id], 'chuck')
sbot.patchwork.getIdsByName(function (err, ids) {
if (err) throw err
t.equal(ids.alice, users.alice.id)
t.equal(ids.robert, users.bob.id)
t.equal(ids.chuck, users.charlie.id)
t.end()
sbot.close()
})
})
})
})
})
tape('conflicting names between followeds are tracked as action items', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob', 'charlie'] },
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
users.charlie.add({ type: 'about', about: users.charlie.id, name: 'bob' }, function (err) {
if (err) throw err
sbot.patchwork.getNamesById(function (err, names) {
if (err) throw err
t.equal(names[users.alice.id], 'alice')
t.equal(names[users.bob.id], 'bob')
t.equal(names[users.charlie.id], 'bob')
sbot.patchwork.getIdsByName(function (err, ids) {
if (err) throw err
t.equal(ids.alice, users.alice.id)
t.equal(ids.bob.length, 2)
sbot.patchwork.getActionItems(function (err, items) {
if (err) throw err
t.equal(items.bob.type, 'name-conflict')
t.equal(items.bob.name, 'bob')
t.equal(items.bob.ids.length, 2)
t.end()
sbot.close()
})
})
})
})
})
})
tape('conflicting names are resolved by unfollowing', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob', 'charlie'] },
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
users.charlie.add({ type: 'about', about: users.charlie.id, name: 'bob' }, function (err) {
if (err) throw err
users.alice.add({ type: 'contact', contact: users.bob.id, following: false }, function (err) {
if (err) throw err
sbot.patchwork.getNamesById(function (err, names) {
if (err) throw err
t.equal(names[users.alice.id], 'alice')
t.equal(names[users.bob.id], 'bob')
t.equal(names[users.charlie.id], 'bob')
sbot.patchwork.getIdsByName(function (err, ids) {
if (err) throw err
t.equal(ids.alice, users.alice.id)
t.equal(ids.bob, users.charlie.id)
sbot.patchwork.getActionItems(function (err, items) {
if (err) throw err
t.equal(Object.keys(items).length, 0)
t.end()
sbot.close()
})
})
})
})
})
})
})
tape('conflicting names are resolved by one of the users self-assigning a new name', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob', 'charlie'] },
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
users.charlie.add({ type: 'about', about: users.charlie.id, name: 'bob' }, function (err) {
if (err) throw err
users.bob.add({ type: 'about', about: users.bob.id, name: 'robert' }, function (err) {
if (err) throw err
sbot.patchwork.getNamesById(function (err, names) {
if (err) throw err
t.equal(names[users.alice.id], 'alice')
t.equal(names[users.bob.id], 'robert')
t.equal(names[users.charlie.id], 'bob')
sbot.patchwork.getIdsByName(function (err, ids) {
if (err) throw err
t.equal(ids.alice, users.alice.id)
t.equal(ids.robert, users.bob.id)
t.equal(ids.bob, users.charlie.id)
sbot.patchwork.getActionItems(function (err, items) {
if (err) throw err
t.equal(Object.keys(items).length, 0)
t.end()
sbot.close()
})
})
})
})
})
})
})
tape('conflicting names are resolved by the local user assigning a new name', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob', 'charlie'] },
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
users.charlie.add({ type: 'about', about: users.charlie.id, name: 'bob' }, function (err) {
if (err) throw err
users.alice.add({ type: 'about', about: users.bob.id, name: 'robert' }, function (err) {
if (err) throw err
sbot.patchwork.getNamesById(function (err, names) {
if (err) throw err
t.equal(names[users.alice.id], 'alice')
t.equal(names[users.bob.id], 'robert')
t.equal(names[users.charlie.id], 'bob')
sbot.patchwork.getIdsByName(function (err, ids) {
if (err) throw err
t.equal(ids.alice, users.alice.id)
t.equal(ids.robert, users.bob.id)
t.equal(ids.bob, users.charlie.id)
sbot.patchwork.getActionItems(function (err, items) {
if (err) throw err
t.equal(Object.keys(items).length, 0)
t.end()
sbot.close()
})
})
})
})
})
})
})

91
api/test/profiles.js Normal file
View File

@@ -0,0 +1,91 @@
var multicb = require('multicb')
var tape = require('tape')
var u = require('./util')
var blobid = '&RYnp9p24dlAPYGhrsFYdGGHIAYM2uM5pr1//RocCF/U=.sha256'
tape('profiles track self-assigned name and profile pic', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob', 'charlie'] },
bob: {},
charlie: {}
}, function (err, users) {
if (err) throw err
var done = multicb()
users.alice.add({ type: 'about', about: users.alice.id, image: blobid }, done())
users.bob.add({ type: 'about', about: users.bob.id, image: blobid }, done())
users.charlie.add({ type: 'about', about: users.charlie.id, image: blobid }, done())
done(function (err) {
if (err) throw err
sbot.patchwork.getAllProfiles(function (err, profiles) {
if (err) throw err
t.equal(profiles[users.alice.id].self.name, 'alice')
t.equal(profiles[users.bob.id].self.name, 'bob')
t.equal(profiles[users.charlie.id].self.name, 'charlie')
t.equal(profiles[users.alice.id].self.image.link, blobid)
t.equal(profiles[users.bob.id].self.image.link, blobid)
t.equal(profiles[users.charlie.id].self.image.link, blobid)
sbot.close()
t.end()
})
})
})
})
tape('profiles track follows, names, and flags between users', function (t) {
var sbot = u.newserver()
u.makeusers(sbot, {
alice: { follows: ['bob', 'charlie'] },
bob: { follows: ['alice', 'charlie'] },
charlie: { follows: ['bob', 'alice'] }
}, function (err, users) {
if (err) throw err
var done = multicb()
users.alice.add({ type: 'about', about: users.bob.id, name: 'robert' }, done())
users.alice.add({ type: 'flag', flag: { link: users.charlie.id, reason: 'such a jerk!' } }, done())
users.bob.add({ type: 'flag', flag: { link: users.charlie.id, reason: 'dont like him' } }, done())
done(function (err) {
if (err) throw err
sbot.patchwork.getAllProfiles(function (err, profiles) {
if (err) throw err
function by(a, b) {
return profiles[users[a].id].assignedBy[users[b].id]
}
function to(a, b) {
return profiles[users[a].id].assignedTo[users[b].id]
}
t.equal(to('alice', 'bob').following, true)
t.equal(to('alice', 'charlie').following, true)
t.equal(by('bob', 'alice').following, true)
t.equal(by('charlie', 'alice').following, true)
t.equal(to('bob', 'alice').following, true)
t.equal(to('bob', 'charlie').following, true)
t.equal(by('alice', 'bob').following, true)
t.equal(by('charlie', 'bob').following, true)
t.equal(to('charlie', 'bob').following, true)
t.equal(to('charlie', 'alice').following, true)
t.equal(by('bob', 'charlie').following, true)
t.equal(by('alice', 'charlie').following, true)
t.equal(to('alice', 'charlie').flagged.reason, 'such a jerk!')
t.equal(by('charlie', 'alice').flagged.reason, 'such a jerk!')
t.equal(to('bob', 'charlie').flagged.reason, 'dont like him')
t.equal(by('charlie', 'bob').flagged.reason, 'dont like him')
t.equal(to('alice', 'bob').name, 'robert')
t.equal(by('bob', 'alice').name, 'robert')
sbot.close()
t.end()
})
})
})
})

52
api/test/util.js Normal file
View File

@@ -0,0 +1,52 @@
var path = require('path')
var fs = require('fs')
var rimraf = require('rimraf')
var osenv = require('osenv')
var multicb = require('multicb')
var ssbkeys = require('ssb-keys')
var createSbot = require('scuttlebot')
.use(require('scuttlebot/plugins/master'))
.use(require('scuttlebot/plugins/gossip'))
.use(require('scuttlebot/plugins/friends'))
.use(require('scuttlebot/plugins/replicate'))
.use(require('scuttlebot/plugins/blobs'))
.use(require('scuttlebot/plugins/invite'))
.use(require('scuttlebot/plugins/block'))
.use(require('scuttlebot/plugins/logging'))
.use(require('scuttlebot/plugins/private'))
.use(require('../'))
var n = 0
exports.newserver = function () {
var dir = path.join(osenv.tmpdir(), 'phoenix-api-test'+(++n))
rimraf.sync(dir)
fs.mkdirSync(dir)
return createSbot({ path: dir, keys: ssbkeys.generate() })
}
exports.makeusers = function (sbot, desc, cb) {
var users = { alice: sbot.createFeed(sbot.keys) }
var done = multicb()
// generate feeds
for (var name in desc) {
if (!users[name])
users[name] = sbot.createFeed(ssbkeys.generate())
console.log(name+':', users[name].id)
}
// generate additional messages
for (var name in desc) {
;(desc[name].follows||[]).forEach(function (name2) {
users[name].add({ type: 'contact', contact: users[name2].id, following: true }, done())
})
users[name].add({ type: 'contact', contact: users[name].id, name: name }, done())
}
done(function (err, msgs) {
if (err) cb(err)
else cb(null, users, msgs)
})
}