Community-Endgame: Alpha-Keys, Bewerbungen, Events, Stats, Triggers, /remind, Social, Temp-Voice + MEE6-Bot-Karte

- Alpha-Keys: Pool im Community-Tab, Ein-Klick-Verteilung per DM an alle Playtester
  (Key bleibt frei, wenn die DM geblockt wird)
- Bewerbungs-Formulare: Builder im neuen Bewerbungen-Tab (bis 5 Fragen),
  Button → Discord-Modal → Review-Embed mit /, Rolle + DM bei Entscheidung
- Events: GuildScheduledEventCreate → Announce-Embed; öffentliche /events-Seite
  aus den Discord-Events (5-min-Cache)
- Server-Stats: activity_daily (Nachrichten/Joins/Leaves) → Balken-Chart auf /level
- Triggers (Auto-Antworten, 30s-Cooldown), /remind (DM-Scheduler),
  Twitch-Live (Helix, App-Creds write-only) + YouTube-RSS-Announcements,
  Temp-Voice (Join to Create, Cleanup bei Leerstand + Start)
- Brand-Tab: MEE6-Style Bot-Identity-Karte (Avatar-Vorschau mit Status-Dot,
  Bot-Name via setUsername, Presence online/idle/dnd, Aktivität)
- Neue Intents: GuildVoiceStates, GuildScheduledEvents; alles smoke-getestet

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 01:02:47 +02:00
co-authored by Claude Fable 5
parent f7b261c648
commit e72e6c8991
16 changed files with 1368 additions and 47 deletions
+30 -1
View File
@@ -7,6 +7,8 @@ import { registerCommunityListeners } from './community.js';
import { registerModTools } from './mod-tools.js';
import { registerLevels } from './levels.js';
import { registerPresence } from './presence.js';
import { registerExtras } from './extras.js';
import { handleApplyButton, handleApplyModal, handleReviewButton } from './app-forms.js';
import { handleRoleMenuButton } from './role-menus.js';
import {
addPlaytester, removePlaytester, isWish, bumpWish,
@@ -28,11 +30,12 @@ import * as timeout from './commands/timeout.js';
import * as purge from './commands/purge.js';
import * as rank from './commands/rank.js';
import * as tag from './commands/tag.js';
import * as remind from './commands/remind.js';
// Alle Commands hier eintragen — jedes Modul exportiert { data, execute }
const commandModules = [
ping, devlogBackfill, bug, playtesterSetup, galerieBackfill,
wunsch, giveaway, ticketSetup, warn, warns, timeout, purge, rank, tag,
wunsch, giveaway, ticketSetup, warn, warns, timeout, purge, rank, tag, remind,
];
export async function startBot() {
@@ -49,6 +52,9 @@ export async function startBot() {
// privilegierten "Server Members Intent" im Developer Portal!
GatewayIntentBits.DirectMessages,
GatewayIntentBits.GuildMembers,
// Temp-Voice (Join to Create) + Event-Ankündigungen
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildScheduledEvents,
],
// Partials: Delete/Reaction-Events für ungecachte Nachrichten + DM-Kanäle
partials: [Partials.Message, Partials.Reaction, Partials.Channel],
@@ -144,6 +150,28 @@ export async function startBot() {
return;
}
// Bewerbungen: Button → Modal → Review-Entscheidung
try {
if (interaction.isButton() && interaction.customId.startsWith('apply:')) {
await handleApplyButton(interaction);
return;
}
if (interaction.isModalSubmit() && interaction.customId.startsWith('applymodal:')) {
await handleApplyModal(interaction);
return;
}
if (interaction.isButton() && interaction.customId.startsWith('appdec:')) {
await handleReviewButton(interaction);
return;
}
} catch (error) {
console.error('[bewerbung] Fehler:', error);
if (!interaction.replied && !interaction.deferred) {
await interaction.reply({ content: '❌ Da ist etwas schiefgelaufen.', flags: MessageFlags.Ephemeral }).catch(() => {});
}
return;
}
// Rollen-Menü-Buttons: rolemenu:<menuId>:<roleId>
if (interaction.isButton() && interaction.customId.startsWith('rolemenu:')) {
try {
@@ -298,6 +326,7 @@ export async function startBot() {
registerModTools(client);
registerLevels(client);
registerPresence(client);
registerExtras(client);
await client.login(config.discordToken);
return client;