feat: federate Delete on post delete as well as purge, topic deletion federates Announce(Delete(Object))

This commit is contained in:
Julian Lam
2025-10-06 13:45:40 -04:00
parent 923ddbc1f1
commit 93b6cb5984
4 changed files with 69 additions and 1 deletions

View File

@@ -350,7 +350,7 @@ activitypubApi.announce = {};
activitypubApi.announce.note = enabledCheck(async (caller, { tid }) => {
const { mainPid: pid, cid } = await topics.getTopicFields(tid, ['mainPid', 'cid']);
// Only remote posts can be announced to real categories
// Only remote posts can be announced to local categories
if (utils.isNumber(pid) || parseInt(cid, 10) === -1) {
return;
}
@@ -379,6 +379,63 @@ activitypubApi.announce.note = enabledCheck(async (caller, { tid }) => {
});
});
activitypubApi.announce.delete = enabledCheck(async ({ uid }, { tid }) => {
const now = new Date();
const { mainPid: pid, cid } = await topics.getTopicFields(tid, ['mainPid', 'cid']);
// Only local categories
if (!utils.isNumber(cid) || parseInt(cid, 10) < 1) {
return;
}
const allowed = await privileges.categories.can('topics:read', cid, activitypub._constants.uid);
if (!allowed) {
activitypub.helpers.log(`[activitypub/api] Not federating announce of pid ${pid} to the fediverse due to privileges.`);
return;
}
const { to, cc, targets } = await activitypub.buildRecipients({
to: [activitypub._constants.publicAddress],
cc: [`${nconf.get('url')}/category/${cid}/followers`],
}, { cid });
const deleteTpl = {
id: `${nconf.get('url')}/topic/${tid}#activity/delete/${now.getTime()}`,
type: 'Delete',
actor: `${nconf.get('url')}/category/${cid}`,
to,
cc,
origin: `${nconf.get('url')}/category/${cid}`,
};
// 7888 variant
await activitypub.send('cid', cid, Array.from(targets), {
id: `${nconf.get('url')}/topic/${tid}#activity/announce/delete/${now.getTime()}`,
type: 'Announce',
actor: `${nconf.get('url')}/category/${cid}`,
to,
cc,
object: {
...deleteTpl,
object: `${nconf.get('url')}/topic/${tid}`,
},
});
// 1b12 variant
await activitypub.send('cid', cid, Array.from(targets), {
id: `${nconf.get('url')}/post/${encodeURIComponent(pid)}#activity/announce/delete/${now.getTime()}`,
type: 'Announce',
actor: `${nconf.get('url')}/category/${cid}`,
to,
cc,
object: {
...deleteTpl,
actor: `${nconf.get('url')}/uid/${uid}`,
object: utils.isNumber(pid) ? `${nconf.get('url')}/post/${pid}` : pid,
},
});
});
activitypubApi.undo = {};
// activitypubApi.undo.follow =

View File

@@ -34,6 +34,7 @@ module.exports = function (Posts) {
await Promise.all([
topics.updateLastPostTimeFromLastPid(postData.tid),
topics.updateTeaser(postData.tid),
isDeleting ? activitypub.notes.delete(pid) : null,
isDeleting ?
db.sortedSetRemove(`cid:${topicData.cid}:pids`, pid) :
db.sortedSetAdd(`cid:${topicData.cid}:pids`, postData.timestamp, pid),

View File

@@ -8,6 +8,7 @@ const categories = require('../categories');
const flags = require('../flags');
const plugins = require('../plugins');
const batch = require('../batch');
const api = require('../api');
const utils = require('../utils');
module.exports = function (Topics) {
@@ -80,6 +81,7 @@ module.exports = function (Topics) {
}
deletedTopic.tags = tags;
await deleteFromFollowersIgnorers(tid);
await api.activitypub.announce.delete({ uid }, { tid }),
await Promise.all([
db.deleteAll([

View File

@@ -7,6 +7,7 @@ const topics = require('.');
const categories = require('../categories');
const user = require('../user');
const plugins = require('../plugins');
const api = require('../api');
const privileges = require('../privileges');
const utils = require('../utils');
@@ -277,6 +278,13 @@ module.exports = function (Topics) {
const oldCid = topicData.cid;
await categories.moveRecentReplies(tid, oldCid, cid);
// AP: Announce(Delete(Object))
if (cid === -1) {
await api.activitypub.announce.delete({ uid: data.uid }, { tid });
} else {
// tbd: api.activitypub.announce.move
}
await Promise.all([
Topics.setTopicFields(tid, {
cid: cid,