From e6979c1d5ae7a62b181bd9c1361ae58e8cc68580 Mon Sep 17 00:00:00 2001
From: MrSerge01 <86667481+MrSerge01@users.noreply.github.com>
Date: Wed, 27 Nov 2024 22:19:14 +0500
Subject: [PATCH] wow uh yes

---
 src/bot.ts                         |   9 +-
 src/commands/Leaderboard.ts        |   6 +-
 src/commands/moderation/Ban.ts     |   9 +-
 src/commands/moderation/Delwarn.ts |  10 +-
 src/commands/moderation/Kick.ts    |   3 +-
 src/commands/moderation/Mute.ts    |  10 +-
 src/commands/moderation/Unban.ts   |   2 +-
 src/commands/moderation/Unmute.ts  |   2 +-
 src/events/guildCreate.ts          |  16 ++-
 src/events/guildMemberAdd.ts       |   6 +-
 src/events/interactionCreate.ts    |  16 ++-
 src/handlers/commands.ts           | 197 ++++++++++-------------------
 src/handlers/events.ts             |  25 ++--
 src/utils/embeds/modEmbed.ts       |  33 ++---
 14 files changed, 147 insertions(+), 197 deletions(-)

diff --git a/src/bot.ts b/src/bot.ts
index bd8e19b..3a9eb41 100644
--- a/src/bot.ts
+++ b/src/bot.ts
@@ -1,6 +1,6 @@
 import { ActivityType, Client } from "discord.js";
-import { Commands } from "./handlers/commands";
-import { Events } from "./handlers/events";
+import { registerCommands } from "./handlers/commands";
+import { loadEvents } from "./handlers/events";
 import { rescheduleUnbans } from "./utils/unbanScheduler";
 
 const client = new Client({
@@ -12,15 +12,14 @@ const client = new Client({
     "GuildMembers",
     "GuildMessages",
     "GuildEmojisAndStickers",
-    "GuildPresences",
     "GuildBans",
     "MessageContent"
   ]
 });
 
 client.on("ready", async () => {
-  await new Events(client).loadEvents();
-  await new Commands(client).registerCommands();
+  await loadEvents(client);
+  await registerCommands(client);
   console.log("ちーっす!");
   rescheduleUnbans(client);
 });
diff --git a/src/commands/Leaderboard.ts b/src/commands/Leaderboard.ts
index b07c8f3..b10e56d 100644
--- a/src/commands/Leaderboard.ts
+++ b/src/commands/Leaderboard.ts
@@ -38,12 +38,12 @@ export default class Leaderboard {
       else return b.xp - a.xp;
     });
 
-    const totalPages = Math.ceil(leaderboardData.length / 5);
+    const totalPages = Math.ceil(leaderboardData.length / 6);
     let page = interaction.options.getNumber("page") || 1;
     page = Math.max(1, Math.min(page, totalPages));
     const generateEmbed = async () => {
-      const start = (page - 1) * 5;
-      const end = start + 5;
+      const start = (page - 1) * 6;
+      const end = start + 6;
       const pageData = leaderboardData.slice(start, end);
 
       const embed = new EmbedBuilder()
diff --git a/src/commands/moderation/Ban.ts b/src/commands/moderation/Ban.ts
index 0dbc4de..9370e85 100644
--- a/src/commands/moderation/Ban.ts
+++ b/src/commands/moderation/Ban.ts
@@ -60,14 +60,13 @@ export default class Ban {
     }
 
     try {
+      await modEmbed(
+        { interaction, user, action: "Banned", duration, dm: true, dbAction: "BAN", expiresAt },
+        reason
+      );
       await guild.members.ban(user.id, { reason: reason ?? undefined });
     } catch (err) {
       console.error("Failed to ban user:", err);
     }
-
-    await modEmbed(
-      { interaction, user, action: "Banned", duration, dm: true, dbAction: "BAN", expiresAt },
-      reason
-    );
   }
 }
