From f6cc556d37bd2289709b79f9dd70212b8656342e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 29 Dec 2025 14:32:34 -0500 Subject: [PATCH] fix: topic crosspost delete and purge handling --- src/topics/crossposts.js | 10 +++++++ src/topics/delete.js | 1 + test/topics/crossposts.js | 60 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/src/topics/crossposts.js b/src/topics/crossposts.js index ce2bcda93a..72cff44424 100644 --- a/src/topics/crossposts.js +++ b/src/topics/crossposts.js @@ -127,4 +127,14 @@ Crossposts.remove = async function (tid, cid, uid) { crossposts = await Crossposts.get(tid); return crossposts; +}; + +Crossposts.removeAll = async function (tid) { + const crosspostIds = await db.getSortedSetMembers(`tid:${tid}:crossposts`); + const crossposts = await db.getObjects(crosspostIds.map(id => `crosspost:${id}`)); + await Promise.all(crossposts.map(async ({ tid, cid, uid }) => { + return Crossposts.remove(tid, cid, uid); + })); + + return []; }; \ No newline at end of file diff --git a/src/topics/delete.js b/src/topics/delete.js index 466d25a0dd..03e756e1fd 100644 --- a/src/topics/delete.js +++ b/src/topics/delete.js @@ -102,6 +102,7 @@ module.exports = function (Topics) { Topics.deleteTopicTags(tid), Topics.events.purge(tid), Topics.thumbs.deleteAll(tid), + Topics.crossposts.removeAll(tid), reduceCounters(tid), ]); plugins.hooks.fire('action:topic.purge', { topic: deletedTopic, uid: uid }); diff --git a/test/topics/crossposts.js b/test/topics/crossposts.js index a018973a50..542e5b22a7 100644 --- a/test/topics/crossposts.js +++ b/test/topics/crossposts.js @@ -288,6 +288,66 @@ describe('Crossposting (& related logic)', () => { }); }); + describe('Deletion', () => { + let tid; + let cid1; + let cid2; + let uid; + + before(async () => { + ({ cid: cid1 } = await categories.create({ name: utils.generateUUID().slice(0, 8) })); + const crosspostCategory = await categories.create({ name: utils.generateUUID().slice(0, 8) }); + cid2 = crosspostCategory.cid; + uid = await user.create({ username: utils.generateUUID().slice(0, 8) }); + const { topicData } = await topics.post({ + uid, + cid: cid1, + title: utils.generateUUID(), + content: utils.generateUUID(), + }); + tid = topicData.tid; + + await topics.crossposts.add(tid, cid2, uid); + await topics.delete(tid, uid); + }); + + it('should maintain crossposts when topic is deleted', async () => { + const crossposts = await topics.crossposts.get(tid); + assert(Array.isArray(crossposts)); + assert.strictEqual(crossposts.length, 1); + }); + }); + + describe('Purging', () => { + let tid; + let cid1; + let cid2; + let uid; + + before(async () => { + ({ cid: cid1 } = await categories.create({ name: utils.generateUUID().slice(0, 8) })); + const crosspostCategory = await categories.create({ name: utils.generateUUID().slice(0, 8) }); + cid2 = crosspostCategory.cid; + uid = await user.create({ username: utils.generateUUID().slice(0, 8) }); + const { topicData } = await topics.post({ + uid, + cid: cid1, + title: utils.generateUUID(), + content: utils.generateUUID(), + }); + tid = topicData.tid; + + await topics.crossposts.add(tid, cid2, uid); + await topics.purge(tid, uid); + }); + + it('should remove crossposts when topic is purged', async () => { + const crossposts = await topics.crossposts.get(tid); + assert(Array.isArray(crossposts)); + assert.strictEqual(crossposts.length, 0); + }); + }); + describe('ActivityPub effects (or lack thereof)', () => { describe('local canonical category', () => { let tid;