diff --git a/src/processor/http/index.ts b/src/processor/http/index.ts index 0301b472c..8f9aa717c 100644 --- a/src/processor/http/index.ts +++ b/src/processor/http/index.ts @@ -3,6 +3,7 @@ import follow from './follow'; import performActivityPub from './perform-activitypub'; import processInbox from './process-inbox'; import reportGitHubFailure from './report-github-failure'; +import unfollow from './unfollow'; const handlers = { deliverPost, @@ -10,6 +11,7 @@ const handlers = { performActivityPub, processInbox, reportGitHubFailure, + unfollow }; export default (job, done) => handlers[job.data.type](job).then(() => done(), done); diff --git a/src/processor/http/unfollow.ts b/src/processor/http/unfollow.ts new file mode 100644 index 000000000..4a8f03391 --- /dev/null +++ b/src/processor/http/unfollow.ts @@ -0,0 +1,54 @@ +import FollowedLog from '../../models/followed-log'; +import Following from '../../models/following'; +import FollowingLog from '../../models/following-log'; +import User, { isRemoteUser, pack as packUser } from '../../models/user'; +import stream from '../../publishers/stream'; +import renderFollow from '../../remote/activitypub/renderer/follow'; +import renderUndo from '../../remote/activitypub/renderer/undo'; +import context from '../../remote/activitypub/renderer/context'; +import request from '../../remote/request'; + +export default async ({ data }) => { + // Delete following + const following = await Following.findOneAndDelete({ _id: data.id }); + if (following === null) { + return; + } + + const promisedFollower = User.findOne({ _id: following.followerId }); + const promisedFollowee = User.findOne({ _id: following.followeeId }); + + await Promise.all([ + // Decrement following count + User.update({ _id: following.followerId }, { $inc: { followingCount: -1 } }), + promisedFollower.then(({ followingCount }) => FollowingLog.insert({ + userId: following.followerId, + count: followingCount - 1 + })), + + // Decrement followers count + User.update({ _id: following.followeeId }, { $inc: { followersCount: -1 } }), + promisedFollowee.then(({ followersCount }) => FollowedLog.insert({ + userId: following.followeeId, + count: followersCount - 1 + })), + + // Publish follow event + Promise.all([promisedFollower, promisedFollowee]).then(async ([follower, followee]) => { + if (isRemoteUser(follower)) { + return; + } + + const promisedPackedUser = packUser(followee, follower); + + if (isRemoteUser(followee)) { + const undo = renderUndo(renderFollow(follower, followee)); + undo['@context'] = context; + + await request(follower, followee.account.inbox, undo); + } + + stream(follower._id, 'unfollow', promisedPackedUser); + }) + ]); +}; diff --git a/src/remote/activitypub/act/undo/index.ts b/src/remote/activitypub/act/undo/index.ts index b43ae8617..c34d56e70 100644 --- a/src/remote/activitypub/act/undo/index.ts +++ b/src/remote/activitypub/act/undo/index.ts @@ -15,7 +15,7 @@ export default async (resolver, actor, activity) => { switch (result.object.$ref) { case 'following': - await unfollow(result.resolver, result.object); + await unfollow(result.object); } })); diff --git a/src/remote/activitypub/act/undo/unfollow.ts b/src/remote/activitypub/act/undo/unfollow.ts index 0523699bf..c17e06e8a 100644 --- a/src/remote/activitypub/act/undo/unfollow.ts +++ b/src/remote/activitypub/act/undo/unfollow.ts @@ -1,24 +1,11 @@ -import FollowedLog from '../../../../models/followed-log'; -import Following from '../../../../models/following'; -import FollowingLog from '../../../../models/following-log'; -import User from '../../../../models/user'; +import queue from '../../../../queue'; -export default async (resolver, { $id }) => { - const following = await Following.findOneAndDelete({ _id: $id }); - if (following === null) { - return; - } - - await Promise.all([ - User.update({ _id: following.followerId }, { $inc: { followingCount: -1 } }), - User.findOne({ _id: following.followerId }).then(({ followingCount }) => FollowingLog.insert({ - userId: following.followerId, - count: followingCount - 1 - })), - User.update({ _id: following.followeeId }, { $inc: { followersCount: -1 } }), - User.findOne({ _id: following.followeeId }).then(({ followersCount }) => FollowedLog.insert({ - userId: following.followeeId, - count: followersCount - 1 - })), - ]); -}; +export default ({ $id }) => new Promise((resolve, reject) => { + queue.create('http', { type: 'unfollow', id: $id }).save(error => { + if (error) { + reject(error); + } else { + resolve(); + } + }); +}); diff --git a/src/remote/activitypub/renderer/undo.ts b/src/remote/activitypub/renderer/undo.ts new file mode 100644 index 000000000..f38e224b6 --- /dev/null +++ b/src/remote/activitypub/renderer/undo.ts @@ -0,0 +1,4 @@ +export default object => ({ + type: 'Undo', + object +}); diff --git a/src/server/api/endpoints/following/delete.ts b/src/server/api/endpoints/following/delete.ts index 5deddc919..bf21bf0cb 100644 --- a/src/server/api/endpoints/following/delete.ts +++ b/src/server/api/endpoints/following/delete.ts @@ -2,9 +2,9 @@ * Module dependencies */ import $ from 'cafy'; -import User, { pack as packUser } from '../../../../models/user'; +import User from '../../../../models/user'; import Following from '../../../../models/following'; -import event from '../../../../publishers/stream'; +import queue from '../../../../queue'; /** * Unfollow a user @@ -49,28 +49,15 @@ module.exports = (params, user) => new Promise(async (res, rej) => { return rej('already not following'); } - // Delete following - await Following.findOneAndDelete({ - _id: exist._id - }); - - // Send response - res(); - - // Decrement following count - User.update({ _id: follower._id }, { - $inc: { - followingCount: -1 + queue.create('http', { + type: 'unfollow', + id: exist._id + }).save(error => { + if (error) { + return rej('unfollow failed'); } - }); - // Decrement followers count - User.update({ _id: followee._id }, { - $inc: { - followersCount: -1 - } + // Send response + res(); }); - - // Publish follow event - event(follower._id, 'unfollow', await packUser(followee, follower)); });