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:
@@ -13,6 +13,7 @@
|
||||
|
||||
import { ErrorState, Loading } from '../core.js'
|
||||
import Empty from './Empty.jsx'
|
||||
import ChatMenu from './ChatMenu.jsx'
|
||||
import { describe, FILTERS, kindsFor } from '../lib/feed.js'
|
||||
import { ago, clock } from '../lib/format.js'
|
||||
import usePolled from '../hooks/usePolled.js'
|
||||
@@ -32,7 +33,7 @@ const TONE = {
|
||||
export default function Feed({ serverId, wipeId, filter, onFilter }) {
|
||||
const kinds = kindsFor(filter)
|
||||
|
||||
const { data, error, loading, at } = usePolled(
|
||||
const { data, error, loading, at, refresh } = usePolled(
|
||||
() => api.servers.events(serverId, { kinds, wipe: wipeId, limit: 100 }),
|
||||
// The key is the QUESTION. Changing server, wipe or filter blanks the rows,
|
||||
// because what is on screen is an answer to a different one; a poll tick
|
||||
@@ -111,10 +112,14 @@ export default function Feed({ serverId, wipeId, filter, onFilter }) {
|
||||
key={event.id}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
gap: 12,
|
||||
alignItems: 'baseline',
|
||||
padding: '7px 0',
|
||||
borderBottom: '1px solid var(--line-soft, var(--line))',
|
||||
// Staff's hidden line (S10): only staff ever get one, dimmed
|
||||
// and marked so the hide can be checked and undone here.
|
||||
opacity: event.hidden ? 0.6 : 1,
|
||||
}}
|
||||
>
|
||||
<time
|
||||
@@ -137,7 +142,17 @@ export default function Feed({ serverId, wipeId, filter, onFilter }) {
|
||||
{line.detail}
|
||||
</span>
|
||||
)}
|
||||
{event.hidden && (
|
||||
<span className="sans" style={{ color: 'var(--mode-maint, #e6c26a)', fontSize: '0.74rem' }}>
|
||||
{' · '}
|
||||
Hidden by staff
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
{/* Report, Hide for me, Block player, and staff's Hide for
|
||||
everyone (USER_SAFETY.md §4.2). The server filtered the feed
|
||||
for this reader, so after any of them the feed is re-read. */}
|
||||
<ChatMenu line={event} onChanged={refresh} />
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user