From 65ea0192faba405ae2fe5c043786ddefb25096d1 Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Sat, 26 Aug 2023 22:29:19 -0600 Subject: [PATCH] Reject Follow request support --- core/activitypub/activity.js | 13 +++++- core/activitypub/follow_util.js | 44 ++++++++++++++++++ core/activitypub/social_manager.js | 74 ++++++++++++++++++++++-------- 3 files changed, 110 insertions(+), 21 deletions(-) diff --git a/core/activitypub/activity.js b/core/activitypub/activity.js index c45ab10e..5464b91c 100644 --- a/core/activitypub/activity.js +++ b/core/activitypub/activity.js @@ -27,12 +27,21 @@ module.exports = class Activity extends ActivityPubObject { } // https://www.w3.org/TR/activitypub/#accept-activity-inbox - static makeAccept(localActor, followRequest) { + static makeAccept(localActor, activity) { return new Activity({ id: Activity.activityObjectId(), type: WellKnownActivity.Accept, actor: localActor, - object: followRequest, // previous request Activity + object: activity, // previous request Activity + }); + } + + static makeReject(localActor, activity) { + return new Activity({ + id: Activity.activityObjectId(), + type: WellKnownActivity.Reject, + actor: localActor.id, + object: activity, }); } diff --git a/core/activitypub/follow_util.js b/core/activitypub/follow_util.js index 396f772c..0f0bd78e 100644 --- a/core/activitypub/follow_util.js +++ b/core/activitypub/follow_util.js @@ -11,6 +11,7 @@ const async = require('async'); exports.sendFollowRequest = sendFollowRequest; exports.sendUnfollowRequest = sendUnfollowRequest; exports.acceptFollowRequest = acceptFollowRequest; +exports.rejectFollowRequest = rejectFollowRequest; function sendFollowRequest(fromUser, toActor, cb) { const fromActorId = fromUser.getProperty(UserProps.ActivityPubActorId); @@ -138,3 +139,46 @@ function acceptFollowRequest(localUser, remoteActor, requestActivity, cb) { } ); } + +function rejectFollowRequest(localUser, requestActor, requestActivity, cb) { + async.series( + [ + callback => { + Actor.fromLocalUser(localUser, (err, localActor) => { + if (err) { + return callback(err); + } + + const reject = Activity.makeReject(localActor, localActor); + reject.sendTo(requestActor.inbox, localUser, (err, respBody, res) => { + if (err) { + return callback(Errors.HttpError(err.message, err.code)); + } + + if (res.statusCode !== 202 && res.statusCode !== 200) { + return callback( + Errors.HttpError( + `Unexpected HTTP status code ${res.statusCode}` + ) + ); + } + + return callback(null); + }); + }); + }, + callback => { + // remove from local requests Collection + return Collection.removeOwnedById( + Collections.FollowRequests, + localUser, + requestActivity.id, + callback + ); + }, + ], + err => { + return cb(err); + } + ); +} diff --git a/core/activitypub/social_manager.js b/core/activitypub/social_manager.js index 0fcec24c..d842a1df 100644 --- a/core/activitypub/social_manager.js +++ b/core/activitypub/social_manager.js @@ -11,6 +11,7 @@ const { sendFollowRequest, sendUnfollowRequest, acceptFollowRequest, + rejectFollowRequest, } = require('./follow_util'); const { Collections } = require('./const'); const EnigAssert = require('../enigma_assert'); @@ -53,14 +54,14 @@ exports.getModule = class activityPubSocialManager extends MenuModule { this.menuMethods = { actorListKeyPressed: (formData, extraArgs, cb) => { + const collection = this.currentCollection; switch (formData.key.name) { case 'space': { - if (this.currentCollection === Collections.Following) { + if (collection === Collections.Following) { return this._toggleFollowing(cb); - } else if ( - this.currentCollection === Collections.FollowRequests - ) { + } + if (collection === Collections.FollowRequests) { return this._acceptFollowRequest(cb); } } @@ -68,16 +69,18 @@ exports.getModule = class activityPubSocialManager extends MenuModule { case 'delete': { - if (this.currentCollection === Collections.Followers) { + if (collection === Collections.Followers) { return this._removeFollower(cb); - } else if ( - this.currentCollection === Collections.FollowRequests - ) { - return this._denyFollowRequest(cb); + } + + if (collection === Collections.FollowRequests) { + return this._rejectFollowRequest(cb); } } break; } + + return cb(null); }, listKeyPressed: (formData, extraArgs, cb) => { const actorListView = this.getView('main', MciViewIds.main.actorList); @@ -308,6 +311,19 @@ exports.getModule = class activityPubSocialManager extends MenuModule { } } + _removeSelectedFollowRequest(actorListView, moveToFollowers) { + const followingActor = this.followRequests.splice( + actorListView.getFocusItemIndex(), + 1 + )[0]; + + if (moveToFollowers) { + this.followerActors.push(followingActor); + } + + this._switchTo(this.currentCollection); // redraw + } + _acceptFollowRequest(cb) { EnigAssert(Collections.FollowRequests === this.currentCollection); @@ -327,28 +343,48 @@ exports.getModule = class activityPubSocialManager extends MenuModule { if (err) { this.client.log.error( { error: err.message }, - 'Failed to fully accept Follow request' + 'Error Accepting Follow request' ); } - const followingActor = this.followRequests.splice( - actorListView.getFocusItemIndex(), - 1 - )[0]; - this.followerActors.push(followingActor); // move to followers - - this._switchTo(this.currentCollection); // redraw + this._removeSelectedFollowRequest(actorListView, true); // true=move to followers return cb(err); }); } _removeFollower(cb) { + // :TODO: Send a Undo return cb(null); } - _denyFollowRequest(cb) { - return cb(null); + _rejectFollowRequest(cb) { + EnigAssert(Collections.FollowRequests === this.currentCollection); + + const actorListView = this.getView('main', MciViewIds.main.actorList); + const selectedActor = this._getSelectedActorItem( + actorListView.getFocusItemIndex() + ); + + if (!selectedActor) { + return cb(null); + } + + const request = selectedActor.request; + EnigAssert(request); + + rejectFollowRequest(this.client.user, selectedActor, request, err => { + if (err) { + this.client.log.error( + { error: err.message }, + 'Error Rejecting Follow request' + ); + } + + this._removeSelectedFollowRequest(actorListView, false); // false=do not move to followers + + return cb(err); + }); } _followingActorToggled(actorInfo, cb) {