diff --git a/src/activitypub/index.js b/src/activitypub/index.js index 09095c8374..98f390ddb7 100644 --- a/src/activitypub/index.js +++ b/src/activitypub/index.js @@ -35,9 +35,14 @@ ActivityPub.getActor = async (input) => { const actor = await ActivityPub.get(uri); + // todo: remove this after ActivityPub.get is updated to handle errors more effectively + if (typeof actor === 'string' || actor.hasOwnProperty('error')) { + return null; + } + const [followers, following] = await Promise.all([ - ActivityPub.get(actor.followers), - ActivityPub.get(actor.following), + actor.followers ? ActivityPub.get(actor.followers) : { totalItems: 0 }, + actor.following ? ActivityPub.get(actor.following) : { totalItems: 0 }, ]); actor.hostname = new URL(uri).hostname; @@ -56,12 +61,16 @@ ActivityPub.mockProfile = async (actors, callerUid = 0) => { actors = [actors]; } - const profiles = await Promise.all(actors.map(async (actor) => { + const profiles = (await Promise.all(actors.map(async (actor) => { // convert uri to actor object if (typeof actor === 'string' && ActivityPub.helpers.isUri(actor)) { actor = await ActivityPub.getActor(actor); } + if (!actor) { + return null; + } + const uid = actor.id; const { preferredUsername, published, icon, image, name, summary, hostname, followerCount, followingCount } = actor; const isFollowing = await db.isSortedSetMember(`followingRemote:${callerUid}`, uid); @@ -97,7 +106,7 @@ ActivityPub.mockProfile = async (actors, callerUid = 0) => { }; return payload; - })); + }))).filter(Boolean); return single ? profiles.pop() : profiles; }; diff --git a/src/controllers/accounts/follow.js b/src/controllers/accounts/follow.js index 44ad00d3de..9fc873db48 100644 --- a/src/controllers/accounts/follow.js +++ b/src/controllers/accounts/follow.js @@ -4,6 +4,8 @@ const user = require('../../user'); const helpers = require('../helpers'); const pagination = require('../../pagination'); +const activitypubController = require('../activitypub'); + const followController = module.exports; followController.getFollowing = async function (req, res, next) { @@ -15,6 +17,10 @@ followController.getFollowers = async function (req, res, next) { }; async function getFollow(tpl, name, req, res) { + if (res.locals.uid === -2) { + return activitypubController.profiles.getFollow(tpl, name, req, res); + } + const { username, userslug, followerCount, followingCount, } = await user.getUserFields(res.locals.uid, [ diff --git a/src/controllers/activitypub/profiles.js b/src/controllers/activitypub/profiles.js index afeab8cedb..e641af3685 100644 --- a/src/controllers/activitypub/profiles.js +++ b/src/controllers/activitypub/profiles.js @@ -1,6 +1,8 @@ 'use strict'; -const { getActor, mockProfile } = require('../../activitypub'); +const { getActor, mockProfile, get } = require('../../activitypub'); +const helpers = require('../helpers'); +const pagination = require('../../pagination'); const controller = module.exports; @@ -14,3 +16,27 @@ controller.get = async function (req, res, next) { const payload = await mockProfile(actor, req.uid); res.render('account/profile', payload); }; + +controller.getFollow = async function (tpl, name, req, res) { + const actor = await getActor(req.params.userslug); + + const { userslug } = req.params; + const { preferredUsername: username, followerCount, followingCount } = actor; + + const page = parseInt(req.query.page, 10) || 1; + + const payload = {}; + payload.title = `[[pages:${tpl}, ${username}]]`; + + const collection = await get(`${actor[name]}?page=${page}`); + const resultsPerPage = collection.orderedItems.length; + payload.users = await mockProfile(collection.orderedItems, req.uid); + + const count = name === 'following' ? followingCount : followerCount; + const pageCount = Math.ceil(count / resultsPerPage); + payload.pagination = pagination.create(page, pageCount); + + payload.breadcrumbs = helpers.buildBreadcrumbs([{ text: username, url: `/user/${userslug}` }, { text: `[[user:${name}]]` }]); + + res.render(tpl, payload); +};