feat(rust): slash commands and the next wipe, server half (phase 16)
Five read-only commands registered with api.registerSlashCommands: /status, /wipe, /top, /online and /clan (D126). Every refusal is private, and any answer narrower than public (online names, a clan roster) goes to the caller alone (D127). No command asks a sidecar. The next wipe (D128, D130): six nullable columns on rust_servers, a pure nextWipe(row, now) with the zone arithmetic through Intl, computed on every read. The public server shape gains nextWipe; the admin shape gains the stored schedule; PUT /admin/rust/servers/:id takes the six fields and writes them only when wipeRule is present. server/commands joins ci/bundle.json, which checkBundle caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -55,7 +55,8 @@ adminRustRouter.put(
|
||||
'/servers/:id',
|
||||
// #swagger.tags = ['Admin · Rust']
|
||||
// #swagger.summary = 'Create or update a Rust server'
|
||||
// #swagger.description = 'Writes one server row. `sidecarToken` is write-only — send it to set or rotate the credential, and omit it or send an empty string to leave the stored one untouched. The id is the slug every URL under the module carries.'
|
||||
// #swagger.description = 'Writes one server row. `sidecarToken` is write-only — send it to set or rotate the credential, and omit it or send an empty string to leave the stored one untouched. The id is the slug every URL under the module carries. The wipe schedule (`wipeRule`, `wipeDay`, `wipeTime`, `wipeTz`, `wipeAnchor`, `wipeOnceAt`) is written only when `wipeRule` is present, so a body without it leaves the stored schedule alone. `wipeRule` is `none`, `forced`, `weekly` or `biweekly`; a weekly or biweekly rule needs `wipeDay` (0 = Sunday), `wipeTime` (`HH:MM`) and an IANA `wipeTz`, and a biweekly rule a `wipeAnchor` date on that day. `wipeOnceAt` is a one-off wipe in the future. A 400 carries one sentence per problem in `errors`.'
|
||||
/* #swagger.requestBody = { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/RustServerSave" } } } } */
|
||||
/* #swagger.responses[204] = { description: 'Saved' } */
|
||||
/* #swagger.responses[400] = { description: 'Invalid body' } */
|
||||
requireRole('admin'),
|
||||
@@ -72,6 +73,16 @@ adminRustRouter.put(
|
||||
body('protocol').optional().isInt({ min: 1, max: 1000 }).toInt(),
|
||||
body('enabled').optional().isBoolean().toBoolean(),
|
||||
body('sortOrder').optional().isInt({ min: -1000, max: 1000 }).toInt(),
|
||||
// The wipe schedule (phase 16, D130). Shape only here; the rules that span
|
||||
// fields — a day for a weekly rule, an anchor on that day, a known zone, a
|
||||
// one-off date in the future — are `nextWipe.validateSchedule`'s, in the
|
||||
// controller, so the form gets one sentence per problem.
|
||||
body('wipeRule').optional().isIn(['none', 'forced', 'weekly', 'biweekly']),
|
||||
body('wipeDay').optional({ values: 'null' }).isInt({ min: 0, max: 6 }),
|
||||
body('wipeTime').optional({ values: 'null' }).isString().isLength({ max: 5 }),
|
||||
body('wipeTz').optional({ values: 'null' }).isString().isLength({ max: 64 }),
|
||||
body('wipeAnchor').optional({ values: 'falsy' }).isISO8601({ strict: true }).isLength({ max: 10 }),
|
||||
body('wipeOnceAt').optional({ values: 'falsy' }).isISO8601({ strict: true }),
|
||||
validate,
|
||||
admin.putServer,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user