From 5e9d47a1d89cbfde4650067ffdb9709fcd6d2f9f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 7 May 2024 12:15:51 -0400 Subject: [PATCH] feat: serve Tombstone objects for soft deleted posts re: #12551 --- src/activitypub/mocks.js | 18 ++++++++++++++++++ test/activitypub.js | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/activitypub/mocks.js b/src/activitypub/mocks.js index 8019ef207c..78f2b8c4b8 100644 --- a/src/activitypub/mocks.js +++ b/src/activitypub/mocks.js @@ -212,6 +212,18 @@ Mocks.actors.category = async (cid) => { Mocks.note = async (post) => { const id = `${nconf.get('url')}/post/${post.pid}`; + + // Return a tombstone for a deleted post + if (post.deleted === true) { + return Mocks.tombstone({ + id, + formerType: 'Note', + attributedTo: `${nconf.get('url')}/uid/${post.user.uid}`, + context: `${nconf.get('url')}/topic/${post.topic.tid}`, + audience: `${nconf.get('url')}/category/${post.category.cid}`, + }); + } + const published = new Date(parseInt(post.timestamp, 10)).toISOString(); // todo: post visibility @@ -341,3 +353,9 @@ Mocks.note = async (post) => { return object; }; + +Mocks.tombstone = async properties => ({ + '@context': 'https://www.w3.org/ns/activitystreams', + type: 'Tombstone', + ...properties, +}); diff --git a/test/activitypub.js b/test/activitypub.js index 20040a74d6..57712b2341 100644 --- a/test/activitypub.js +++ b/test/activitypub.js @@ -15,6 +15,7 @@ const meta = require('../src/meta'); const user = require('../src/user'); const categories = require('../src/categories'); const topics = require('../src/topics'); +const posts = require('../src/posts'); const activitypub = require('../src/activitypub'); describe('ActivityPub integration', () => { @@ -361,7 +362,7 @@ describe('ActivityPub integration', () => { }); describe('Serving of local assets to remote clients', () => { - describe('Note', () => { + describe.only('Note', () => { let cid; let uid; @@ -415,7 +416,43 @@ describe('ActivityPub integration', () => { }); describe('Soft deleted', () => { + let body; + let response; + let postData; + before(async () => { + ({ postData } = await topics.post({ + uid, + cid, + title: utils.generateUUID(), + content: utils.generateUUID(), + })); + + await posts.delete(postData.pid, uid); + + ({ body, response } = await request.get(`${nconf.get('url')}/post/${postData.pid}`, { + headers: { + Accept: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', + }, + })); + }); + + it('should return a 200 response on an existing post', () => { + assert.strictEqual(response.statusCode, 200); + }); + + it('should return a Tombstone object', () => { + assert.strictEqual(body.type, 'Tombstone'); + }); + + it('should still retain the existing id and former type', () => { + assert.strictEqual(body.id, `${nconf.get('url')}/post/${postData.pid}`); + assert.strictEqual(body.formerType, 'Note'); + }); + + it('should still contain contextual information (context, audience, attributedTo)', () => { + assert(['context', 'audience', 'attributedTo'].every(prop => body.hasOwnProperty(prop) && body[prop])); + }); }); }); });