mirror of
https://github.com/ancsemi/Haven.git
synced 2026-10-28 17:47:30 +00:00
91 lines
3.8 KiB
JavaScript
91 lines
3.8 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Marking a message NSFW (src/messageNsfw.js): the author marks their own,
|
|
* a moderator marks anyone's, an author cannot lift a moderator's mark, and
|
|
* the mark travels with history and thread replies.
|
|
*
|
|
* node --test test/messageNsfw.integration.test.js
|
|
*/
|
|
|
|
const test = require('node:test');
|
|
const assert = require('node:assert');
|
|
const path = require('node:path');
|
|
const Database = require('better-sqlite3');
|
|
const { createHarness, wait } = require('./socketServerHarness');
|
|
|
|
const PORT = 3496;
|
|
const h = createHarness(PORT, 'message-nsfw');
|
|
|
|
test.before(() => h.start());
|
|
test.after(() => h.stop());
|
|
|
|
test('who may mark a message NSFW', async (t) => {
|
|
const admin = await h.register('admin');
|
|
const bob = await h.register('bob');
|
|
const carol = await h.register('carol');
|
|
const A = await h.connect(admin.token);
|
|
const B = await h.connect(bob.token);
|
|
const C = await h.connect(carol.token);
|
|
const db = new Database(path.join(h.dataDir, 'haven.db'));
|
|
db.pragma('busy_timeout = 5000');
|
|
t.after(() => db.close());
|
|
|
|
A.emit('create-channel', { name: 'talk' });
|
|
let ch;
|
|
for (let i = 0; i < 30 && !ch; i++) {
|
|
ch = db.prepare('SELECT id, code FROM channels WHERE name = ?').get('talk');
|
|
if (!ch) await wait(100);
|
|
}
|
|
assert.ok(ch, 'channel created');
|
|
for (const s of [A, B, C]) { s.emit('join-channel', { code: ch.code }); await wait(100); }
|
|
for (const s of [A, B, C]) s.emit('enter-channel', { code: ch.code });
|
|
await wait(200);
|
|
|
|
const post = (userId, content, threadId = null) => Number(db.prepare('INSERT INTO messages (channel_id, user_id, content, thread_id) VALUES (?, ?, ?, ?)')
|
|
.run(ch.id, userId, content, threadId).lastInsertRowid);
|
|
const mark = (sock, messageId, nsfw) => new Promise((res) => sock.emit('set-message-nsfw', { messageId, nsfw }, res));
|
|
const stored = (id) => db.prepare('SELECT nsfw, nsfw_by FROM messages WHERE id = ?').get(id);
|
|
|
|
const mine = post(bob.id, 'https://example.com/video');
|
|
|
|
// Someone else without moderation rights cannot.
|
|
assert.ok((await mark(C, mine, true)).error, 'carol refused');
|
|
assert.strictEqual(stored(mine).nsfw, 0);
|
|
|
|
// The author can, and everyone in the channel hears about it.
|
|
const heard = new Promise((res) => C.once('message-nsfw', res));
|
|
assert.ok((await mark(B, mine, true)).success);
|
|
const ev = await heard;
|
|
assert.deepStrictEqual({ id: ev.messageId, nsfw: ev.nsfw, code: ev.channelCode }, { id: mine, nsfw: true, code: ch.code });
|
|
|
|
// History carries it, and only on the marked message.
|
|
const plain = post(bob.id, 'plain');
|
|
const hist = await new Promise((res) => { C.once('message-history', res); C.emit('get-messages', { code: ch.code }); });
|
|
assert.strictEqual(hist.messages.find((m) => m.id === mine).nsfw, true);
|
|
assert.ok(!('nsfw' in hist.messages.find((m) => m.id === plain)), 'nothing extra on ordinary messages');
|
|
|
|
// The author lifts their own mark.
|
|
assert.ok((await mark(B, mine, false)).success);
|
|
assert.strictEqual(stored(mine).nsfw, 0);
|
|
|
|
// A moderator's mark stays until a moderator lifts it.
|
|
assert.ok((await mark(A, mine, true)).success, 'the admin marks anyone\'s');
|
|
assert.ok((await mark(B, mine, false)).error, 'the author cannot lift it');
|
|
assert.strictEqual(stored(mine).nsfw, 1);
|
|
const audit = db.prepare("SELECT action FROM audit_log WHERE action = 'message_nsfw_on'").get();
|
|
assert.ok(audit, 'the moderator\'s mark is in the audit log');
|
|
assert.ok((await mark(A, mine, false)).success);
|
|
assert.strictEqual(stored(mine).nsfw, 0);
|
|
|
|
// Thread replies carry it too.
|
|
const reply = post(bob.id, 'in a thread', plain);
|
|
assert.ok((await mark(B, reply, true)).success);
|
|
const th = await new Promise((res) => { C.once('thread-messages', res); C.emit('get-thread-messages', { parentId: plain }); });
|
|
assert.strictEqual(th.messages.find((m) => m.id === reply).nsfw, true);
|
|
|
|
A.disconnect();
|
|
B.disconnect();
|
|
C.disconnect();
|
|
});
|