feat(safety): report, block and hide chat lines (MODULE_API 1.21.0)
Some checks failed
PR Checks / client-build (pull_request) Successful in 51s
PR Checks / frozen-manifest (pull_request) Successful in 53s
PR Checks / server-tests (pull_request) Failing after -17s

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:
2026-10-30 09:04:08 -05:00
parent 1fb685fa0f
commit dd9b8b2711
24 changed files with 1182 additions and 25 deletions

View File

@@ -175,6 +175,18 @@ module.exports = {
pushActivity: (items) => need().teams.activity.push(items),
},
// Report, block and hide (MODULE_API.md §2.3, 1.21.0; USER_SAFETY.md S11, S13).
// Read only, both of them. `forViewer(userId)` is what one reader has blocked
// and hidden that touches this module — the accounts they block (already
// checked against staff, S8, and with linked Steam blocks already turned into
// account blocks, S14), this module's own unlinked Steam blocks, and their hides
// on `rust.chat`. `staffAmong(userIds)` is which accounts are staff, for a chat
// line's `canBlock`. Wrapped as calls, like `emit`. See `safety.js`.
safety: {
forViewer: (userId) => need().safety.forViewer(userId),
staffAmong: (userIds) => need().safety.staffAmong(userIds),
},
// Deployment facts. `moduleRoot` is the absolute path to `modules/<id>/` — the
// only correct way to find a file you shipped, because the working directory is
// core's and the module's location is the loader's business.