feat: ♻️ centralized error classes

I have cleaned up some code by moving some regular used throw new messages to a error class file
This commit is contained in:
Axel Olausson Holtenäs 2023-10-01 16:10:58 +02:00
parent 0c3f53950c
commit a816129dd2
25 changed files with 151 additions and 182 deletions

View file

@ -9,6 +9,10 @@ import CreditsManager from "../../../../../../handlers/CreditsManager";
import prisma from "../../../../../../handlers/prisma";
import generateCooldownName from "../../../../../../helpers/generateCooldownName";
import deferReply from "../../../../../../utils/deferReply";
import {
GuildNotFoundError,
UserNotFoundError,
} from "../../../../../../utils/errors";
import sendResponse from "../../../../../../utils/sendResponse";
const cooldownManager = new CooldownManager();
@ -22,18 +26,8 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
const { guild, user } = interaction;
await deferReply(interaction, false);
if (!guild) {
throw new Error(
"Oops! It looks like you're not part of a guild. Join a guild to embark on this adventure!"
);
}
if (!user) {
throw new Error(
"Oops! We couldn't find your user information. Please try again or contact support for assistance."
);
}
if (!guild) throw new GuildNotFoundError();
if (!user) throw new UserNotFoundError();
const guildCreditsSettings = await prisma.guildCreditsSettings.upsert({
where: { id: guild.id },

View file

@ -9,6 +9,10 @@ import CreditsManager from "../../../../../../handlers/CreditsManager";
import prisma from "../../../../../../handlers/prisma";
import generateCooldownName from "../../../../../../helpers/generateCooldownName";
import deferReply from "../../../../../../utils/deferReply";
import {
GuildNotFoundError,
UserNotFoundError,
} from "../../../../../../utils/errors";
import sendResponse from "../../../../../../utils/sendResponse";
const cooldownManager = new CooldownManager();
@ -25,17 +29,8 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, false);
if (!guild) {
throw new Error(
"Oops! It looks like you're not part of a guild. Join a guild to embark on this adventure!"
);
}
if (!user) {
throw new Error(
"Oops! We couldn't find your user information. Please try again or contact support for assistance."
);
}
if (!guild) throw new GuildNotFoundError();
if (!user) throw new UserNotFoundError();
const guildCreditsSettings = await prisma.guildCreditsSettings.upsert({
where: { id: guild.id },

View file

@ -9,6 +9,10 @@ import CreditsManager from "../../../../../../handlers/CreditsManager";
import prisma from "../../../../../../handlers/prisma";
import generateCooldownName from "../../../../../../helpers/generateCooldownName";
import deferReply from "../../../../../../utils/deferReply";
import {
GuildNotFoundError,
UserNotFoundError,
} from "../../../../../../utils/errors";
import sendResponse from "../../../../../../utils/sendResponse";
const cooldownManager = new CooldownManager();
@ -24,18 +28,8 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
const { guild, user } = interaction;
await deferReply(interaction, false);
if (!guild) {
throw new Error(
"Oops! It looks like you're not part of a guild. Join a guild to embark on this adventure!"
);
}
if (!user) {
throw new Error(
"Oops! We couldn't find your user information. Please try again or contact support for assistance."
);
}
if (!guild) throw new GuildNotFoundError();
if (!user) throw new UserNotFoundError();
const guildCreditsSettings = await prisma.guildCreditsSettings.upsert({
where: { id: guild.id },

View file

@ -7,6 +7,7 @@ import {
} from "discord.js";
import CreditsManager from "../../../../handlers/CreditsManager";
import deferReply from "../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../utils/errors";
import sendResponse from "../../../../utils/sendResponse";
const creditsManager = new CreditsManager();
@ -26,11 +27,9 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
export const execute = async (interaction: ChatInputCommandInteraction) => {
const { options, user, guild } = interaction;
await deferReply(interaction, false);
if (!guild) {
throw new Error("This command can only be used in guild environments. ❌");
}
await deferReply(interaction, false);
if (!guild) throw new GuildNotFoundError();
const checkAccount = options.getUser("account") || user;
const creditAccount = await creditsManager.balance(guild, checkAccount);

View file

@ -9,6 +9,7 @@ import {
import CreditsManager from "../../../../handlers/CreditsManager";
import upsertGuildMember from "../../../../helpers/upsertGuildMember";
import deferReply from "../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../utils/errors";
import sendResponse from "../../../../utils/sendResponse";
const creditsManager = new CreditsManager();
@ -39,17 +40,15 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
};
export const execute = async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
const { options, user, guild } = interaction;
const recipient = options.getUser("account");
await deferReply(interaction, true);
if (!guild) throw new GuildNotFoundError();
const recipient = options.getUser("account", true);
const amount = options.getInteger("amount");
const message = options.getString("message");
if (!guild || !user || !recipient) {
throw new Error("Invalid interaction data");
}
if (typeof amount !== "number" || amount < 1) {
throw new Error("Please enter a valid number of credits to gift");
}

View file

@ -6,6 +6,7 @@ import {
} from "discord.js";
import CreditsManager from "../../../../handlers/CreditsManager";
import deferReply from "../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../utils/errors";
import sendResponse from "../../../../utils/sendResponse";
const creditsManager = new CreditsManager();
@ -20,10 +21,7 @@ export const execute = async (interaction: CommandInteraction) => {
const { guild, client, user } = interaction;
await deferReply(interaction, false);
if (!guild) {
throw new Error("Unable to find the guild.");
}
if (!guild) throw new GuildNotFoundError();
const topTen = await creditsManager.topUsers(guild, 10);

View file

@ -10,6 +10,7 @@ import CreditsManager from "../../../../handlers/CreditsManager";
import prisma from "../../../../handlers/prisma";
import generateCooldownName from "../../../../helpers/generateCooldownName";
import deferReply from "../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../utils/errors";
import sendResponse from "../../../../utils/sendResponse";
import jobs from "./jobs";
@ -28,18 +29,7 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
const { guild, user } = interaction;
await deferReply(interaction, false);
if (!guild) {
throw new Error(
"Oops! It seems like you're not part of a guild. Join a guild to use this command!"
);
}
if (!user) {
throw new Error(
"Oops! It looks like we couldn't find your user information. Please try again or contact support for assistance."
);
}
if (!guild) throw new GuildNotFoundError();
const chance = new Chance();

View file

@ -7,6 +7,7 @@ import {
import CreditsManager from "../../../../../../handlers/CreditsManager";
import checkPermission from "../../../../../../utils/checkPermission";
import deferReply from "../../../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../../../utils/errors";
import sendResponse from "../../../../../../utils/sendResponse";
const creditsManager = new CreditsManager();
@ -40,19 +41,11 @@ export const execute = async (
await deferReply(interaction, false);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
if (!guild) {
throw new Error("We could not get the current guild from Discord.");
}
if (!guild) throw new GuildNotFoundError();
const discordReceiver = options.getUser("user", true);
const creditsAmount = options.getInteger("amount", true);
if (!discordReceiver || typeof creditsAmount !== "number") {
await sendResponse(interaction, "Invalid user or credit amount provided.");
return;
}
const embedSuccess = new EmbedBuilder()
.setColor(process.env.EMBED_COLOR_SUCCESS)
.setAuthor({ name: "💳 Credits Manager" })

View file

@ -14,6 +14,7 @@ import { v4 as uuidv4 } from "uuid";
import CtrlPanelAPI from "../../../../../../services/CtrlPanelAPI";
import checkPermission from "../../../../../../utils/checkPermission";
import deferReply from "../../../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../../../utils/errors";
import sendResponse from "../../../../../../utils/sendResponse";
// Function
@ -47,18 +48,13 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
if (!guild) throw new GuildNotFoundError();
if (!guild) throw new Error("This command can only be used in guilds");
const ctrlPanelAPI = new CtrlPanelAPI(guild);
const uses = options?.getInteger("uses");
const creditAmount = options?.getInteger("credit");
const channel = options?.getChannel("channel");
if (!uses) throw new Error("Amount of uses is required.");
if (!creditAmount) throw new Error("Amount of credits is required.");
if (!channel) throw new Error("Channel is required.");
if (!guild) throw new Error("Guild is required.");
const uses = options?.getInteger("uses", true);
const creditAmount = options?.getInteger("credit", true);
const channel = options?.getChannel("channel", true);
const embedSuccess = new EmbedBuilder()
.setTitle(":toolbox:︱Giveaway")

View file

@ -7,6 +7,7 @@ import {
import CreditsManager from "../../../../../../handlers/CreditsManager";
import checkPermission from "../../../../../../utils/checkPermission";
import deferReply from "../../../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../../../utils/errors";
import sendResponse from "../../../../../../utils/sendResponse";
const creditsManager = new CreditsManager();
@ -38,18 +39,10 @@ export const execute = async (
await deferReply(interaction, false);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
if (!guild) throw new GuildNotFoundError();
if (!guild) {
throw new Error("We could not get the current guild from Discord.");
}
const discordReceiver = options.getUser("user");
const creditsAmount = options.getInteger("amount");
if (!discordReceiver || typeof creditsAmount !== "number") {
await sendResponse(interaction, "Invalid user or credit amount provided.");
return;
}
const discordReceiver = options.getUser("user", true);
const creditsAmount = options.getInteger("amount", true);
const embedSuccess = new EmbedBuilder()
.setColor(process.env.EMBED_COLOR_SUCCESS)

View file

@ -7,6 +7,7 @@ import {
import CreditsManager from "../../../../../../handlers/CreditsManager";
import checkPermission from "../../../../../../utils/checkPermission";
import deferReply from "../../../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../../../utils/errors";
import sendResponse from "../../../../../../utils/sendResponse";
const creditsManager = new CreditsManager();
@ -38,18 +39,10 @@ export const execute = async (
await deferReply(interaction, false);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
if (!guild) throw new GuildNotFoundError();
if (!guild) {
throw new Error("We could not get the current guild from Discord.");
}
const discordReceiver = options.getUser("user");
const creditsAmount = options.getInteger("amount");
if (!discordReceiver || typeof creditsAmount !== "number") {
await sendResponse(interaction, "Invalid user or credit amount provided.");
return;
}
const discordReceiver = options.getUser("user", true);
const creditsAmount = options.getInteger("amount", true);
const embedSuccess = new EmbedBuilder()
.setColor(process.env.EMBED_COLOR_SUCCESS)

View file

@ -7,6 +7,7 @@ import {
import CreditsManager from "../../../../../../handlers/CreditsManager";
import checkPermission from "../../../../../../utils/checkPermission";
import deferReply from "../../../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../../../utils/errors";
import sendResponse from "../../../../../../utils/sendResponse";
const creditsManager = new CreditsManager();
@ -44,18 +45,11 @@ export const execute = async (
await deferReply(interaction, false);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
if (!guild) throw new GuildNotFoundError();
if (!guild) {
throw new Error("We could not get the current guild from Discord.");
}
const fromUser = options.getUser("from-user");
const toUser = options.getUser("to-user");
const creditsAmount = options.getInteger("amount");
if (!fromUser || !toUser || typeof creditsAmount !== "number") {
throw new Error("Invalid user(s) or credit amount provided.");
}
const fromUser = options.getUser("from-user", true);
const toUser = options.getUser("to-user", true);
const creditsAmount = options.getInteger("amount", true);
const transactionResult = await creditsManager.transfer(
guild,

View file

@ -8,6 +8,10 @@ import {
} from "discord.js";
import checkPermission from "../../../../utils/checkPermission";
import deferReply from "../../../../utils/deferReply";
import {
ChannelNotFoundError,
GuildNotFoundError,
} from "../../../../utils/errors";
import sendResponse from "../../../../utils/sendResponse";
// Function
@ -31,23 +35,23 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
};
export const execute = async (interaction: ChatInputCommandInteraction) => {
const { user, options, channel } = interaction;
if (!channel) {
throw new Error("The bot failed to find the channel to prune messages in.");
}
const { guild, user, options, channel } = interaction;
await deferReply(interaction, false);
checkPermission(interaction, PermissionsBitField.Flags.ManageMessages);
if (!guild) throw new GuildNotFoundError();
if (!channel) throw new ChannelNotFoundError();
const count = options.getInteger("count");
const count = options.getInteger("count", true);
const bots = options.getBoolean("bots");
if (!count || count < 1 || count > 99) {
if (count < 1 || count > 99) {
throw new Error(
"Please provide a number between 1 and 99 for the prune command."
);
}
if (channel.type !== ChannelType.GuildText) return;
if (channel.type !== ChannelType.GuildText)
throw new Error("This channel is not a text channel in a guild!");
const messagesToDelete = await channel.messages
.fetch({ limit: count + 1 }) // Fetch count + 1 messages to exclude the interaction message itself

View file

@ -10,6 +10,10 @@ import prisma from "../../../../handlers/prisma";
import generateCooldownName from "../../../../helpers/generateCooldownName";
import upsertGuildMember from "../../../../helpers/upsertGuildMember";
import deferReply from "../../../../utils/deferReply";
import {
ChannelNotFoundError,
GuildNotFoundError,
} from "../../../../utils/errors";
import sendResponse from "../../../../utils/sendResponse";
const cooldownManager = new CooldownManager();
@ -35,16 +39,16 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
export const execute = async (
interaction: ChatInputCommandInteraction
): Promise<void> => {
await deferReply(interaction, true);
const { options, guild, user } = interaction;
if (!guild) throw new Error("A guild is required.");
await deferReply(interaction, true);
if (!guild) throw new GuildNotFoundError();
const quoteUser = options.getUser("user", true);
const quoteString = options.getString("message", true);
if (quoteUser.id == user.id) throw new Error("One cannot quote oneself.");
await upsertGuildMember(guild, user);
await upsertGuildMember(guild, quoteUser);
@ -61,7 +65,7 @@ export const execute = async (
guildQuotesSettings.quoteChannelId
);
if (!channel) throw new Error("No channel found.");
if (!channel) throw new ChannelNotFoundError();
if (channel.type !== ChannelType.GuildText)
throw new Error("The channel is not a text channel.");

View file

@ -22,14 +22,11 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
};
export const execute = async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, false);
const { options, user } = interaction;
await deferReply(interaction, false);
const checkUser = options.getUser("user") || user;
if (!user) throw new Error("User unavailable");
const userReputation = await reputationManager.check(checkUser);
const interactionEmbed = new EmbedBuilder()

View file

@ -8,6 +8,7 @@ import CooldownManager from "../../../../handlers/CooldownManager";
import ReputationManager from "../../../../handlers/ReputationManager";
import generateCooldownName from "../../../../helpers/generateCooldownName";
import deferReply from "../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../utils/errors";
import sendResponse from "../../../../utils/sendResponse";
const cooldownManager = new CooldownManager();
@ -37,21 +38,13 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
export const execute = async (interaction: ChatInputCommandInteraction) => {
const { options, user, guild } = interaction;
await deferReply(interaction, true);
if (!guild) {
throw new Error("This command can only be used in guilds");
}
await deferReply(interaction, true);
if (!guild) throw new GuildNotFoundError();
const targetUser = options.getUser("user", true);
const reputationType = options.getString("type", true);
if (!targetUser) {
throw new Error(
"Sorry, we were unable to find the user you are trying to give reputation to."
);
}
if (reputationType !== "positive" && reputationType !== "negative") {
throw new Error("Invalid reputation type");
}

View file

@ -7,6 +7,7 @@ import {
import prisma from "../../../../handlers/prisma";
import checkPermission from "../../../../utils/checkPermission";
import deferReply from "../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../utils/errors";
import sendResponse from "../../../../utils/sendResponse";
export const builder = (command: SlashCommandSubcommandBuilder) => {
@ -32,26 +33,14 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
};
export const execute = async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { guild, options, user } = interaction;
const workBonusChance = options.getNumber("work-bonus-chance");
const workPenaltyChance = options.getNumber("work-penalty-chance");
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
if (!guild) throw new GuildNotFoundError();
if (!guild) {
throw new Error("Guild not found.");
}
if (typeof workBonusChance !== "number") {
throw new Error("Work Bonus Chance must be a number.");
}
if (typeof workPenaltyChance !== "number") {
throw new Error("Work Penalty Chance must be a number.");
}
const workBonusChance = options.getNumber("work-bonus-chance", true);
const workPenaltyChance = options.getNumber("work-penalty-chance", true);
const upsertGuildCreditsSettings = await prisma.guildCreditsSettings.upsert({
where: {

View file

@ -9,6 +9,7 @@ import CtrlPanelAPI, {
} from "../../../../services/CtrlPanelAPI";
import checkPermission from "../../../../utils/checkPermission";
import deferReply from "../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../utils/errors";
import logger from "../../../../utils/logger";
import sendResponse from "../../../../utils/sendResponse";
@ -35,12 +36,11 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
};
export const execute = async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { guild, options, user } = interaction;
if (!guild) throw new Error("Guild unavailable");
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
if (!guild) throw new GuildNotFoundError();
const scheme = options.getString("scheme", true);
const domain = options.getString("domain", true);

View file

@ -7,6 +7,7 @@ import {
import prisma from "../../../../handlers/prisma";
import checkPermission from "../../../../utils/checkPermission";
import deferReply from "../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../utils/errors";
import sendResponse from "../../../../utils/sendResponse";
export const builder = (command: SlashCommandSubcommandBuilder) => {
@ -22,19 +23,15 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
};
export const execute = async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { guild, options, user } = interaction;
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
if (!guild) throw new GuildNotFoundError();
const quoteStatus = options.getBoolean("status", true);
const quoteChannel = options.getChannel("channel", true);
if (!guild) {
throw new Error("Guild not found.");
}
const upsertGuildQuotesSettings = await prisma.guildQuotesSettings.upsert({
where: {
id: guild.id,

View file

@ -11,6 +11,7 @@ import { v4 as uuidv4 } from "uuid";
import CreditsManager from "../../../handlers/CreditsManager";
import CtrlPanelAPI from "../../../services/CtrlPanelAPI";
import deferReply from "../../../utils/deferReply";
import { GuildNotFoundError } from "../../../utils/errors";
import sendResponse from "../../../utils/sendResponse";
const creditsManager = new CreditsManager();
@ -30,15 +31,13 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
};
export const execute = async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
const { options, guild, user, client } = interaction;
if (!guild) throw new Error("This command can only be executed in a guild");
await deferReply(interaction, true);
if (!guild) throw new GuildNotFoundError();
const ctrlPanelAPI = new CtrlPanelAPI(guild);
const withdrawalAmount = options.getInteger("withdraw", true);
await creditsManager.take(guild, user, withdrawalAmount);
const voucherCode = uuidv4();

View file

@ -8,6 +8,7 @@ import {
SlashCommandSubcommandBuilder,
} from "discord.js";
import deferReply from "../../../../utils/deferReply";
import { GuildNotFoundError } from "../../../../utils/errors";
import sendResponse from "../../../../utils/sendResponse";
export const builder = (command: SlashCommandSubcommandBuilder) => {
@ -17,13 +18,10 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
};
export const execute = async (interaction: CommandInteraction) => {
await deferReply(interaction, false);
const { user, guild, client } = interaction;
if (!guild) {
throw new Error("This command is only available in guilds");
}
await deferReply(interaction, false);
if (!guild) throw new GuildNotFoundError();
const guildCount = client.guilds.cache.size;
const memberCount = client.guilds.cache.reduce(

View file

@ -18,12 +18,10 @@ export const builder = (command: SlashCommandSubcommandBuilder) => {
};
export const execute = async (interaction: CommandInteraction) => {
await deferReply(interaction, false);
const { options, user } = interaction;
await deferReply(interaction, false);
const userOption = options.getUser("user");
const targetUser = userOption || user;
const embed = new EmbedBuilder()

View file

@ -0,0 +1,10 @@
import { Guild, Interaction } from "discord.js";
export default function ensureGuildExists(interaction: Interaction): Guild {
if (!interaction.guild) {
throw new Error(
"Oops! It looks like you're not part of a guild. Join a guild to embark on this adventure!"
);
}
return interaction.guild;
}

View file

@ -0,0 +1,10 @@
import { Interaction, User } from "discord.js";
export default function ensureUserExists(interaction: Interaction): User {
if (!interaction.user) {
throw new Error(
"Oops! We couldn't find your user information. Please try again or contact support for assistance."
);
}
return interaction.user;
}

32
src/utils/errors.ts Normal file
View file

@ -0,0 +1,32 @@
class CustomError extends Error {
constructor(message: string) {
super(message);
this.name = this.constructor.name;
}
}
class GuildNotFoundError extends CustomError {
constructor() {
super(
"Guild not found: You are not part of a guild. Join a guild to embark on this adventure."
);
}
}
class UserNotFoundError extends CustomError {
constructor() {
super(
"User not found: We couldn't retrieve your user information. Please try again or contact support for assistance."
);
}
}
class ChannelNotFoundError extends CustomError {
constructor() {
super(
"Channel not found: We couldn't retrieve the channel. Please try again or contact support for assistance."
);
}
}
export { GuildNotFoundError, UserNotFoundError, ChannelNotFoundError };