diff --git a/src/commands/moderation/Delwarn.ts b/src/commands/moderation/Delwarn.ts
index 88af050..2e610d2 100644
--- a/src/commands/moderation/Delwarn.ts
+++ b/src/commands/moderation/Delwarn.ts
@@ -38,7 +38,7 @@ export default class Delwarn {
     if (
       await errorCheck(
         PermissionsBitField.Flags.ModerateMembers,
-        { interaction, user, action: "Remove a warn" },
+        { interaction, user, action: "Remove a warning" },
         { allErrors: true, botError: false },
         "Moderate Members"
       )
@@ -46,7 +46,7 @@ export default class Delwarn {
       return;
 
     if (newWarns.length == warns.length)
-      return await errorEmbed(interaction, `There is no warn with the id of ${id}.`);
+      return await errorEmbed(interaction, `There is no warning with the id of ${id}.`);
 
     const embed = new EmbedBuilder()
       .setAuthor({ name: `•  Removed a warning from ${name}`, iconURL: user.displayAvatarURL() })
@@ -65,6 +65,10 @@ export default class Delwarn {
     const dmChannel = (await user.createDM().catch(() => null)) as DMChannel | null;
     if (!dmChannel) return;
     if (user.bot) return;
-    await dmChannel.send({ embeds: [embed.setTitle("Your warning has been removed.")] });
+    try {
+      await dmChannel.send({ embeds: [embed.setTitle("Your warning has been removed.")] });
+    } catch (e) {
+      console.log(e);
+    }
   }
 }
diff --git a/src/commands/moderation/Kick.ts b/src/commands/moderation/Kick.ts
index c67bae8..44b18cf 100644
--- a/src/commands/moderation/Kick.ts
+++ b/src/commands/moderation/Kick.ts
@@ -40,11 +40,10 @@ export default class Kick {
       );
 
     const reason = interaction.options.getString("reason");
+    await modEmbed({ interaction, user, action: "Kicked", dm: true, dbAction: "KICK" }, reason);
     await interaction.guild?.members.cache
       .get(user.id)
       ?.kick(reason ?? undefined)
       .catch(error => console.error(error));
-
-    await modEmbed({ interaction, user, action: "Kicked", dm: true, dbAction: "KICK" }, reason);
   }
 }
diff --git a/src/commands/moderation/Mute.ts b/src/commands/moderation/Mute.ts
index b32ad71..8212cf1 100644
--- a/src/commands/moderation/Mute.ts
+++ b/src/commands/moderation/Mute.ts
@@ -52,15 +52,15 @@ export default class Mute {
       Date.parse(new Date().toISOString()) + Date.parse(new Date(ms(duration)).toISOString())
     ).toISOString();
 
-    await interaction.guild?.members.cache
-      .get(user.id)
-      ?.edit({ communicationDisabledUntil: time, reason: reason ?? undefined })
-      .catch(error => console.error(error));
-
     await modEmbed(
       { interaction, user, action: "Muted", duration, dm: true, dbAction: "MUTE" },
       reason,
       true
     );
+
+    await interaction.guild?.members.cache
+      .get(user.id)
+      ?.edit({ communicationDisabledUntil: time, reason: reason ?? undefined })
+      .catch(error => console.error(error));
   }
 }
diff --git a/src/commands/moderation/Unban.ts b/src/commands/moderation/Unban.ts
index a8d5d8e..bff235d 100644
--- a/src/commands/moderation/Unban.ts
+++ b/src/commands/moderation/Unban.ts
@@ -46,7 +46,7 @@ export default class Unban {
         "The user was never banned."
       );
 
-    await guild.members.unban(id, reason ?? undefined).catch(error => console.error(error));
     await modEmbed({ interaction, user: target, action: "Unbanned" }, reason);
+    await guild.members.unban(id, reason ?? undefined).catch(error => console.error(error));
   }
 }
