possibly finished current features
diff --git a/src/commands/mod/about.ts b/src/commands/mod/about.ts
index ab3ca49..0a9d962 100644
--- a/src/commands/mod/about.ts
+++ b/src/commands/mod/about.ts
@@ -3,7 +3,6 @@
import Discord, {
CommandInteraction,
GuildMember,
- Interaction,
Message,
ActionRowBuilder,
ButtonBuilder,
@@ -401,12 +400,7 @@
});
let out;
try {
- out = await modalInteractionCollector(
- m,
- (m: Interaction) =>
- (m as MessageComponentInteraction | ModalSubmitInteraction).channelId === interaction.channelId,
- (m) => m.customId === "modify"
- );
+ out = await modalInteractionCollector(m, interaction.user);
} catch (e) {
timedOut = true;
continue;
diff --git a/src/commands/settings/automod.ts b/src/commands/settings/automod.ts
index c3cac04..f10cf67 100644
--- a/src/commands/settings/automod.ts
+++ b/src/commands/settings/automod.ts
@@ -8,11 +8,8 @@
ChannelSelectMenuBuilder,
ChannelSelectMenuInteraction,
CommandInteraction,
- Interaction,
Message,
- MessageComponentInteraction,
ModalBuilder,
- ModalSubmitInteraction,
RoleSelectMenuBuilder,
RoleSelectMenuInteraction,
StringSelectMenuBuilder,
@@ -317,12 +314,7 @@
await i.showModal(modal);
let out;
try {
- out = await modalInteractionCollector(
- m,
- (m: Interaction) =>
- (m as MessageComponentInteraction | ModalSubmitInteraction).channelId === interaction.channelId,
- (m) => m.customId === "back"
- );
+ out = await modalInteractionCollector(m, interaction.user);
} catch (e) {
break;
}
@@ -612,12 +604,7 @@
await i.showModal(modal);
let out;
try {
- out = await modalInteractionCollector(
- m,
- (m: Interaction) =>
- (m as MessageComponentInteraction | ModalSubmitInteraction).channelId === interaction.channelId,
- (m) => m.customId === "back"
- );
+ out = await modalInteractionCollector(m, interaction.user);
} catch (e) {
break;
}
@@ -912,7 +899,8 @@
}
}
- } while(!closed)
+ } while(!closed);
+ await interaction.deleteReply()
};
diff --git a/src/commands/settings/logs/attachment.ts b/src/commands/settings/logs/attachment.ts
index 6f825bc..545e3ff 100644
--- a/src/commands/settings/logs/attachment.ts
+++ b/src/commands/settings/logs/attachment.ts
@@ -1,195 +1,105 @@
import { LoadingEmbed } from "../../../utils/defaults.js";
-import { ChannelType } from "discord-api-types/v9";
-import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ButtonInteraction } from "discord.js";
+import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelSelectMenuBuilder } from "discord.js";
import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
-import confirmationMessage from "../../../utils/confirmationMessage.js";
import getEmojiByName from "../../../utils/getEmojiByName.js";
import type { SlashCommandSubcommandBuilder } from "discord.js";
import client from "../../../utils/client.js";
+import { getCommandMentionByName } from "../../../utils/getCommandDataByName.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
.setName("attachments")
.setDescription("Where attachments should be logged to (Premium only)")
- .addChannelOption((option) =>
- option
- .setName("channel")
- .setDescription("The channel to log attachments in")
- .addChannelTypes(ChannelType.GuildText)
- .setRequired(false)
- );
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
- const m = (await interaction.reply({
+ await interaction.reply({
embeds: LoadingEmbed,
ephemeral: true,
fetchReply: true
- })) as Discord.Message;
- if (interaction.options.get("channel")?.channel) {
- let channel;
- try {
- channel = interaction.options.get("channel")?.channel;
- } catch {
- return await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setEmoji("CHANNEL.TEXT.DELETE")
- .setTitle("Attachment Log Channel")
- .setDescription("The channel you provided is not a valid channel")
- .setStatus("Danger")
- ]
- });
- }
- channel = channel as Discord.TextChannel;
- if (channel.guild.id !== interaction.guild!.id) {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Attachment Log Channel")
- .setDescription("You must choose a channel in this server")
- .setStatus("Danger")
- .setEmoji("CHANNEL.TEXT.DELETE")
- ]
- });
- }
- const confirmation = await new confirmationMessage(interaction)
- .setEmoji("CHANNEL.TEXT.EDIT")
- .setTitle("Attachment Log Channel")
- .setDescription(
- "This will be the channel all attachments will be sent to.\n\n" +
- `Are you sure you want to set the attachment log channel to <#${channel.id}>?`
- )
- .setColor("Warning")
- .setFailedMessage("No changes were made", "Success", "CHANNEL.TEXT.CREATE")
- .setInverted(true)
- .send(true);
- if (confirmation.cancelled) return;
- if (confirmation.success) {
- try {
- await client.database.guilds.write(interaction.guild!.id, {
- "logging.attachments.channel": channel.id
- });
- const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger;
- const data = {
- meta: {
- type: "attachmentChannelUpdate",
- displayName: "Attachment Log Channel Updated",
- calculateType: "nucleusSettingsUpdated",
- color: NucleusColors.yellow,
- emoji: "CHANNEL.TEXT.EDIT",
- timestamp: new Date().getTime()
- },
- list: {
- memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
- changedBy: entry(interaction.user.id, renderUser(interaction.user)),
- channel: entry(channel.id, renderChannel(channel))
- },
- hidden: {
- guild: interaction.guild!.id
- }
- };
- log(data);
- } catch (e) {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Attachment Log Channel")
- .setDescription("Something went wrong and the attachment log channel could not be set")
- .setStatus("Danger")
- .setEmoji("CHANNEL.TEXT.DELETE")
- ],
- components: []
- });
- }
- } else {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Attachment Log Channel")
- .setDescription("No changes were made")
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- ],
- components: []
- });
- }
- }
- let clicks = 0;
- const data = await client.database.guilds.read(interaction.guild!.id);
- let channel = data.logging.staff.channel;
+ })
- let timedOut = false;
- while (!timedOut) {
- await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Attachment Log Channel")
- .setDescription(
- channel
- ? `Your attachment log channel is currently set to <#${channel}>`
- : "This server does not have an attachment log channel" +
- (await client.database.premium.hasPremium(interaction.guild!.id)
- ? ""
- : "\n\nThis server does not have premium, so this feature is disabled")
- )
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- ],
- components: [
- new ActionRowBuilder<ButtonBuilder>().addComponents([
- new ButtonBuilder()
- .setCustomId("clear")
- .setLabel(clicks ? "Click again to confirm" : "Reset channel")
- .setEmoji(getEmojiByName(clicks ? "TICKETS.ISSUE" : "CONTROL.CROSS", "id"))
- .setStyle(ButtonStyle.Danger)
- .setDisabled(!channel)
- ])
- ]
- });
- let i;
- try {
- i = await m.awaitMessageComponent({
- time: 300000,
- filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id }
- });
- } catch (e) {
- timedOut = true;
- continue;
- }
- await i.deferUpdate();
- if ((i.component as unknown as ButtonInteraction).customId === "clear") {
- clicks ++;
- if (clicks === 2) {
- clicks = 0;
- await client.database.guilds.write(interaction.guild!.id, null, ["logging.announcements.channel"]);
- channel = null;
- }
- }
- }
- await interaction.editReply({
+ if(!client.database.premium.hasPremium(interaction.guild!.id)) return interaction.editReply({
embeds: [
new EmojiEmbed()
- .setTitle("Attachment Log Channel")
- .setDescription(
- channel
- ? `Your attachment log channel is currently set to <#${channel}>`
- : "This server does not have an attachment log channel"
- )
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- .setFooter({ text: "Message closed" })
- ],
- components: [
- new ActionRowBuilder<ButtonBuilder>().addComponents([
+ .setTitle("Premium Required")
+ .setDescription(`This feature is exclusive to ${getCommandMentionByName("nucleus/premium")} servers.`)
+ .setStatus("Danger")
+ .setEmoji("NUCLEUS.PREMIUM")
+ ]
+ });
+
+ let data = await client.database.guilds.read(interaction.guild!.id);
+ let channel = data.logging.staff.channel;
+
+ let closed = false;
+ do {
+ const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>()
+ .addComponents(
+ new ChannelSelectMenuBuilder()
+ .setCustomId("channel")
+ .setPlaceholder("Select a channel")
+ );
+ const buttons = new ActionRowBuilder<ButtonBuilder>()
+ .addComponents(
new ButtonBuilder()
.setCustomId("clear")
.setLabel("Clear")
- .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
- .setStyle(ButtonStyle.Secondary)
- .setDisabled(true)
- ])
- ]
- });
+ .setStyle(ButtonStyle.Danger)
+ .setEmoji(getEmojiByName("CONTROL.CROSS", "id") as Discord.APIMessageComponentEmoji)
+ .setDisabled(!channel),
+ new ButtonBuilder()
+ .setCustomId("save")
+ .setLabel("Save")
+ .setStyle(ButtonStyle.Success)
+ .setEmoji(getEmojiByName("ICONS.SAVE", "id") as Discord.APIMessageComponentEmoji)
+ .setDisabled(channel === data.logging.staff.channel)
+ );
+
+ const embed = new EmojiEmbed()
+ .setTitle("Attachments")
+ .setDescription(
+ `The channel to send all attachments from the server, allowing you to check them if they are deleted` +
+ `**Channel:** ${channel ? `<#${channel}>` : "*None*"}\n`
+ )
+ .setStatus("Success")
+ .setEmoji("CHANNEL.TEXT.CREATE")
+
+ await interaction.editReply({
+ embeds: [embed],
+ components: [channelMenu, buttons]
+ });
+
+ let i: Discord.ButtonInteraction | Discord.SelectMenuInteraction;
+ try {
+ i = (await interaction.channel!.awaitMessageComponent({
+ filter: (i) => i.user.id === interaction.user.id,
+ time: 300000
+ })) as Discord.ButtonInteraction | Discord.SelectMenuInteraction;
+ } catch (e) {
+ closed = true;
+ break;
+ }
+ await i.deferUpdate();
+ if(i.isButton()) {
+ switch (i.customId) {
+ case "clear": {
+ channel = null;
+ break;
+ }
+ case "save": {
+ await client.database.guilds.write(interaction.guild!.id, {
+ "logging.attachments.channel": channel
+ });
+ data = await client.database.guilds.read(interaction.guild!.id);
+ break;
+ }
+ }
+ } else {
+ channel = i.values[0]!;
+ }
+
+ } while (!closed);
+ await interaction.deleteReply()
};
const check = (interaction: CommandInteraction, _partial: boolean = false) => {
diff --git a/src/commands/settings/logs/events.ts b/src/commands/settings/logs/events.ts
index f2ec13a..a1f24fa 100644
--- a/src/commands/settings/logs/events.ts
+++ b/src/commands/settings/logs/events.ts
@@ -1,9 +1,11 @@
import { LoadingEmbed } from "../../../utils/defaults.js";
-import Discord, { CommandInteraction, Message, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder, EmbedBuilder } from "discord.js";
-import { SlashCommandSubcommandBuilder, StringSelectMenuOptionBuilder } from "discord.js";
-import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
+import Discord, { CommandInteraction, ActionRowBuilder, ChannelSelectMenuBuilder, ChannelType, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, ButtonInteraction, StringSelectMenuInteraction, ChannelSelectMenuInteraction, APIMessageComponentEmoji } from "discord.js";
+import type { SlashCommandSubcommandBuilder } from "discord.js";
import client from "../../../utils/client.js";
+import compare from "lodash";
import { toHexArray, toHexInteger } from "../../../utils/calculate.js";
+import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
+import getEmojiByName from "../../../utils/getEmojiByName.js";
const logs: Record<string, string> = {
channelUpdate: "Channels created, deleted or modified",
@@ -24,85 +26,135 @@
webhookUpdate: "Webhooks created or deleted",
guildMemberVerify: "Member runs verify",
autoModeratorDeleted: "Messages auto deleted by Nucleus",
- nucleusSettingsUpdated: "Nucleus' settings updated by a moderator",
- ticketUpdate: "Tickets created or deleted"
+ ticketUpdate: "Tickets created or deleted",
+ //nucleusSettingsUpdated: "Nucleus' settings updated by a moderator" // TODO
};
const command = (builder: SlashCommandSubcommandBuilder) =>
- builder.setName("events").setDescription("Sets what events should be logged");
+ builder
+ .setName("events")
+ .setDescription("The general log channel for the server, and setting what events to show")
const callback = async (interaction: CommandInteraction): Promise<void> => {
- await interaction.reply({
+ const m = (await interaction.reply({
embeds: LoadingEmbed,
- fetchReply: true,
- ephemeral: true
- });
- let m: Message;
- let timedOut = false;
+ ephemeral: true,
+ fetchReply: true
+ })) as Discord.Message;
+
+ let config = await client.database.guilds.read(interaction.guild!.id);
+ let data = Object.assign({}, config.logging.logs);
+ let closed = false;
+ let show = false;
do {
- const config = await client.database.guilds.read(interaction.guild!.id);
- const converted = toHexArray(config.logging.logs.toLog);
- const selectPane = new StringSelectMenuBuilder()
- .setPlaceholder("Set events to log")
- .setMaxValues(Object.keys(logs).length)
- .setCustomId("logs")
- .setMinValues(0)
- Object.keys(logs).map((e, i) => {
- selectPane.addOptions(new StringSelectMenuOptionBuilder()
- .setLabel(logs[e]!)
- .setValue(i.toString())
- .setDefault(converted.includes(e))
+ const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>()
+ .addComponents(
+ new ChannelSelectMenuBuilder()
+ .setCustomId("channel")
+ .setPlaceholder("Select a channel")
+ .setChannelTypes(ChannelType.GuildText)
+ )
+ const buttons = new ActionRowBuilder<ButtonBuilder>()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId("switch")
+ .setLabel(data.enabled ? "Enabled" : "Disabled")
+ .setStyle(data.enabled ? ButtonStyle.Success : ButtonStyle.Danger)
+ .setEmoji(getEmojiByName((data.enabled ? "CONTROL.TICK" : "CONTROL.CROSS"), "id") as APIMessageComponentEmoji),
+ new ButtonBuilder()
+ .setCustomId("remove")
+ .setLabel("Remove")
+ .setStyle(ButtonStyle.Danger)
+ .setDisabled(!data.channel),
+ new ButtonBuilder()
+ .setCustomId("show")
+ .setLabel("Manage Events")
+ .setStyle(ButtonStyle.Primary),
+ new ButtonBuilder()
+ .setCustomId("save")
+ .setLabel("Save")
+ .setStyle(ButtonStyle.Success)
+ .setDisabled(compare.isEqual(data, config.logging.logs))
+ )
+
+ const converted = toHexArray(data.toLog);
+ const toLogMenu = new ActionRowBuilder<StringSelectMenuBuilder>()
+ .addComponents(
+ new StringSelectMenuBuilder()
+ .setPlaceholder("Set events to log")
+ .setMaxValues(Object.keys(logs).length)
+ .setCustomId("logs")
+ .setMinValues(0)
+ )
+ Object.keys(logs).map((e) => {
+ toLogMenu.components[0]!.addOptions(
+ new StringSelectMenuOptionBuilder()
+ .setLabel(logs[e]!)
+ .setValue(e)
+ .setDefault(converted.includes(e))
)
});
- m = (await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Logging Events")
- .setDescription(
- "Below are the events being logged in the server. You can toggle them on and off in the dropdown"
- )
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- ],
- components: [
- new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectPane),
- new ActionRowBuilder<ButtonBuilder>().addComponents([
- new ButtonBuilder().setLabel("Select all").setStyle(ButtonStyle.Primary).setCustomId("all"),
- new ButtonBuilder().setLabel("Select none").setStyle(ButtonStyle.Danger).setCustomId("none")
- ])
- ]
- })) as Message;
- let i;
+
+ const embed = new EmojiEmbed()
+ .setTitle("General Log Channel")
+ .setStatus("Success")
+ .setEmoji("CHANNEL.TEXT.CREATE")
+ .setDescription(
+ `This is the channel that all events you set to be logged will be stored\n` +
+ `**Channel:** ${data.channel ? `<#${data.channel}>` : "None"}\n`
+ )
+
+ let components: ActionRowBuilder<ButtonBuilder | ChannelSelectMenuBuilder | StringSelectMenuBuilder>[] = [channelMenu, buttons];
+ if(show) components.push(toLogMenu);
+
+ await interaction.editReply({
+ embeds: [embed],
+ components: components
+ });
+
+ let i: ButtonInteraction | StringSelectMenuInteraction | ChannelSelectMenuInteraction;
try {
i = await m.awaitMessageComponent({
- time: 300000,
- filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id }
- });
+ filter: (i) => i.user.id === interaction.user.id,
+ time: 300000
+ }) as ButtonInteraction | StringSelectMenuInteraction | ChannelSelectMenuInteraction;
} catch (e) {
- timedOut = true;
- continue;
+ closed = true;
+ break;
}
- await i.deferUpdate();
- if (i.isStringSelectMenu() && i.customId === "logs") {
- const selected = i.values;
- const newLogs = toHexInteger(selected.map((e: string) => Object.keys(logs)[parseInt(e)]!));
- await client.database.guilds.write(interaction.guild!.id, {
- "logging.logs.toLog": newLogs
- });
- } else if (i.customId === "all") {
- const newLogs = toHexInteger(Object.keys(logs).map((e) => e));
- await client.database.guilds.write(interaction.guild!.id, {
- "logging.logs.toLog": newLogs
- });
- } else if (i.customId === "none") {
- await client.database.guilds.write(interaction.guild!.id, {
- "logging.logs.toLog": 0
- });
- }
- } while (!timedOut);
- await interaction.editReply({ embeds: [new EmbedBuilder(m.embeds[0]!.data).setFooter({ text: "Message timed out" })] });
- return;
+ await i.deferUpdate();
+
+ if(i.isButton()) {
+ switch(i.customId) {
+ case "show": {
+ show = !show;
+ break;
+ }
+ case "switch": {
+ data.enabled = !data.enabled;
+ break;
+ }
+ case "save": {
+ await client.database.guilds.write(interaction.guild!.id, {"logging.logs": data});
+ config = await client.database.guilds.read(interaction.guild!.id);
+ data = Object.assign({}, config.logging.logs);
+ break;
+ }
+ case "remove": {
+ data.channel = null;
+ break;
+ }
+ }
+ } else if(i.isStringSelectMenu()) {
+ let hex = toHexInteger(i.values);
+ data.toLog = hex;
+ } else if(i.isChannelSelectMenu()) {
+ data.channel = i.values[0]!;
+ }
+
+ } while (!closed);
+ await interaction.deleteReply()
};
const check = (interaction: CommandInteraction, _partial: boolean = false) => {
diff --git a/src/commands/settings/logs/general.ts b/src/commands/settings/logs/general.ts
deleted file mode 100644
index 9861d26..0000000
--- a/src/commands/settings/logs/general.ts
+++ /dev/null
@@ -1,197 +0,0 @@
-import { LoadingEmbed } from "../../../utils/defaults.js";
-import { ChannelType } from "discord-api-types/v9";
-import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ButtonInteraction, ButtonComponent } from "discord.js";
-import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
-import confirmationMessage from "../../../utils/confirmationMessage.js";
-import getEmojiByName from "../../../utils/getEmojiByName.js";
-import type { SlashCommandSubcommandBuilder } from "discord.js";
-import client from "../../../utils/client.js";
-
-const command = (builder: SlashCommandSubcommandBuilder) =>
- builder
- .setName("general")
- .setDescription("Sets or shows the log channel")
- .addChannelOption((option) =>
- option
- .setName("channel")
- .setDescription("The channel to set the log channel to")
- .addChannelTypes(ChannelType.GuildText)
- );
-
-const callback = async (interaction: CommandInteraction): Promise<unknown> => {
- const m = (await interaction.reply({
- embeds: LoadingEmbed,
- ephemeral: true,
- fetchReply: true
- })) as Discord.Message;
- if (interaction.options.get("channel")?.channel) {
- let channel;
- try {
- channel = interaction.options.get("channel")?.channel;
- } catch {
- return await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setEmoji("CHANNEL.TEXT.DELETE")
- .setTitle("Log Channel")
- .setDescription("The channel you provided is not a valid channel")
- .setStatus("Danger")
- ]
- });
- }
- channel = channel as Discord.TextChannel;
- if (channel.guild.id !== interaction.guild!.id) {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Log Channel")
- .setDescription("You must choose a channel in this server")
- .setStatus("Danger")
- .setEmoji("CHANNEL.TEXT.DELETE")
- ]
- });
- }
- const confirmation = await new confirmationMessage(interaction)
- .setEmoji("CHANNEL.TEXT.EDIT")
- .setTitle("Log Channel")
- .setDescription(`Are you sure you want to set the log channel to <#${channel.id}>?`)
- .setColor("Warning")
- .setFailedMessage("No changes were made", "Success", "CHANNEL.TEXT.CREATE")
- .setInverted(true)
- .send(true);
- if (confirmation.cancelled) return;
- if (confirmation.success) {
- try {
- await client.database.guilds.write(interaction.guild!.id, {
- "logging.logs.channel": channel.id
- });
- const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger;
- const data = {
- meta: {
- type: "logChannelUpdate",
- displayName: "Log Channel Changed",
- calculateType: "nucleusSettingsUpdated",
- color: NucleusColors.yellow,
- emoji: "CHANNEL.TEXT.EDIT",
- timestamp: new Date().getTime()
- },
- list: {
- memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
- changedBy: entry(interaction.user.id, renderUser(interaction.user)),
- channel: entry(channel.id, renderChannel(channel))
- },
- hidden: {
- guild: channel.guild.id
- }
- };
- log(data);
- } catch (e) {
- console.log(e);
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Log Channel")
- .setDescription("Something went wrong and the log channel could not be set")
- .setStatus("Danger")
- .setEmoji("CHANNEL.TEXT.DELETE")
- ],
- components: []
- });
- }
- } else {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Log Channel")
- .setDescription("No changes were made")
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- ],
- components: []
- });
- }
- }
- let clicks = 0;
- const data = await client.database.guilds.read(interaction.guild!.id);
- let channel = data.logging.logs.channel;
- let timedOut = false;
- while (!timedOut) {
- await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Log channel")
- .setDescription(
- channel
- ? `Your log channel is currently set to <#${channel}>`
- : "This server does not have a log channel"
- )
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- ],
- components: [
- new ActionRowBuilder<ButtonBuilder>().addComponents([
- new ButtonBuilder()
- .setCustomId("clear")
- .setLabel(clicks ? "Click again to confirm" : "Reset channel")
- .setEmoji(getEmojiByName(clicks ? "TICKETS.ISSUE" : "CONTROL.CROSS", "id"))
- .setStyle(ButtonStyle.Danger)
- .setDisabled(!channel)
- ])
- ]
- });
- let i: ButtonInteraction;
- try {
- i = await m.awaitMessageComponent({
- time: 300000,
- filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id }
- }) as ButtonInteraction;
- } catch (e) {
- timedOut = true;
- }
- i = i!
- await i.deferUpdate();
- if ((i.component as ButtonComponent).customId === "clear") {
- clicks ++;
- if (clicks === 2) {
- clicks = 0;
- await client.database.guilds.write(interaction.guild!.id, null, ["logging.logs.channel"]);
- channel = null;
- }
- }
- }
- await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Log channel")
- .setDescription(
- channel
- ? `Your log channel is currently set to <#${channel}>`
- : "This server does not have a log channel"
- )
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- .setFooter({ text: "Message closed" })
- ],
- components: [
- new ActionRowBuilder<ButtonBuilder>().addComponents([
- new ButtonBuilder()
- .setCustomId("clear")
- .setLabel("Clear")
- .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
- .setStyle(ButtonStyle.Secondary)
- .setDisabled(true)
- ])
- ]
- });
-};
-
-const check = (interaction: CommandInteraction, _partial: boolean = false) => {
- const member = interaction.member as Discord.GuildMember;
- if (!member.permissions.has("ManageGuild"))
- return "You must have the *Manage Server* permission to use this command";
- return true;
-};
-
-export { command };
-export { callback };
-export { check };
diff --git a/src/commands/settings/logs/warnings.ts b/src/commands/settings/logs/warnings.ts
index 3855d34..6e5482c 100644
--- a/src/commands/settings/logs/warnings.ts
+++ b/src/commands/settings/logs/warnings.ts
@@ -1,8 +1,6 @@
import { LoadingEmbed } from "../../../utils/defaults.js";
-import { ChannelType } from "discord-api-types/v9";
-import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ButtonComponent } from "discord.js";
+import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelSelectMenuBuilder } from "discord.js";
import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
-import confirmationMessage from "../../../utils/confirmationMessage.js";
import getEmojiByName from "../../../utils/getEmojiByName.js";
import type { SlashCommandSubcommandBuilder } from "discord.js";
import client from "../../../utils/client.js";
@@ -11,182 +9,86 @@
builder
.setName("warnings")
.setDescription("Settings for the staff notifications channel")
- .addChannelOption((option) =>
- option
- .setName("channel")
- .setDescription("The channel to set the staff notifications channel to")
- .addChannelTypes(ChannelType.GuildText)
- .setRequired(false)
- );
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (!interaction.guild) return;
- const m = (await interaction.reply({
+ await interaction.reply({
embeds: LoadingEmbed,
ephemeral: true,
fetchReply: true
- })) as Discord.Message;
- if (interaction.options.get("channel")?.channel) {
- let channel;
- try {
- channel = interaction.options.get("channel")?.channel;
- } catch {
- return await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setEmoji("CHANNEL.TEXT.DELETE")
- .setTitle("Staff Notifications Channel")
- .setDescription("The channel you provided is not a valid channel")
- .setStatus("Danger")
- ]
- });
- }
- channel = channel as Discord.TextChannel;
- if (channel.guild.id !== interaction.guild.id) {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Staff Notifications Channel")
- .setDescription("You must choose a channel in this server")
- .setStatus("Danger")
- .setEmoji("CHANNEL.TEXT.DELETE")
- ]
- });
- }
- const confirmation = await new confirmationMessage(interaction)
- .setEmoji("CHANNEL.TEXT.EDIT")
- .setTitle("Staff Notifications Channel")
- .setDescription(
- "This will be the channel all notifications, updates, user reports etc. will be sent to.\n\n" +
- `Are you sure you want to set the staff notifications channel to <#${channel.id}>?`
- )
- .setColor("Warning")
- .setFailedMessage("No changes were made", "Success", "CHANNEL.TEXT.CREATE")
- .setInverted(true)
- .send(true);
- if (confirmation.cancelled) return;
- if (confirmation.success) {
- try {
- await client.database.guilds.write(interaction.guild.id, {
- "logging.staff.channel": channel.id
- });
- const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger;
- const data = {
- meta: {
- type: "staffChannelUpdate",
- displayName: "Staff Notifications Channel Updated",
- calculateType: "nucleusSettingsUpdated",
- color: NucleusColors.yellow,
- emoji: "CHANNEL.TEXT.EDIT",
- timestamp: new Date().getTime()
- },
- list: {
- memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
- changedBy: entry(interaction.user.id, renderUser(interaction.user)),
- channel: entry(channel.id, renderChannel(channel))
- },
- hidden: {
- guild: interaction.guild.id
- }
- };
- log(data);
- } catch (e) {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Staff Notifications Channel")
- .setDescription("Something went wrong and the staff notifications channel could not be set")
- .setStatus("Danger")
- .setEmoji("CHANNEL.TEXT.DELETE")
- ],
- components: []
- });
- }
- } else {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Staff Notifications Channel")
- .setDescription("No changes were made")
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- ],
- components: []
- });
- }
- }
- let clicks = 0;
- const data = await client.database.guilds.read(interaction.guild.id);
+ })
+
+ let data = await client.database.guilds.read(interaction.guild.id);
let channel = data.logging.staff.channel;
- let timedOut = false;
- while (!timedOut) {
- await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Staff Notifications channel")
- .setDescription(
- channel
- ? `Your staff notifications channel is currently set to <#${channel}>`
- : "This server does not have a staff notifications channel"
- )
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- ],
- components: [
- new ActionRowBuilder<ButtonBuilder>().addComponents([
- new ButtonBuilder()
- .setCustomId("clear")
- .setLabel(clicks ? "Click again to confirm" : "Reset channel")
- .setEmoji(getEmojiByName(clicks ? "TICKETS.ISSUE" : "CONTROL.CROSS", "id"))
- .setStyle(ButtonStyle.Danger)
- .setDisabled(!channel)
- ])
- ]
- });
- let i;
- try {
- i = await m.awaitMessageComponent({
- time: 300000,
- filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id }
- });
- } catch (e) {
- timedOut = true;
- continue;
- }
- await i.deferUpdate();
- if ((i.component as ButtonComponent).customId === "clear") {
- clicks ++;
- if (clicks === 2) {
- clicks = 0;
- await client.database.guilds.write(interaction.guild.id, null, ["logging.staff.channel"]);
- channel = null;
- }
- }
- }
- await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Staff Notifications channel")
- .setDescription(
- channel
- ? `Your staff notifications channel is currently set to <#${channel}>`
- : "This server does not have a staff notifications channel"
- )
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- .setFooter({ text: "Message closed" })
- ],
- components: [
- new ActionRowBuilder<ButtonBuilder>().addComponents([
+ let closed = false;
+ do {
+ const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>()
+ .addComponents(
+ new ChannelSelectMenuBuilder()
+ .setCustomId("channel")
+ .setPlaceholder("Select a channel")
+ );
+ const buttons = new ActionRowBuilder<ButtonBuilder>()
+ .addComponents(
new ButtonBuilder()
.setCustomId("clear")
.setLabel("Clear")
- .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
- .setStyle(ButtonStyle.Secondary)
- .setDisabled(true)
- ])
- ]
- });
+ .setStyle(ButtonStyle.Danger)
+ .setEmoji(getEmojiByName("CONTROL.CROSS", "id") as Discord.APIMessageComponentEmoji)
+ .setDisabled(!channel),
+ new ButtonBuilder()
+ .setCustomId("save")
+ .setLabel("Save")
+ .setStyle(ButtonStyle.Success)
+ .setEmoji(getEmojiByName("ICONS.SAVE", "id") as Discord.APIMessageComponentEmoji)
+ .setDisabled(channel === data.logging.staff.channel)
+ );
+
+ const embed = new EmojiEmbed()
+ .setTitle("Staff Notifications Channel")
+ .setStatus("Success")
+ .setEmoji("CHANNEL.TEXT.CREATE")
+ .setDescription(
+ `Logs which require an action from a moderator or administrator will be sent to this channel.\n` +
+ `**Channel:** ${channel ? `<#${channel}>` : "*None*"}\n`
+ )
+
+ await interaction.editReply({
+ embeds: [embed],
+ components: [channelMenu, buttons]
+ });
+
+ let i: Discord.ButtonInteraction | Discord.SelectMenuInteraction;
+ try {
+ i = (await interaction.channel!.awaitMessageComponent({
+ filter: (i) => i.user.id === interaction.user.id,
+ time: 300000
+ })) as Discord.ButtonInteraction | Discord.SelectMenuInteraction;
+ } catch (e) {
+ closed = true;
+ break;
+ }
+ await i.deferUpdate();
+ if(i.isButton()) {
+ switch (i.customId) {
+ case "clear": {
+ channel = null;
+ break;
+ }
+ case "save": {
+ await client.database.guilds.write(interaction.guild!.id, {
+ "logging.warnings.channel": channel
+ });
+ data = await client.database.guilds.read(interaction.guild!.id);
+ break;
+ }
+ }
+ } else {
+ channel = i.values[0]!;
+ }
+ } while (!closed);
+
+ await interaction.deleteReply()
};
const check = (interaction: CommandInteraction, _partial: boolean = false) => {
diff --git a/src/commands/settings/moderation.ts b/src/commands/settings/moderation.ts
index ffd3063..c7f0dd0 100644
--- a/src/commands/settings/moderation.ts
+++ b/src/commands/settings/moderation.ts
@@ -1,5 +1,5 @@
import { LoadingEmbed } from "../../utils/defaults.js";
-import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ButtonComponent, TextInputBuilder, Message, RoleSelectMenuBuilder } from "discord.js";
+import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ButtonComponent, TextInputBuilder, RoleSelectMenuBuilder } from "discord.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../utils/getEmojiByName.js";
import type { SlashCommandSubcommandBuilder } from "discord.js";
@@ -12,17 +12,16 @@
.setDescription("Links and text shown to a user after a moderator action is performed")
const callback = async (interaction: CommandInteraction): Promise<void> => {
- await interaction.reply({
+ const m = await interaction.reply({
embeds: LoadingEmbed,
ephemeral: true,
fetchReply: true
});
- let m: Message;
let timedOut = false;
while (!timedOut) {
const config = await client.database.guilds.read(interaction.guild!.id);
const moderation = config.moderation;
- m = await interaction.editReply({
+ await interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Moderation Commands")
@@ -152,11 +151,7 @@
});
let out: Discord.ModalSubmitInteraction | null;
try {
- out = await modalInteractionCollector(
- m,
- (m) => m.channel!.id === interaction.channel!.id,
- (_) => true
- ) as Discord.ModalSubmitInteraction | null;
+ out = await modalInteractionCollector(m, interaction.user) as Discord.ModalSubmitInteraction | null;
} catch (e) {
continue;
}
@@ -175,6 +170,7 @@
}
}
}
+ await interaction.deleteReply()
};
const check = (interaction: CommandInteraction, _partial: boolean = false) => {
diff --git a/src/commands/settings/rolemenu.ts b/src/commands/settings/rolemenu.ts
index 02752c0..cccb6f6 100644
--- a/src/commands/settings/rolemenu.ts
+++ b/src/commands/settings/rolemenu.ts
@@ -144,11 +144,7 @@
let out: Discord.ModalSubmitInteraction | null;
try {
- out = await modalInteractionCollector(
- m,
- (m) => m.channel!.id === interaction.channel!.id,
- (_) => true
- ) as Discord.ModalSubmitInteraction | null;
+ out = await modalInteractionCollector(m, interaction.user) as Discord.ModalSubmitInteraction | null;
} catch (e) {
console.error(e);
out = null;
@@ -472,7 +468,8 @@
}
}
- } while (!closed)
+ } while (!closed);
+ await interaction.deleteReply()
};
const check = (interaction: CommandInteraction, _partial: boolean = false) => {
diff --git a/src/commands/settings/stats.ts b/src/commands/settings/stats.ts
index f8a57b7..d46b57e 100644
--- a/src/commands/settings/stats.ts
+++ b/src/commands/settings/stats.ts
@@ -74,7 +74,6 @@
type ObjectSchema = Record<string, {name: string, enabled: boolean}>
-
const addStatsChannel = async (interaction: CommandInteraction, m: Message, currentObject: ObjectSchema): Promise<ObjectSchema> => {
let closed = false;
let cancelled = false;
@@ -172,11 +171,7 @@
});
showModal(i, {name: newChannelName, enabled: newChannelEnabled})
- const out: Discord.ModalSubmitInteraction | ButtonInteraction| null = await modalInteractionCollector(
- m,
- (m) => m.channel!.id === interaction.channel!.id && m.user!.id === interaction.user!.id,
- (i) => i.channel!.id === interaction.channel!.id && i.user!.id === interaction.user!.id && i.message!.id === m.id
- );
+ const out: Discord.ModalSubmitInteraction | ButtonInteraction| null = await modalInteractionCollector(m, interaction.user);
if (!out) continue;
if (out.isButton()) continue;
newChannelName = out.fields.getTextInputValue("text");
@@ -340,11 +335,7 @@
});
let out: Discord.ModalSubmitInteraction | null;
try {
- out = await modalInteractionCollector(
- m,
- (m) => m.channel!.id === interaction.channel!.id,
- (_) => true
- ) as Discord.ModalSubmitInteraction | null;
+ out = await modalInteractionCollector(m, interaction.user) as Discord.ModalSubmitInteraction | null;
} catch (e) {
continue;
}
@@ -396,6 +387,7 @@
}
} while (!closed);
+ await interaction.deleteReply()
};
const check = (interaction: CommandInteraction, _partial: boolean = false) => {
diff --git a/src/commands/settings/tickets.ts b/src/commands/settings/tickets.ts
index 3d718dc..af74475 100644
--- a/src/commands/settings/tickets.ts
+++ b/src/commands/settings/tickets.ts
@@ -181,11 +181,7 @@
});
let out;
try {
- out = await modalInteractionCollector(
- m,
- (m) => m.user.id === interaction.user.id,
- (m) => m.customId === "back"
- );
+ out = await modalInteractionCollector(m, interaction.user);
} catch (e) {
continue;
}
@@ -207,6 +203,7 @@
}
}
}
+ await interaction.deleteReply()
};
@@ -384,11 +381,7 @@
});
let out;
try {
- out = await modalInteractionCollector(
- m,
- (m) => m.user.id === interaction.user.id,
- (m) => m.customId === "back"
- );
+ out = await modalInteractionCollector(m, interaction.user);
} catch (e) {
continue;
}
diff --git a/src/commands/settings/tracks.ts b/src/commands/settings/tracks.ts
index a353324..612d069 100644
--- a/src/commands/settings/tracks.ts
+++ b/src/commands/settings/tracks.ts
@@ -63,11 +63,7 @@
let out: ModalSubmitInteraction | null;
try {
- out = await modalInteractionCollector(
- m,
- (m) => m.channel!.id === interaction.channel!.id,
- (_) => true
- ) as ModalSubmitInteraction | null;
+ out = await modalInteractionCollector(m, interaction.user) as ModalSubmitInteraction | null;
} catch (e) {
console.error(e);
out = null;
@@ -440,7 +436,8 @@
}
}
- } while (!closed)
+ } while (!closed);
+ await interaction.deleteReply()
}
const check = (interaction: CommandInteraction, _partial: boolean = false) => {
diff --git a/src/commands/settings/verify.ts b/src/commands/settings/verify.ts
index 1d695f8..920beb4 100644
--- a/src/commands/settings/verify.ts
+++ b/src/commands/settings/verify.ts
@@ -1,33 +1,25 @@
import { LoadingEmbed } from "../../utils/defaults.js";
import Discord, {
CommandInteraction,
- Interaction,
Message,
ActionRowBuilder,
ButtonBuilder,
- MessageComponentInteraction,
- ModalSubmitInteraction,
- Role,
ButtonStyle,
- StringSelectMenuBuilder,
- TextInputBuilder,
- EmbedBuilder,
- ButtonComponent
+ RoleSelectMenuBuilder,
+ APIMessageComponentEmoji
} from "discord.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
-import confirmationMessage from "../../utils/confirmationMessage.js";
import getEmojiByName from "../../utils/getEmojiByName.js";
import type { SlashCommandSubcommandBuilder } from "discord.js";
import client from "../../utils/client.js";
-import { modalInteractionCollector } from "../../utils/dualCollector.js";
+import { getCommandMentionByName } from "../../utils/getCommandDataByName.js";
+
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
.setName("verify")
- .setDescription("Manage the role given after typing /verify")
- .addRoleOption((option) =>
- option.setName("role").setDescription("The role to give after verifying").setRequired(false)
- );
+ .setDescription("Manage the role given after a user runs /verify")
+
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (!interaction.guild) return;
@@ -36,153 +28,79 @@
ephemeral: true,
fetchReply: true
})) as Message;
- if (interaction.options.get("role")?.role) {
- let role: Role;
- try {
- role = interaction.options.get("role")?.role as Role;
- } catch {
- return await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setEmoji("GUILD.ROLES.DELETE")
- .setTitle("Verify Role")
- .setDescription("The role you provided is not a valid role")
- .setStatus("Danger")
- ]
- });
- }
- role = role as Discord.Role;
- if (role.guild.id !== interaction.guild.id) {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Verify Role")
- .setDescription("You must choose a role in this server")
- .setStatus("Danger")
- .setEmoji("GUILD.ROLES.DELETE")
- ]
- });
- }
- const confirmation = await new confirmationMessage(interaction)
- .setEmoji("GUILD.ROLES.EDIT")
- .setTitle("Verify Role")
- .setDescription(`Are you sure you want to set the verify role to <@&${role.id}>?`)
- .setColor("Warning")
- .setFailedMessage("No changes were made", "Warning", "GUILD.ROLES.DELETE")
- .setInverted(true)
- .send(true);
- if (confirmation.cancelled) return;
- if (confirmation.success) {
- try {
- await client.database.guilds.write(interaction.guild.id, {
- "verify.role": role.id,
- "verify.enabled": true
- });
- const { log, NucleusColors, entry, renderUser, renderRole } = client.logger;
- const data = {
- meta: {
- type: "verifyRoleChanged",
- displayName: "Verify Role Changed",
- calculateType: "nucleusSettingsUpdated",
- color: NucleusColors.green,
- emoji: "CONTROL.BLOCKTICK",
- timestamp: new Date().getTime()
- },
- list: {
- memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
- changedBy: entry(interaction.user.id, renderUser(interaction.user)),
- role: entry(role.id, renderRole(role))
- },
- hidden: {
- guild: interaction.guild.id
- }
- };
- log(data);
- } catch (e) {
- console.log(e);
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Verify Role")
- .setDescription("Something went wrong while setting the verify role")
- .setStatus("Danger")
- .setEmoji("GUILD.ROLES.DELETE")
- ],
- components: []
- });
- }
- } else {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Verify Role")
- .setDescription("No changes were made")
- .setStatus("Success")
- .setEmoji("GUILD.ROLES.CREATE")
- ],
- components: []
- });
- }
- }
- let clicks = 0;
- const data = await client.database.guilds.read(interaction.guild.id);
- let role = data.verify.role;
- let timedOut = false;
- while (!timedOut) {
+ let closed = false;
+ let config = await client.database.guilds.read(interaction.guild.id);
+ let data = Object.assign({}, config.verify);
+ do {
+ console.log(config.verify, data)
+ const selectMenu = new ActionRowBuilder<RoleSelectMenuBuilder>()
+ .addComponents(
+ new RoleSelectMenuBuilder()
+ .setCustomId("role")
+ .setPlaceholder("Select a role")
+ );
+
+ const buttons = new ActionRowBuilder<ButtonBuilder>()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId("switch")
+ .setLabel(data.enabled ? "Disabled" : "Enabled")
+ .setStyle(data.enabled ? ButtonStyle.Danger : ButtonStyle.Success)
+ .setEmoji(getEmojiByName(data.enabled ? "CONTROL.TICK" : "CONTROL.CROSS", "id") as APIMessageComponentEmoji),
+ new ButtonBuilder()
+ .setCustomId("save")
+ .setLabel("Save")
+ .setStyle(ButtonStyle.Success)
+ .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
+ .setDisabled(data.role === config.verify.role && data.enabled === config.verify.enabled)
+ );
+
+ const embed = new EmojiEmbed()
+ .setTitle("Verify Role")
+ .setDescription(
+ `Select a role to be given to users after they run ${getCommandMentionByName("verify")}` +
+ `\n\nCurrent role: ${config.verify.role ? `<@&${config.verify.role}>` : "None"}`
+ )
+ .setStatus("Success")
+ .setEmoji("CHANNEL.TEXT.CREATE");
+
await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Verify Role")
- .setDescription(
- role ? `Your verify role is currently set to <@&${role}>` : "You have not set a verify role"
- )
- .setStatus("Success")
- .setEmoji("GUILD.ROLES.CREATE")
- ],
- components: [
- new ActionRowBuilder<ButtonBuilder>().addComponents([
- new ButtonBuilder()
- .setCustomId("clear")
- .setLabel(clicks ? "Click again to confirm" : "Reset role")
- .setEmoji(getEmojiByName(clicks ? "TICKETS.ISSUE" : "CONTROL.CROSS", "id"))
- .setStyle(ButtonStyle.Danger)
- .setDisabled(!role),
- new ButtonBuilder()
- .setCustomId("send")
- .setLabel("Add verify button")
- .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
- .setStyle(ButtonStyle.Primary)
- ])
- ]
+ embeds: [embed],
+ components: [selectMenu, buttons]
});
- let i: MessageComponentInteraction;
+
+ let i;
try {
i = await m.awaitMessageComponent({
time: 300000,
- filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id }
+ filter: (i) => { return i.user.id === interaction.user.id }
});
} catch (e) {
- timedOut = true;
+ closed = true;
continue;
}
+
await i.deferUpdate();
- if ((i.component as ButtonComponent).customId === "clear") {
- clicks ++;
- if (clicks === 2) {
- clicks = 0;
- await client.database.guilds.write(interaction.guild.id, null, ["verify.role", "verify.enabled"]);
- role = null;
+
+ if(i.isButton()) {
+ switch (i.customId) {
+ case "save": {
+ client.database.guilds.write(interaction.guild.id, {"verify": data} )
+ config = await client.database.guilds.read(interaction.guild.id);
+ break
+ }
+ case "switch": {
+ data.enabled = !data.enabled;
+ break
+ }
}
} else {
- await i.deferUpdate();
- break;
+ data.role = i.values[0]!;
}
- } // TODO: On save, clear SEN
- await interaction.editReply({
- embeds: [new EmbedBuilder(m.embeds[0]!.data).setFooter({ text: "Message closed" })],
- components: []
- });
+
+ } while (!closed);
+ await interaction.deleteReply()
};
const check = (interaction: CommandInteraction, _partial: boolean = false) => {
diff --git a/src/commands/settings/welcome.ts b/src/commands/settings/welcome.ts
index b9c1b9f..ae55fc0 100644
--- a/src/commands/settings/welcome.ts
+++ b/src/commands/settings/welcome.ts
@@ -1,304 +1,260 @@
import { LoadingEmbed } from "../../utils/defaults.js";
import Discord, {
- Channel,
CommandInteraction,
- Message,
+ AutocompleteInteraction,
ActionRowBuilder,
ButtonBuilder,
- MessageComponentInteraction,
- Role,
ButtonStyle,
- AutocompleteInteraction,
- GuildChannel,
- EmbedBuilder
+ APIMessageComponentEmoji,
+ ChannelSelectMenuBuilder,
+ RoleSelectMenuBuilder,
+ RoleSelectMenuInteraction,
+ ChannelSelectMenuInteraction,
+ ButtonInteraction,
+ ModalBuilder,
+ TextInputBuilder,
+ TextInputStyle,
+ ModalSubmitInteraction,
} from "discord.js";
import type { SlashCommandSubcommandBuilder } from "discord.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import client from "../../utils/client.js";
-import confirmationMessage from "../../utils/confirmationMessage.js";
-import generateKeyValueList from "../../utils/generateKeyValueList.js";
-import { ChannelType } from "discord-api-types/v9";
import getEmojiByName from "../../utils/getEmojiByName.js";
+import convertCurlyBracketString from "../../utils/convertCurlyBracketString.js";
+import { modalInteractionCollector } from "../../utils/dualCollector.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
.setName("welcome")
.setDescription("Messages and roles sent or given when someone joins the server")
- .addStringOption((option) =>
- option
- .setName("message")
- .setDescription("The message to send when someone joins the server")
- .setAutocomplete(true)
- )
- .addRoleOption((option) =>
- option.setName("role").setDescription("The role given when someone joins the server")
- )
- .addRoleOption((option) =>
- option.setName("ping").setDescription("The role pinged when someone joins the server")
- )
- .addChannelOption((option) =>
- option
- .setName("channel")
- .setDescription("The channel the welcome message should be sent to")
- .addChannelTypes(ChannelType.GuildText)
- );
-const callback = async (interaction: CommandInteraction): Promise<unknown> => {
- const { renderRole, renderChannel, log, NucleusColors, entry, renderUser } = client.logger;
- await interaction.reply({
+const callback = async (interaction: CommandInteraction): Promise<void> => {
+ const { renderChannel } = client.logger;
+ const m = await interaction.reply({
embeds: LoadingEmbed,
fetchReply: true,
ephemeral: true
});
- let m: Message;
- if (
- interaction.options.get("role")?.role ||
- interaction.options.get("channel")?.channel ||
- interaction.options.get("message")?.value as string
- ) {
- let role: Role | null;
- let ping: Role | null;
- let channel: Channel | null;
- const message: string | null = interaction.options.get("message")?.value as string | null;
- try {
- role = interaction.options.get("role")?.role as Role | null;
- ping = interaction.options.get("ping")?.role as Role | null;
- } catch {
- return await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setEmoji("GUILD.ROLES.DELETE")
- .setTitle("Welcome Events")
- .setDescription("The role you provided is not a valid role")
- .setStatus("Danger")
- ]
- });
- }
- try {
- channel = interaction.options.get("channel")?.channel as Channel | null;
- } catch {
- return await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setEmoji("GUILD.ROLES.DELETE")
- .setTitle("Welcome Events")
- .setDescription("The channel you provided is not a valid channel")
- .setStatus("Danger")
- ]
- });
- }
- const options: {
- role?: string;
- ping?: string;
- channel?: string;
- message?: string;
- } = {};
-
- if (role) options.role = renderRole(role);
- if (ping) options.ping = renderRole(ping);
- if (channel) options.channel = renderChannel(channel as GuildChannel);
- if (message) options.message = "\n> " + message;
- const confirmation = await new confirmationMessage(interaction)
- .setEmoji("GUILD.ROLES.EDIT")
- .setTitle("Welcome Events")
- .setDescription(generateKeyValueList(options))
- .setColor("Warning")
- .setFailedMessage("No changes were made", "Success", "GUILD.ROLES.CREATE")
- .setInverted(true)
- .send(true);
- if (confirmation.cancelled) return;
- if (confirmation.success) {
- try {
- const toChange: {
- "welcome.role"?: string;
- "welcome.ping"?: string;
- "welcome.channel"?: string;
- "welcome.message"?: string;
- } = {};
- if (role) toChange["welcome.role"] = role.id;
- if (ping) toChange["welcome.ping"] = ping.id;
- if (channel) toChange["welcome.channel"] = channel.id;
- if (message) toChange["welcome.message"] = message;
- await client.database.guilds.write(interaction.guild!.id, toChange);
- const list: {
- memberId: ReturnType<typeof entry>;
- changedBy: ReturnType<typeof entry>;
- role?: ReturnType<typeof entry>;
- ping?: ReturnType<typeof entry>;
- channel?: ReturnType<typeof entry>;
- message?: ReturnType<typeof entry>;
- } = {
- memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
- changedBy: entry(interaction.user.id, renderUser(interaction.user))
- };
- if (role) list.role = entry(role.id, renderRole(role));
- if (ping) list.ping = entry(ping.id, renderRole(ping));
- if (channel) list.channel = entry(channel.id, renderChannel(channel as GuildChannel));
- if (message) list.message = entry(message, `\`${message}\``);
- const data = {
- meta: {
- type: "welcomeSettingsUpdated",
- displayName: "Welcome Settings Changed",
- calculateType: "nucleusSettingsUpdated",
- color: NucleusColors.green,
- emoji: "CONTROL.BLOCKTICK",
- timestamp: new Date().getTime()
- },
- list: list,
- hidden: {
- guild: interaction.guild!.id
- }
- };
- log(data);
- } catch (e) {
- console.log(e);
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Welcome Events")
- .setDescription("Something went wrong while updating welcome settings")
- .setStatus("Danger")
- .setEmoji("GUILD.ROLES.DELETE")
- ],
- components: []
- });
- }
- } else {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Welcome Events")
- .setDescription("No changes were made")
- .setStatus("Success")
- .setEmoji("GUILD.ROLES.CREATE")
- ],
- components: []
- });
- }
- }
- let lastClicked = null;
- let timedOut = false;
+ let closed = false;
+ let config = await client.database.guilds.read(interaction.guild!.id);
+ let data = Object.assign({}, config.welcome);
do {
- const config = await client.database.guilds.read(interaction.guild!.id);
- m = (await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Welcome Events")
- .setDescription(
- `**Message:** ${config.welcome.message ? `\n> ${config.welcome.message}` : "*None set*"}\n` +
- `**Role:** ${
- config.welcome.role
- ? renderRole((await interaction.guild!.roles.fetch(config.welcome.role))!)
- : "*None set*"
- }\n` +
- `**Ping:** ${
- config.welcome.ping
- ? renderRole((await interaction.guild!.roles.fetch(config.welcome.ping))!)
- : "*None set*"
- }\n` +
- `**Channel:** ${
- config.welcome.channel
- ? config.welcome.channel === "dm"
- ? "DM"
- : renderChannel((await interaction.guild!.channels.fetch(config.welcome.channel))!)
- : "*None set*"
- }`
+ const buttons = new ActionRowBuilder<ButtonBuilder>()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId("switch")
+ .setLabel(data.enabled ? "Enabled" : "Disabled")
+ .setStyle(data.enabled ? ButtonStyle.Success : ButtonStyle.Danger)
+ .setEmoji(getEmojiByName(data.enabled ? "CONTROL.TICK" : "CONTROL.CROSS", "id") as APIMessageComponentEmoji),
+ new ButtonBuilder()
+ .setCustomId("message")
+ .setLabel((data.message ? "Change" : "Set") + "Message")
+ .setStyle(ButtonStyle.Primary)
+ .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
+ new ButtonBuilder()
+ .setCustomId("channelDM")
+ .setLabel("Send in DMs")
+ .setStyle(ButtonStyle.Primary)
+ .setDisabled(data.channel === "dm"),
+ new ButtonBuilder()
+ .setCustomId("role")
+ .setLabel("Clear Role")
+ .setStyle(ButtonStyle.Danger)
+ .setEmoji(getEmojiByName("CONTROL.CROSS", "id") as APIMessageComponentEmoji),
+ new ButtonBuilder()
+ .setCustomId("save")
+ .setLabel("Save")
+ .setStyle(ButtonStyle.Success)
+ .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
+ .setDisabled(
+ data.enabled === config.welcome.enabled &&
+ data.message === config.welcome.message &&
+ data.role === config.welcome.role &&
+ data.ping === config.welcome.ping &&
+ data.channel === config.welcome.channel
)
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- ],
- components: [
- new ActionRowBuilder<ButtonBuilder>().addComponents([
- new ButtonBuilder()
- .setLabel(lastClicked === "clear-message" ? "Click again to confirm" : "Clear Message")
- .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
- .setCustomId("clear-message")
- .setDisabled(!config.welcome.message)
- .setStyle(ButtonStyle.Danger),
- new ButtonBuilder()
- .setLabel(lastClicked === "clear-role" ? "Click again to confirm" : "Clear Role")
- .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
- .setCustomId("clear-role")
- .setDisabled(!config.welcome.role)
- .setStyle(ButtonStyle.Danger),
- new ButtonBuilder()
- .setLabel(lastClicked === "clear-ping" ? "Click again to confirm" : "Clear Ping")
- .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
- .setCustomId("clear-ping")
- .setDisabled(!config.welcome.ping)
- .setStyle(ButtonStyle.Danger),
- new ButtonBuilder()
- .setLabel(lastClicked === "clear-channel" ? "Click again to confirm" : "Clear Channel")
- .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
- .setCustomId("clear-channel")
- .setDisabled(!config.welcome.channel)
- .setStyle(ButtonStyle.Danger),
- new ButtonBuilder()
- .setLabel("Set Channel to DM")
- .setCustomId("set-channel-dm")
- .setDisabled(config.welcome.channel === "dm")
- .setStyle(ButtonStyle.Secondary)
- ])
- ]
- })) as Message;
- let i: MessageComponentInteraction;
+ );
+
+ const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>()
+ .addComponents(
+ new ChannelSelectMenuBuilder()
+ .setCustomId("channel")
+ .setPlaceholder("Select a channel to send welcome messages to")
+ );
+ const roleMenu = new ActionRowBuilder<RoleSelectMenuBuilder>()
+ .addComponents(
+ new RoleSelectMenuBuilder()
+ .setCustomId("roleToGive")
+ .setPlaceholder("Select a role to give to the member when they join the server")
+ );
+ const pingMenu = new ActionRowBuilder<RoleSelectMenuBuilder>()
+ .addComponents(
+ new RoleSelectMenuBuilder()
+ .setCustomId("roleToPing")
+ .setPlaceholder("Select a role to ping when a member joins the server")
+ );
+
+ const embed = new EmojiEmbed()
+ .setTitle("Welcome Settings")
+ .setStatus("Success")
+ .setDescription(
+ `${getEmojiByName(data.enabled ? "CONTROL.TICK" : "CONTROL.CROSS")} Welcome messages and roles are ${data.enabled ? "enabled" : "disabled"}\n` +
+ `**Welcome message:** ${data.message ?
+ `\n> ` +
+ await convertCurlyBracketString(
+ data.message,
+ interaction.user.id,
+ interaction.user.username,
+ interaction.guild!.name,
+ interaction.guild!.members
+ )
+ : "*None*"}\n` +
+ `**Send message in:** ` + (data.channel ? (data.channel == "dm" ? "DMs" : renderChannel(data.channel)) : `*None set*`) + `\n` +
+ `**Role to ping:** ` + (data.ping ? `<@&${data.ping}>` : `*None set*`) + `\n` +
+ `**Role given on join:** ` + (data.role ? `<@&${data.role}>` : `*None set*`)
+ )
+
+ await interaction.editReply({
+ embeds: [embed],
+ components: [buttons, channelMenu, roleMenu, pingMenu]
+ });
+
+ let i: RoleSelectMenuInteraction | ChannelSelectMenuInteraction | ButtonInteraction;
try {
i = await m.awaitMessageComponent({
- time: 300000,
- filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id }
- });
+ filter: (interaction) => interaction.user.id === interaction.user.id,
+ time: 300000
+ }) as RoleSelectMenuInteraction | ChannelSelectMenuInteraction | ButtonInteraction;
} catch (e) {
- timedOut = true;
+ closed = true;
continue;
}
- await i.deferUpdate();
- if (i.customId === "clear-message") {
- if (lastClicked === "clear-message") {
- await client.database.guilds.write(interaction.guild!.id, {
- "welcome.message": null
- });
- lastClicked = null;
- } else {
- lastClicked = "clear-message";
+
+ if(i.isButton()) {
+ switch(i.customId) {
+ case "switch": {
+ await i.deferUpdate();
+ data.enabled = !data.enabled;
+ break;
+ }
+ case "message": {
+ const modal = new ModalBuilder()
+ .setCustomId("modal")
+ .setTitle("Welcome Message")
+ .addComponents(
+ new ActionRowBuilder<TextInputBuilder>().addComponents(
+ new TextInputBuilder()
+ .setCustomId("ex1")
+ .setLabel("Server Info (1/3)")
+ .setPlaceholder(
+ `{serverName} - This server's name\n\n` +
+ `These placeholders will be replaced with the server's name, etc..`
+ )
+ .setMaxLength(1)
+ .setRequired(false)
+ .setStyle(TextInputStyle.Paragraph)
+ ),
+ new ActionRowBuilder<TextInputBuilder>().addComponents(
+ new TextInputBuilder()
+ .setCustomId("ex2")
+ .setLabel("Member Counts (2/3) - {MemberCount:...}")
+ .setPlaceholder(
+ `{:all} - Total member count\n` +
+ `{:humans} - Total non-bot users\n` +
+ `{:bots} - Number of bots\n`
+ )
+ .setMaxLength(1)
+ .setRequired(false)
+ .setStyle(TextInputStyle.Paragraph)
+ ),
+ new ActionRowBuilder<TextInputBuilder>().addComponents(
+ new TextInputBuilder()
+ .setCustomId("ex3")
+ .setLabel("Member who joined (3/3) - {member:...}")
+ .setPlaceholder(
+ `{:name} - The members name\n`
+ )
+ .setMaxLength(1)
+ .setRequired(false)
+ .setStyle(TextInputStyle.Paragraph)
+ ),
+ new ActionRowBuilder<TextInputBuilder>()
+ .addComponents(
+ new TextInputBuilder()
+ .setCustomId("message")
+ .setPlaceholder("Enter a message to send when someone joins the server")
+ .setValue(data.message ?? "")
+ .setLabel("Message")
+ .setStyle(TextInputStyle.Paragraph)
+ )
+ )
+ const button = new ActionRowBuilder<ButtonBuilder>()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId("back")
+ .setLabel("Back")
+ .setStyle(ButtonStyle.Secondary)
+ .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
+ )
+ await i.showModal(modal)
+ await i.editReply({
+ embeds: [
+ new EmojiEmbed()
+ .setTitle("Welcome Settings")
+ .setDescription("Modal opened. If you can't see it, click back and try again.")
+ .setStatus("Success")
+ ],
+ components: [button]
+ });
+
+ let out: ModalSubmitInteraction | null;
+ try {
+ out = await modalInteractionCollector(m, interaction.user) as ModalSubmitInteraction | null;
+ } catch (e) {
+ console.error(e);
+ out = null;
+ }
+ if(!out) break;
+ data.message = out.fields.getTextInputValue("message") ?? null;
+ break;
+ }
+ case "save": {
+ await i.deferUpdate();
+ await client.database.guilds.write(interaction.guild!.id, {"welcome": data});
+ config = await client.database.guilds.read(interaction.guild!.id);
+ data = Object.assign({}, config.welcome);
+ break;
+ }
+ case "channelDM": {
+ await i.deferUpdate();
+ data.channel = "dm";
+ break;
+ }
+ case "role": {
+ await i.deferUpdate();
+ data.role = null;
+ break;
+ }
}
- } else if (i.customId === "clear-role") {
- if (lastClicked === "clear-role") {
- await client.database.guilds.write(interaction.guild!.id, {
- "welcome.role": null
- });
- lastClicked = null;
- } else {
- lastClicked = "clear-role";
+ } else if (i.isRoleSelectMenu()) {
+ await i.deferUpdate();
+ switch(i.customId) {
+ case "roleToGive": {
+ data.role = i.values[0]!;
+ break
+ }
+ case "roleToPing": {
+ data.ping = i.values[0]!;
+ break
+ }
}
- } else if (i.customId === "clear-ping") {
- if (lastClicked === "clear-ping") {
- await client.database.guilds.write(interaction.guild!.id, {
- "welcome.ping": null
- });
- lastClicked = null;
- } else {
- lastClicked = "clear-ping";
- }
- } else if (i.customId === "clear-channel") {
- if (lastClicked === "clear-channel") {
- await client.database.guilds.write(interaction.guild!.id, {
- "welcome.channel": null
- });
- lastClicked = null;
- } else {
- lastClicked = "clear-channel";
- }
- } else if (i.customId === "set-channel-dm") {
- await client.database.guilds.write(interaction.guild!.id, {
- "welcome.channel": "dm"
- });
- lastClicked = null;
+ } else {
+ await i.deferUpdate();
+ data.channel = i.values[0]!;
}
- } while (!timedOut);
- await interaction.editReply({
- embeds: [new EmbedBuilder(m.embeds[0]!.data).setFooter({ text: "Message timed out" })],
- components: []
- });
+
+ } while (!closed);
+ await interaction.deleteReply()
};
const check = (interaction: CommandInteraction, _partial: boolean = false) => {
@@ -341,4 +297,4 @@
return autocompletions;
};
-export { command, callback, check, autocomplete };
+export { command, callback, check, autocomplete };
\ No newline at end of file