From 807c3eac12b77cdec1d4f97f24d40dfbe0516a07 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 6 May 2024 15:14:32 -0400 Subject: [PATCH] feat: on post edit, also target anyone who announced the post and their followers re: #12537 --- src/api/activitypub.js | 16 ++++++++++++---- src/upgrades/4.0.0/remote_user_urls.js | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/api/activitypub.js b/src/api/activitypub.js index b91f52277aa6..6af8950c16c6 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -94,13 +94,12 @@ activitypubApi.unfollow = enabledCheck(async (caller, { type, id, actor }) => { activitypubApi.create = {}; // this might be better genericised... tbd. some of to/cc is built in mocks. -async function buildRecipients(object, uid) { +async function buildRecipients(object, { pid, uid }) { const followers = await db.getSortedSetMembers(`followersRemote:${uid}`); let { to, cc } = object; to = new Set(to); cc = new Set(cc); - // Directly address user if inReplyTo const parentId = await posts.getPostField(object.inReplyTo, 'uid'); if (activitypub.helpers.isUri(parentId) && to.has(parentId)) { @@ -111,6 +110,15 @@ async function buildRecipients(object, uid) { targets.delete(`${nconf.get('url')}/uid/${uid}/followers`); // followers URL not targeted targets.delete(activitypub._constants.publicAddress); // public address not targeted + // Announcers and their followers + if (pid) { + const announcers = (await activitypub.notes.announce.list({ pid })).map(({ actor }) => actor); + const announcersFollowers = (await user.getUsersFields(announcers, ['followersUrl'])) + .filter(o => o.hasOwnProperty('followersUrl')) + .map(({ followersUrl }) => followersUrl); + [...announcers, ...announcersFollowers].forEach(uri => targets.add(uri)); + } + object.to = Array.from(to); object.cc = Array.from(cc); return { targets }; @@ -129,7 +137,7 @@ activitypubApi.create.post = enabledCheck(async (caller, { pid }) => { } const object = await activitypub.mocks.note(post); - const { targets } = await buildRecipients(object, post.user.uid); + const { targets } = await buildRecipients(object, { uid: post.user.uid }); const { cid } = post.category; const followers = await activitypub.notes.getCategoryFollowers(cid); @@ -175,7 +183,7 @@ activitypubApi.update.profile = enabledCheck(async (caller, { uid }) => { activitypubApi.update.note = enabledCheck(async (caller, { post }) => { const object = await activitypub.mocks.note(post); - const { targets } = await buildRecipients(object, post.user.uid); + const { targets } = await buildRecipients(object, { pid: post.pid, uid: post.user.uid }); const allowed = await privileges.posts.can('topics:read', post.pid, activitypub._constants.uid); if (!allowed) { diff --git a/src/upgrades/4.0.0/remote_user_urls.js b/src/upgrades/4.0.0/remote_user_urls.js index 9a9aa8b8a30e..9c4a1a192467 100644 --- a/src/upgrades/4.0.0/remote_user_urls.js +++ b/src/upgrades/4.0.0/remote_user_urls.js @@ -15,8 +15,8 @@ module.exports = { let actorIds = await db.getSortedSetMembers('usersRemote:lastCrawled'); progress.total = actorIds.length; - const exists = await Promise.all(actorIds.map(async id => await db.isObjectField(`userRemote:${id}`, 'url'))); - actorIds = actorIds.filter((id, idx) => !exists[idx]); + const exists = await Promise.all(actorIds.map(async id => await db.isObjectFields(`userRemote:${id}`, ['url', 'followersUrl']))); + actorIds = actorIds.filter((id, idx) => !exists[idx].every(Boolean)); // Increment ones that were already completed progress.incr(progress.total - actorIds.length);