USER_SAFETY.md step 2 (core), with S11-S14 decided while building it. - Reports: POST /player/reports takes any target type, core's forum types or a module's registered ones. One resolver (model/safety/targets.js) answers "what is this item, for this reader" and 404s an item the reader cannot see. Every report stores content_reports.snapshot; the queue shows a module item from it. - Hide for everyone: POST /admin/moderation/reports/:id/hide hides the item through its own moderation (forum hide as staff, or the module's hide) and actions the report with actioned_with = 'hide'. - Blocks (user_blocks) name an item, never a person, and land on the author's account first (S12); an unlinked game identity is blocked as itself and becomes an account block once linked (S14). Staff cannot be blocked; a block on someone later promoted stops applying (S8). - Hide for me (user_hidden_items), /auth/me/blocks and /auth/me/hidden. - Forum reads filter blocked authors and hidden items on the server and carry canBlock per thread and post. - MODULE_API 1.21.0: api.registerReportTargets, api.registerGameIdentities, ctx.safety.forViewer and ctx.safety.staffAmong, so a module filters its own per-viewer feeds on the server (S11) and marks lines canBlock (S13). - Web: Hide for me / Block author in the forum menus, a Blocked section on both account pages, Hide for everyone in the Reports queue. - Tests, OpenAPI, route/guard/engagement manifests regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
86 lines
2.5 KiB
JavaScript
86 lines
2.5 KiB
JavaScript
// /auth/me/blocks and /auth/me/hidden — a member's own blocks and hides
|
|
// (USER_SAFETY.md §4.1). Self-scoped on req.user.id; requireAuth is the group's.
|
|
|
|
const safety = require('../../../model/safety/userSafety.model')
|
|
const log = require('../../../utils/logger')('safety')
|
|
|
|
const fail = (res, err, what) => {
|
|
if (err && err.status === 503) {
|
|
return res.status(503).json({ code: 'module_unavailable', message: 'The game module did not answer. Try again in a moment.' })
|
|
}
|
|
log.error(`${what} failed`, { message: err.message })
|
|
return res.status(500).json({ message: 'Internal Server Error' })
|
|
}
|
|
|
|
const refused = (res, result) => res.status(result.status || 400).json({ code: result.code, message: result.error })
|
|
|
|
async function listBlocks(req, res) {
|
|
try {
|
|
return res.json({ blocks: await safety.listBlocks(req.user) })
|
|
} catch (err) {
|
|
return fail(res, err, 'list blocks')
|
|
}
|
|
}
|
|
|
|
async function createBlock(req, res) {
|
|
try {
|
|
const result = await safety.blockAuthorOf({
|
|
actor: req.user,
|
|
targetType: req.body.targetType,
|
|
targetId: req.body.targetId,
|
|
})
|
|
if (!result.ok) return refused(res, result)
|
|
return res.status(201).json({ block: result.block })
|
|
} catch (err) {
|
|
return fail(res, err, 'create block')
|
|
}
|
|
}
|
|
|
|
async function deleteBlock(req, res) {
|
|
try {
|
|
const result = await safety.unblock(req.user, Number(req.params.id))
|
|
if (!result.ok) return refused(res, result)
|
|
return res.json({ ok: true })
|
|
} catch (err) {
|
|
return fail(res, err, 'delete block')
|
|
}
|
|
}
|
|
|
|
async function listHidden(req, res) {
|
|
try {
|
|
return res.json({ hidden: await safety.listHidden(req.user) })
|
|
} catch (err) {
|
|
return fail(res, err, 'list hidden')
|
|
}
|
|
}
|
|
|
|
async function createHidden(req, res) {
|
|
try {
|
|
const result = await safety.hide(req.user, req.body.targetType, req.body.targetId)
|
|
if (!result.ok) return refused(res, result)
|
|
return res.json({ ok: true })
|
|
} catch (err) {
|
|
return fail(res, err, 'hide item')
|
|
}
|
|
}
|
|
|
|
async function deleteHidden(req, res) {
|
|
try {
|
|
const result = await safety.unhide(req.user, req.params.targetType, Number(req.params.targetId))
|
|
if (!result.ok) return refused(res, result)
|
|
return res.json({ ok: true })
|
|
} catch (err) {
|
|
return fail(res, err, 'unhide item')
|
|
}
|
|
}
|
|
|
|
async function clearHidden(req, res) {
|
|
try {
|
|
return res.json({ ok: true, cleared: await safety.clearHidden(req.user) })
|
|
} catch (err) {
|
|
return fail(res, err, 'clear hidden')
|
|
}
|
|
}
|
|
|
|
module.exports = { listBlocks, createBlock, deleteBlock, listHidden, createHidden, deleteHidden, clearHidden }
|