fix: regression where topic moves during Announce(Create(Note)) stopped working, added test for #14040, fix broken AP test helper mock

This commit is contained in:
Julian Lam
2026-03-26 12:04:40 -04:00
parent 781ed3447b
commit 4d3211caba
5 changed files with 70 additions and 17 deletions

View File

@@ -53,7 +53,7 @@ inbox.create = async (req) => {
cid = Array.from(cids)[0];
}
const asserted = await activitypub.notes.assert(0, object, { cid });
const asserted = await activitypub.notes.assert(req.uid || 0, object, { cid });
if (asserted) {
await activitypub.feps.announce(object.id, req.body);
// api.activitypub.add(req, { pid: object.id });
@@ -461,7 +461,7 @@ inbox.announce = async (req) => {
return;
}
const assertion = await activitypub.notes.assert(0, pid, { cid, skipChecks: true });
const assertion = await activitypub.notes.assert(req.uid || 0, pid, { cid, skipChecks: true });
if (!assertion) {
return;
}

View File

@@ -121,7 +121,7 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => {
if (options.cid && cid === -1) {
// Move topic if currently uncategorized
await api.topics.move({ uid: 'system' }, { tid, cid: options.cid });
await topics.tools.move(tid, { cid: options.cid, uid: 'system' });
}
const exists = await posts.exists(chain.map(p => p.pid));

View File

@@ -233,7 +233,7 @@ module.exports = function (Topics) {
};
topicTools.move = async function (tid, data) {
const cid = parseInt(data.cid, 10);
const cid = utils.isNumber(data.cid) ? parseInt(data.cid, 10) : data.cid;
const topicData = await Topics.getTopicData(tid);
if (!topicData) {
throw new Error('[[error:no-topic]]');
@@ -241,7 +241,7 @@ module.exports = function (Topics) {
if (cid === topicData.cid) {
throw new Error('[[error:cant-move-topic-to-same-category]]');
}
if (!utils.isNumber(cid) || !utils.isNumber(topicData.cid)) {
if (data.uid !== 'system' && (!utils.isNumber(cid) || !utils.isNumber(topicData.cid))) {
throw new Error('[[error:cant-move-topic-to-from-remote-categories]]');
}

View File

@@ -55,12 +55,13 @@ Helpers.mocks.group = (override = {}) => {
type: 'Group',
...override,
});
const { hostname } = new URL(id);
activitypub._cache.set(`0;${id}`, actor);
activitypub.helpers._webfingerCache.set(`${actor.preferredUsername}@example.org`, {
activitypub.helpers._webfingerCache.set(`${actor.preferredUsername}@${hostname}`, {
actorUri: id,
username: id,
hostname: 'example.org',
hostname,
});
return { id, actor };

View File

@@ -183,20 +183,72 @@ describe('Inbox', () => {
});
describe('(Create)', () => {
it('should create a new topic in a remote category if addressed', async () => {
const { id: remoteCid } = helpers.mocks.group();
const { id, note } = helpers.mocks.note({
audience: [remoteCid],
describe('newly-discovered topic', () => {
before(async function () {
const { id: remoteCid } = helpers.mocks.group();
const { id, note } = helpers.mocks.note({
audience: [remoteCid],
});
this.id = id;
this.remoteCid = remoteCid;
let { activity } = helpers.mocks.create(note);
({ activity } = helpers.mocks.announce({ actor: remoteCid, object: activity }));
await activitypub.inbox.announce({ body: activity });
});
let { activity } = helpers.mocks.create(note);
({ activity } = helpers.mocks.announce({ actor: remoteCid, object: activity }));
await activitypub.inbox.announce({ body: activity });
it('should create a new topic in a remote category if addressed', async function () {
assert(await posts.exists(this.id));
assert(await posts.exists(id));
const cid = await posts.getCidByPid(this.id);
assert.strictEqual(cid, this.remoteCid);
});
});
const cid = await posts.getCidByPid(id);
assert.strictEqual(cid, remoteCid);
describe.only('known topic in cid -1 (author domain != announcer domain)', async () => {
/**
* This happens if follower receives object from microblog user before the community announces it.
* It's probably more likely to occur because the Create(Note) is a single hop whereas the reflected
* Announce(Create(Note)) takes two hops.
*
* If the author and announcer domain are the same, the object should already be correctly classified.
*/
before(async function () {
const { id: remoteCid } = helpers.mocks.group({
id: `https://example.social/${utils.generateUUID()}`,
});
await activitypub.actors.assertGroup([remoteCid]);
const uid = await user.create({ username: utils.generateUUID().slice(0, 10) });
this.uid = uid;
this.remoteCid = remoteCid;
});
it('should create a topic in cid -1', async function () {
const { id, note } = helpers.mocks.note({
to: [activitypub._constants.publicAddress, this.remoteCid],
});
const { activity } = helpers.mocks.create(note);
await activitypub.inbox.create({ uid: this.uid, body: activity });
this.id = id;
this.note = note;
this.activity = activity;
const cid = await posts.getCidByPid(this.id);
assert.strictEqual(cid, -1);
});
it('should handle the Announce(Create) from the remote category', async function () {
const { activity } = helpers.mocks.announce({ actor: this.remoteCid, object: this.activity });
await activitypub.inbox.announce({ uid: this.uid, body: activity });
});
it('should be categorized in the remote category', async function () {
const cid = await posts.getCidByPid(this.id);
assert.strictEqual(cid, this.remoteCid);
});
});
});