diff --git a/src/api/activitypub.js b/src/api/activitypub.js index 4701c0ca51..43dad015b1 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -13,6 +13,7 @@ const winston = require('winston'); const db = require('../database'); const user = require('../user'); +const categories = require('../categories'); const meta = require('../meta'); const privileges = require('../privileges'); const activitypub = require('../activitypub'); @@ -43,7 +44,14 @@ activitypubApi.follow = enabledCheck(async (caller, { type, id, actor } = {}) => throw new Error('[[error:activitypub.invalid-id]]'); } - actor = actor.includes('@') ? await user.getUidByUserslug(actor) : actor; + if (actor.includes('@')) { + const [uid, cid] = await Promise.all([ + user.getUidByUserslug(actor), + categories.getCidByHandle(actor), + ]); + + actor = uid || cid; + } const isFollowing = await db.isSortedSetMember(type === 'uid' ? `followingRemote:${id}` : `cid:${id}:following`, actor); if (isFollowing) { // already following @@ -73,10 +81,21 @@ activitypubApi.unfollow = enabledCheck(async (caller, { type, id, actor }) => { throw new Error('[[error:activitypub.invalid-id]]'); } - actor = actor.includes('@') ? await user.getUidByUserslug(actor) : actor; + if (actor.includes('@')) { + const [uid, cid] = await Promise.all([ + user.getUidByUserslug(actor), + categories.getCidByHandle(actor), + ]); - const isFollowing = await db.isSortedSetMember(type === 'uid' ? `followingRemote:${id}` : `cid:${id}:following`, actor); - if (!isFollowing) { // already not following + actor = uid || cid; + } + + const [isFollowing, isPending] = await Promise.all([ + db.isSortedSetMember(type === 'uid' ? `followingRemote:${id}` : `cid:${id}:following`, actor), + db.isSortedSetMember(`followRequests:${type === 'uid' ? 'uid' : 'cid'}.${id}`, actor), + ]); + + if (!isFollowing && !isPending) { // already not following/pending return; } diff --git a/src/categories/index.js b/src/categories/index.js index 308516cd97..de7ff6d769 100644 --- a/src/categories/index.js +++ b/src/categories/index.js @@ -85,7 +85,13 @@ Categories.getCategoryById = async function (data) { }; Categories.getCidByHandle = async function (handle) { - return await db.sortedSetScore('categoryhandle:cid', handle); + let cid = await db.sortedSetScore('categoryhandle:cid', handle); + if (!cid) { + // remote cids + cid = await db.getObjectField('handle:cid', handle); + } + + return cid; }; Categories.getAllCidsFromSet = async function (key) { diff --git a/src/upgrades/4.3.2/fix_category_sync_null_values.js b/src/upgrades/4.3.2/fix_category_sync_null_values.js new file mode 100644 index 0000000000..e81590cf27 --- /dev/null +++ b/src/upgrades/4.3.2/fix_category_sync_null_values.js @@ -0,0 +1,12 @@ +'use strict'; + +const db = require('../../database'); + +module.exports = { + name: 'Fix null values in category synchronization list', + timestamp: Date.UTC(2025, 4, 8), + method: async () => { + const cids = await db.getSortedSetMembers('categories:cid'); + await db.sortedSetsRemove(cids.map(cid => `followRequests:cid.${cid}`), 'null'); + }, +};