Add: Purge command for message deletion

Added /admin purge with subcommands:
- amount: Delete X messages (1-100)
- time: Delete messages from last X minutes/hours
- user: Delete X messages from specific user
- all: Delete all possible messages (max 100)

Features:
- Only works in the channel where executed
- Requires ModerateMembers permission
- Filters messages older than 14 days (Discord API limit)
- Logs purge actions to moderation log channel

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-23 15:01:44 +01:00
parent 362437bcd5
commit b0f153f135

View File

@@ -137,6 +137,55 @@ const command: Command = {
option.setName('duration_value')
.setDescription('Dauer in Sekunden')
.setMinValue(0)))
.addSubcommandGroup(group =>
group
.setName('purge')
.setDescription('Löscht Nachrichten im Channel')
.addSubcommand(subcommand =>
subcommand
.setName('amount')
.setDescription('Löscht X Nachrichten')
.addIntegerOption(option =>
option.setName('count')
.setDescription('Anzahl der Nachrichten (1-100)')
.setRequired(true)
.setMinValue(1)
.setMaxValue(100)))
.addSubcommand(subcommand =>
subcommand
.setName('time')
.setDescription('Löscht Nachrichten der letzten X Minuten/Stunden')
.addIntegerOption(option =>
option.setName('duration')
.setDescription('Dauer')
.setRequired(true)
.setMinValue(1))
.addStringOption(option =>
option.setName('unit')
.setDescription('Zeiteinheit')
.setRequired(true)
.addChoices(
{ name: 'Minuten', value: 'min' },
{ name: 'Stunden', value: 'hour' }
)))
.addSubcommand(subcommand =>
subcommand
.setName('user')
.setDescription('Löscht Nachrichten eines bestimmten Nutzers')
.addUserOption(option =>
option.setName('target')
.setDescription('Der Nutzer')
.setRequired(true))
.addIntegerOption(option =>
option.setName('count')
.setDescription('Anzahl der Nachrichten (1-100)')
.setRequired(true)
.setMinValue(1)
.setMaxValue(100)))
.addSubcommand(subcommand =>
subcommand
.setName('all')
.setDescription('Löscht alle möglichen Nachrichten (max 100)')))
.addSubcommand(subcommand =>
subcommand
.setName('help')
@@ -162,6 +211,10 @@ const command: Command = {
{ name: '`/admin unmute <nutzer>`', value: 'Entmutet einen Nutzer.', inline: false },
{ name: '`/admin ban <nutzer> [grund] [delete_days]`', value: 'Bannt einen Nutzer vom Server.\ndelete_days: Nachrichten der letzten X Tage löschen (0-7).', inline: false },
{ name: '`/admin unban <id>`', value: 'Entbannt einen Nutzer (via ID oder @username).', inline: false },
{ name: '`/admin purge amount <1-100>`', value: 'Löscht X Nachrichten im Channel.', inline: false },
{ name: '`/admin purge time <dauer> <min|hour>`', value: 'Löscht Nachrichten der letzten X Minuten/Stunden.', inline: false },
{ name: '`/admin purge user <nutzer> <1-100>`', value: 'Löscht X Nachrichten eines bestimmten Nutzers.', inline: false },
{ name: '`/admin purge all`', value: 'Löscht alle möglichen Nachrichten (max 100).', inline: false },
{ name: '`/admin config <setting> [wert]`', value: 'Konfiguriert das Warn-System.\nSettings: warn_threshold, warn_action, warn_mute_duration, show', inline: false },
{ name: 'Warn-System', value: 'Automatische Aktionen bei X Warnungen:\n`/admin config warn_action kick|mute|ban`', inline: false }
)
@@ -507,6 +560,115 @@ const command: Command = {
return;
}
}
// Handle purge subcommands
const subcommandGroup = interaction.options.getSubcommandGroup();
if (subcommandGroup === 'purge') {
const purgeSubcommand = interaction.options.getSubcommand();
const channel = interaction.channel;
if (!channel || !channel.isTextBased()) {
await interaction.reply({ content: '❌ Dieser Befehl kann nur in Text-Channels verwendet werden.', flags: [MessageFlags.Ephemeral] });
return;
}
// Defer reply since bulk delete can take time
await interaction.deferReply({ flags: [MessageFlags.Ephemeral] });
let deletedCount = 0;
try {
if (purgeSubcommand === 'amount') {
const count = interaction.options.getInteger('count')!;
const messages = await channel.messages.fetch({ limit: count + 1 }); // +1 for the command message
const twoWeeksAgo = Date.now() - 14 * 24 * 60 * 60 * 1000;
const filtered = messages.filter((m: any) => m.createdTimestamp > twoWeeksAgo);
await (channel as any).bulkDelete(filtered, true);
deletedCount = filtered.size - 1; // -1 for command message
await interaction.editReply(`${deletedCount} Nachrichten gelöscht.`);
}
else if (purgeSubcommand === 'time') {
const duration = interaction.options.getInteger('duration')!;
const unit = interaction.options.getString('unit')!;
const unitMs: Record<string, number> = {
min: 60 * 1000,
hour: 60 * 60 * 1000
};
const cutoff = Date.now() - (duration * unitMs[unit]);
const messages = await channel.messages.fetch({ limit: 100 });
const twoWeeksAgo = Date.now() - 14 * 24 * 60 * 60 * 1000;
const filtered = messages.filter((m: any) =>
m.createdTimestamp > cutoff &&
m.createdTimestamp > twoWeeksAgo
);
await (channel as any).bulkDelete(filtered, true);
deletedCount = filtered.size;
const unitName = unit === 'min' ? 'Minute(n)' : 'Stunde(n)';
await interaction.editReply(`${deletedCount} Nachrichten der letzten ${duration} ${unitName} gelöscht.`);
}
else if (purgeSubcommand === 'user') {
const target = interaction.options.getUser('target')!;
const count = interaction.options.getInteger('count')!;
const messages = await channel.messages.fetch({ limit: 100 });
const twoWeeksAgo = Date.now() - 14 * 24 * 60 * 60 * 1000;
const userMessages = messages.filter((m: any) =>
m.author.id === target.id &&
m.createdTimestamp > twoWeeksAgo
).first(count);
if (userMessages.length === 0) {
await interaction.editReply(`Keine Nachrichten von ${target.tag} gefunden.`);
return;
}
await (channel as any).bulkDelete(userMessages, true);
deletedCount = userMessages.length;
await interaction.editReply(`${deletedCount} Nachrichten von ${target.tag} gelöscht.`);
}
else if (purgeSubcommand === 'all') {
const messages = await channel.messages.fetch({ limit: 100 });
const twoWeeksAgo = Date.now() - 14 * 24 * 60 * 60 * 1000;
const filtered = messages.filter((m: any) => m.createdTimestamp > twoWeeksAgo);
await (channel as any).bulkDelete(filtered, true);
deletedCount = filtered.size;
await interaction.editReply(`${deletedCount} Nachrichten gelöscht.`);
}
// Log the purge action
if (deletedCount > 0) {
const embed = new EmbedBuilder()
.setTitle('🗑️ Nachrichten gelöscht (Purge)')
.setColor(0x9b59b6)
.addFields(
{ name: 'Channel', value: `<#${channel.id}>`, inline: true },
{ name: 'Moderator', value: `${interaction.user.tag} (<@${interaction.user.id}>)`, inline: true },
{ name: 'Anzahl', value: `${deletedCount} Nachrichten`, inline: true },
{ name: 'Typ', value: purgeSubcommand === 'amount' ? 'Nach Anzahl' :
purgeSubcommand === 'time' ? 'Nach Zeit' :
purgeSubcommand === 'user' ? 'Nach Nutzer' : 'Alle', inline: true }
)
.setTimestamp();
await sendModerationLog(interaction.client, guildId, 'messages', embed);
}
} catch (error) {
console.error('[ADMIN] Purge error:', error);
await interaction.editReply('❌ Fehler beim Löschen der Nachrichten.');
}
return;
}
},
};