loads of changes, most mod commands done
diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts
index 7c52b13..6d895f5 100644
--- a/src/commands/mod/purge.ts
+++ b/src/commands/mod/purge.ts
@@ -1,20 +1,194 @@
-import { CommandInteraction } from "discord.js";
+import Discord, { CommandInteraction, GuildChannel, GuildMember, TextChannel } from "discord.js";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { WrappedCheck } from "jshaiku";
+import confirmationMessage from "../../utils/confirmationMessage.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import keyValueList from "../../utils/generateKeyValueList.js";
+import getEmojiByName from "../../utils/getEmojiByName.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
.setName("purge")
- .setDescription("Clears messages in a channel")
+ .setDescription("Bulk deletes messages in a channel")
+ .addIntegerOption(option => option
+ .setName("amount")
+ .setDescription("The amount of messages to delete")
+ .setRequired(false)
+ .setMinValue(1)
+ .setMaxValue(50))
+ .addChannelOption(option => option.setName("channel").setDescription("The channel to purge messages from").setRequired(false))
+ .addUserOption(option => option.setName("user").setDescription("The user to purge messages from").setRequired(false))
+ .addStringOption(option => option.setName("reason").setDescription("The reason for the purge").setRequired(false))
-const callback = (interaction: CommandInteraction) => {
- interaction.reply("Command incomplete [mod/purge]");
+const callback = async (interaction: CommandInteraction) => {
+ let channel = (interaction.options.getChannel("channel") as GuildChannel) ?? interaction.channel
+ let thischannel
+ if ((interaction.options.getChannel("channel") as GuildChannel) == null) {
+ thischannel = true
+ } else {
+ thischannel = (interaction.options.getChannel("channel") as GuildChannel).id == interaction.channel.id
+ }
+ if (!(["GUILD_TEXT", "GUILD_NEWS", "GUILD_NEWS_THREAD", "GUILD_PUBLIC_THREAD", "GUILD_PRIVATE_THREAD"].includes(channel.type.toString()))) {
+ return await interaction.reply({
+ embeds: [
+ new EmojiEmbed()
+ .setEmoji("CHANNEL.PURGE.RED")
+ .setTitle("Purge")
+ .setDescription("You cannot purge this channel")
+ .setStatus("Danger")
+ ],
+ components: [],
+ ephemeral: true,
+ })
+ }
+ // TODO:[Modals] Replace this with a modal
+ if ( !interaction.options.getInteger("amount") ) {
+ await interaction.reply({
+ embeds: [
+ new EmojiEmbed()
+ .setEmoji("CHANNEL.PURGE.RED")
+ .setTitle("Purge")
+ .setDescription("Select how many messages to delete")
+ .setStatus("Danger")
+ ],
+ components: [],
+ ephemeral: true,
+ fetchReply: true
+ })
+ let deleted = []
+ while (true) {
+ let m = await interaction.editReply({
+ embeds: [
+ new EmojiEmbed()
+ .setEmoji("CHANNEL.PURGE.RED")
+ .setTitle("Purge")
+ .setDescription("Select how many messages to delete. You can continue clicking until all messages are cleared.")
+ .setStatus("Danger")
+ ],
+ components: [
+ new Discord.MessageActionRow().addComponents([
+ new Discord.MessageButton()
+ .setCustomId("1")
+ .setLabel("1")
+ .setStyle("SECONDARY"),
+ new Discord.MessageButton()
+ .setCustomId("3")
+ .setLabel("3")
+ .setStyle("SECONDARY"),
+ new Discord.MessageButton()
+ .setCustomId("5")
+ .setLabel("5")
+ .setStyle("SECONDARY")
+ ]),
+ new Discord.MessageActionRow().addComponents([
+ new Discord.MessageButton()
+ .setCustomId("10")
+ .setLabel("10")
+ .setStyle("SECONDARY"),
+ new Discord.MessageButton()
+ .setCustomId("25")
+ .setLabel("25")
+ .setStyle("SECONDARY"),
+ new Discord.MessageButton()
+ .setCustomId("50")
+ .setLabel("50")
+ .setStyle("SECONDARY")
+ ]),
+ new Discord.MessageActionRow().addComponents([
+ new Discord.MessageButton()
+ .setCustomId("done")
+ .setLabel("Done")
+ .setStyle("SUCCESS")
+ .setEmoji(getEmojiByName("CONTROL.TICK", "id"))
+ ])
+ ]
+ })
+ let component;
+ try {
+ component = await (m as Discord.Message).awaitMessageComponent({filter: (m) => m.user.id === interaction.user.id, time: 2.5 * 60 * 1000});
+ } catch (e) { break; }
+ component.deferUpdate();
+ if (component.customId === "done") break;
+ let amount;
+ try { amount = parseInt(component.customId); } catch { break; }
+ await (channel as TextChannel).bulkDelete(amount, true); // TODO: Add to deleted list | TODO: Support for users
+ }
+ if (deleted.length === 0) return await interaction.editReply({
+ embeds: [
+ new EmojiEmbed()
+ .setEmoji("CHANNEL.PURGE.RED")
+ .setTitle("Purge")
+ .setDescription("No messages were deleted")
+ .setStatus("Danger")
+ ],
+ components: []
+ })
+ return await interaction.editReply({
+ embeds: [
+ new EmojiEmbed()
+ .setEmoji("CHANNEL.PURGE.GREEN")
+ .setTitle("Purge")
+ .setDescription(`Deleted ${deleted.length} messages`)
+ .setStatus("Success")
+ ],
+ components: []
+ })
+ } else {
+ if (await new confirmationMessage(interaction)
+ .setEmoji("CHANNEL.PURGE.RED")
+ .setTitle("Purge")
+ .setDescription(keyValueList({
+ "channel": `<#${channel.id}> (${(channel as GuildChannel).name})` + (thischannel ? " [This channel]" : ""),
+ "amount": interaction.options.getInteger("amount").toString(),
+ "reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
+ }))
+ .setColor("Danger")
+ // pluralize("day", interaction.options.getInteger("amount"))
+ // const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
+ .send()) {
+ try {
+ let messages = await (channel as TextChannel).bulkDelete(interaction.options.getInteger("amount"), true) // TODO: Support for users
+ let out = ""
+ messages.reverse().forEach(message => {
+ out += `${message.author.username}#${message.author.discriminator} (${message.author.id})\n`
+ let lines = message.content.split("\n")
+ lines.forEach(line => {out += `> ${line}\n`}) // TODO: Humanize timestamp
+ out += `\n\n`
+ }) // TODO: Upload as file
+ await interaction.editReply({embeds: [new EmojiEmbed()
+ .setEmoji(`CHANNEL.PURGE.GREEN`)
+ .setTitle(`Purge`)
+ .setDescription("Messages cleared")
+ .setStatus("Success")
+ ], components: []})
+ } catch {
+ await interaction.editReply({embeds: [new EmojiEmbed()
+ .setEmoji("CHANNEL.PURGE.RED")
+ .setTitle(`Purge`)
+ .setDescription("Something went wrong and no messages were deleted")
+ .setStatus("Danger")
+ ], components: []})
+ }
+ } else {
+ await interaction.editReply({embeds: [new EmojiEmbed()
+ .setEmoji("CHANNEL.PURGE.GREEN")
+ .setTitle(`Purge`)
+ .setDescription("No changes were made")
+ .setStatus("Success")
+ ], components: []})
+ }
+ }
}
const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
- return true;
+ // Allow the owner to purge
+ if ((interaction.member as GuildMember).id == interaction.guild.ownerId) return true
+ // Check if the user has manage_messages permission
+ if (! (interaction.member as GuildMember).permissions.has("MANAGE_MESSAGES")) throw "You do not have the `manage_messages` permission";
+ // Check if nucleus has the manage_messages permission
+ if (! interaction.guild.me.permissions.has("MANAGE_MESSAGES")) throw "I do not have the `manage_messages` permission";
+ // Allow warn
+ return true
}
-export { command };
-export { callback };
-export { check };
\ No newline at end of file
+export { command, callback, check };
\ No newline at end of file