feat: update Remove(Context) to use target instead of origin, federate out Move(Context) on topic move between local cids

This commit is contained in:
Julian Lam
2025-10-22 15:04:47 -04:00
parent 3ede64d8a1
commit d02e188a5f
4 changed files with 49 additions and 13 deletions

View File

@@ -86,14 +86,12 @@ inbox.remove = async (req) => {
if (!isContext) { if (!isContext) {
return; // don't know how to handle other types return; // don't know how to handle other types
} }
console.log('isContext?', isContext);
const mainPid = await activitypub.contexts.getItems(0, object.id, { returnRootId: true }); const mainPid = await activitypub.contexts.getItems(0, object.id, { returnRootId: true });
const exists = await posts.exists(mainPid); const exists = await posts.exists(mainPid);
if (!exists) { if (!exists) {
return; // post not cached; do nothing. return; // post not cached; do nothing.
} }
console.log('mainPid is', mainPid);
// Ensure that cid is same-origin as the actor // Ensure that cid is same-origin as the actor
const tid = await posts.getPostField(mainPid, 'tid'); const tid = await posts.getPostField(mainPid, 'tid');

View File

@@ -533,7 +533,7 @@ ActivityPub.buildRecipients = async function (object, { pid, uid, cid }) {
* - Builds a list of targets for activitypub.send to consume * - Builds a list of targets for activitypub.send to consume
* - Extends to and cc since the activity can be addressed more widely * - Extends to and cc since the activity can be addressed more widely
* - Optional parameters: * - Optional parameters:
* - `cid`: includes followers of the passed-in cid (local only) * - `cid`: includes followers of the passed-in cid (local only, can also be an array)
* - `uid`: includes followers of the passed-in uid (local only) * - `uid`: includes followers of the passed-in uid (local only)
* - `pid`: includes post announcers and all topic participants * - `pid`: includes post announcers and all topic participants
*/ */
@@ -551,12 +551,15 @@ ActivityPub.buildRecipients = async function (object, { pid, uid, cid }) {
} }
if (cid) { if (cid) {
cid = Array.isArray(cid) ? cid : [cid];
await Promise.all(cid.map(async (cid) => {
const cidFollowers = await ActivityPub.notes.getCategoryFollowers(cid); const cidFollowers = await ActivityPub.notes.getCategoryFollowers(cid);
followers = followers.concat(cidFollowers); followers = followers.concat(cidFollowers);
const followersUrl = `${nconf.get('url')}/category/${cid}/followers`; const followersUrl = `${nconf.get('url')}/category/${cid}/followers`;
if (!to.has(followersUrl)) { if (!to.has(followersUrl)) {
cc.add(followersUrl); cc.add(followersUrl);
} }
}));
} }
const targets = new Set([...followers, ...to, ...cc]); const targets = new Set([...followers, ...to, ...cc]);

View File

@@ -351,10 +351,9 @@ Out.remove.context = enabledCheck(async (uid, tid) => {
const { to, cc, targets } = await activitypub.buildRecipients({ const { to, cc, targets } = await activitypub.buildRecipients({
to: [activitypub._constants.publicAddress], to: [activitypub._constants.publicAddress],
cc: [`${nconf.get('url')}/category/${cid}/followers`], cc: [],
}, { cid }); }, { cid });
// Remove(Context)
await activitypub.send('uid', uid, Array.from(targets), { await activitypub.send('uid', uid, Array.from(targets), {
id: `${nconf.get('url')}/topic/${tid}#activity/remove/${now.getTime()}`, id: `${nconf.get('url')}/topic/${tid}#activity/remove/${now.getTime()}`,
type: 'Remove', type: 'Remove',
@@ -362,7 +361,43 @@ Out.remove.context = enabledCheck(async (uid, tid) => {
to, to,
cc, cc,
object: `${nconf.get('url')}/topic/${tid}`, object: `${nconf.get('url')}/topic/${tid}`,
origin: `${nconf.get('url')}/category/${cid}`, target: `${nconf.get('url')}/category/${cid}`,
});
});
Out.move = {};
Out.move.context = enabledCheck(async (uid, tid) => {
// Federates Move(Context); where Context is the tid
const now = new Date();
const { cid, oldCid } = await topics.getTopicFields(tid, ['cid', 'oldCid']);
// This check may be revised if inter-community moderation becomes real.
const isNotLocal = id => !utils.isNumber(cid) || parseInt(cid, 10) < 1;
if ([cid, oldCid].some(isNotLocal)) {
return;
}
const allowed = await privileges.categories.can('topics:read', cid, activitypub._constants.uid);
if (!allowed) {
activitypub.helpers.log(`[activitypub/api] Not federating move of tid ${tid} to the fediverse due to privileges.`);
return;
}
const { to, cc, targets } = await activitypub.buildRecipients({
to: [activitypub._constants.publicAddress],
cc: [],
}, { cid: [cid, oldCid] });
await activitypub.send('uid', uid, Array.from(targets), {
id: `${nconf.get('url')}/topic/${tid}#activity/move/${now.getTime()}`,
type: 'Move',
actor: `${nconf.get('url')}/uid/${uid}`,
to,
cc,
object: `${nconf.get('url')}/topic/${tid}`,
origin: `${nconf.get('url')}/category/${oldCid}`,
target: `${nconf.get('url')}/category/${cid}`,
}); });
}); });

View File

@@ -326,7 +326,7 @@ topicsAPI.move = async (caller, { tid, cid }) => {
activitypub.out.remove.context(caller.uid, tid); activitypub.out.remove.context(caller.uid, tid);
// tbd: activitypubApi.undo.announce? // tbd: activitypubApi.undo.announce?
} else { } else {
// tbd: activitypubApi.move activitypub.out.move.context(caller.uid, tid);
activitypub.out.announce.category(tid); activitypub.out.announce.category(tid);
} }
} }