From 93b362fe30de959c0404e08fcc834e03a045b064 Mon Sep 17 00:00:00 2001 From: nick <62725534+nicklvh@users.noreply.github.com> Date: Mon, 25 Mar 2024 00:06:15 +0000 Subject: [PATCH] feat: improve settings command --- prisma/schema.prisma | 44 +++- src/classes/Helpers.ts | 83 +++--- src/commands/settings/settings.ts | 419 ++++++++++++++++-------------- 3 files changed, 301 insertions(+), 245 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index f00e50c..2ce8e97 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -11,25 +11,48 @@ datasource db { } model Guild { - id String @id + id String @id + members Member[] + logging Logging? + fun Fun? + banned Boolean? @default(false) + starboard Starboard? + modlogs Modlog[] +} + +model Fun { + enabled Boolean @default(false) + economyEnabled Boolean @default(false) + countingId String? + countingEnabled Boolean @default(false) + guildId String @unique + guild Guild @relation(fields: [guildId], references: [id]) +} + +model Logging { + enabled Boolean @default(false) modlogId String? - welcomeId String? auditlogId String? - members Member[] - logging Boolean? @default(false) - welcome Boolean? @default(false) - starboard Boolean? @default(false) - fun Boolean? @default(false) - banned Boolean? @default(false) + welcomeId String? + guildId String @unique + guild Guild @relation(fields: [guildId], references: [id]) +} + +model Starboard { + enabled Boolean @default(false) + starsRequired Int? @default(5) + starredMessages String[] + guildId String @unique + guild Guild @relation(fields: [guildId], references: [id]) } model Member { - id String @id + id String @id coins Int? xp Int? level Int? - Guild Guild @relation(fields: [guildId], references: [id]) guildId String + Guild Guild @relation(fields: [guildId], references: [id]) } model Modlog { @@ -39,6 +62,7 @@ model Modlog { type ModerationType createdAt DateTime @unique @default(now()) guildId String + guild Guild @relation(fields: [guildId], references: [id]) } model Ban { diff --git a/src/classes/Helpers.ts b/src/classes/Helpers.ts index 1aba8dc..cd72d1f 100644 --- a/src/classes/Helpers.ts +++ b/src/classes/Helpers.ts @@ -1,7 +1,7 @@ import { ModerationType } from "@prisma/client"; import { container } from "@sapphire/framework"; import { - Guild, + Guild as DiscordGuild, type GuildTextBasedChannel, ChatInputCommandInteraction, User, @@ -11,19 +11,47 @@ import { import { ModerationTypeNamesPast } from "../types/index.js"; export class Helpers { - public async welcomeChecks( - guild: Guild - ): Promise { - const guildInDB = await container.prisma.guild.findUnique({ - where: { - id: guild.id, + public async getGuild(guildId: string) { + let guild = await container.prisma.guild.findUnique({ + where: { id: guildId }, + include: { + logging: true, + starboard: true, + fun: true, + modlogs: true, }, }); - if (!guildInDB || !guildInDB.logging || !guildInDB.welcomeId) return false; + if (!guild) { + guild = await container.prisma.guild.create({ + data: { + id: guildId, + starboard: { create: {} }, + logging: { create: {} }, + fun: { create: {} }, + }, + include: { + logging: true, + starboard: true, + fun: true, + modlogs: true, + }, + }); + } + + return guild; + } + + public async welcomeChecks( + guild: DiscordGuild + ): Promise { + const guildInDB = await this.getGuild(guild.id); + + if (!guildInDB.logging?.enabled || !guildInDB.logging.welcomeId) + return false; const welcomeChannel = await container.client.channels - .fetch(guildInDB.welcomeId) + .fetch(guildInDB.logging.welcomeId) .catch(() => container.logger.error( `Invalid welcome channel ID for Guild ${guild.name} (${guild.id})` @@ -36,18 +64,15 @@ export class Helpers { } public async auditlogChecks( - guild: Guild + guild: DiscordGuild ): Promise { - const guildInDB = await container.prisma.guild.findUnique({ - where: { - id: guild.id, - }, - }); + const guildInDB = await this.getGuild(guild.id); - if (!guildInDB || !guildInDB.logging || !guildInDB.auditlogId) return false; + if (!guildInDB.logging?.enabled || !guildInDB.logging.auditlogId) + return false; const loggingChannel = await container.client.channels - .fetch(guildInDB.auditlogId) + .fetch(guildInDB.logging.auditlogId) .catch(() => container.logger.error( `Invalid logging channel ID for Guild ${guild.name} (${guild.id})` @@ -99,7 +124,7 @@ export class Helpers { private async sendModMsgToUser( type: ModerationType, user: User, - guild: Guild, + guild: DiscordGuild, reason: string ) { const embed = new EmbedBuilder() @@ -144,33 +169,21 @@ export class Helpers { private async sendModMsgToModlog( type: ModerationType, - guild: Guild, + guild: DiscordGuild, user: User, moderator: User, reason: string ) { - let guildInDB = await container.prisma.guild.findUnique({ - where: { - id: guild.id, - }, - })!; - - if (!guildInDB) { - guildInDB = await container.prisma.guild.create({ - data: { - id: guild.id, - }, - })!; - } + const guildInDB = await this.getGuild(guild.id); - if (!guildInDB || !guildInDB.modlogId) return; + if (!guildInDB.logging!.enabled || !guildInDB.logging!.modlogId) return; const modlogChannel = await guild.channels - .fetch(guildInDB.modlogId!) + .fetch(guildInDB.logging!.modlogId) .catch(() => container.logger.error( `[${guild.name} (${guild.id})] Could not fetch modlog channel ${ - guildInDB!.modlogId + guildInDB.logging!.modlogId }` ) ); diff --git a/src/commands/settings/settings.ts b/src/commands/settings/settings.ts index 6e33e82..77dbc7d 100644 --- a/src/commands/settings/settings.ts +++ b/src/commands/settings/settings.ts @@ -5,25 +5,21 @@ import { ButtonBuilder, ButtonStyle, ChannelSelectMenuBuilder, - ChannelSelectMenuInteraction, ChannelType, EmbedBuilder, MessageComponentInteraction, PermissionFlagsBits, + bold, } from "discord.js"; -import type { Guild } from "@prisma/client"; import { Time } from "@sapphire/time-utilities"; @ApplyOptions({ name: "settings", description: "change the settings of the bot for the current server", requiredUserPermissions: ["ManageGuild"], - requiredClientPermissions: ["ManageGuild"], runIn: CommandOptionsRunTypeEnum.GuildAny, }) export class SettingsCommand extends Command { - private guildId = ""; - public override registerApplicationCommands(registry: Command.Registry) { registry.registerChatInputCommand((builder) => builder @@ -36,9 +32,9 @@ export class SettingsCommand extends Command { public override async chatInputRun( interaction: Command.ChatInputCommandInteraction<"cached"> ) { - this.guildId = interaction.guildId!; - - const guildInDB: Guild = await this.getGuild(); + const guildInDB = await this.container.helpers.getGuild( + interaction.guildId + ); const loggingButton = new ButtonBuilder() .setLabel("Logging") @@ -74,6 +70,8 @@ export class SettingsCommand extends Command { exitButton ); + const { logging, fun, starboard } = guildInDB; + const message = await interaction.reply({ embeds: [ new EmbedBuilder() @@ -86,9 +84,9 @@ export class SettingsCommand extends Command { { name: "Use the buttons below to configure the server.", value: [ - `**Logging:** ${guildInDB?.logging ? "✅" : "❌"}`, - `**Starboard:** ${guildInDB?.starboard ? "✅" : "❌"}`, - `**Fun:** ${guildInDB?.fun ? "✅" : "❌"}`, + `**Logging:** ${logging!.enabled ? "✅" : "❌"}`, + `**Starboard:** ${starboard!.enabled ? "✅" : "❌"}`, + `**Fun:** ${fun!.enabled ? "✅" : "❌"}`, ].join("\n"), }, ]), @@ -105,8 +103,13 @@ export class SettingsCommand extends Command { collector.on( "collect", async (componentInteraction: MessageComponentInteraction<"cached">) => { + this.container.logger.info(componentInteraction.customId); + collector.resetTimer(); + const { logging, fun, starboard } = + await this.container.helpers.getGuild(interaction.guildId); + const goBackButton = new ButtonBuilder() .setCustomId("goBack") .setLabel("Home") @@ -117,18 +120,20 @@ export class SettingsCommand extends Command { goBackButton ); - const guild: Guild = await this.getGuild(); - const id = componentInteraction.customId; if (componentInteraction.isButton()) { - if (id === "logging" || "starboard" || "fun") { - const dbOption = guild[id as "logging" | "starboard" | "fun"]; - + if (id === "logging" || id === "starboard" || id === "fun") { const toggleButton = new ButtonBuilder() - .setCustomId(`${id}${dbOption ? "Disable" : "Enable"}`) - .setLabel(dbOption ? "Disable" : "Enable") - .setStyle(dbOption ? ButtonStyle.Danger : ButtonStyle.Success); + .setCustomId( + `${id}${guildInDB[id]!.enabled ? "Disable" : "Enable"}` + ) + .setLabel(guildInDB[id]!.enabled ? "Disable" : "Enable") + .setStyle( + guildInDB[id]!.enabled + ? ButtonStyle.Danger + : ButtonStyle.Success + ); if (id === "logging") { await componentInteraction.update({ @@ -142,9 +147,9 @@ export class SettingsCommand extends Command { { name: `Use the buttons below to edit the respective channel and settings`, value: [ - `**Modlog:** ${guild.modlogId ? `<#${guild.modlogId}>` : "Not set"}`, - `**Auditlog:** ${guild.auditlogId ? `<#${guild.auditlogId}>` : "Not set"}`, - `**Welcome:** ${guild.welcomeId ? `<#${guild.welcomeId}>` : "Not set"}`, + `**Modlog:** ${logging!.modlogId ? `<#${logging!.modlogId}>` : "Disabled"}`, + `**Auditlog:** ${logging!.auditlogId ? `<#${logging!.auditlogId}>` : "Disabled"}`, + `**Welcome:** ${logging!.welcomeId ? `<#${logging!.welcomeId}>` : "Disabled"}`, ].join("\n"), }, ]) @@ -171,227 +176,254 @@ export class SettingsCommand extends Command { }); } - if (id === "modlog" || id === "auditlog" || id === "welcome") { - const channelSelector = new ChannelSelectMenuBuilder() - .addChannelTypes(ChannelType.GuildText) - .setCustomId(`${id}ChannelSelect`); - - const disableButton = new ButtonBuilder() - .setLabel("Disable") - .setStyle(ButtonStyle.Danger) - .setCustomId(`${id}DisableMod`); - - const channelRow = - new ActionRowBuilder().addComponents( - channelSelector - ); - - const goBackAndDisableRow = - new ActionRowBuilder().addComponents( - goBackButton, - disableButton - ); - - const name = `${id}Id` as "modlogId" | "auditlogId" | "welcomeId"; - - const channel = guild[name]; - + if (id === "starboard") { await componentInteraction.update({ embeds: [ new EmbedBuilder() .setAuthor({ - name: `Configuring the ${id} channel`, + name: "Configuring the starboard system", iconURL: interaction.guild.iconURL() as string, }) - .setColor("Blue") - .setDescription( - `Pick a channel below to edit the ${id} channel for \`${ - interaction.guild!.name - }\`${channel ? "\nDisable it by selecting `Disable`" : ""}` - ), - ], - components: [ - channelRow, - channel ? goBackAndDisableRow : goBackRow, - ], - }); - } - - if (id === "goBack") { - const guildInDB: Guild = await this.getGuild(); - - await componentInteraction.update({ - embeds: [ - new EmbedBuilder() - .setAuthor({ - name: `Configure ${interaction.guild!.name}`, - iconURL: interaction.guild.iconURL() ?? undefined, - }) - .setColor("Blue") .addFields([ { - name: "Use the buttons below to configure the server.", + name: `Use the buttons below to edit the settings for ${bold(`${interaction.guild.name}'s`)} starboard!`, value: [ - `**Logging:** ${guildInDB?.logging ? "✅" : "❌"}`, - `**Starboard:** ${guildInDB?.starboard ? "✅" : "❌"}`, - `**Fun:** ${guildInDB?.fun ? "✅" : "❌"}`, + `**Stars Required:** ${bold(starboard?.starsRequired?.toString()!)}`, ].join("\n"), }, - ]), + ]) + .setColor("Yellow"), + ], + components: [ + new ActionRowBuilder().addComponents( + toggleButton + ), + goBackRow, ], - components: [mainRow, exitRow], }); } + } - if (id.endsWith("DisableMod")) { - const name = id.split("DisableMod")[0]; + if (id === "modlog" || id === "auditlog" || id === "welcome") { + const channelSelector = new ChannelSelectMenuBuilder() + .addChannelTypes(ChannelType.GuildText) + .setCustomId(`${id}ChannelSelect`); - const customId = `${name}Id`; + const disableButton = new ButtonBuilder() + .setLabel("Disable") + .setStyle(ButtonStyle.Danger) + .setCustomId(`${id}Disable`); - await this.container.prisma.guild.update({ - where: { - id: interaction.guildId!, - }, - data: { - [customId]: null, + const channelRow = + new ActionRowBuilder().addComponents( + channelSelector + ); + + const goBackAndDisableRow = + new ActionRowBuilder().addComponents( + goBackButton, + disableButton + ); + + const name = `${id}Id` as "modlogId" | "auditlogId" | "welcomeId"; + + const channel = logging![name]; + + await componentInteraction.update({ + embeds: [ + new EmbedBuilder() + .setAuthor({ + name: `Configuring the ${id} channel`, + iconURL: interaction.guild.iconURL() as string, + }) + .setColor("Blue") + .setDescription( + `Pick a channel below to edit the ${id} channel for \`${ + interaction.guild!.name + }\`${channel ? "\nDisable it by selecting `Disable`" : ""}` + ), + ], + components: [ + channelRow, + channel ? goBackAndDisableRow : goBackRow, + ], + }); + } + + if (id === "goBack") { + await componentInteraction.update({ + embeds: [ + new EmbedBuilder() + .setAuthor({ + name: `Configure ${interaction.guild!.name}`, + iconURL: interaction.guild.iconURL() ?? undefined, + }) + .setColor("Blue") + .addFields([ + { + name: "Use the buttons below to configure the server.", + value: [ + `**Logging:** ${logging!.enabled ? "✅" : "❌"}`, + `**Starboard:** ${starboard!.enabled ? "✅" : "❌"}`, + `**Fun:** ${fun!.enabled ? "✅" : "❌"}`, + ].join("\n"), + }, + ]), + ], + components: [mainRow, exitRow], + }); + } + + if (id.endsWith("Enable")) { + const name = id.split("Enable")[0]; + + await this.container.prisma.guild.update({ + where: { + id: interaction.guildId!, + }, + data: { + [name]: { + update: { + enabled: true, + }, }, - }); + }, + }); - await componentInteraction.update({ - embeds: [ - new EmbedBuilder() - .setAuthor({ - name: `Success`, - iconURL: interaction.guild.iconURL() as string, - }) - .setColor("Blue") - .setDescription( - `Successfully disabled the ${name} channel for \`${interaction.guild!.name}\`` - ), - ], - components: [goBackRow], - }); - } + await componentInteraction.update({ + embeds: [ + new EmbedBuilder() + .setAuthor({ + name: `Success`, + iconURL: interaction.guild.iconURL() as string, + }) + .setColor("Blue") + .setDescription( + `Successfully ${bold("enabled")} the ${name} system for \`${interaction.guild!.name}\`` + ), + ], + components: [goBackRow], + }); + } - if (id.endsWith("Enable")) { - const name = id.split("Enable")[0]; + if (id.endsWith("Disable")) { + let name = id.split("Disable")[0]; + let data = null; + + if (name === "modlog" || name == "auditlog" || name === "welcome") { + name = name + "Id"; + data = { + logging: { + update: { + [name]: null, + }, + }, + }; + } + if (data) { await this.container.prisma.guild.update({ where: { id: interaction.guildId!, }, - data: { - [name]: true, - }, - }); - - await componentInteraction.update({ - embeds: [ - new EmbedBuilder() - .setAuthor({ - name: `Success`, - iconURL: interaction.guild.iconURL() as string, - }) - .setColor("Blue") - .setDescription( - `Successfully enabled the ${name} system for \`${interaction.guild!.name}\`` - ), - ], - components: [goBackRow], + data, }); - } - - if (id.endsWith("Disable")) { - const name = id.split("Disable")[0]; - + } else { await this.container.prisma.guild.update({ where: { id: interaction.guildId!, }, data: { - [name]: false, + [name]: { + update: { + enabled: false, + }, + }, }, }); - - await componentInteraction.update({ - embeds: [ - new EmbedBuilder() - .setAuthor({ - name: `Success`, - iconURL: interaction.guild.iconURL() as string, - }) - .setColor("Blue") - .setDescription( - `Successfully disabled the ${name} system for \`${interaction.guild!.name}\`` - ), - ], - components: [goBackRow], - }); } - } - if (componentInteraction.isChannelSelectMenu()) { - componentInteraction = - componentInteraction as ChannelSelectMenuInteraction<"cached">; - - const channelId = ( - componentInteraction as ChannelSelectMenuInteraction<"cached"> - ).values[0]; + await componentInteraction.update({ + embeds: [ + new EmbedBuilder() + .setAuthor({ + name: `Success`, + iconURL: interaction.guild.iconURL() as string, + }) + .setColor("Blue") + .setDescription( + `Successfully ${bold("disabled")} the ${name.endsWith("Id") ? name.split("Id")[0] : name} ${name.endsWith("Id") ? "channel" : "system"} for \`${interaction.guild!.name}\`` + ), + ], + components: [goBackRow], + }); + } - const name = id.split("ChannelSelect")[0]; + if (id === "exit") { + collector.emit("dispose", componentInteraction); + } + } - const customId = `${name}Id` as - | "modlogId" - | "auditlogId" - | "welcomeId"; + if (componentInteraction.isChannelSelectMenu()) { + const channelId = componentInteraction.values[0]; - if (guild[customId] === channelId) { - await componentInteraction.update({ - embeds: [ - new EmbedBuilder() - .setAuthor({ - name: `Error while editing ${interaction.guild!.name}`, - iconURL: interaction.guild.iconURL() as string, - }) - .setColor("Blue") - .setDescription( - `<#${channelId}> is already set as the ${name} channel!` - ), - ], - components: [goBackRow], - }); - return; - } + const name = id.split("ChannelSelect")[0]; - await this.container.prisma.guild.update({ - where: { - id: interaction.guildId!, - }, - data: { - [customId]: channelId, - }, - }); + const customId = `${name}Id` as + | "modlogId" + | "auditlogId" + | "welcomeId"; + if (logging![customId] === channelId) { await componentInteraction.update({ embeds: [ new EmbedBuilder() .setAuthor({ - name: `Success`, + name: `Error while editing ${interaction.guild!.name}`, iconURL: interaction.guild.iconURL() as string, }) .setColor("Blue") .setDescription( - `Successfully set the ${name} channel to <#${channelId}>` + `<#${channelId}> is already set as the ${name} channel!` ), ], components: [goBackRow], }); + return; } + + await this.container.prisma.guild.update({ + where: { + id: interaction.guildId!, + }, + data: { + logging: { + update: { + [customId]: channelId, + }, + }, + }, + }); + + await componentInteraction.update({ + embeds: [ + new EmbedBuilder() + .setAuthor({ + name: `Success`, + iconURL: interaction.guild.iconURL() as string, + }) + .setColor("Blue") + .setDescription( + `Successfully set the ${name} channel to <#${channelId}>` + ), + ], + components: [goBackRow], + }); } } ); - collector.on("dispose", async () => { + collector.on("dispose", async (componentInteraction) => { const embed = new EmbedBuilder() .setAuthor({ name: "Exited", @@ -402,20 +434,7 @@ export class SettingsCommand extends Command { ) .setColor("Blue"); - await interaction.editReply({ embeds: [embed] }); + await componentInteraction.update({ embeds: [embed], components: [] }); }); } - - private async getGuild(): Promise { - let guild: Guild | null = await this.container.prisma.guild.findUnique({ - where: { id: this.guildId }, - }); - - if (!guild) - guild = await this.container.prisma.guild.create({ - data: { id: this.guildId }, - }); - - return guild; - } }