add Undo support to unfollow

This commit is contained in:
Will Murphy 2019-09-25 17:15:39 -05:00
parent dbf8e5a413
commit e47dd9286f
4 changed files with 51 additions and 15 deletions

View file

@ -7,7 +7,8 @@ const pubFederation = require('./federation')
module.exports = { module.exports = {
address, address,
addToOutbox, addToOutbox,
build build,
undo
} }
function build (type, actorId, object, to, cc, etc) { function build (type, actorId, object, to, cc, etc) {
@ -61,11 +62,26 @@ async function address (activity) {
} }
function addToOutbox (actor, activity) { function addToOutbox (actor, activity) {
return Promise.all([ const tasks = [
// ensure object is cached, but don't alter representation in activity
// so activities can be sent with objects as links
//pubObject.resolve(activity.object),
store.stream.save(activity), store.stream.save(activity),
address(activity).then(addresses => pubFederation.deliver(actor, activity, addresses)) address(activity).then(addresses => pubFederation.deliver(actor, activity, addresses))
]) ]
// ensure activity object is cached if local, but do not try to resolve links
// because Mastodon won't resolve activity IRIs
if (pubUtils.validateObject(activity.object)) {
tasks.push(pubObject.resolve(activity.object))
}
return Promise.all(tasks)
}
function undo (activity, undoActor) {
if (!pubUtils.validateActivity(activity)) {
if (!activity || Object.prototype.toString.call(activity) !== '[object String]') {
throw new Error('Invalid undo target')
}
activity = { id: activity }
}
// matches the target activity with the actor from the undo
// so actors can only undo their own activities
return store.stream.remove(activity, undoActor)
} }

View file

@ -24,7 +24,7 @@ function deliver (actor, activity, addresses) {
delete activity.bcc delete activity.bcc
} }
const requests = addresses.map(addr => { const requests = addresses.map(addr => {
console.log(`delivering to${addr}`) console.log(`delivering to ${addr}`)
return request({ return request({
method: 'POST', method: 'POST',
url: addr, url: addr,

View file

@ -6,14 +6,19 @@ const store = require('../store')
router.post('/', net.validators.activity, net.security.verifySignature, function (req, res) { router.post('/', net.validators.activity, net.security.verifySignature, function (req, res) {
req.body._meta = { _target: pub.utils.usernameToIRI(req.user) } req.body._meta = { _target: pub.utils.usernameToIRI(req.user) }
console.log(req.body); console.log(req.body)
const toDo = {
saveActivity: true,
saveObject: false
}
// side effects // side effects
switch (req.body.type) { switch (req.body.type) {
case 'Accept': case 'Accept':
// TODO - side effect necessary for following collection? // TODO - side effect necessary for following collection?
break break
case 'Follow': case 'Follow':
//req.body._meta._target = req.body.object.id // TODO resolve object and ensure specified target matches inbox user
// req.body._meta._target = req.body.object.id
// send acceptance reply // send acceptance reply
pub.actor.getOrCreateActor(req.user, true) pub.actor.getOrCreateActor(req.user, true)
.then(user => { .then(user => {
@ -24,6 +29,7 @@ router.post('/', net.validators.activity, net.security.verifySignature, function
.catch(e => console.log(e)) .catch(e => console.log(e))
break break
case 'Create': case 'Create':
toDo.saveObject = true
pub.actor.getOrCreateActor(req.user, true) pub.actor.getOrCreateActor(req.user, true)
.then(user => { .then(user => {
const to = [user.followers] const to = [user.followers]
@ -31,15 +37,23 @@ router.post('/', net.validators.activity, net.security.verifySignature, function
pub.utils.actorFromActivity(req.body), pub.utils.actorFromActivity(req.body),
'https://www.w3.org/ns/activitystreams#Public' 'https://www.w3.org/ns/activitystreams#Public'
] ]
const accept = pub.activity.build('Announce', user.id, req.body.object.id, to, cc) const announce = pub.activity.build('Announce', user.id, req.body.object.id, to, cc)
return pub.activity.addToOutbox(user, accept) return pub.activity.addToOutbox(user, announce)
}).catch(e => console.log(e)) }).catch(e => console.log(e))
break break
case 'Undo':
pub.activity.undo(req.body.object, req.body.actor)
.catch(err => console.log(err))
break
} }
Promise.all([ const tasks = []
pub.object.resolve(req.body.object), if (toDo.saveObject) {
store.stream.save(req.body) tasks.push(pub.object.resolve(req.body.object))
]).then(() => res.status(200).send()) }
if (toDo.saveActivity) {
tasks.push(store.stream.save(req.body))
}
Promise.all(tasks).then(() => res.status(200).send())
.catch(err => { .catch(err => {
console.log(err) console.log(err)
res.status(500).send() res.status(500).send()

View file

@ -2,6 +2,7 @@
const connection = require('./connection') const connection = require('./connection')
module.exports = { module.exports = {
get, get,
remove,
save save
} }
@ -34,3 +35,8 @@ async function save (activity) {
// server object ID avoids mutating local copy of document // server object ID avoids mutating local copy of document
.insertOne(activity, { forceServerObjectId: true }) .insertOne(activity, { forceServerObjectId: true })
} }
function remove (activity, actor) {
return connection.getDb().collection('streams')
.deleteMany({ id: activity.id, actor: actor })
}