diff --git a/src/commands/moderation/Unmute.ts b/src/commands/moderation/Unmute.ts
index 622e95b..3ec6fad 100644
--- a/src/commands/moderation/Unmute.ts
+++ b/src/commands/moderation/Unmute.ts
@@ -37,7 +37,7 @@ export default class Unmute {
         "The user was never muted."
       );
 
-    await target.edit({ communicationDisabledUntil: null }).catch(error => console.error(error));
     await modEmbed({ interaction, user, action: "Unmuted" });
+    await target.edit({ communicationDisabledUntil: null }).catch(error => console.error(error));
   }
 }
diff --git a/src/events/guildCreate.ts b/src/events/guildCreate.ts
index dd2242d..353f0bc 100644
--- a/src/events/guildCreate.ts
+++ b/src/events/guildCreate.ts
@@ -1,14 +1,14 @@
 import { EmbedBuilder, type DMChannel } from "discord.js";
-import { Commands } from "../handlers/commands";
+import { commands } from "../handlers/commands";
 import { genColor } from "../utils/colorGen";
 import { randomise } from "../utils/randomise";
 import { Event } from "../utils/types";
 
 export default (async function run(guild) {
-  const dmChannel = (await (await guild.fetchOwner()).createDM().catch(() => null)) as
-    | DMChannel
-    | undefined;
+  const owner = await guild.fetchOwner();
+  if (owner.user.bot) return;
 
+  const dmChannel = (await owner.createDM().catch(() => null)) as DMChannel | undefined;
   let emojis = ["💖", "💝", "💓", "💗", "💘", "💟", "💕", "💞"];
   if (Math.round(Math.random() * 100) <= 5) emojis = ["⌨️", "💻", "🖥️"];
 
@@ -29,6 +29,10 @@ export default (async function run(guild) {
     .setThumbnail(client.user.displayAvatarURL())
     .setColor(genColor(200));
 
-  await new Commands(client).registerCommandsForGuild(guild);
-  if (dmChannel) await dmChannel.send({ embeds: [embed] });
+  await guild.commands.set(commands.map(command => command.data));
+  try {
+    if (dmChannel) await dmChannel.send({ embeds: [embed] });
+  } catch (e) {
+    console.log(e);
+  }
 } as Event<"guildCreate">);
diff --git a/src/events/guildMemberAdd.ts b/src/events/guildMemberAdd.ts
index fa6673a..8913927 100644
--- a/src/events/guildMemberAdd.ts
+++ b/src/events/guildMemberAdd.ts
@@ -31,5 +31,9 @@ export default (async function run(member) {
   if (user.bot) return;
 
   replace(member, getSetting(guildID, "welcome", "dm_text") as string, embed);
-  await dmChannel.send({ embeds: [embed] }).catch(() => null);
+  try {
+    await dmChannel.send({ embeds: [embed] }).catch(() => null);
+  } catch (e) {
+    return console.log(e);
+  }
 } as Event<"guildMemberAdd">);
diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts
index e5efaf6..6103392 100644
--- a/src/events/interactionCreate.ts
+++ b/src/events/interactionCreate.ts
@@ -1,14 +1,18 @@
-import { Commands } from "../handlers/commands";
+import { commands, subCommands } from "../handlers/commands";
 import { Event } from "../utils/types";
 
 export default (async function run(interaction) {
   if (!interaction.isChatInputCommand() && !interaction.isAutocomplete()) return;
-  const command = await new Commands(interaction.client).getCommand(
-    interaction.commandName,
-    interaction.options
-  );
-  if (!command) return;
+  let command;
+  const subCommand = subCommands.filter(
+    subCommand => subCommand.data.name == interaction.options.getSubcommand(false)
+  )[0];
+
+  if (!subCommand)
+    command = commands.filter(command => command.data.name == interaction.commandName)[0];
+  else command = subCommand;
 
+  if (!command) return;
   if (interaction.isChatInputCommand()) command.run(interaction);
   if (command.autocomplete) command.autocomplete(interaction);
 } as Event<"interactionCreate">);
diff --git a/src/handlers/commands.ts b/src/handlers/commands.ts
index b0f7e4a..a271bde 100644
--- a/src/handlers/commands.ts
+++ b/src/handlers/commands.ts
@@ -1,148 +1,89 @@
-import {
-  Guild,
-  SlashCommandBuilder,
-  SlashCommandSubcommandBuilder,
-  SlashCommandSubcommandGroupBuilder,
-  type Client
-} from "discord.js";
+import { SlashCommandBuilder, SlashCommandSubcommandBuilder, type Client } from "discord.js";
 import { readdirSync } from "fs";
 import { join } from "path";
 import { pathToFileURL } from "url";
 import { getDisabledCommands } from "../utils/database/disabledCommands";
 
 export let commands: { data: SlashCommandBuilder; run: any; autocomplete: any }[] = [];
-let subcommands: { data: SlashCommandSubcommandBuilder; run: any; autocomplete: any }[] = [];
-export class Commands {
-  client: Client;
-  constructor(client: Client) {
-    this.client = client;
-  }
-
-  private async createSubCommand(name: string, ...disabledCommands: string[]) {
-    const commandsPath = join(process.cwd(), "src", "commands");
-    const run = [];
-    const autocomplete = [];
-    const command = new SlashCommandBuilder()
-      .setName(name.toLowerCase())
-      .setDescription("This command has no description.");
-
-    for (const subCommandFile of readdirSync(join(commandsPath, name), {
-      withFileTypes: true
-    })) {
-      const subCommandName = subCommandFile.name.replaceAll(".ts", "");
-      if (
-        disabledCommands?.find(
-          command => command?.split("/")?.[0] == name && command?.split("/")?.[1] == subCommandName
-        )
+export let subCommands: { data: SlashCommandSubcommandBuilder; run: any; autocomplete: any }[] = [];
+async function createSubCommand(name: string, client: Client, ...disabledCommands: string[]) {
+  const commandsPath = join(process.cwd(), "src", "commands");
+  const run = [];
+  const autocomplete = [];
+  const command = new SlashCommandBuilder()
+    .setName(name.toLowerCase())
+    .setDescription("This command has no description.");
+
+  for (const subCommandFile of readdirSync(join(commandsPath, name), {
+    withFileTypes: true
+  })) {
+    const subCommandName = subCommandFile.name.replaceAll(".ts", "");
+    if (
+      disabledCommands?.find(
+        command => command?.split("/")?.[0] == name && command?.split("/")?.[1] == subCommandName
       )
-        continue;
-
-      if (subCommandFile.isFile()) {
-        const subCommandModule = await import(
-          pathToFileURL(join(commandsPath, name, subCommandFile.name)).toString()
-        );
-        const subCommand = new subCommandModule.default();
-
-        command.addSubcommand(subCommand.data);
-        run.push(subCommand.run);
-        subcommands.push({
-          data: subCommand.data,
-          run: subCommand.run,
-          autocomplete: subCommand.autocomplete
-        });
-
-        if ("autocompleteHandler" in subCommand) {
-          subCommand.autocompleteHandler(this.client);
-          autocomplete.push(subCommand.autocomplete);
-        }
-        continue;
-      }
-
-      const subCommandGroup = new SlashCommandSubcommandGroupBuilder()
-        .setName(subCommandName.toLowerCase())
-        .setDescription("This subcommand group has no description.");
-
-      const subCommandGroupFiles = readdirSync(join(commandsPath, name, subCommandFile.name), {
-        withFileTypes: true
-      });
-      for (const subCommandGroupFile of subCommandGroupFiles) {
-        if (!subCommandGroupFile.isFile()) continue;
-        if (
-          disabledCommands?.find(
-            command =>
-              command?.split("/")?.[0] == name &&
-              command?.split("/")?.[1] == subCommandFile.name.replaceAll(".ts", "") &&
-              command?.split("/")?.[2] == subCommandGroupFile.name.replaceAll(".ts", "")
-          )
-        )
-          continue;
-
-        const subCommand = await import(
-          pathToFileURL(
-            join(commandsPath, name, subCommandFile.name, subCommandGroupFile.name)
-          ).toString()
-        );
-        subCommandGroup.addSubcommand(new subCommand.default().data);
-      }
-      command.addSubcommandGroup(subCommandGroup);
+    )
+      continue;
+
+    if (!subCommandFile.isFile()) continue;
+    const subCommandModule = await import(
+      pathToFileURL(join(commandsPath, name, subCommandFile.name)).toString()
+    );
+    const subCommand = new subCommandModule.default();
+
+    command.addSubcommand(subCommand.data);
+    run.push(subCommand.run);
+    subCommands.push({
+      data: subCommand.data,
+      run: subCommand.run,
+      autocomplete: subCommand.autocomplete
+    });
+
+    if ("autocompleteHandler" in subCommand) {
+      subCommand.autocompleteHandler(client);
+      autocomplete.push(subCommand.autocomplete);
     }
-
-    return { data: command, run: run, autocomplete: autocomplete };
   }
 
-  async loadCommands(...disabledCommands: string[]) {
-    const commandsPath = join(process.cwd(), "src", "commands");
-    const commandFiles = readdirSync(commandsPath, { withFileTypes: true });
-
-    for (const commandFile of commandFiles) {
-      const name = commandFile.name;
-      if (disabledCommands?.includes(name.replaceAll(".ts", ""))) continue;
-
-      if (commandFile.isFile()) {
-        const commandImport = await import(pathToFileURL(join(commandsPath, name)).toString());
-        commands.push(new commandImport.default());
-        continue;
-      }
+  return { data: command, run: run, autocomplete: autocomplete };
+}
 
-      const subCommand = await this.createSubCommand(
-        name,
-        join(commandsPath, name),
-        ...disabledCommands
-      );
+async function loadCommands(client: Client, ...disabledCommands: string[]) {
+  const commandsPath = join(process.cwd(), "src", "commands");
+  for (const commandFile of readdirSync(commandsPath, { withFileTypes: true })) {
+    const name = commandFile.name;
+    if (disabledCommands?.includes(name.replaceAll(".ts", ""))) continue;
 
-      commands.push({
-        data: subCommand.data,
-        run: subCommand.run,
-        autocomplete: subCommand.autocomplete
-      });
+    if (commandFile.isFile()) {
+      const commandImport = await import(pathToFileURL(join(commandsPath, name)).toString());
+      commands.push(new commandImport.default());
+      continue;
     }
 
-    return commands;
-  }
-
-  async registerCommandsForGuild(guild: Guild) {
-    await guild.commands.set(commands.map(command => command.data));
+    const subCommand = await createSubCommand(
+      name,
+      client,
+      join(commandsPath, name),
+      ...disabledCommands
+    );
+
+    commands.push({
+      data: subCommand.data,
+      run: subCommand.run,
+      autocomplete: subCommand.autocomplete
+    });
   }
 
-  async registerCommands(): Promise<any[]> {
-    await this.loadCommands();
-    const guilds = this.client.guilds.cache;
-
-    for (const guildID of guilds.keys()) {
-      const disabledCommands = getDisabledCommands(guildID);
-      if (disabledCommands.length > 0) await this.loadCommands(...disabledCommands);
-      await guilds.get(guildID)?.commands.set(commands.map(command => command.data));
-    }
-
-    return commands;
-  }
+  return commands;
+}
 
-  async getCommand(name: string, options: any) {
-    const subcommandName = options.getSubcommand(false);
+export async function registerCommands(client: Client) {
+  await loadCommands(client);
+  const guilds = client.guilds.cache;
 
-    const command = commands.filter(command => command.data.name == name)[0];
-    const subcommand = subcommands.filter(subcommand => subcommand.data.name == subcommandName)[0];
-    if (!subcommand) return command;
-    return subcommand;
+  for (const guildID of guilds.keys()) {
+    const disabledCommands = getDisabledCommands(guildID);
+    if (disabledCommands.length > 0) await loadCommands(client, ...disabledCommands);
+    await guilds.get(guildID)?.commands.set(commands.map(command => command.data));
   }
 }
diff --git a/src/handlers/events.ts b/src/handlers/events.ts
index 3ac1b39..707f232 100644
--- a/src/handlers/events.ts
+++ b/src/handlers/events.ts
@@ -3,24 +3,17 @@ import { readdirSync } from "fs";
 import { join } from "path";
 import { pathToFileURL } from "url";
 
-export class Events {
-  client: Client;
-  events: any[] = [];
-  constructor(client: Client) {
-    this.client = client;
-  }
-
-  async loadEvents() {
-    const eventsPath = join(process.cwd(), "src", "events");
+let events = [];
+export async function loadEvents(client: Client) {
+  const eventsPath = join(process.cwd(), "src", "events");
 
-    for (const eventFile of readdirSync(eventsPath)) {
-      if (!eventFile.endsWith("ts")) continue;
+  for (const eventFile of readdirSync(eventsPath)) {
+    if (!eventFile.endsWith("ts")) continue;
 
-      const event = (await import(pathToFileURL(join(eventsPath, eventFile)).toString())).default;
-      const eventName = eventFile.split(".ts")[0];
-      const clientEvent = this.client.on(eventName, event);
+    const event = (await import(pathToFileURL(join(eventsPath, eventFile)).toString())).default;
+    const eventName = eventFile.split(".ts")[0];
+    const clientEvent = client.on(eventName, event);
 
-      this.events.push({ name: eventName, event: clientEvent });
-    }
+    events.push({ name: eventName, event: clientEvent });
   }
 }
diff --git a/src/utils/embeds/modEmbed.ts b/src/utils/embeds/modEmbed.ts
index b598c5e..26a5ef7 100644
--- a/src/utils/embeds/modEmbed.ts
+++ b/src/utils/embeds/modEmbed.ts
@@ -110,7 +110,7 @@ export async function modEmbed(
   let author = `•  ${action} ${name}`;
   reason ? generalValues.push(`**Reason**: ${reason}`) : generalValues.push("*No reason provided*");
   if (duration) generalValues.push(`**Duration**: ${ms(ms(duration), { long: true })}`);
-  if (dbAction) {
+  if (dbAction)
     try {
       const id = addModeration(
         guild.id,
@@ -124,7 +124,6 @@ export async function modEmbed(
     } catch (error) {
       console.error(error);
     }
-  }
 
   const embed = new EmbedBuilder()
     .setAuthor({ name: author, iconURL: user.displayAvatarURL() })
@@ -139,17 +138,21 @@ export async function modEmbed(
   if (!dm) return;
   const dmChannel = await user.createDM().catch(() => null);
   if (!dmChannel || !guild.members.cache.get(user.id) || user.bot) return;
-  await dmChannel
-    .send({
-      embeds: [
-        embed
-          .setAuthor({
-            name: `•  You got ${action.toLowerCase()}.`,
-            iconURL: user.displayAvatarURL()
-          })
-          .setDescription(generalValues.slice(+!showModerator, generalValues.length).join("\n"))
-          .setColor(genColor(0))
-      ]
-    })
-    .catch(() => null);
+  try {
+    await dmChannel
+      .send({
+        embeds: [
+          embed
+            .setAuthor({
+              name: `•  You got ${action.toLowerCase()}.`,
+              iconURL: user.displayAvatarURL()
+            })
+            .setDescription(generalValues.slice(+!showModerator, generalValues.length).join("\n"))
+            .setColor(genColor(0))
+        ]
+      })
+      .catch(() => null);
+  } catch (e) {
+    return console.log(e);
+  }
 }