- 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>
96 lines
3.8 KiB
JavaScript
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'})`
|
|
);
|
|
}
|