feat(safety): report, block and hide chat lines (MODULE_API 1.21.0)
USER_SAFETY.md step 3, the module half of report, block and hide. - server/safety.js registers the rust.chat report target (snapshot for one reader, null when they could not have seen the line; staff's hide and unhide) and the steam game identity (ownersOf from rust_account_links). - The events feed filters chat per reader, in the query: lines from a blocked account's Steam ids, the reader's unlinked Steam-ID blocks and the lines they hid. Signed-in readers get canBlock on each chat line (false for their own and for staff-linked players). Lines staff hid for everyone are left out for everyone but staff, who get them with hidden: true. - rust_events gains hidden_at and hidden_by (ALTER ... IF NOT EXISTS). - POST /admin/rust/chat/:id/hide and /unhide (admin, moderator), logged. - The feed's chat lines get a menu: Report, Hide for me, Block player, and for staff Hide for everyone / Show to everyone again. - coreApi ^1.21.0; ci/core-ref.json pinned to the website#233 merge; routes.manifest.json and swagger-fragment.json regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
45
client/test/safety.test.js
Normal file
45
client/test/safety.test.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// ── A chat line's menu (USER_SAFETY.md §4.2) ───────────────────────────────
|
||||
//
|
||||
// The server decides what a reader sees and whether a line's speaker can be
|
||||
// blocked; this asks that the menu shows exactly what it said, and nothing a
|
||||
// signed-out reader could use.
|
||||
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
|
||||
import { CHAT_TARGET, HIDE_ROLES, REPORT_REASONS, chatActions } from '../src/lib/safety.js'
|
||||
|
||||
const chat = (extra = {}) => ({ id: 1, kind: 'player.chat', steamId: '7656', frame: { name: 'Rusty', message: 'gg' }, ...extra })
|
||||
|
||||
test('the target is the one the server registers', () => {
|
||||
assert.equal(CHAT_TARGET, 'rust.chat')
|
||||
})
|
||||
|
||||
test('the six reasons are core’s report enum', () => {
|
||||
assert.deepEqual(REPORT_REASONS.map(([value]) => value).sort(), ['abuse', 'illegal', 'impersonation', 'other', 'sexual', 'spam'])
|
||||
assert.ok(REPORT_REASONS.every(([, label]) => typeof label === 'string' && label.length > 0))
|
||||
})
|
||||
|
||||
test('a signed-out reader is told to sign in, and offered nothing else (S6)', () => {
|
||||
assert.deepEqual(chatActions(chat({ canBlock: true }), null), { signIn: true, report: false, hide: false, block: false, staff: null })
|
||||
})
|
||||
|
||||
test('a member can report and hide any line, and block only where the server said so', () => {
|
||||
const member = { role: 'player' }
|
||||
assert.deepEqual(chatActions(chat({ canBlock: true }), member), { signIn: false, report: true, hide: true, block: true, staff: null })
|
||||
assert.equal(chatActions(chat({ canBlock: false }), member).block, false)
|
||||
// A line with no word from the server is not blockable.
|
||||
assert.equal(chatActions(chat(), member).block, false)
|
||||
})
|
||||
|
||||
test('admins and moderators can hide for everyone, and undo it; editors cannot', () => {
|
||||
assert.deepEqual([...HIDE_ROLES].sort(), ['admin', 'moderator'])
|
||||
assert.equal(chatActions(chat(), { role: 'moderator' }).staff, 'hide')
|
||||
assert.equal(chatActions(chat({ hidden: true }), { role: 'admin' }).staff, 'unhide')
|
||||
assert.equal(chatActions(chat(), { role: 'editor' }).staff, null)
|
||||
})
|
||||
|
||||
test('only chat lines have a menu', () => {
|
||||
assert.equal(chatActions({ id: 2, kind: 'player.death' }, { role: 'player' }), null)
|
||||
assert.equal(chatActions(null, { role: 'player' }), null)
|
||||
})
|
||||
Reference in New Issue
Block a user