// /player/reports — file a report about any reportable item (USER_SAFETY.md §4.1). // // One route for every target: core's forum types and every module's registered // types (`rust.chat`, …). The forum's own `/teams/:slug/forum/report` keeps // working and goes through the same model. // // A signed-in account is required (S6), which the player group's gate gives: // a queue anybody with `curl` could fill is a queue staff stop reading. const express = require('express') const { body } = require('express-validator') const reports = require('../../../model/reports/contentReports.model') const validate = require('../../../middleware/validate') const { makeLimiter } = require('../../../middleware/rateLimit') const log = require('../../../utils/logger')('reports') const reportsRouter = express.Router() // The forum report route's cap, for the forum report route's reason (TEAMS.md // §5.6's third rule): a report costs the reporter nothing and costs a staffer // attention. const reportLimiter = makeLimiter({ windowMs: 60 * 60 * 1000, max: 10, label: 'content-report', message: 'Too many reports. Please give staff a chance to look at the ones you have raised.', }) async function createReport(req, res) { try { const result = await reports.file({ actor: req.user, targetType: req.body.targetType, targetId: req.body.targetId, reason: req.body.reason, detail: req.body.detail, }) if (!result.ok) return res.status(result.status || 400).json({ message: result.error }) return res.json({ ok: true, reportId: result.reportId }) } catch (err) { if (err.status === 503) return res.status(503).json({ message: 'The game module did not answer. Try again in a moment.' }) log.error('file report failed', { message: err.message }) return res.status(500).json({ message: 'Internal Server Error' }) } } reportsRouter.post( '/', // #swagger.tags = ['Player · Reports'] // #swagger.summary = 'Report an item to site staff' // #swagger.description = 'Files a report about a forum thread, post or upload, or a game module’s item (e.g. `rust.chat`, a Rust chat line; MODULE_API 1.21.0). The reporter must be able to see the item: one they cannot see answers 404, the same as one that does not exist. Filing changes nothing about the item; it opens a row in the staff Reports queue with a snapshot of what the item said, which outlives the item. Reports reach site staff and nobody else.' /* #swagger.requestBody = { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ReportRequest" } } } } */ // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }] /* #swagger.responses[200] = { description: 'Raised', content: { "application/json": { schema: { type: 'object', properties: { ok: { type: 'boolean' }, reportId: { type: 'integer' } } } } } } */ /* #swagger.responses[400] = { description: 'Unknown target type or reason', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */ /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */ /* #swagger.responses[404] = { description: 'No such item, or not one this account can see', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */ /* #swagger.responses[409] = { description: 'You already have an open report on this', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */ /* #swagger.responses[429] = { description: 'Too many reports (rate limited)', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */ /* #swagger.responses[503] = { description: 'The game module that owns the item did not answer', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */ reportLimiter, body('targetType').isString().trim().isLength({ min: 1, max: 32 }), body('targetId').isInt({ min: 1 }).toInt(), body('reason').isIn(reports.REASONS), body('detail').optional().isString().trim().isLength({ max: 500 }), validate, createReport, ) module.exports = reportsRouter