Files
d4rkbot/src/bot/client.js
T
D4rkst3randClaude Opus 4.8 71d2bb07f1 Devlog-Löschung: Discord-Delete-Sync + Admin-Button im Webinterface
- MessageDelete-Listener (mit Partials): in Discord gelöschte Devlogs verschwinden
  automatisch aus dem Archiv, inkl. lokaler Bilder
- DELETE /api/devlogs/:id (nur Admin) + ✕-Button auf den Karten (nur für Admin sichtbar)
- Anlass: Test-Post mit Commit-Liste von vor der Prosa-Sperre stand noch im Archiv

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 01:16:44 +02:00

96 lines
3.8 KiB
JavaScript

// Discord-Client: Commands laden, registrieren und Interactions verarbeiten
import { Client, Collection, Events, GatewayIntentBits, Partials, REST, Routes } from 'discord.js';
import { config } from '../config.js';
import { archiveDevlogMessage, removeDevlog } from './devlog-archive.js';
import * as ping from './commands/ping.js';
import * as devlogBackfill from './commands/devlog-backfill.js';
// Alle Commands hier eintragen — jedes Modul exportiert { data, execute }
const commandModules = [ping, devlogBackfill];
export async function startBot() {
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
// Für das Devlog-Archiv: Nachrichten im Devlog-Kanal mitlesen
// (erfordert aktivierten "Message Content Intent" im Developer Portal!)
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
// Partials, damit MessageDelete auch für ungecachte (ältere) Nachrichten feuert
partials: [Partials.Message],
});
// Commands in Collection ablegen für schnellen Zugriff im Interaction-Handler
client.commands = new Collection();
for (const command of commandModules) {
client.commands.set(command.data.name, command);
}
client.once(Events.ClientReady, async (readyClient) => {
console.log(`[bot] Eingeloggt als ${readyClient.user.tag}`);
await registerCommands();
});
// Live-Archivierung: neue Devlogs (Webhook-Posts im Devlog-Kanal) sofort sichern
client.on(Events.MessageCreate, async (message) => {
if (message.channelId !== config.devlogChannelId) return;
try {
if (await archiveDevlogMessage(message)) {
console.log(`[devlog] Neues Devlog archiviert (${message.id})`);
}
} catch (error) {
console.error('[devlog] Archivierung fehlgeschlagen:', error);
}
});
// In Discord gelöscht = im Archiv gelöscht (inkl. lokaler Bilder)
client.on(Events.MessageDelete, async (message) => {
if (message.channelId !== config.devlogChannelId) return;
try {
if (await removeDevlog(message.id)) {
console.log(`[devlog] Archiv-Eintrag entfernt (Discord-Nachricht ${message.id} gelöscht)`);
}
} catch (error) {
console.error('[devlog] Archiv-Löschung fehlgeschlagen:', error);
}
});
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand()) return;
const command = client.commands.get(interaction.commandName);
if (!command) return;
try {
await command.execute(interaction);
} catch (error) {
console.error(`[bot] Fehler bei /${interaction.commandName}:`, error);
const reply = { content: '❌ Da ist etwas schiefgelaufen.', ephemeral: true };
if (interaction.replied || interaction.deferred) {
await interaction.followUp(reply).catch(() => {});
} else {
await interaction.reply(reply).catch(() => {});
}
}
});
await client.login(config.discordToken);
return client;
}
/** Slash-Commands bei Discord registrieren (Guild = sofort sichtbar, global = bis zu 1h Delay) */
async function registerCommands() {
const rest = new REST().setToken(config.discordToken);
const body = commandModules.map((c) => c.data.toJSON());
const route = config.discordGuildId
? Routes.applicationGuildCommands(config.discordClientId, config.discordGuildId)
: Routes.applicationCommands(config.discordClientId);
await rest.put(route, { body });
console.log(
`[bot] ${body.length} Slash-Command(s) registriert (${config.discordGuildId ? 'Guild' : 'global'})`
);
}