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:
@@ -14,6 +14,7 @@ const core = require('../../core')
|
||||
|
||||
const db = require('../../model/servers/servers.db')
|
||||
const mapImages = require('../../mapImages')
|
||||
const nextWipe = require('../../model/servers/nextWipe')
|
||||
const servers = require('../../model/servers/servers.model')
|
||||
const sidecar = require('../../sidecarClient')
|
||||
|
||||
@@ -28,6 +29,29 @@ async function listServers(req, res) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The wipe schedule a save carries (phase 16, D130), normalised for storage — or
|
||||
* `null` when the body carries none, which leaves the stored one alone.
|
||||
*
|
||||
* Only the fields the rule reads are kept: a weekly rule's day left behind after
|
||||
* the operator switched to `forced` would be a value nothing reads and the form
|
||||
* would show back to them as if it meant something.
|
||||
*/
|
||||
function scheduleFrom(body) {
|
||||
if (body.wipeRule === undefined) return null
|
||||
const rule = body.wipeRule
|
||||
const weekly = rule === 'weekly' || rule === 'biweekly'
|
||||
const blank = (v) => v === undefined || v === null || v === ''
|
||||
return {
|
||||
wipeRule: rule,
|
||||
wipeDay: weekly ? Number(body.wipeDay) : null,
|
||||
wipeTime: weekly ? body.wipeTime : null,
|
||||
wipeTz: weekly ? body.wipeTz : null,
|
||||
wipeAnchor: rule === 'biweekly' ? body.wipeAnchor : null,
|
||||
wipeOnceAt: blank(body.wipeOnceAt) ? null : new Date(body.wipeOnceAt),
|
||||
}
|
||||
}
|
||||
|
||||
async function putServer(req, res) {
|
||||
const { id } = req.params
|
||||
const { name, sidecarBaseUrl, sidecarToken, protocol, enabled, sortOrder } = req.body
|
||||
@@ -43,6 +67,13 @@ async function putServer(req, res) {
|
||||
return res.status(400).json({ message: 'A new server needs its sidecar token' })
|
||||
}
|
||||
|
||||
// Checked whole before anything is written, so a bad schedule saves nothing
|
||||
// rather than half a row. The sentences go back as they are: the form shows
|
||||
// them beside the fields.
|
||||
const schedule = scheduleFrom(req.body)
|
||||
const problems = schedule ? nextWipe.validateSchedule(req.body) : []
|
||||
if (problems.length) return res.status(400).json({ message: problems.join(' '), errors: problems })
|
||||
|
||||
await db.upsertServer({
|
||||
id,
|
||||
name,
|
||||
@@ -56,6 +87,7 @@ async function putServer(req, res) {
|
||||
enabled: enabled === undefined ? true : enabled,
|
||||
sortOrder: sortOrder === undefined ? 0 : sortOrder,
|
||||
})
|
||||
if (schedule) await db.setSchedule(id, schedule)
|
||||
|
||||
await core.activity.log({
|
||||
req,
|
||||
@@ -66,6 +98,9 @@ async function putServer(req, res) {
|
||||
sidecarBaseUrl,
|
||||
// Whether the credential was rotated, never the credential.
|
||||
tokenChanged: Boolean(sidecarToken),
|
||||
// The schedule as written, when the save carried one. Nothing in it is a
|
||||
// secret, and "who moved the wipe" is a question players will ask.
|
||||
...(schedule ? { schedule: { ...schedule, wipeOnceAt: schedule.wipeOnceAt ? schedule.wipeOnceAt.toISOString() : null } } : {}),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -183,4 +218,4 @@ async function renderMap(req, res) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { listServers, putServer, deleteServer, testServer, fetchMap, renderMap }
|
||||
module.exports = { scheduleFrom, listServers, putServer, deleteServer, testServer, fetchMap, renderMap }
|
||||
|
||||
Reference in New Issue
Block a user