diff --git a/src/activitypub/mocks.js b/src/activitypub/mocks.js index c9bcaedd9a..8ebec0cee8 100644 --- a/src/activitypub/mocks.js +++ b/src/activitypub/mocks.js @@ -720,7 +720,8 @@ Mocks.notes.public = async (post) => { * audience is exposed as part of 1b12 but is now ignored by Lemmy. * Remove this and most references to audience in 2026. */ - let audience = `${nconf.get('url')}/category/${post.category.cid}`; // default + let audience = utils.isNumber(post.category.cid) ? // default + `${nconf.get('url')}/category/${post.category.cid}` : post.category.cid; if (inReplyTo) { const chain = await activitypub.notes.getParentChain(post.uid, inReplyTo); chain.forEach((post) => { diff --git a/src/api/activitypub.js b/src/api/activitypub.js index a6ba295b06..39cf3e5534 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -129,7 +129,7 @@ activitypubApi.create.note = enabledCheck(async (caller, { pid, post }) => { await Promise.all([ activitypub.send('uid', caller.uid, Array.from(targets), activity), activitypub.feps.announce(pid, activity), - // activitypubApi.add(caller, { pid }), + // utils.isNumber(post.cid) ? activitypubApi.add(caller, { pid }) : undefined, ]); }); diff --git a/src/api/topics.js b/src/api/topics.js index 572183a195..7a8ed44203 100644 --- a/src/api/topics.js +++ b/src/api/topics.js @@ -87,9 +87,7 @@ topicsAPI.create = async function (caller, data) { socketHelpers.notifyNew(caller.uid, 'newTopic', { posts: [result.postData], topic: result.topicData }); if (!isScheduling) { - setTimeout(() => { - activitypubApi.create.note(caller, { pid: result.postData.pid }); - }, 5000); + await activitypubApi.create.note(caller, { pid: result.postData.pid }); } return result.topicData; diff --git a/test/activitypub/actors.js b/test/activitypub/actors.js index cd683b6a92..d33524abf8 100644 --- a/test/activitypub/actors.js +++ b/test/activitypub/actors.js @@ -159,7 +159,7 @@ describe('Group assertion', () => { }); it('should contain an entry in categories search zset', async () => { - const exists = await db.isSortedSetMember('categories:name', `${actorData.preferredUsername.toLowerCase()}:${actorUri}`); + const exists = await db.isSortedSetMember('categories:name', `${actorData.name.toLowerCase()}:${actorUri}`); assert(exists); }); @@ -545,9 +545,10 @@ describe('Pruning', () => { const { id: uid } = helpers.mocks.person(); await activitypub.actors.assert([uid]); + const total = await db.sortedSetCard('usersRemote:lastCrawled'); const result = await activitypub.actors.prune(); - assert.strictEqual(result.counts.deleted, 1); + assert.strictEqual(result.counts.deleted, total); assert.strictEqual(result.counts.preserved, 0); assert.strictEqual(result.counts.missing, 0); }); @@ -591,10 +592,11 @@ describe('Pruning', () => { const { id: cid } = helpers.mocks.group(); await activitypub.actors.assertGroup([cid]); + const total = await db.sortedSetCard('usersRemote:lastCrawled'); const result = await activitypub.actors.prune(); assert.strictEqual(result.counts.deleted, 1); - assert.strictEqual(result.counts.preserved, 0); + assert.strictEqual(result.counts.preserved, total - 1); }); it('should do nothing if the category has topics in it', async () => { @@ -606,10 +608,11 @@ describe('Pruning', () => { }); await activitypub.notes.assert(0, id); + const total = await db.sortedSetCard('usersRemote:lastCrawled'); const result = await activitypub.actors.prune(); assert.strictEqual(result.counts.deleted, 0); - assert.strictEqual(result.counts.preserved, 1); + assert.strictEqual(result.counts.preserved, total); assert(result.preserved.has(cid)); }); }); diff --git a/test/activitypub/helpers.js b/test/activitypub/helpers.js index dc2e491086..4bb3abe385 100644 --- a/test/activitypub/helpers.js +++ b/test/activitypub/helpers.js @@ -28,8 +28,8 @@ Helpers.mocks.person = (override = {}) => { outbox: `${id}/outbox`, type: 'Person', - name: slugify(uuid), - preferredUsername: uuid, + name: slugify(id), + preferredUsername: id, publicKey: { id: `${id}#key`, diff --git a/test/activitypub/notes.js b/test/activitypub/notes.js index 5157bc5645..543fb255db 100644 --- a/test/activitypub/notes.js +++ b/test/activitypub/notes.js @@ -17,12 +17,12 @@ const utils = require('../../src/utils'); const helpers = require('./helpers'); describe('Notes', () => { - describe('Assertion', () => { - before(async () => { - meta.config.activitypubEnabled = 1; - await install.giveWorldPrivileges(); - }); + before(async () => { + meta.config.activitypubEnabled = 1; + await install.giveWorldPrivileges(); + }); + describe('Assertion', () => { describe('Public objects', () => { it('should pull a remote root-level object by its id and create a new topic', async () => { const { id } = helpers.mocks.note(); @@ -229,6 +229,103 @@ describe('Notes', () => { }); }); + describe('Creation', () => { + let uid; + + before(async () => { + uid = await user.create({ username: utils.generateUUID() }); + }); + + describe('Local categories', () => { + let cid; + + before(async () => { + ({ cid } = await categories.create({ name: utils.generateUUID() })); + }); + + afterEach(() => { + activitypub._sent.clear(); + }); + + describe('new topics', () => { + let activity; + + before(async () => { + const { tid } = await api.topics.create({ uid }, { + cid, + title: utils.generateUUID(), + content: utils.generateUUID(), + }); + + assert(tid); + assert.strictEqual(activitypub._sent.size, 1); + const key = Array.from(activitypub._sent.keys())[0]; + activity = activitypub._sent.get(key); + }); + + it('should federate out a Create activity', () => { + assert(activity && activity.to); + assert.strictEqual(activity.type, 'Create'); + }); + + it('should have the local category addressed', () => { + const addressees = new Set([ + ...(activity.to || []), + ...(activity.cc || []), + ...(activity.bcc || []), + ...(activity.object.to || []), + ...(activity.object.cc || []), + ...(activity.object.bcc || []), + ]); + + assert(addressees.has(`${nconf.get('url')}/category/${cid}`)); + }); + }); + }); + + describe('Remote Categories', () => { + let cid; + + before(async () => { + ({ id: cid } = helpers.mocks.group()); + await activitypub.actors.assert([cid]); + }); + + afterEach(() => { + activitypub._sent.clear(); + }); + + describe('new topics', () => { + it('should federate out a Create activity with the remote community addressed', async () => { + const { tid } = await api.topics.create({ uid }, { + cid, + title: utils.generateUUID(), + content: utils.generateUUID(), + }); + + assert(tid); + assert.strictEqual(activitypub._sent.size, 1); + + const key = Array.from(activitypub._sent.keys())[0]; + const activity = activitypub._sent.get(key); + assert(activity && activity.to); + assert.strictEqual(activity.type, 'Create'); + + const addressees = new Set([ + ...(activity.to || []), + ...(activity.cc || []), + ...(activity.bcc || []), + ...(activity.object.to || []), + ...(activity.object.cc || []), + ...(activity.object.bcc || []), + ]); + + assert(addressees.has(cid)); + }); + }); + }); + }); + describe('Inbox Synchronization', () => { let cid; let uid;