From 8b4efb2cb90c7662b197d7f8538563a76fa06099 Mon Sep 17 00:00:00 2001 From: D4rkst3r Date: Fri, 4 Sep 2026 10:58:47 +0200 Subject: [PATCH] feat(bot): Whitelist-Rolle kommt vom Panel, nicht aus der Umgebung Zwei Aenderungen, die zusammengehoeren. 1. darfWhitelist las ein Feld, das es nicht mehr gibt ------------------------------------------------------ /person im Spielserver nimmt jetzt das zu pruefende Recht als Parameter und antwortet mit `darf` statt mit `darfWhitelist`. Der alte Zugriff haette ab sofort still immer false ergeben - also: jeder im Team ausgesperrt, ohne eine Fehlermeldung, die darauf hindeutet. `person()` nimmt das Recht jetzt optional mit; ohne Recht bleibt der Aufruf, was er war. 2. Die Rollen-ID stand an zwei Orten ------------------------------------ Sie muss zu der passen, die der Spielserver prueft. Stimmen sie nicht ueberein, zeigt /whitelist status "hat die Rolle" fuer eine Rolle, die den Zutritt gar nicht oeffnet - ein Fehler, der wie eine richtige Antwort aussieht. Deshalb wird sie nur noch an EINEM Ort eingetragen: auf der Einstellungsseite des Adminpanels. Der Bot holt sie ueber /bot/config, 30 Sekunden gepuffert. Ein Fehlschlag wird NICHT gepuffert, sonst bliebe eine Stoerung eine halbe Minute stehen, nachdem sie vorbei ist. WHITELIST_ROLE_ID bleibt als Rueckfall, damit der Befehl auch dann noch etwas anzeigen kann, wenn das Panel nicht antwortet. Co-Authored-By: Claude Opus 5 --- docker-compose.yml | 8 +++++-- src/bot/commands/whitelist.js | 34 ++++++++++++++++++++++-------- src/panel.js | 39 +++++++++++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index cf061d2..d906dbd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -49,8 +49,12 @@ services: # eingerichtet" sagt. ACP_URL: ${ACP_URL:-} ACP_BOT_TOKEN: ${ACP_BOT_TOKEN:-} - # Die Discord-Rolle, die den Zutritt oeffnet. Muss dieselbe sein, die der - # Spielserver prueft (Convar d4rk_discord:role). + # Die Discord-Rolle, die den Zutritt oeffnet. NUR NOCH RUECKFALL: seit + # dem 04.09.2026 holt der Bot sie vom Adminpanel (/bot/config), wo sie + # auf der Seite "Einstellungen" eingetragen wird. Was dort steht, gewinnt. + # + # Der Rueckfall bleibt, damit /whitelist auch dann noch etwas anzeigen + # kann, wenn das Panel gerade nicht antwortet. WHITELIST_ROLE_ID: ${WHITELIST_ROLE_ID:-} # HTTP-Endpoint für Gitea-Webhooks + Webinterface # NPM leitet bot.d4rkst3r.de → host.docker.internal:3080 diff --git a/src/bot/commands/whitelist.js b/src/bot/commands/whitelist.js index 9120e05..cf3f8ba 100644 --- a/src/bot/commands/whitelist.js +++ b/src/bot/commands/whitelist.js @@ -24,13 +24,27 @@ // gemessen hat, ist ein Schreibbefehl ins Ungewisse. import { SlashCommandBuilder, MessageFlags } from 'discord.js'; -import { person, panelBereit, darfWhitelist } from '../../panel.js'; +import { person, panelBereit, darfWhitelist, konfig } from '../../panel.js'; -// Die Rollen-ID kommt aus derselben Umgebung wie der Rest der Botkonfiguration. -// Sie ist kein Geheimnis, aber sie muss zu der passen, die der Spielserver -// prüft (`d4rk_discord:role`) — stimmen sie nicht überein, zeigt dieser Befehl -// „hat die Rolle" für eine Rolle, die den Zutritt gar nicht öffnet. -const WHITELIST_ROLLE = process.env.WHITELIST_ROLE_ID || ''; +/* + DIE ROLLEN-ID STEHT IM PANEL, NICHT HIER. + + Sie ist kein Geheimnis, aber sie muss zu der passen, die der Spielserver + prüft (`d4rk_discord:role`) — stimmen sie nicht überein, zeigt dieser Befehl + „hat die Rolle" für eine Rolle, die den Zutritt gar nicht öffnet. Genau + deshalb wird sie an EINEM Ort eingetragen: auf der Einstellungsseite des + Adminpanels. + + Die Umgebungsvariable bleibt als Rückfall, damit der Bot auch dann läuft, + wenn das Panel gerade nicht antwortet. +*/ +async function whitelistRolle() { + const k = await konfig(); + + if (k.ok && k.whitelistRolle) return k.whitelistRolle; + + return process.env.WHITELIST_ROLE_ID || ''; +} const GRUENDE = { nicht_eingerichtet: @@ -99,16 +113,18 @@ export async function execute(interaction) { Verbindung. Wer sie hier vom Server erwartet, bekommt eine Antwort, die geraten wäre. */ - let rolleText = 'nicht prüfbar — `WHITELIST_ROLE_ID` ist nicht gesetzt'; + const rolle = await whitelistRolle(); - if (WHITELIST_ROLLE) { + let rolleText = 'nicht prüfbar — im Adminpanel ist keine Whitelist-Rolle eingetragen'; + + if (rolle) { const mitglied = await interaction.guild?.members .fetch(ziel.id) .catch(() => null); rolleText = !mitglied ? 'nicht auf diesem Discord' - : mitglied.roles.cache.has(WHITELIST_ROLLE) + : mitglied.roles.cache.has(rolle) ? '**ja**' : '**nein**'; } diff --git a/src/panel.js b/src/panel.js index 838e6c0..4661e71 100644 --- a/src/panel.js +++ b/src/panel.js @@ -74,8 +74,11 @@ async function hole(weg) { * fehlende Quelle als „nichts gefunden" zu lesen wäre der Fehler, den diese * Flags verhindern. */ -export async function person(discordId) { - const a = await hole(`person?discord=${encodeURIComponent(discordId)}`); +export async function person(discordId, recht) { + // `recht` ist optional. Wird eines mitgegeben, prueft der Spielserver es + // gleich mit und legt `darf` in die Antwort - eine Frage, eine Runde. + const zusatz = recht ? `&recht=${encodeURIComponent(recht)}` : ''; + const a = await hole(`person?discord=${encodeURIComponent(discordId)}${zusatz}`); if (!a.ok) return a; @@ -91,12 +94,40 @@ export async function person(discordId) { * Beides wäre geraten, also wird es unterschieden. */ export async function darfWhitelist(discordId) { - const p = await person(discordId); + const p = await person(discordId, 'd4rk.whitelist'); if (!p.ok) return { bekannt: false, grund: p.grund }; if (p.rolleGelesen === false) return { bekannt: false, grund: 'rechtesystem_stumm' }; if (!p.rolle) return { bekannt: true, darf: false, grund: 'keine_rolle' }; if (p.rechtGelesen === false) return { bekannt: false, grund: 'recht_nicht_lesbar' }; - return { bekannt: true, darf: p.darfWhitelist === true, rolle: p.rolle }; + return { bekannt: true, darf: p.darf === true, rolle: p.rolle }; +} + +/** + * Die Einstellungen, die im Panel eingetragen sind. + * + * WARUM DER BOT SIE NICHT SELBST FUEHRT: sonst stuende die Whitelist-Rolle an + * zwei Orten — hier in der Umgebung und dort auf der Seite. Zwei Orte fuer + * dieselbe Wahrheit heisst, dass eine Aenderung eine der beiden vergisst, und + * der Fehler sieht dann aus wie „die Rolle wird nicht erkannt". + * + * Kurz gepuffert, damit nicht jeder Befehl eine Runde ueber das Netz macht. + * Ein Fehlschlag wird NICHT gepuffert — sonst bliebe eine Stoerung eine Minute + * lang stehen, nachdem sie vorbei ist. + */ +let konfigStand = null; +let konfigZeit = 0; + +export async function konfig() { + if (konfigStand && Date.now() - konfigZeit < 30000) return konfigStand; + + const a = await hole('config'); + + if (!a.ok) return a; + + konfigStand = a; + konfigZeit = Date.now(); + + return a; }