refactor: remove announceObject in favour of feps.announce, added create activity mock to support

This commit is contained in:
Julian Lam
2025-03-11 12:27:26 -04:00
parent 866cd5398f
commit 74443c3b15
6 changed files with 84 additions and 59 deletions

View File

@@ -3,7 +3,6 @@
const nconf = require('nconf');
const posts = require('../posts');
const utils = require('../utils');
const activitypub = module.parent.exports;
const Feps = module.exports;
@@ -53,36 +52,3 @@ Feps.announce = async function announce(id, activity) {
object: activity,
});
};
Feps.announceObject = async function announceObject(id) {
let localId;
if (String(id).startsWith(nconf.get('url'))) {
({ id: localId } = await activitypub.helpers.resolveLocalId(id));
}
const cid = await posts.getCidByPid(localId || id);
if (cid === -1) {
return;
}
const followers = await activitypub.notes.getCategoryFollowers(cid);
if (!followers.length) {
return;
}
let author = await posts.getPostField(id, 'uid');
if (utils.isNumber(author)) {
author = `${nconf.get('url')}/uid/${author}`;
} else if (!author.startsWith(nconf.get('url'))) {
followers.unshift(author);
}
activitypub.helpers.log(`[activitypub/inbox.announce(1b12)] Announcing object (${id}) to followers of cid ${cid}`);
await activitypub.send('cid', cid, followers, {
id: `${nconf.get('url')}/post/${encodeURIComponent(id)}#activity/announce/${Date.now()}`,
type: 'Announce',
actor: `${nconf.get('url')}/category/${cid}`,
to: [`${nconf.get('url')}/category/${cid}/followers`],
cc: [author, activitypub._constants.publicAddress],
object: utils.isNumber(id) ? `${nconf.get('url')}/post/${id}` : id,
});
};

View File

@@ -754,6 +754,38 @@ Mocks.notes.private = async ({ messageObj }) => {
return object;
};
Mocks.activities = {};
Mocks.activities.create = async (pid, uid, post) => {
// Local objects only, post optional
if (!utils.isNumber(pid)) {
throw new Error('[[error:invalid-pid]]');
}
if (!post) {
post = (await posts.getPostSummaryByPids([pid], uid, { stripTags: false })).pop();
if (!post) {
throw new Error('[[error:invalid-pid]]');
}
}
const object = await activitypub.mocks.notes.public(post);
const { to, cc, targets } = await activitypub.buildRecipients(object, { pid, uid: post.user.uid });
object.to = to;
object.cc = cc;
const activity = {
id: `${object.id}#activity/create/${Date.now()}`,
type: 'Create',
actor: object.attributedTo,
to,
cc,
object,
};
return { activity, targets };
};
Mocks.tombstone = async properties => ({
'@context': 'https://www.w3.org/ns/activitystreams',
type: 'Tombstone',

View File

@@ -124,23 +124,11 @@ activitypubApi.create.note = enabledCheck(async (caller, { pid, post }) => {
return;
}
const object = await activitypub.mocks.notes.public(post);
const { to, cc, targets } = await activitypub.buildRecipients(object, { pid, uid: post.user.uid });
object.to = to;
object.cc = cc;
const payload = {
id: `${object.id}#activity/create/${Date.now()}`,
type: 'Create',
actor: object.attributedTo,
to,
cc,
object,
};
const { payload: activity, targets } = await activitypub.mocks.activities.create(pid, caller.uid, post);
await Promise.all([
activitypub.send('uid', caller.uid, Array.from(targets), payload),
activitypub.feps.announce(pid, payload),
activitypub.send('uid', caller.uid, Array.from(targets), activity),
activitypub.feps.announce(pid, activity),
activitypubApi.add(caller, { pid }),
]);
});

View File

@@ -342,7 +342,8 @@ topicsAPI.move = async (caller, { tid, cid }) => {
if (!topicData.deleted) {
socketHelpers.sendNotificationToTopicOwner(tid, caller.uid, 'move', 'notifications:moved-your-topic');
activitypubApi.announce.note(caller, { tid });
activitypub.feps.announceObject(topicData.mainPid);
const { activity } = await activitypub.mocks.activities.create(topicData.mainPid, caller.uid);
await activitypub.feps.announce(topicData.mainPid, activity);
}
await events.log({

View File

@@ -88,9 +88,11 @@ module.exports = function (Topics) {
}),
db.sortedSetsAdd(['topics:votes', `cid:${cid}:tids:votes`], mainPost.votes, tid),
Topics.events.log(fromTid, { type: 'fork', uid, href: `/topic/${tid}` }),
activitypub.feps.announceObject(pids[0]),
]);
const { activity } = await activitypub.mocks.activities.create(pids[0], uid);
await activitypub.feps.announce(pids[0], activity);
plugins.hooks.fire('action:topic.fork', { tid, fromTid, uid });
return await Topics.getTopicData(tid);

View File

@@ -22,8 +22,8 @@ describe('FEPs', () => {
await install.giveWorldPrivileges();
});
describe.only('1b12', () => {
describe('announceObject()', () => {
describe('1b12', () => {
describe('announce()', () => {
let cid;
let uid;
let adminUid;
@@ -49,7 +49,7 @@ describe('FEPs', () => {
});
it('should be called when a topic is moved from uncategorized to another category', async () => {
const { topicData } = await topics.post({
const { topicData, postData } = await topics.post({
uid,
cid: -1,
title: utils.generateUUID(),
@@ -63,7 +63,13 @@ describe('FEPs', () => {
cid,
});
assert.strictEqual(activitypub._sent.size, 1);
assert.strictEqual(activitypub._sent.size, 2);
const key = Array.from(activitypub._sent.keys())[0];
const activity = activitypub._sent.get(key);
assert(activity && activity.object && typeof activity.object === 'object');
assert.strictEqual(activity.object.id, `${nconf.get('url')}/post/${postData.pid}`);
});
it('should be called for a newly forked topic', async () => {
@@ -78,17 +84,47 @@ describe('FEPs', () => {
topics.reply({ uid, tid, content: utils.generateUUID() }),
topics.reply({ uid, tid, content: utils.generateUUID() }),
]);
const forked = await topics.createTopicFromPosts(
await topics.createTopicFromPosts(
adminUid, utils.generateUUID(), [reply1Pid, reply2Pid], tid, cid
);
assert.strictEqual(activitypub._sent.size, 1);
assert.strictEqual(activitypub._sent.size, 2);
const key = Array.from(activitypub._sent.keys())[0];
const activity = activitypub._sent.get(key);
assert(activity);
assert.strictEqual(activity.object, `${nconf.get('url')}/post/${reply1Pid}`);
assert(activity && activity.object && typeof activity.object === 'object');
assert.strictEqual(activity.object.id, `${nconf.get('url')}/post/${reply1Pid}`);
});
// it('should be called when a post is moved to another topic', async () => {
//
// });
});
describe('announceObject()', () => {
let cid;
let uid;
let adminUid;
before(async () => {
const name = utils.generateUUID();
const description = utils.generateUUID();
({ cid } = await categories.create({ name, description }));
adminUid = await user.create({ username: utils.generateUUID() });
await groups.join('administrators', adminUid);
uid = await user.create({ username: utils.generateUUID() });
const { id: followerId, actor } = helpers.mocks.actor();
activitypub._cache.set(`0;${followerId}`, actor);
user.setCategoryWatchState(followerId, [cid], categories.watchStates.tracking);
activitypub._sent.clear();
});
afterEach(() => {
activitypub._sent.clear();
});
});
});