2024-05-09 15:48:58 -04:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
const assert = require('assert');
|
2025-02-26 12:29:36 -05:00
|
|
|
const nconf = require('nconf');
|
2024-05-09 15:48:58 -04:00
|
|
|
|
2025-02-28 13:36:54 -05:00
|
|
|
const db = require('../mocks/databasemock');
|
2025-02-25 14:24:56 -05:00
|
|
|
const meta = require('../../src/meta');
|
|
|
|
|
const install = require('../../src/install');
|
2024-05-09 15:48:58 -04:00
|
|
|
const user = require('../../src/user');
|
|
|
|
|
const categories = require('../../src/categories');
|
2025-02-26 12:29:36 -05:00
|
|
|
const posts = require('../../src/posts');
|
2024-05-09 15:48:58 -04:00
|
|
|
const topics = require('../../src/topics');
|
|
|
|
|
const activitypub = require('../../src/activitypub');
|
|
|
|
|
const utils = require('../../src/utils');
|
|
|
|
|
|
2025-02-26 12:29:36 -05:00
|
|
|
const helpers = require('./helpers');
|
|
|
|
|
|
2024-05-09 15:48:58 -04:00
|
|
|
describe('Notes', () => {
|
2025-02-25 14:24:56 -05:00
|
|
|
describe('Assertion', () => {
|
|
|
|
|
before(async () => {
|
|
|
|
|
meta.config.activitypubEnabled = 1;
|
|
|
|
|
await install.giveWorldPrivileges();
|
|
|
|
|
});
|
|
|
|
|
|
2025-02-26 12:29:36 -05:00
|
|
|
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();
|
2025-02-26 13:06:31 -05:00
|
|
|
const assertion = await activitypub.notes.assert(0, id, { skipChecks: true });
|
|
|
|
|
assert(assertion);
|
|
|
|
|
|
|
|
|
|
const { tid, count } = assertion;
|
|
|
|
|
assert(tid);
|
2025-02-26 12:29:36 -05:00
|
|
|
assert.strictEqual(count, 1);
|
|
|
|
|
|
|
|
|
|
const exists = await topics.exists(tid);
|
|
|
|
|
assert(exists);
|
2025-02-25 14:24:56 -05:00
|
|
|
});
|
|
|
|
|
|
2025-02-26 12:29:36 -05:00
|
|
|
it('should assert if the cc property is missing', async () => {
|
|
|
|
|
const { id } = helpers.mocks.note({ cc: 'remove' });
|
2025-02-26 13:06:31 -05:00
|
|
|
const assertion = await activitypub.notes.assert(0, id, { skipChecks: true });
|
|
|
|
|
assert(assertion);
|
|
|
|
|
|
|
|
|
|
const { tid, count } = assertion;
|
|
|
|
|
assert(tid);
|
|
|
|
|
assert.strictEqual(count, 1);
|
|
|
|
|
|
|
|
|
|
const exists = await topics.exists(tid);
|
|
|
|
|
assert(exists);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should assert if the object is of type Video', async () => {
|
|
|
|
|
const { id } = helpers.mocks.note({
|
|
|
|
|
type: 'Video',
|
|
|
|
|
});
|
|
|
|
|
const assertion = await activitypub.notes.assert(0, id, { skipChecks: true });
|
|
|
|
|
assert(assertion);
|
|
|
|
|
|
|
|
|
|
const { tid, count } = assertion;
|
|
|
|
|
assert(tid);
|
2025-02-26 12:29:36 -05:00
|
|
|
assert.strictEqual(count, 1);
|
2025-02-25 14:24:56 -05:00
|
|
|
|
2025-02-26 12:29:36 -05:00
|
|
|
const exists = await topics.exists(tid);
|
|
|
|
|
assert(exists);
|
|
|
|
|
});
|
2025-02-25 14:24:56 -05:00
|
|
|
});
|
|
|
|
|
|
2025-02-26 12:29:36 -05:00
|
|
|
describe('Private objects', () => {
|
|
|
|
|
let recipientUid;
|
|
|
|
|
|
|
|
|
|
before(async () => {
|
|
|
|
|
recipientUid = await user.create({ username: utils.generateUUID().slice(0, 8) });
|
2025-02-25 14:24:56 -05:00
|
|
|
});
|
|
|
|
|
|
2025-02-26 12:29:36 -05:00
|
|
|
it('should NOT create a new topic or post when asserting a private note', async () => {
|
|
|
|
|
const { id, note } = helpers.mocks.note({
|
|
|
|
|
to: [`${nconf.get('url')}/uid/${recipientUid}`],
|
|
|
|
|
cc: [],
|
|
|
|
|
});
|
|
|
|
|
const { activity } = helpers.mocks.create(note);
|
|
|
|
|
const { roomId } = await activitypub.inbox.create({ body: activity });
|
|
|
|
|
assert(roomId);
|
|
|
|
|
assert(utils.isNumber(roomId));
|
|
|
|
|
|
|
|
|
|
const exists = await posts.exists(id);
|
|
|
|
|
assert(!exists);
|
|
|
|
|
});
|
2025-02-25 14:24:56 -05:00
|
|
|
|
2025-02-26 12:29:36 -05:00
|
|
|
it('should still assert if the cc property is missing', async () => {
|
|
|
|
|
const { id, note } = helpers.mocks.note({
|
|
|
|
|
to: [`${nconf.get('url')}/uid/${recipientUid}`],
|
|
|
|
|
cc: 'remove',
|
|
|
|
|
});
|
|
|
|
|
const { activity } = helpers.mocks.create(note);
|
|
|
|
|
const { roomId } = await activitypub.inbox.create({ body: activity });
|
|
|
|
|
assert(roomId);
|
|
|
|
|
assert(utils.isNumber(roomId));
|
|
|
|
|
});
|
2025-02-25 14:24:56 -05:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2024-05-09 15:48:58 -04:00
|
|
|
describe('Inbox Synchronization', () => {
|
|
|
|
|
let cid;
|
|
|
|
|
let uid;
|
|
|
|
|
let topicData;
|
|
|
|
|
|
|
|
|
|
before(async () => {
|
|
|
|
|
({ cid } = await categories.create({ name: utils.generateUUID().slice(0, 8) }));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
|
uid = await user.create({ username: utils.generateUUID().slice(0, 10) });
|
|
|
|
|
({ topicData } = await topics.post({
|
|
|
|
|
cid,
|
|
|
|
|
uid,
|
|
|
|
|
title: utils.generateUUID(),
|
|
|
|
|
content: utils.generateUUID(),
|
|
|
|
|
}));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should add a topic to a user\'s inbox if user is a recipient in OP', async () => {
|
|
|
|
|
await db.setAdd(`post:${topicData.mainPid}:recipients`, [uid]);
|
|
|
|
|
await activitypub.notes.syncUserInboxes(topicData.tid);
|
|
|
|
|
const inboxed = await db.isSortedSetMember(`uid:${uid}:inbox`, topicData.tid);
|
|
|
|
|
|
|
|
|
|
assert.strictEqual(inboxed, true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should add a topic to a user\'s inbox if a user is a recipient in a reply', async () => {
|
|
|
|
|
const uid = await user.create({ username: utils.generateUUID().slice(0, 10) });
|
|
|
|
|
const { pid } = await topics.reply({
|
|
|
|
|
tid: topicData.tid,
|
|
|
|
|
uid,
|
|
|
|
|
content: utils.generateUUID(),
|
|
|
|
|
});
|
|
|
|
|
await db.setAdd(`post:${pid}:recipients`, [uid]);
|
|
|
|
|
await activitypub.notes.syncUserInboxes(topicData.tid);
|
|
|
|
|
const inboxed = await db.isSortedSetMember(`uid:${uid}:inbox`, topicData.tid);
|
|
|
|
|
|
|
|
|
|
assert.strictEqual(inboxed, true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should maintain a list of recipients at the topic level', async () => {
|
|
|
|
|
await db.setAdd(`post:${topicData.mainPid}:recipients`, [uid]);
|
|
|
|
|
await activitypub.notes.syncUserInboxes(topicData.tid);
|
|
|
|
|
const [isRecipient, count] = await Promise.all([
|
|
|
|
|
db.isSetMember(`tid:${topicData.tid}:recipients`, uid),
|
|
|
|
|
db.setCount(`tid:${topicData.tid}:recipients`),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
assert(isRecipient);
|
|
|
|
|
assert.strictEqual(count, 1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should add topic to a user\'s inbox if it is explicitly passed in as an argument', async () => {
|
|
|
|
|
await activitypub.notes.syncUserInboxes(topicData.tid, uid);
|
|
|
|
|
const inboxed = await db.isSortedSetMember(`uid:${uid}:inbox`, topicData.tid);
|
|
|
|
|
|
|
|
|
|
assert.strictEqual(inboxed, true);
|
|
|
|
|
});
|
2024-07-05 12:00:19 -04:00
|
|
|
|
|
|
|
|
it('should remove a topic from a user\'s inbox if that user is no longer a recipient in any contained posts', async () => {
|
|
|
|
|
await activitypub.notes.syncUserInboxes(topicData.tid, uid);
|
|
|
|
|
await activitypub.notes.syncUserInboxes(topicData.tid);
|
|
|
|
|
const inboxed = await db.isSortedSetMember(`uid:${uid}:inbox`, topicData.tid);
|
|
|
|
|
|
|
|
|
|
assert.strictEqual(inboxed, false);
|
|
|
|
|
});
|
2024-05-09 15:48:58 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('Deletion', () => {
|
|
|
|
|
let cid;
|
|
|
|
|
let uid;
|
|
|
|
|
let topicData;
|
|
|
|
|
|
|
|
|
|
before(async () => {
|
|
|
|
|
({ cid } = await categories.create({ name: utils.generateUUID().slice(0, 8) }));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
|
uid = await user.create({ username: utils.generateUUID().slice(0, 10) });
|
|
|
|
|
({ topicData } = await topics.post({
|
|
|
|
|
cid,
|
|
|
|
|
uid,
|
|
|
|
|
title: utils.generateUUID(),
|
|
|
|
|
content: utils.generateUUID(),
|
|
|
|
|
}));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should clean up recipient sets for the post', async () => {
|
|
|
|
|
const { pid } = await topics.reply({
|
|
|
|
|
pid: `https://example.org/${utils.generateUUID().slice(0, 8)}`,
|
|
|
|
|
tid: topicData.tid,
|
|
|
|
|
uid,
|
|
|
|
|
content: utils.generateUUID(),
|
|
|
|
|
});
|
|
|
|
|
await db.setAdd(`post:${pid}:recipients`, [uid]);
|
|
|
|
|
await activitypub.notes.delete([pid]);
|
|
|
|
|
|
|
|
|
|
const inboxed = await db.isSetMember(`post:${pid}:recipients`, uid);
|
|
|
|
|
assert(!inboxed);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|