diff --git a/.gitignore b/.gitignore index 0ae1541..9f176fb 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,9 @@ package-lock.json !**/config/index.ts !**/config/example.*.ts +# Build +build/ + # Logs logs diff --git a/src/commands/config/index.ts b/src/commands/config/index.ts new file mode 100644 index 0000000..4110d5c --- /dev/null +++ b/src/commands/config/index.ts @@ -0,0 +1,43 @@ +// Dependencies +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +// Modules +import modules from "./modules"; + +// Handlers +import logger from "../../logger"; + +export const builder = new SlashCommandBuilder() + .setName("config") + .setDescription("Manage guild configurations.") + + .addSubcommand(modules.pterodactyl.builder) + .addSubcommand(modules.credits.builder) + .addSubcommand(modules.points.builder) + .addSubcommand(modules.welcome.builder) + .addSubcommand(modules.audits.builder) + .addSubcommand(modules.shop.builder) + .addSubcommand(modules.embeds.builder); + +export const moduleData = modules; + +// Function +export const execute = async (interaction: CommandInteraction) => { + switch (interaction.options?.getSubcommand()) { + case "pterodactyl": + return modules.pterodactyl.execute(interaction); + case "credits": + return modules.credits.execute(interaction); + case "points": + return modules.points.execute(interaction); + case "welcome": + return modules.welcome.execute(interaction); + case "audits": + return modules.audits.execute(interaction); + case "shop": + return modules.shop.execute(interaction); + case "embeds": + return modules.embeds.execute(interaction); + } +}; diff --git a/src/plugins/config/modules/audits.ts b/src/commands/config/modules/audits/index.ts similarity index 93% rename from src/plugins/config/modules/audits.ts rename to src/commands/config/modules/audits/index.ts index 817c990..0ea9a17 100644 --- a/src/plugins/config/modules/audits.ts +++ b/src/commands/config/modules/audits/index.ts @@ -2,13 +2,13 @@ import { CommandInteraction, Permissions } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; +import logger from "../../../../logger"; // Models -import guildSchema from "@schemas/guild"; +import guildSchema from "../../../../database/schemas/guild"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import { ChannelType } from "discord-api-types/v10"; diff --git a/src/plugins/config/modules/credits.ts b/src/commands/config/modules/credits/index.ts similarity index 96% rename from src/plugins/config/modules/credits.ts rename to src/commands/config/modules/credits/index.ts index 3e20851..8ec5998 100644 --- a/src/plugins/config/modules/credits.ts +++ b/src/commands/config/modules/credits/index.ts @@ -2,13 +2,13 @@ import { CommandInteraction, Permissions } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; //Handlers -import logger from "@logger"; +import logger from "../../../../logger"; // Models -import guildSchema from "@schemas/guild"; +import guildSchema from "../../../../database/schemas/guild"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function diff --git a/src/commands/config/modules/embeds/components/getValues/index.ts b/src/commands/config/modules/embeds/components/getValues/index.ts new file mode 100644 index 0000000..d511a52 --- /dev/null +++ b/src/commands/config/modules/embeds/components/getValues/index.ts @@ -0,0 +1,38 @@ +import { ColorResolvable, CommandInteraction } from "discord.js"; +import guildSchema from "../../../../../../database/schemas/guild"; +import getEmbedConfig from "../../../../../../helpers/getEmbedConfig"; + +export default async (interaction: CommandInteraction) => { + const { options, guild } = interaction; + + if (!guild) throw new Error("Guild not found"); + + const embedConfig = await getEmbedConfig(guild); + if (!embedConfig) throw new Error("Embed config not found"); + + // Get new values + const newSuccessColor = options.getString("success-color") as ColorResolvable; + const newWaitColor = options.getString("wait-color") as ColorResolvable; + const newErrorColor = options.getString("error-color") as ColorResolvable; + const newFooterIcon = options.getString("footer-icon"); + const newFooterText = options.getString("footer-text"); + + // Get guild values + const guildData = await guildSchema.findOne({ + guildId: guild.id, + }); + if (!guildData) throw new Error("Guild data not found"); + if (!guildData?.embeds) + throw new Error("Guild embed configuration not found"); + let { successColor, waitColor, errorColor, footerText, footerIcon } = + guildData.embeds; + + // Set new values + successColor = newSuccessColor || successColor; + waitColor = newWaitColor || waitColor; + errorColor = newErrorColor || errorColor; + footerIcon = newFooterIcon || footerIcon; + footerText = newFooterText || footerText; + + return { successColor, waitColor, errorColor, footerText, footerIcon }; +}; diff --git a/src/commands/config/modules/embeds/index.ts b/src/commands/config/modules/embeds/index.ts new file mode 100644 index 0000000..94f1db8 --- /dev/null +++ b/src/commands/config/modules/embeds/index.ts @@ -0,0 +1,104 @@ +// Dependencies +import { + ColorResolvable, + CommandInteraction, + MessageEmbed, + Permissions, +} from "discord.js"; + +//Handlers +import logger from "../../../../logger"; + +// Models +import guildSchema from "../../../../database/schemas/guild"; +import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; +import getValues from "./components/getValues"; + +// Function +export default { + metadata: { + guildOnly: true, + ephemeral: true, + permissions: [Permissions.FLAGS.MANAGE_GUILD], + }, + + builder: (command: SlashCommandSubcommandBuilder) => { + return command + .setName("embeds") + .setDescription(`Embeds`) + .addStringOption((option) => + option + .setName("success-color") + .setDescription("No provided description") + ) + .addStringOption((option) => + option.setName("wait-color").setDescription("No provided description") + ) + .addStringOption((option) => + option.setName("error-color").setDescription("No provided description") + ) + .addStringOption((option) => + option.setName("footer-icon").setDescription("No provided description") + ) + .addStringOption((option) => + option.setName("footer-text").setDescription("No provided description") + ); + }, + execute: async (interaction: CommandInteraction) => { + const { guild } = interaction; + if (!guild) throw new Error("Guild not found"); + + const { successColor, waitColor, errorColor, footerText, footerIcon } = + await getValues(interaction); + + // Initialize embed object + const embed = new MessageEmbed() + .setTitle("[:tools:] Embeds") + .setFooter({ text: footerText, iconURL: footerIcon }) + .setTimestamp(new Date()); + + // Get guild values + const guildData = await guildSchema.findOne({ + guildId: guild.id, + }); + if (!guildData) throw new Error("Guild data not found"); + + await guildData.save().then(async () => { + embed + .setDescription("Following embed configuration will be used.") + .setColor(successColor) + .addFields([ + { + name: "🟢 Success Color", + value: `${successColor}`, + inline: true, + }, + { + name: "🟡 Wait Color", + value: `${waitColor}`, + inline: true, + }, + { + name: "🔴 Error Color", + value: `${errorColor}`, + inline: true, + }, + { + name: "🖼️ Footer Icon", + value: `${footerIcon}`, + inline: true, + }, + { + name: "📄 Footer Text", + value: `${footerText}`, + inline: true, + }, + ]); + + return interaction.editReply({ + embeds: [embed], + }); + }); + }, +}; diff --git a/src/commands/config/modules/index.ts b/src/commands/config/modules/index.ts new file mode 100644 index 0000000..09a9f5a --- /dev/null +++ b/src/commands/config/modules/index.ts @@ -0,0 +1,9 @@ +import audits from "./audits"; +import credits from "./credits"; +import points from "./points"; +import pterodactyl from "./pterodactyl"; +import shop from "./shop"; +import welcome from "./welcome"; +import embeds from "./embeds"; + +export default { audits, credits, points, pterodactyl, shop, welcome, embeds }; diff --git a/src/plugins/config/modules/points.ts b/src/commands/config/modules/points/index.ts similarity index 95% rename from src/plugins/config/modules/points.ts rename to src/commands/config/modules/points/index.ts index a7e24a2..0693916 100644 --- a/src/plugins/config/modules/points.ts +++ b/src/commands/config/modules/points/index.ts @@ -2,13 +2,13 @@ import { CommandInteraction, Permissions } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; +import logger from "../../../../logger"; // Models -import guildSchema from "@schemas/guild"; +import guildSchema from "../../../../database/schemas/guild"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function diff --git a/src/plugins/config/modules/pterodactyl.ts b/src/commands/config/modules/pterodactyl/index.ts similarity index 89% rename from src/plugins/config/modules/pterodactyl.ts rename to src/commands/config/modules/pterodactyl/index.ts index e6673e1..52e65b0 100644 --- a/src/plugins/config/modules/pterodactyl.ts +++ b/src/commands/config/modules/pterodactyl/index.ts @@ -2,14 +2,14 @@ import { CommandInteraction, Permissions } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; +import logger from "../../../../logger"; // Models -import apiSchema from "@schemas/api"; -import encryption from "@handlers/encryption"; +import apiSchema from "../../../../database/schemas/api"; +import encryption from "../../../../handlers/encryption"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function diff --git a/src/plugins/config/modules/shop.ts b/src/commands/config/modules/shop/index.ts similarity index 93% rename from src/plugins/config/modules/shop.ts rename to src/commands/config/modules/shop/index.ts index e9f4d9f..a775385 100644 --- a/src/plugins/config/modules/shop.ts +++ b/src/commands/config/modules/shop/index.ts @@ -2,13 +2,13 @@ import { CommandInteraction, Permissions } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; +import logger from "../../../../logger"; // Models -import guildSchema from "@schemas/guild"; +import guildSchema from "../../../../database/schemas/guild"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function diff --git a/src/plugins/config/modules/welcome.ts b/src/commands/config/modules/welcome/index.ts similarity index 74% rename from src/plugins/config/modules/welcome.ts rename to src/commands/config/modules/welcome/index.ts index 48399c7..e6d5e9b 100644 --- a/src/plugins/config/modules/welcome.ts +++ b/src/commands/config/modules/welcome/index.ts @@ -2,13 +2,13 @@ import { CommandInteraction, Permissions } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; +import logger from "../../../../logger"; // Models -import guildSchema from "@schemas/guild"; +import guildSchema from "../../../../database/schemas/guild"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import { ChannelType } from "discord-api-types/v10"; @@ -96,39 +96,39 @@ export default { await guildDB?.save()?.then(async () => { logger?.silly(`Guild welcome updated.`); + if (!guildDB?.welcome?.status) { + return interaction?.editReply({ + embeds: [ + { + title: "[:tools:] Welcome", + description: `This module is currently disabled, please enable it to continue.`, + color: successColor, + timestamp: new Date(), + footer: { + iconURL: footerIcon, + text: footerText, + }, + }, + ], + }); + } + return interaction?.editReply({ embeds: [ { - title: ":hammer: Settings - Guild [Welcome]", - description: `Welcome settings updated.`, + title: "[:tools:] Welcome", + description: `The following configuration will be used. + + [👋] **Welcome** + + ㅤ**Channel**: <#${guildDB?.welcome?.joinChannel}> + ㅤ**Message**: ${guildDB?.welcome?.joinChannelMessage} + + [🚪] **Leave** + + ㅤ**Channel**: <#${guildDB?.welcome?.leaveChannel}> + ㅤ**Message**: ${guildDB?.welcome?.leaveChannelMessage}`, color: successColor, - fields: [ - { - name: "🤖 Status", - value: `${guildDB?.welcome?.status}`, - inline: true, - }, - { - name: "🌊 Join Channel", - value: `${guildDB?.welcome?.joinChannel}`, - inline: true, - }, - { - name: "🌊 Leave Channel", - value: `${guildDB?.welcome?.leaveChannel}`, - inline: true, - }, - { - name: "📄 Join Channel Message", - value: `${guildDB?.welcome?.joinChannelMessage}`, - inline: true, - }, - { - name: "📄 Leave Channel Message", - value: `${guildDB?.welcome?.leaveChannelMessage}`, - inline: true, - }, - ], timestamp: new Date(), footer: { iconURL: footerIcon, diff --git a/src/commands/counters/index.ts b/src/commands/counters/index.ts new file mode 100644 index 0000000..da17e90 --- /dev/null +++ b/src/commands/counters/index.ts @@ -0,0 +1,19 @@ +import { CommandInteraction } from "discord.js"; +import { SlashCommandBuilder } from "@discordjs/builders"; +import logger from "../../logger"; + +import modules from "../../commands/counters/modules"; + +export const builder = new SlashCommandBuilder() + .setName("counters") + .setDescription("View guild counters") + + .addSubcommand(modules.view.builder); + +export const moduleData = modules; + +export const execute = async (interaction: CommandInteraction) => { + if (interaction.options.getSubcommand() === "view") { + await modules.view.execute(interaction); + } +}; diff --git a/src/commands/counters/modules/index.ts b/src/commands/counters/modules/index.ts new file mode 100644 index 0000000..dc539f8 --- /dev/null +++ b/src/commands/counters/modules/index.ts @@ -0,0 +1,3 @@ +import view from "./view"; + +export default { view }; diff --git a/src/plugins/counters/modules/view/index.ts b/src/commands/counters/modules/view/index.ts similarity index 93% rename from src/plugins/counters/modules/view/index.ts rename to src/commands/counters/modules/view/index.ts index d672f0d..b509dd5 100644 --- a/src/plugins/counters/modules/view/index.ts +++ b/src/commands/counters/modules/view/index.ts @@ -1,10 +1,10 @@ -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; import { CommandInteraction, MessageEmbed } from "discord.js"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import { ChannelType } from "discord-api-types/v10"; -import counterSchema from "@schemas/counter"; +import counterSchema from "../../../../database/schemas/counter"; export default { metadata: { guildOnly: true, ephemeral: false }, diff --git a/src/commands/credits/index.ts b/src/commands/credits/index.ts new file mode 100644 index 0000000..02c03a5 --- /dev/null +++ b/src/commands/credits/index.ts @@ -0,0 +1,37 @@ +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; +import logger from "../../logger"; + +import modules from "./modules"; + +export const builder = new SlashCommandBuilder() + .setName("credits") + .setDescription("Manage your credits.") + + .addSubcommand(modules.balance.builder) + .addSubcommand(modules.gift.builder) + .addSubcommand(modules.top.builder) + .addSubcommand(modules.work.builder); + +export const moduleData = modules; + +export const execute = async (interaction: CommandInteraction) => { + const { options } = interaction; + + switch (options.getSubcommand()) { + case "balance": + await modules.balance.execute(interaction); + break; + case "gift": + await modules.gift.execute(interaction); + break; + case "top": + await modules.top.execute(interaction); + break; + case "work": + await modules.work.execute(interaction); + break; + default: + logger.silly(`Unknown subcommand ${options.getSubcommand()}`); + } +}; diff --git a/src/plugins/credits/modules/balance/index.ts b/src/commands/credits/modules/balance/index.ts similarity index 92% rename from src/plugins/credits/modules/balance/index.ts rename to src/commands/credits/modules/balance/index.ts index 60ee17e..2387d57 100644 --- a/src/plugins/credits/modules/balance/index.ts +++ b/src/commands/credits/modules/balance/index.ts @@ -1,10 +1,10 @@ -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; import { CommandInteraction, MessageEmbed } from "discord.js"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; -import logger from "@logger"; +import logger from "../../../../logger"; -import fetchUser from "@helpers/fetchUser"; +import fetchUser from "../../../../helpers/fetchUser"; export default { metadata: { guildOnly: true, ephemeral: true }, diff --git a/src/plugins/credits/modules/gift/index.ts b/src/commands/credits/modules/gift/index.ts similarity index 75% rename from src/plugins/credits/modules/gift/index.ts rename to src/commands/credits/modules/gift/index.ts index 0325ab0..9873c02 100644 --- a/src/plugins/credits/modules/gift/index.ts +++ b/src/commands/credits/modules/gift/index.ts @@ -2,16 +2,15 @@ import { CommandInteraction, MessageEmbed } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; +import logger from "../../../../logger"; -// Helpers -import saveUser from "@helpers/saveUser"; +import mongoose from "mongoose"; // Models -import fetchUser from "@helpers/fetchUser"; +import fetchUser from "../../../../helpers/fetchUser"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function @@ -184,53 +183,69 @@ export default { }); } - // Withdraw amount from fromUserDB - fromUserDB.credits -= optionAmount; + const session = await mongoose.startSession(); - // Deposit amount to toUserDB - toUserDB.credits += optionAmount; + session.startTransaction(); - // Save users - await saveUser(fromUserDB, toUserDB).then(async () => { - // Get DM user object - const dmUser = client.users.cache.get(optionUser.id); + try { + // Withdraw amount from fromUserDB + fromUserDB.credits -= optionAmount; - if (dmUser == null) return; + // Deposit amount to toUserDB + toUserDB.credits += optionAmount; - // Send DM to user - await dmUser - .send({ - embeds: [ - embed - .setDescription( - `${ - user.tag - } has gifted you ${optionAmount} credits with reason: ${ - optionReason || "unspecified" - }` - ) - .setColor(successColor), - ], - }) - .catch(async (error) => - logger.error(`[Gift] Error sending DM to user: ${error}`) - ); + await fromUserDB.save(); - logger.silly( - `[Gift] Successfully gifted ${optionAmount} credits to ${optionUser.tag}` - ); + await toUserDB.save(); + + await session.commitTransaction(); + } catch (error) { + await session.abortTransaction(); + session.endSession(); + logger.error(`${error}`); return interaction.editReply({ embeds: [ embed .setDescription( - `Successfully gifted ${optionAmount} credits to ${ - optionUser.tag - } with reason: ${optionReason || "unspecified"}` + "An error occurred while trying to gift credits. Please try again." ) - .setColor(successColor), + .setColor(errorColor), ], }); + } finally { + // ending the session + session.endSession(); + } + + // Get DM user object + const dmUser = client.users.cache.get(optionUser.id); + + if (!dmUser) throw new Error("User not found"); + + // Send DM to user + await dmUser.send({ + embeds: [ + embed + .setDescription( + `${user.tag} has gifted you ${optionAmount} credits with reason: ${ + optionReason || "unspecified" + }` + ) + .setColor(successColor), + ], + }); + + return interaction.editReply({ + embeds: [ + embed + .setDescription( + `Successfully gifted ${optionAmount} credits to ${ + optionUser.tag + } with reason: ${optionReason || "unspecified"}` + ) + .setColor(successColor), + ], }); }, }; diff --git a/src/commands/credits/modules/index.ts b/src/commands/credits/modules/index.ts new file mode 100644 index 0000000..20edcaf --- /dev/null +++ b/src/commands/credits/modules/index.ts @@ -0,0 +1,6 @@ +import balance from "./balance"; +import gift from "./gift"; +import top from "./top"; +import work from "./work"; + +export default { balance, gift, top, work }; diff --git a/src/plugins/credits/modules/top/index.ts b/src/commands/credits/modules/top/index.ts similarity index 90% rename from src/plugins/credits/modules/top/index.ts rename to src/commands/credits/modules/top/index.ts index 747f1bc..0aaa2f8 100644 --- a/src/plugins/credits/modules/top/index.ts +++ b/src/commands/credits/modules/top/index.ts @@ -1,10 +1,10 @@ -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; import { CommandInteraction, MessageEmbed } from "discord.js"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; -import logger from "@logger"; +import logger from "../../../../logger"; -import userSchema, { IUser } from "@schemas/user"; +import userSchema, { IUser } from "../../../../database/schemas/user"; export default { metadata: { guildOnly: true, ephemeral: false }, diff --git a/src/plugins/credits/modules/work/index.ts b/src/commands/credits/modules/work/index.ts similarity index 90% rename from src/plugins/credits/modules/work/index.ts rename to src/commands/credits/modules/work/index.ts index 1cde8cb..7f29629 100644 --- a/src/plugins/credits/modules/work/index.ts +++ b/src/commands/credits/modules/work/index.ts @@ -4,17 +4,17 @@ import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import Chance from "chance"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; +import logger from "../../../../logger"; // Models -import timeoutSchema from "@schemas/timeout"; +import timeoutSchema from "../../../../database/schemas/timeout"; // Helpers -import fetchUser from "@helpers/fetchUser"; -import fetchGuild from "@helpers/fetchGuild"; +import fetchUser from "../../../../helpers/fetchUser"; +import fetchGuild from "../../../../helpers/fetchGuild"; export default { metadata: { guildOnly: true, ephemeral: true }, diff --git a/src/commands/fun/index.ts b/src/commands/fun/index.ts new file mode 100644 index 0000000..5c71cd2 --- /dev/null +++ b/src/commands/fun/index.ts @@ -0,0 +1,23 @@ +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; +import logger from "../../logger"; + +import modules from "../../commands/fun/modules"; + +export const builder = new SlashCommandBuilder() + .setName("fun") + .setDescription("Fun commands.") + + .addSubcommand(modules.meme.builder); + +export const moduleData = modules; + +export const execute = async (interaction: CommandInteraction) => { + const { options } = interaction; + + if (options.getSubcommand() === "meme") { + await modules.meme.execute(interaction); + } else { + logger.silly(`Unknown subcommand ${options.getSubcommand()}`); + } +}; diff --git a/src/commands/fun/modules/index.ts b/src/commands/fun/modules/index.ts new file mode 100644 index 0000000..53aeddc --- /dev/null +++ b/src/commands/fun/modules/index.ts @@ -0,0 +1,5 @@ +import meme from "./meme"; + +export default { + meme, +}; diff --git a/src/commands/fun/modules/meme/index.ts b/src/commands/fun/modules/meme/index.ts new file mode 100644 index 0000000..c168557 --- /dev/null +++ b/src/commands/fun/modules/meme/index.ts @@ -0,0 +1,59 @@ +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; + +import axios from "axios"; +import { CommandInteraction, MessageEmbed } from "discord.js"; +import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; + +export default { + metadata: { guildOnly: false, ephemeral: false }, + + builder: (command: SlashCommandSubcommandBuilder) => { + return command.setName("meme").setDescription("Get a meme from r/memes)"); + }, + + execute: async (interaction: CommandInteraction) => { + const { guild } = interaction; + + const embedConfig = await getEmbedConfig(guild); + + await axios + .get("https://www.reddit.com/r/memes/random/.json") + .then(async (res) => { + const response = res.data[0].data.children; + const content = response[0].data; + + const embed = new MessageEmbed() + .setAuthor({ + name: content.title, + iconURL: + "https://www.redditinc.com/assets/images/site/reddit-logo.png", + url: `https://reddit.com${content.permalink}`, + }) + .setTitle("[:sweat_smile:] Meme") + .addFields([ + { + name: "Author", + value: `[${content.author}](https://reddit.com/user/${content.author})`, + inline: true, + }, + { + name: "Votes", + value: `${content.ups}/${content.downs}`, + inline: true, + }, + ]) + .setTimestamp(new Date()) + .setImage(content.url) + .setFooter({ + text: embedConfig.footerText, + iconURL: embedConfig.footerIcon, + }) + .setColor(embedConfig.successColor); + + return interaction.editReply({ embeds: [embed] }); + }) + .catch((error) => { + throw new Error(error.message); + }); + }, +}; diff --git a/src/commands/manage/index.ts b/src/commands/manage/index.ts new file mode 100644 index 0000000..14b5f6c --- /dev/null +++ b/src/commands/manage/index.ts @@ -0,0 +1,29 @@ +//Dependencies +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +// Groups +import modules from "../../commands/manage/modules"; +import logger from "../../logger"; + +export const moduleData = modules; + +// Function +export const builder = new SlashCommandBuilder() + .setName("manage") + .setDescription("Manage the bot.") + .addSubcommandGroup(modules.counters.builder) + .addSubcommandGroup(modules.credits.builder); + +export const execute = async (interaction: CommandInteraction) => { + // Destructure + const { options } = interaction; + + if (options?.getSubcommandGroup() === "credits") { + return modules.credits.execute(interaction); + } + + if (options?.getSubcommandGroup() === "counters") { + return modules.counters.execute(interaction); + } +}; diff --git a/src/commands/manage/modules/counters/index.ts b/src/commands/manage/modules/counters/index.ts new file mode 100644 index 0000000..36d6cd9 --- /dev/null +++ b/src/commands/manage/modules/counters/index.ts @@ -0,0 +1,37 @@ +// Dependencies +import { SlashCommandSubcommandGroupBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +import logger from "../../../../logger"; + +// Modules +import modules from "./modules"; + +// Function +export const moduleData = modules; + +export const builder = (group: SlashCommandSubcommandGroupBuilder) => { + return group + .setName("counters") + .setDescription("Manage guild counters.") + .addSubcommand(modules.add.builder) + .addSubcommand(modules.remove.builder); +}; + +export const execute = async (interaction: CommandInteraction) => { + const { options } = interaction; + + if (options?.getSubcommand() === "add") { + logger?.silly(`Executing create subcommand`); + + return modules.add.execute(interaction); + } + + if (options?.getSubcommand() === "remove") { + logger?.silly(`Executing delete subcommand`); + + return modules.remove.execute(interaction); + } + + logger?.silly(`Unknown subcommand ${options?.getSubcommand()}`); +}; diff --git a/src/plugins/manage/modules/counters/modules/add/index.ts b/src/commands/manage/modules/counters/modules/add/index.ts similarity index 93% rename from src/plugins/manage/modules/counters/modules/add/index.ts rename to src/commands/manage/modules/counters/modules/add/index.ts index b4c6e99..cdefbb8 100644 --- a/src/plugins/manage/modules/counters/modules/add/index.ts +++ b/src/commands/manage/modules/counters/modules/add/index.ts @@ -4,12 +4,12 @@ import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import { ChannelType } from "discord-api-types/v10"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../../../helpers/getEmbedConfig"; -import logger from "@logger"; +import logger from "../../../../../../logger"; // Models -import counterSchema from "@schemas/counter"; +import counterSchema from "../../../../../../database/schemas/counter"; // Function export default { diff --git a/src/commands/manage/modules/counters/modules/index.ts b/src/commands/manage/modules/counters/modules/index.ts new file mode 100644 index 0000000..bc9da9c --- /dev/null +++ b/src/commands/manage/modules/counters/modules/index.ts @@ -0,0 +1,4 @@ +import add from "./add"; +import remove from "./remove"; + +export default { add, remove }; diff --git a/src/plugins/manage/modules/counters/modules/remove/index.ts b/src/commands/manage/modules/counters/modules/remove/index.ts similarity index 92% rename from src/plugins/manage/modules/counters/modules/remove/index.ts rename to src/commands/manage/modules/counters/modules/remove/index.ts index 8a61687..295f2b0 100644 --- a/src/plugins/manage/modules/counters/modules/remove/index.ts +++ b/src/commands/manage/modules/counters/modules/remove/index.ts @@ -2,13 +2,13 @@ import { CommandInteraction, MessageEmbed, Permissions } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; +import logger from "../../../../../../logger"; // Models -import counterSchema from "@schemas/counter"; +import counterSchema from "../../../../../../database/schemas/counter"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import { ChannelType } from "discord-api-types/v10"; diff --git a/src/commands/manage/modules/credits/index.ts b/src/commands/manage/modules/credits/index.ts new file mode 100644 index 0000000..5e215ec --- /dev/null +++ b/src/commands/manage/modules/credits/index.ts @@ -0,0 +1,33 @@ +import { CommandInteraction } from "discord.js"; +import { SlashCommandSubcommandGroupBuilder } from "@discordjs/builders"; +import logger from "../../../../logger"; + +import modules from "./modules"; + +export const moduleData = modules; + +export const builder = (group: SlashCommandSubcommandGroupBuilder) => { + return group + .setName("credits") + .setDescription("Manage the credits of a user.") + .addSubcommand(modules.give.builder) + .addSubcommand(modules.set.builder) + .addSubcommand(modules.take.builder) + .addSubcommand(modules.transfer.builder) + .addSubcommand(modules.drop.builder); +}; + +export const execute = async (interaction: CommandInteraction) => { + switch (interaction.options.getSubcommand()) { + case "give": + return modules.give.execute(interaction); + case "set": + return modules.set.execute(interaction); + case "take": + return modules.take.execute(interaction); + case "transfer": + return modules.transfer.execute(interaction); + case "drop": + return modules.drop.execute(interaction); + } +}; diff --git a/src/commands/manage/modules/credits/modules/drop/index.ts b/src/commands/manage/modules/credits/modules/drop/index.ts new file mode 100644 index 0000000..d5129ea --- /dev/null +++ b/src/commands/manage/modules/credits/modules/drop/index.ts @@ -0,0 +1,126 @@ +// Dependencies +import { CommandInteraction, MessageEmbed, Permissions } from "discord.js"; +import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; +import { v4 as uuidv4 } from "uuid"; +import axios from "axios"; +import apiSchema from "../../../../../../database/schemas/api"; +import encryption from "../../../../../../handlers/encryption"; + +// Configurations +import getEmbedConfig from "../../../../../../helpers/getEmbedConfig"; + +// Handlers +import logger from "../../../../../../logger"; + +// Helpers +import pluralize from "../../../../../../helpers/pluralize"; + +// Models +import fetchUser from "../../../../../../helpers/fetchUser"; + +// Function +export default { + metadata: { + guildOnly: true, + ephemeral: true, + permissions: [Permissions.FLAGS.MANAGE_GUILD], + }, + + builder: (command: SlashCommandSubcommandBuilder) => { + return command + .setName("drop") + .setDescription("Drop some credits for specified amount of users.") + .addIntegerOption((option) => + option + .setName("uses") + .setDescription("How many users should be able to use this.") + .setRequired(true) + ) + .addIntegerOption((option) => + option + .setName("credit") + .setDescription(`How much credits provided per use.`) + .setRequired(true) + ) + .addChannelOption((option) => + option + .setName("channel") + .setDescription("The channel to send the message to.") + .setRequired(true) + ); + }, + execute: async (interaction: CommandInteraction) => { + if (interaction.guild == null) return; + const { errorColor, successColor, footerText, footerIcon } = + await getEmbedConfig(interaction.guild); // Destructure + const { guild, options } = interaction; + + 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."); + + const embed = new MessageEmbed() + .setTitle("[:toolbox:] Drop") + .setFooter({ text: footerText, iconURL: footerIcon }); + + const code = uuidv4(); + + const apiCredentials = await apiSchema?.findOne({ + guildId: guild?.id, + }); + + if (!apiCredentials) return; + + const api = axios?.create({ + baseURL: apiCredentials.url, + headers: { + Authorization: `Bearer ${encryption.decrypt(apiCredentials.token)}`, + }, + }); + + const shopUrl = apiCredentials?.url?.replace("/api", "/store"); + + await api + .post("vouchers", { + uses, + code, + credits: creditAmount, + memo: `${interaction?.createdTimestamp} - ${interaction?.user?.id}`, + }) + .then(async () => { + await interaction.editReply({ + embeds: [ + embed + .setColor(successColor) + .setDescription(`Successfully crated code: ${code}`), + ], + }); + + const discordChannel = guild.channels.cache.get(channel.id); + + if (!discordChannel) return; + + if (discordChannel.type !== "GUILD_TEXT") return; + + discordChannel.send({ + embeds: [ + new MessageEmbed() + .setTitle("[:parachute:] Code Drop!") + .addFields([ + { name: "Code", value: `${code}`, inline: true }, + { name: "Amount", value: `${creditAmount}`, inline: true }, + { name: "Uses", value: `${uses}`, inline: true }, + ]) + .setDescription( + `${interaction.user} dropped a voucher! You can use the code [here](${shopUrl})!` + ) + .setColor(successColor), + ], + }); + }); + }, +}; diff --git a/src/plugins/manage/modules/credits/modules/give/index.ts b/src/commands/manage/modules/credits/modules/give/index.ts similarity index 95% rename from src/plugins/manage/modules/credits/modules/give/index.ts rename to src/commands/manage/modules/credits/modules/give/index.ts index cec0376..ebbc762 100644 --- a/src/plugins/manage/modules/credits/modules/give/index.ts +++ b/src/commands/manage/modules/credits/modules/give/index.ts @@ -3,16 +3,16 @@ import { CommandInteraction, MessageEmbed, Permissions } from "discord.js"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; +import logger from "../../../../../../logger"; // Helpers -import pluralize from "@helpers/pluralize"; +import pluralize from "../../../../../../helpers/pluralize"; // Models -import fetchUser from "@helpers/fetchUser"; +import fetchUser from "../../../../../../helpers/fetchUser"; // Function export default { diff --git a/src/commands/manage/modules/credits/modules/index.ts b/src/commands/manage/modules/credits/modules/index.ts new file mode 100644 index 0000000..07b72e6 --- /dev/null +++ b/src/commands/manage/modules/credits/modules/index.ts @@ -0,0 +1,7 @@ +import give from "./give"; +import set from "./set"; +import take from "./take"; +import transfer from "./transfer"; +import drop from "./drop"; + +export default { give, set, take, transfer, drop }; diff --git a/src/plugins/manage/modules/credits/modules/set/index.ts b/src/commands/manage/modules/credits/modules/set/index.ts similarity index 95% rename from src/plugins/manage/modules/credits/modules/set/index.ts rename to src/commands/manage/modules/credits/modules/set/index.ts index a7d86a2..a8e1771 100644 --- a/src/plugins/manage/modules/credits/modules/set/index.ts +++ b/src/commands/manage/modules/credits/modules/set/index.ts @@ -2,15 +2,15 @@ import { CommandInteraction, MessageEmbed, Permissions } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; +import logger from "../../../../../../logger"; // Helpers // Models -import fetchUser from "@helpers/fetchUser"; +import fetchUser from "../../../../../../helpers/fetchUser"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function diff --git a/src/plugins/manage/modules/credits/modules/take/index.ts b/src/commands/manage/modules/credits/modules/take/index.ts similarity index 95% rename from src/plugins/manage/modules/credits/modules/take/index.ts rename to src/commands/manage/modules/credits/modules/take/index.ts index 9c823b9..5cf794a 100644 --- a/src/plugins/manage/modules/credits/modules/take/index.ts +++ b/src/commands/manage/modules/credits/modules/take/index.ts @@ -2,16 +2,16 @@ import { CommandInteraction, MessageEmbed, Permissions } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; +import logger from "../../../../../../logger"; // Helpers -import pluralize from "@helpers/pluralize"; +import pluralize from "../../../../../../helpers/pluralize"; // Models -import fetchUser from "@helpers/fetchUser"; +import fetchUser from "../../../../../../helpers/fetchUser"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function diff --git a/src/plugins/manage/modules/credits/modules/transfer/index.ts b/src/commands/manage/modules/credits/modules/transfer/index.ts similarity index 78% rename from src/plugins/manage/modules/credits/modules/transfer/index.ts rename to src/commands/manage/modules/credits/modules/transfer/index.ts index 19de23a..011e603 100644 --- a/src/plugins/manage/modules/credits/modules/transfer/index.ts +++ b/src/commands/manage/modules/credits/modules/transfer/index.ts @@ -1,17 +1,16 @@ // Dependencies import { CommandInteraction, MessageEmbed, Permissions } from "discord.js"; +import mongoose from "mongoose"; + // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../../../helpers/getEmbedConfig"; // Handlers -import logger from "@logger"; - -// Helpers -import saveUser from "@helpers/saveUser"; +import logger from "../../../../../../logger"; // Models -import fetchUser from "@helpers/fetchUser"; +import fetchUser from "../../../../../../helpers/fetchUser"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function @@ -193,38 +192,66 @@ export default { }); } - // Withdraw amount from fromUser - fromUser.credits -= optionAmount; + const session = await mongoose.startSession(); - // Deposit amount to toUser - toUser.credits += optionAmount; + session.startTransaction(); - // Save users - await saveUser(fromUser, toUser)?.then(async () => { - logger?.silly(`Saved users`); + try { + // Withdraw amount from fromUserDB + fromUser.credits -= optionAmount; - return interaction?.editReply({ + // Deposit amount to toUserDB + toUser.credits += optionAmount; + + await fromUser.save(); + + await toUser.save(); + + await session.commitTransaction(); + } catch (error) { + await session.abortTransaction(); + session.endSession(); + logger.error(`${error}`); + + return interaction.editReply({ embeds: [ new MessageEmbed() .setTitle("[:toolbox:] Manage - Credits (Transfer)") - .setDescription(`Transferred ${optionAmount} credits.`) - .addFields( - { - name: `${optionFromUser?.username} Balance`, - value: `${fromUser?.credits}`, - inline: true, - }, - { - name: `${optionToUser?.username} Balance`, - value: `${toUser?.credits}`, - inline: true, - } + .setDescription( + "An error occurred while trying to gift credits. Please try again." ) + .setColor(errorColor) .setTimestamp(new Date()) .setColor(successColor) .setFooter({ text: footerText, iconURL: footerIcon }), ], }); + } finally { + // ending the session + session.endSession(); + } + + return interaction?.editReply({ + embeds: [ + new MessageEmbed() + .setTitle("[:toolbox:] Manage - Credits (Transfer)") + .setDescription(`Transferred ${optionAmount} credits.`) + .addFields( + { + name: `${optionFromUser?.username} Balance`, + value: `${fromUser?.credits}`, + inline: true, + }, + { + name: `${optionToUser?.username} Balance`, + value: `${toUser?.credits}`, + inline: true, + } + ) + .setTimestamp(new Date()) + .setColor(successColor) + .setFooter({ text: footerText, iconURL: footerIcon }), + ], }); }, }; diff --git a/src/commands/manage/modules/index.ts b/src/commands/manage/modules/index.ts new file mode 100644 index 0000000..c55982f --- /dev/null +++ b/src/commands/manage/modules/index.ts @@ -0,0 +1,4 @@ +import * as counters from "./counters"; +import * as credits from "./credits"; + +export default { counters, credits }; diff --git a/src/commands/profile/index.ts b/src/commands/profile/index.ts new file mode 100644 index 0000000..2039179 --- /dev/null +++ b/src/commands/profile/index.ts @@ -0,0 +1,29 @@ +// Dependencies +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +// Modules +import modules from "../../commands/profile/modules"; + +// Handlers +import logger from "../../logger"; + +export const moduleData = modules; + +// Function +export const builder = new SlashCommandBuilder() + .setName("profile") + .setDescription("Check a profile.") + .addSubcommand(modules.view.builder); + +export const execute = async (interaction: CommandInteraction) => { + const { options } = interaction; + + if (options?.getSubcommand() === "view") { + logger?.silly(`Executing view subcommand`); + + return modules.view.execute(interaction); + } + + logger?.silly(`No subcommand found`); +}; diff --git a/src/commands/profile/modules/index.ts b/src/commands/profile/modules/index.ts new file mode 100644 index 0000000..dc539f8 --- /dev/null +++ b/src/commands/profile/modules/index.ts @@ -0,0 +1,3 @@ +import view from "./view"; + +export default { view }; diff --git a/src/plugins/profile/modules/view.ts b/src/commands/profile/modules/view.ts similarity index 93% rename from src/plugins/profile/modules/view.ts rename to src/commands/profile/modules/view.ts index c6704a3..5a59fd3 100644 --- a/src/plugins/profile/modules/view.ts +++ b/src/commands/profile/modules/view.ts @@ -2,12 +2,12 @@ import { CommandInteraction } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../helpers/getEmbedConfig"; // Models -import fetchUser from "@helpers/fetchUser"; +import fetchUser from "../../../helpers/fetchUser"; -import logger from "@logger"; +import logger from "../../../logger"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function diff --git a/src/commands/reputation/index.ts b/src/commands/reputation/index.ts new file mode 100644 index 0000000..b0812d4 --- /dev/null +++ b/src/commands/reputation/index.ts @@ -0,0 +1,29 @@ +// Dependencies +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +// Modules +import modules from "./modules"; + +// Handlers +import logger from "../../logger"; + +export const moduleData = modules; + +// Function +export const builder = new SlashCommandBuilder() + .setName("reputation") + .setDescription("Manage reputation.") + .addSubcommand(modules.give.builder); + +export const execute = async (interaction: CommandInteraction) => { + const { options } = interaction; + + if (options?.getSubcommand() === "give") { + logger?.silly(`Executing give subcommand`); + + await modules.give.execute(interaction); + } + + logger?.silly(`No subcommand found`); +}; diff --git a/src/plugins/reputation/modules/give.ts b/src/commands/reputation/modules/give.ts similarity index 93% rename from src/plugins/reputation/modules/give.ts rename to src/commands/reputation/modules/give.ts index 949f9c9..c55e909 100644 --- a/src/plugins/reputation/modules/give.ts +++ b/src/commands/reputation/modules/give.ts @@ -2,16 +2,16 @@ import { CommandInteraction } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../helpers/getEmbedConfig"; -import { timeout } from "@config/reputation"; +import { timeout } from "../../../config/reputation"; // Handlers -import logger from "@logger"; +import logger from "../../../logger"; // Models -import timeoutSchema from "@schemas/timeout"; -import fetchUser from "@helpers/fetchUser"; +import timeoutSchema from "../../../database/schemas/timeout"; +import fetchUser from "../../../helpers/fetchUser"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function diff --git a/src/commands/reputation/modules/index.ts b/src/commands/reputation/modules/index.ts new file mode 100644 index 0000000..e891cf0 --- /dev/null +++ b/src/commands/reputation/modules/index.ts @@ -0,0 +1,3 @@ +import give from "./give"; + +export default { give }; diff --git a/src/commands/shop/index.ts b/src/commands/shop/index.ts new file mode 100644 index 0000000..2ef6f65 --- /dev/null +++ b/src/commands/shop/index.ts @@ -0,0 +1,36 @@ +// Dependencies +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +// Modules +import modules from "./modules"; + +// Handlers +import logger from "../../logger"; + +export const moduleData = modules; + +// Function +export const builder = new SlashCommandBuilder() + .setName("shop") + .setDescription("Shop for credits and custom roles.") + .addSubcommand(modules.pterodactyl.builder) + .addSubcommandGroup(modules.roles.builder); + +export const execute = async (interaction: CommandInteraction) => { + const { options } = interaction; + + if (options?.getSubcommand() === "pterodactyl") { + logger.silly(`Executing pterodactyl subcommand`); + + return modules.pterodactyl.execute(interaction); + } + + if (options?.getSubcommandGroup() === "roles") { + logger?.silly(`Subcommand group is roles`); + + return modules.roles.execute(interaction); + } + + logger?.silly(`No subcommand found.`); +}; diff --git a/src/commands/shop/modules/index.ts b/src/commands/shop/modules/index.ts new file mode 100644 index 0000000..d191ec6 --- /dev/null +++ b/src/commands/shop/modules/index.ts @@ -0,0 +1,4 @@ +import pterodactyl from "./pterodactyl"; +import * as roles from "./roles"; + +export default { pterodactyl, roles }; diff --git a/src/plugins/shop/modules/pterodactyl.ts b/src/commands/shop/modules/pterodactyl.ts similarity index 95% rename from src/plugins/shop/modules/pterodactyl.ts rename to src/commands/shop/modules/pterodactyl.ts index 22da19c..daa698d 100644 --- a/src/plugins/shop/modules/pterodactyl.ts +++ b/src/commands/shop/modules/pterodactyl.ts @@ -2,15 +2,15 @@ import { CommandInteraction } from "discord.js"; import { v4 as uuidv4 } from "uuid"; import axios from "axios"; -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../helpers/getEmbedConfig"; -import logger from "@logger"; -import encryption from "@handlers/encryption"; +import logger from "../../../logger"; +import encryption from "../../../handlers/encryption"; -import pluralize from "@helpers/pluralize"; +import pluralize from "../../../helpers/pluralize"; -import apiSchema from "@schemas/api"; -import fetchUser from "@helpers/fetchUser"; +import apiSchema from "../../../database/schemas/api"; +import fetchUser from "../../../helpers/fetchUser"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; export default { diff --git a/src/commands/shop/modules/roles/index.ts b/src/commands/shop/modules/roles/index.ts new file mode 100644 index 0000000..bdec977 --- /dev/null +++ b/src/commands/shop/modules/roles/index.ts @@ -0,0 +1,65 @@ +// Dependencies +import { SlashCommandSubcommandGroupBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +// Handlers +import logger from "../../../../logger"; + +import getEmbedConfig from "../../../../helpers/getEmbedConfig"; + +// Modules +import modules from "./modules"; + +import guildSchema from "../../../../database/schemas/guild"; + +export const moduleData = modules; + +// Function +export const builder = (group: SlashCommandSubcommandGroupBuilder) => { + return group + .setName("roles") + .setDescription("Shop for custom roles.") + .addSubcommand(modules.buy.builder) + .addSubcommand(modules.cancel.builder); +}; + +export const execute = async (interaction: CommandInteraction) => { + if (interaction.guild == null) return; + const { errorColor, footerText, footerIcon } = await getEmbedConfig( + interaction.guild + ); + const { options, guild } = interaction; + + const guildDB = await guildSchema?.findOne({ + guildId: guild?.id, + }); + + if (guildDB === null) return; + + if (!guildDB.shop.roles.status) { + logger.silly(`Shop roles disabled.`); + + return interaction?.editReply({ + embeds: [ + { + title: ":dollar: Shop - Roles", + description: "This server has disabled shop roles.", + color: errorColor, + timestamp: new Date(), + footer: { + iconURL: footerIcon, + text: footerText, + }, + }, + ], + }); + } + + if (options?.getSubcommand() === "buy") { + await modules.buy.execute(interaction); + } + + if (options?.getSubcommand() === "cancel") { + await modules.cancel.execute(interaction); + } +}; diff --git a/src/plugins/shop/modules/roles/modules/buy.ts b/src/commands/shop/modules/roles/modules/buy.ts similarity index 90% rename from src/plugins/shop/modules/roles/modules/buy.ts rename to src/commands/shop/modules/roles/modules/buy.ts index 4e4528d..b92ba7a 100644 --- a/src/plugins/shop/modules/roles/modules/buy.ts +++ b/src/commands/shop/modules/roles/modules/buy.ts @@ -6,17 +6,17 @@ import { } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../../helpers/getEmbedConfig"; // Models -import shopRolesSchema from "@schemas/shopRole"; -import guildSchema from "@schemas/guild"; +import shopRolesSchema from "../../../../../database/schemas/shopRole"; +import guildSchema from "../../../../../database/schemas/guild"; -import logger from "@logger"; +import logger from "../../../../../logger"; // Helpers -import pluralize from "@helpers/pluralize"; -import fetchUser from "@helpers/fetchUser"; +import pluralize from "../../../../../helpers/pluralize"; +import fetchUser from "../../../../../helpers/fetchUser"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function diff --git a/src/plugins/shop/modules/roles/modules/cancel.ts b/src/commands/shop/modules/roles/modules/cancel.ts similarity index 90% rename from src/plugins/shop/modules/roles/modules/cancel.ts rename to src/commands/shop/modules/roles/modules/cancel.ts index 546dbc7..cf16d95 100644 --- a/src/plugins/shop/modules/roles/modules/cancel.ts +++ b/src/commands/shop/modules/roles/modules/cancel.ts @@ -2,16 +2,16 @@ import { CommandInteraction, GuildMemberRoleManager } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../../../helpers/getEmbedConfig"; // Models -import shopRolesSchema from "@schemas/shopRole"; +import shopRolesSchema from "../../../../../database/schemas/shopRole"; -import logger from "@logger"; +import logger from "../../../../../logger"; // Helpers -import pluralize from "@helpers/pluralize"; -import fetchUser from "@helpers/fetchUser"; +import pluralize from "../../../../../helpers/pluralize"; +import fetchUser from "../../../../../helpers/fetchUser"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function diff --git a/src/plugins/shop/modules/roles/modules/index.ts b/src/commands/shop/modules/roles/modules/index.ts similarity index 100% rename from src/plugins/shop/modules/roles/modules/index.ts rename to src/commands/shop/modules/roles/modules/index.ts diff --git a/src/commands/utility/index.ts b/src/commands/utility/index.ts new file mode 100644 index 0000000..6fb52db --- /dev/null +++ b/src/commands/utility/index.ts @@ -0,0 +1,38 @@ +// Dependencies +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +// Modules +import modules from "../../commands/utility/modules"; + +// Handlers +import logger from "../../logger"; + +export const moduleData = modules; + +// Function +export const builder = new SlashCommandBuilder() + .setName("utility") + .setDescription("Common utility.") + + .addSubcommand(modules.lookup.builder) + .addSubcommand(modules.about.builder) + .addSubcommand(modules.stats.builder) + .addSubcommand(modules.avatar.builder); + +export const execute = async (interaction: CommandInteraction) => { + const { options } = interaction; + + switch (options.getSubcommand()) { + case "lookup": + return modules.lookup.execute(interaction); + case "about": + return modules.about.execute(interaction); + case "stats": + return modules.stats.execute(interaction); + case "avatar": + return modules.avatar.execute(interaction); + default: + logger.error(`Unknown subcommand ${options.getSubcommand()}`); + } +}; diff --git a/src/plugins/utility/modules/about.ts b/src/commands/utility/modules/about.ts similarity index 90% rename from src/plugins/utility/modules/about.ts rename to src/commands/utility/modules/about.ts index 8011d51..18eca4c 100644 --- a/src/plugins/utility/modules/about.ts +++ b/src/commands/utility/modules/about.ts @@ -2,9 +2,9 @@ import { CommandInteraction } from "discord.js"; // Configurations -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../helpers/getEmbedConfig"; -import { hosterName, hosterUrl } from "@config/other"; +import { hosterName, hosterUrl } from "../../../config/other"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; // Function diff --git a/src/plugins/utility/modules/avatar.ts b/src/commands/utility/modules/avatar.ts similarity index 95% rename from src/plugins/utility/modules/avatar.ts rename to src/commands/utility/modules/avatar.ts index b060be3..57110cf 100644 --- a/src/plugins/utility/modules/avatar.ts +++ b/src/commands/utility/modules/avatar.ts @@ -1,4 +1,4 @@ -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../helpers/getEmbedConfig"; import { CommandInteraction, MessageEmbed } from "discord.js"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; diff --git a/src/commands/utility/modules/index.ts b/src/commands/utility/modules/index.ts new file mode 100644 index 0000000..cd69316 --- /dev/null +++ b/src/commands/utility/modules/index.ts @@ -0,0 +1,11 @@ +import avatar from "./avatar"; +import about from "./about"; +import lookup from "./lookup"; +import stats from "./stats"; + +export default { + avatar, + about, + lookup, + stats, +}; diff --git a/src/plugins/utility/modules/lookup.ts b/src/commands/utility/modules/lookup.ts similarity index 96% rename from src/plugins/utility/modules/lookup.ts rename to src/commands/utility/modules/lookup.ts index 241b7ce..a5825f9 100644 --- a/src/plugins/utility/modules/lookup.ts +++ b/src/commands/utility/modules/lookup.ts @@ -1,11 +1,11 @@ import axios from "axios"; import { CommandInteraction } from "discord.js"; -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../helpers/getEmbedConfig"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; -import embedBuilder from "@root/helpers/embedBuilder"; +import embedBuilder from "../../../helpers/embedBuilder"; export default { metadata: { guildOnly: false, ephemeral: false }, diff --git a/src/plugins/utility/modules/stats.ts b/src/commands/utility/modules/stats.ts similarity index 97% rename from src/plugins/utility/modules/stats.ts rename to src/commands/utility/modules/stats.ts index a7f44a0..805b948 100644 --- a/src/plugins/utility/modules/stats.ts +++ b/src/commands/utility/modules/stats.ts @@ -1,4 +1,4 @@ -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../../helpers/getEmbedConfig"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import { CommandInteraction } from "discord.js"; diff --git a/src/config/example.other.ts b/src/config/example.other.ts index 3a86a51..1695d42 100644 --- a/src/config/example.other.ts +++ b/src/config/example.other.ts @@ -9,3 +9,6 @@ export const hosterName = "someone"; // Hoster Url export const hosterUrl = "scheme://domain.tld"; + +// Winston log level +export const logLevel = "info"; diff --git a/src/database/index.ts b/src/database/index.ts index b7dd3b6..9060935 100644 --- a/src/database/index.ts +++ b/src/database/index.ts @@ -2,10 +2,10 @@ import mongoose from "mongoose"; // Dependencies -import logger from "@logger"; +import logger from "../logger"; // Configuration -import { url } from "@config/database"; +import { url } from "../config/database"; export default async () => { await mongoose.connect(url).then(async (connection) => { diff --git a/src/database/schemas/api.ts b/src/database/schemas/api.ts index 12519d2..5a78afd 100644 --- a/src/database/schemas/api.ts +++ b/src/database/schemas/api.ts @@ -1,10 +1,11 @@ import { Snowflake } from "discord.js"; import { model, Schema } from "mongoose"; +import { IEncryptionData } from "../../interfaces/EncryptionData"; export interface IApi { guildId: Snowflake; url: string; - token: { iv: string; content: string }; + token: IEncryptionData; } const apiSchema = new Schema( diff --git a/src/events/guildCreate/index.ts b/src/events/guildCreate/index.ts index 01b70f6..a309884 100644 --- a/src/events/guildCreate/index.ts +++ b/src/events/guildCreate/index.ts @@ -1,20 +1,20 @@ -// 3rd party dependencies import { Guild } from "discord.js"; +import updatePresence from "../../helpers/updatePresence"; +import fetchGuild from "../../helpers/fetchGuild"; +import logger from "../../logger"; +import { IEventOptions } from "../../interfaces/EventOptions"; -// Dependencies -import updatePresence from "@helpers/updatePresence"; -import fetchGuild from "@helpers/fetchGuild"; -import logger from "@logger"; - -export default { - async execute(guild: Guild) { - const { client } = guild; - - logger?.silly(`Added to guild: ${guild.name} (${guild.id})`); - - await fetchGuild(guild); - await updatePresence(client); - - logger.silly(`guildCreate: ${guild}`); - }, +export const options: IEventOptions = { + type: "on", +}; + +export const execute = async (guild: Guild) => { + const { client } = guild; + + logger?.silly(`Added to guild: ${guild.name} (${guild.id})`); + + await fetchGuild(guild); + await updatePresence(client); + + logger.silly(`guildCreate: ${guild}`); }; diff --git a/src/events/guildDelete/index.ts b/src/events/guildDelete/index.ts index 123393c..be090b8 100644 --- a/src/events/guildDelete/index.ts +++ b/src/events/guildDelete/index.ts @@ -2,19 +2,22 @@ import { Guild } from "discord.js"; // Dependencies -import updatePresence from "@helpers/updatePresence"; -import dropGuild from "@helpers/dropGuild"; -import logger from "@logger"; +import updatePresence from "../../helpers/updatePresence"; +import dropGuild from "../../helpers/dropGuild"; +import logger from "../../logger"; +import { IEventOptions } from "../../interfaces/EventOptions"; -export default { - async execute(guild: Guild) { - const { client } = guild; - - logger?.silly(`Deleted from guild: ${guild.name} (${guild.id})`); - - await dropGuild(guild); - await updatePresence(client); - - logger.silly(`guildDelete: ${guild}`); - }, +export const options: IEventOptions = { + type: "on", +}; + +export const execute = async (guild: Guild) => { + const { client } = guild; + + logger?.silly(`Deleted from guild: ${guild.name} (${guild.id})`); + + await dropGuild(guild); + await updatePresence(client); + + logger.silly(`guildDelete: ${guild}`); }; diff --git a/src/events/guildMemberAdd/audits.ts b/src/events/guildMemberAdd/audits.ts index c47c78e..6e140c6 100644 --- a/src/events/guildMemberAdd/audits.ts +++ b/src/events/guildMemberAdd/audits.ts @@ -1,9 +1,9 @@ -import logger from "@logger"; +import logger from "../../logger"; import { GuildMember, MessageEmbed, TextChannel } from "discord.js"; -import guildSchema from "@schemas/guild"; +import guildSchema from "../../database/schemas/guild"; -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../helpers/getEmbedConfig"; export default { execute: async (member: GuildMember) => { diff --git a/src/events/guildMemberAdd/index.ts b/src/events/guildMemberAdd/index.ts index 9ece541..0dff9bf 100644 --- a/src/events/guildMemberAdd/index.ts +++ b/src/events/guildMemberAdd/index.ts @@ -2,23 +2,26 @@ import { GuildMember } from "discord.js"; // Dependencies -import updatePresence from "@helpers/updatePresence"; -import fetchUser from "@helpers/fetchUser"; -import logger from "@logger"; +import updatePresence from "../../helpers/updatePresence"; +import fetchUser from "../../helpers/fetchUser"; +import logger from "../../logger"; import joinMessage from "../guildMemberAdd/joinMessage"; import audits from "../guildMemberAdd/audits"; +import { IEventOptions } from "../../interfaces/EventOptions"; -export default { - async execute(member: GuildMember) { - const { client, user, guild } = member; - - logger?.silly( - `New member: ${user.tag} (${user.id}) added to guild: ${guild.name} (${guild.id})` - ); - - await audits.execute(member); - await joinMessage.execute(member); - await fetchUser(user, guild); - await updatePresence(client); - }, +export const options: IEventOptions = { + type: "on", +}; + +export const execute = async (member: GuildMember) => { + const { client, user, guild } = member; + + logger?.silly( + `New member: ${user.tag} (${user.id}) added to guild: ${guild.name} (${guild.id})` + ); + + await audits.execute(member); + await joinMessage.execute(member); + await fetchUser(user, guild); + await updatePresence(client); }; diff --git a/src/events/guildMemberAdd/joinMessage.ts b/src/events/guildMemberAdd/joinMessage.ts index bf7aec3..db0a745 100644 --- a/src/events/guildMemberAdd/joinMessage.ts +++ b/src/events/guildMemberAdd/joinMessage.ts @@ -1,8 +1,8 @@ import { GuildMember, MessageEmbed, TextChannel } from "discord.js"; -import guildSchema from "@schemas/guild"; +import guildSchema from "../../database/schemas/guild"; -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../helpers/getEmbedConfig"; export default { execute: async (member: GuildMember) => { diff --git a/src/events/guildMemberRemove/audits.ts b/src/events/guildMemberRemove/audits.ts index 620e52e..9f2c343 100644 --- a/src/events/guildMemberRemove/audits.ts +++ b/src/events/guildMemberRemove/audits.ts @@ -1,9 +1,9 @@ -import logger from "@logger"; +import logger from "../../logger"; import { GuildMember, MessageEmbed, TextChannel } from "discord.js"; -import guildSchema from "@schemas/guild"; +import guildSchema from "../../database/schemas/guild"; -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../helpers/getEmbedConfig"; export default { execute: async (member: GuildMember) => { diff --git a/src/events/guildMemberRemove/index.ts b/src/events/guildMemberRemove/index.ts index 3d28c31..502aad4 100644 --- a/src/events/guildMemberRemove/index.ts +++ b/src/events/guildMemberRemove/index.ts @@ -2,23 +2,26 @@ import { GuildMember } from "discord.js"; // Dependencies -import updatePresence from "@helpers/updatePresence"; -import dropUser from "@helpers/dropUser"; -import logger from "@logger"; +import updatePresence from "../../helpers/updatePresence"; +import dropUser from "../../helpers/dropUser"; +import logger from "../../logger"; import leaveMessage from "./leaveMessage"; import audits from "./audits"; +import { IEventOptions } from "../../interfaces/EventOptions"; -export default { - async execute(member: GuildMember) { - const { client, user, guild } = member; - - logger?.silly( - `Removed member: ${user.tag} (${user.id}) from guild: ${guild.name} (${guild.id})` - ); - - await audits.execute(member); - await leaveMessage.execute(member); - await dropUser(user, guild); - await updatePresence(client); - }, +export const options: IEventOptions = { + type: "on", +}; + +export const execute = async (member: GuildMember) => { + const { client, user, guild } = member; + + logger?.silly( + `Removed member: ${user.tag} (${user.id}) from guild: ${guild.name} (${guild.id})` + ); + + await audits.execute(member); + await leaveMessage.execute(member); + await dropUser(user, guild); + await updatePresence(client); }; diff --git a/src/events/guildMemberRemove/leaveMessage.ts b/src/events/guildMemberRemove/leaveMessage.ts index efed730..427866b 100644 --- a/src/events/guildMemberRemove/leaveMessage.ts +++ b/src/events/guildMemberRemove/leaveMessage.ts @@ -1,8 +1,8 @@ import { GuildMember, MessageEmbed, TextChannel } from "discord.js"; -import guildSchema from "@schemas/guild"; +import guildSchema from "../../database/schemas/guild"; -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../helpers/getEmbedConfig"; export default { execute: async (member: GuildMember) => { diff --git a/src/events/interactionCreate/audits.ts b/src/events/interactionCreate/audits.ts index c6df788..3a311c5 100644 --- a/src/events/interactionCreate/audits.ts +++ b/src/events/interactionCreate/audits.ts @@ -1,9 +1,9 @@ -import logger from "@logger"; +import logger from "../../logger"; import { Interaction, MessageEmbed, TextChannel } from "discord.js"; -import guildSchema from "@schemas/guild"; +import guildSchema from "../../database/schemas/guild"; -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../helpers/getEmbedConfig"; export default { execute: async (interaction: Interaction) => { diff --git a/src/events/interactionCreate/components/isCommand.ts b/src/events/interactionCreate/components/isCommand.ts index 30edc4c..3addf8b 100644 --- a/src/events/interactionCreate/components/isCommand.ts +++ b/src/events/interactionCreate/components/isCommand.ts @@ -1,11 +1,12 @@ // Dependencies import { CommandInteraction, MessageEmbed } from "discord.js"; -import logger from "@logger"; +import logger from "../../../logger"; -import deferReply from "@root/helpers/deferReply"; -import getEmbedConfig from "@helpers/getEmbedConfig"; -import getCommandMetadata from "@helpers/getCommandMetadata"; +import deferReply from "../../../helpers/deferReply"; +import getEmbedConfig from "../../../helpers/getEmbedConfig"; +import getCommandMetadata from "../../../helpers/getCommandMetadata"; +import capitalizeFirstLetter from "../../../helpers/capitalizeFirstLetter"; export default async (interaction: CommandInteraction) => { if (!interaction.isCommand()) return; @@ -89,10 +90,12 @@ export default async (interaction: CommandInteraction) => { return interaction.editReply({ embeds: [ new MessageEmbed() - .setTitle("Error") - .setDescription( - `There was an error executing the command: **${currentCommand?.data?.name}**.` + .setTitle( + `[:x:] ${capitalizeFirstLetter( + interaction.options.getSubcommand() + )}` ) + .setDescription(`${"``"}${error}${"``"}`) .setColor(errorColor) .setTimestamp(new Date()) .setFooter({ text: footerText, iconURL: footerIcon }), diff --git a/src/events/interactionCreate/index.ts b/src/events/interactionCreate/index.ts index 2848f39..7e173dc 100644 --- a/src/events/interactionCreate/index.ts +++ b/src/events/interactionCreate/index.ts @@ -2,19 +2,22 @@ import { CommandInteraction } from "discord.js"; // Dependencies -import isCommand from "@root/events/interactionCreate/components/isCommand"; -import logger from "@logger"; +import isCommand from "../../events/interactionCreate/components/isCommand"; +import logger from "../../logger"; import audits from "./audits"; +import { IEventOptions } from "../../interfaces/EventOptions"; -export default { - async execute(interaction: CommandInteraction) { - const { guild, id } = interaction; - - logger?.silly( - `New interaction: ${id} in guild: ${guild?.name} (${guild?.id})` - ); - - await audits.execute(interaction); - await isCommand(interaction); - }, +export const options: IEventOptions = { + type: "on", +}; + +export const execute = async (interaction: CommandInteraction) => { + const { guild, id } = interaction; + + logger?.silly( + `New interaction: ${id} in guild: ${guild?.name} (${guild?.id})` + ); + + await audits.execute(interaction); + await isCommand(interaction); }; diff --git a/src/events/messageCreate/index.ts b/src/events/messageCreate/index.ts index 004ca71..f5beddf 100644 --- a/src/events/messageCreate/index.ts +++ b/src/events/messageCreate/index.ts @@ -1,10 +1,14 @@ import { Message } from "discord.js"; -import modules from "@events/messageCreate/modules"; +import modules from "../../events/messageCreate/modules"; -export default { - async execute(message: Message) { - await modules.credits.execute(message); - await modules.points.execute(message); - await modules.counters.execute(message); - }, +import { IEventOptions } from "../../interfaces/EventOptions"; + +export const options: IEventOptions = { + type: "on", +}; + +export const execute = async (message: Message) => { + await modules.credits.execute(message); + await modules.points.execute(message); + await modules.counters.execute(message); }; diff --git a/src/events/messageCreate/modules/counters/index.ts b/src/events/messageCreate/modules/counters/index.ts index a65a4db..882fbc6 100644 --- a/src/events/messageCreate/modules/counters/index.ts +++ b/src/events/messageCreate/modules/counters/index.ts @@ -1,7 +1,7 @@ import { Message } from "discord.js"; -import logger from "@logger"; -import counterSchema from "@schemas/counter"; +import logger from "../../../../logger"; +import counterSchema from "../../../../database/schemas/counter"; export default { execute: async (message: Message) => { diff --git a/src/events/messageCreate/modules/credits/index.ts b/src/events/messageCreate/modules/credits/index.ts index 856c308..1058490 100644 --- a/src/events/messageCreate/modules/credits/index.ts +++ b/src/events/messageCreate/modules/credits/index.ts @@ -1,9 +1,9 @@ -import logger from "@logger"; -import timeouts from "@schemas/timeout"; +import logger from "../../../../logger"; +import timeouts from "../../../../database/schemas/timeout"; import { Message } from "discord.js"; -import fetchUser from "@helpers/fetchUser"; -import fetchGuild from "@helpers/fetchGuild"; +import fetchUser from "../../../../helpers/fetchUser"; +import fetchGuild from "../../../../helpers/fetchGuild"; export default { execute: async (message: Message) => { diff --git a/src/events/messageCreate/modules/index.ts b/src/events/messageCreate/modules/index.ts index e2d04fb..aff2dd3 100644 --- a/src/events/messageCreate/modules/index.ts +++ b/src/events/messageCreate/modules/index.ts @@ -1,6 +1,6 @@ -import counters from "@events/messageCreate/modules/counters"; -import credits from "@events/messageCreate/modules/credits"; -import points from "@events/messageCreate/modules/points"; +import counters from "./counters"; +import credits from "./credits"; +import points from "./points"; export default { counters, diff --git a/src/events/messageCreate/modules/points/index.ts b/src/events/messageCreate/modules/points/index.ts index e4d3aa4..12b683a 100644 --- a/src/events/messageCreate/modules/points/index.ts +++ b/src/events/messageCreate/modules/points/index.ts @@ -1,8 +1,8 @@ -import logger from "@logger"; -import timeouts from "@schemas/timeout"; +import logger from "../../../../logger"; +import timeouts from "../../../../database/schemas/timeout"; -import fetchUser from "@helpers/fetchUser"; -import fetchGuild from "@helpers/fetchGuild"; +import fetchUser from "../../../../helpers/fetchUser"; +import fetchGuild from "../../../../helpers/fetchGuild"; import { Message } from "discord.js"; export default { diff --git a/src/events/messageDelete/audits.ts b/src/events/messageDelete/audits.ts index 1f37b59..eb28000 100644 --- a/src/events/messageDelete/audits.ts +++ b/src/events/messageDelete/audits.ts @@ -1,9 +1,9 @@ -import logger from "@logger"; +import logger from "../../logger"; import { Message, MessageEmbed, TextChannel } from "discord.js"; -import guildSchema from "@schemas/guild"; +import guildSchema from "../../database/schemas/guild"; -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../helpers/getEmbedConfig"; export default { execute: async (message: Message) => { diff --git a/src/events/messageDelete/index.ts b/src/events/messageDelete/index.ts index 77223d2..7279add 100644 --- a/src/events/messageDelete/index.ts +++ b/src/events/messageDelete/index.ts @@ -1,10 +1,13 @@ import { Message } from "discord.js"; -import audits from "@events/messageDelete/audits"; +import audits from "../../events/messageDelete/audits"; import counter from "./modules/counter"; +import { IEventOptions } from "../../interfaces/EventOptions"; -export default { - async execute(message: Message) { - await audits.execute(message); - await counter(message); - }, +export const options: IEventOptions = { + type: "on", +}; + +export const execute = async (message: Message) => { + await audits.execute(message); + await counter(message); }; diff --git a/src/events/messageDelete/modules/counter.ts b/src/events/messageDelete/modules/counter.ts index 6169b45..e488ae4 100644 --- a/src/events/messageDelete/modules/counter.ts +++ b/src/events/messageDelete/modules/counter.ts @@ -2,8 +2,8 @@ import { Message } from "discord.js"; // Models -import counterSchema from "@schemas/counter"; -import logger from "@logger"; +import counterSchema from "../../../database/schemas/counter"; +import logger from "../../../logger"; export default async (message: Message) => { const { guild, channel, author, content } = message; diff --git a/src/events/messageUpdate/audits.ts b/src/events/messageUpdate/audits.ts index c9bed8a..3438666 100644 --- a/src/events/messageUpdate/audits.ts +++ b/src/events/messageUpdate/audits.ts @@ -1,10 +1,10 @@ /* eslint-disable no-loops/no-loops */ -import logger from "@logger"; +import logger from "../../logger"; import { Message, MessageEmbed, TextChannel } from "discord.js"; -import guildSchema from "@schemas/guild"; +import guildSchema from "../../database/schemas/guild"; -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../helpers/getEmbedConfig"; export default { execute: async (oldMessage: Message, newMessage: Message) => { diff --git a/src/events/messageUpdate/index.ts b/src/events/messageUpdate/index.ts index 9238805..263d53e 100644 --- a/src/events/messageUpdate/index.ts +++ b/src/events/messageUpdate/index.ts @@ -1,24 +1,27 @@ // Dependencies import { Message } from "discord.js"; -import logger from "@logger"; +import logger from "../../logger"; // Modules import counter from "./modules/counter"; import audits from "./audits"; +import { IEventOptions } from "../../interfaces/EventOptions"; -export default { - async execute(oldMessage: Message, newMessage: Message) { - const { author, guild } = newMessage; - - await audits.execute(oldMessage, newMessage); - - logger?.silly( - `Message update event fired by ${author.tag} (${author.id}) in guild: ${guild?.name} (${guild?.id})` - ); - - if (author?.bot) return logger?.silly(`Message update event fired by bot`); - - await counter(newMessage); - }, +export const options: IEventOptions = { + type: "on", +}; + +export const execute = async (oldMessage: Message, newMessage: Message) => { + const { author, guild } = newMessage; + + await audits.execute(oldMessage, newMessage); + + logger?.silly( + `Message update event fired by ${author.tag} (${author.id}) in guild: ${guild?.name} (${guild?.id})` + ); + + if (author?.bot) return logger?.silly(`Message update event fired by bot`); + + await counter(newMessage); }; diff --git a/src/events/messageUpdate/modules/counter.ts b/src/events/messageUpdate/modules/counter.ts index 465b00a..8ea7087 100644 --- a/src/events/messageUpdate/modules/counter.ts +++ b/src/events/messageUpdate/modules/counter.ts @@ -2,8 +2,8 @@ import { Message } from "discord.js"; // Models -import counterSchema from "@schemas/counter"; -import logger from "@logger"; +import counterSchema from "../../../database/schemas/counter"; +import logger from "../../../logger"; export default async (message: Message) => { const { guild, channel, author, content } = message; diff --git a/src/events/ready/index.ts b/src/events/ready/index.ts index b312f73..bd1e060 100644 --- a/src/events/ready/index.ts +++ b/src/events/ready/index.ts @@ -1,25 +1,21 @@ // Dependencies import { Client } from "discord.js"; -import logger from "@logger"; +import logger from "../../logger"; // Helpers -import updatePresence from "@helpers/updatePresence"; -import deployCommands from "@handlers/deployCommands"; -import devMode from "@handlers/devMode"; +import updatePresence from "../../helpers/updatePresence"; +import deployCommands from "../../handlers/deployCommands"; +import devMode from "../../handlers/devMode"; +import { IEventOptions } from "../../interfaces/EventOptions"; -export default { - once: true, - async execute(client: Client) { - logger.info("Ready!"); - - await updatePresence(client); - await devMode(client); - await deployCommands(client); - - client.guilds?.cache.forEach((guild) => { - logger.silly( - `${client.user?.tag} (${client.user?.id}) is in guild: ${guild.name} (${guild.id}) with member count of ${guild.memberCount}` - ); - }); - }, +export const options: IEventOptions = { + type: "once", +}; + +export const execute = async (client: Client) => { + logger.info("Discord's API client is ready!"); + + await updatePresence(client); + await devMode(client); + await deployCommands(client); }; diff --git a/src/handlers/commands.ts b/src/handlers/commands.ts deleted file mode 100644 index 81b1eeb..0000000 --- a/src/handlers/commands.ts +++ /dev/null @@ -1,36 +0,0 @@ -import fs from "fs"; // fs -import { Collection } from "discord.js"; // discord.js -import { Client } from "@root/types/common/discord"; -import logger from "@logger"; - -export default async (client: Client) => { - client.commands = new Collection(); - - fs.readdir("./src/plugins", async (error, plugins) => { - if (error) { - return logger.error(`Error reading plugins: ${error}`); - } - - await Promise.all( - plugins.map(async (pluginName, index) => { - const plugin = await import(`../plugins/${pluginName}`); - - await client.commands.set( - plugin.default.builder.name, - plugin.default, - plugin.default.metadata - ); - - logger.verbose( - `Loaded plugin ${index + 1}/${plugins.length}: ${pluginName}` - ); - }) - ) - .then(async () => { - logger.info(`Started all ${plugins.length} plugins.`); - }) - .catch(async (err) => { - logger.error(`${err}`); - }); - }); -}; diff --git a/src/handlers/deployCommands.ts b/src/handlers/deployCommands.ts index 4ca0923..2123da7 100644 --- a/src/handlers/deployCommands.ts +++ b/src/handlers/deployCommands.ts @@ -1,32 +1,28 @@ -// @ts-ignore -import { token, clientId } from "@config/discord"; -// @ts-ignore -import { devMode, guildId } from "@config/other"; +import { token, clientId } from "../config/discord"; +import { devMode, guildId } from "../config/other"; import logger from "../logger"; -import { Client } from "@root/types/common/discord"; +import { Client } from "discord.js"; import { REST } from "@discordjs/rest"; import { Routes } from "discord-api-types/v9"; -import { SlashCommandBuilder } from "@discordjs/builders"; import { RESTPostAPIApplicationCommandsJSONBody } from "discord-api-types/v10"; -export default async (client: Client) => { - const pluginList: Array = []; +import { ICommand } from "../interfaces/Command"; - interface IPluginData { - builder: SlashCommandBuilder; - } +export default async (client: Client) => { + const commandList: Array = []; + + logger.info("Gathering command list"); await Promise.all( - client.commands.map(async (pluginData: IPluginData) => { - pluginList.push(pluginData.builder.toJSON()); - logger.verbose( - `Plugin is ready for deployment: ${pluginData.builder.name}` - ); + client.commands.map(async (commandData: ICommand) => { + commandList.push(commandData.builder.toJSON()); + + logger.verbose(`${commandData.builder.name} pushed to list`); }) ) .then(async () => { - logger.info("All plugins are ready to be deployed."); + logger.info(`Finished gathering command list.`); }) .catch(async (error) => { logger.error(`${error}`); @@ -36,10 +32,10 @@ export default async (client: Client) => { await rest .put(Routes.applicationCommands(clientId), { - body: pluginList, + body: commandList, }) .then(async () => { - logger.info(`Successfully deployed plugins to Discord's API`); + logger.info(`Finished updating command list.`); }) .catch(async (error) => { logger.error(`${error}`); @@ -48,11 +44,9 @@ export default async (client: Client) => { if (devMode) { await rest .put(Routes.applicationGuildCommands(clientId, guildId), { - body: pluginList, + body: commandList, }) - .then(async () => - logger.info(`Successfully deployed guild plugins to Discord's API`) - ) + .then(async () => logger.info(`Finished updating guild command list.`)) .catch(async (error) => { logger.error(`${error}`); }); diff --git a/src/handlers/devMode.ts b/src/handlers/devMode.ts index 53a2cd6..764fbcf 100644 --- a/src/handlers/devMode.ts +++ b/src/handlers/devMode.ts @@ -1,10 +1,10 @@ // Dependencies import { Client } from "discord.js"; -import logger from "@logger"; +import logger from "../logger"; // Configuration -import { devMode, guildId } from "@config/other"; +import { devMode, guildId } from "../config/other"; export default async (client: Client) => { if (!devMode) { diff --git a/src/handlers/encryption.ts b/src/handlers/encryption.ts index cab28ff..de5a7b9 100644 --- a/src/handlers/encryption.ts +++ b/src/handlers/encryption.ts @@ -1,16 +1,12 @@ import crypto from "crypto"; -// @ts-ignore -import { secretKey, algorithm } from "@config/encryption"; +import { secretKey, algorithm } from "../config/encryption"; + +import { IEncryptionData } from "../interfaces/EncryptionData"; const iv = crypto.randomBytes(16); -interface IEncrypt { - iv: string; - content: string; -} - -const encrypt = (text: crypto.BinaryLike): IEncrypt => { +const encrypt = (text: crypto.BinaryLike): IEncryptionData => { const cipher = crypto.createCipheriv(algorithm, secretKey, iv); const encrypted = Buffer.concat([cipher.update(text), cipher.final()]); @@ -20,7 +16,7 @@ const encrypt = (text: crypto.BinaryLike): IEncrypt => { }; }; -const decrypt = (hash: IEncrypt) => { +const decrypt = (hash: IEncryptionData) => { const decipher = crypto.createDecipheriv( algorithm, secretKey, diff --git a/src/handlers/events.ts b/src/handlers/events.ts deleted file mode 100644 index f7da9c1..0000000 --- a/src/handlers/events.ts +++ /dev/null @@ -1,37 +0,0 @@ -import fs from "fs"; // fs -import { Client } from "discord.js"; // discord.js -import logger from "@logger"; - -export default async (client: Client) => { - fs.readdir("./src/events", async (error, events) => { - if (error) { - return logger.error(`Error reading plugins: ${error}`); - } - - await Promise.all( - events.map(async (eventName, index) => { - const event = await import(`../events/${eventName}`); - - logger.verbose( - `Loaded event ${index + 1}/${events.length}: ${eventName}` - ); - - if (event.once) { - return client.once(eventName, async (...args) => - event.default.execute(...args) - ); - } - - return client.on(eventName, async (...args) => - event.default.execute(...args) - ); - }) - ) - .then(async () => { - logger.info(`Started all ${events.length} events.`); - }) - .catch(async (err) => { - logger.error(`${err}`); - }); - }); -}; diff --git a/src/handlers/schedules/index.ts b/src/handlers/schedules/index.ts index 20ed685..c6a1cef 100644 --- a/src/handlers/schedules/index.ts +++ b/src/handlers/schedules/index.ts @@ -2,10 +2,10 @@ import { Client } from "discord.js"; import schedule from "node-schedule"; -import logger from "@logger"; +import logger from "../../logger"; // Jobs -import shopRoles from "@jobs/shopRoles"; +import shopRoles from "../../jobs/shopRoles"; export default async (client: Client) => { const expression = "*/5 * * * *"; diff --git a/src/helpers/capitalizeFirstLetter/index.ts b/src/helpers/capitalizeFirstLetter/index.ts new file mode 100644 index 0000000..1190b36 --- /dev/null +++ b/src/helpers/capitalizeFirstLetter/index.ts @@ -0,0 +1,3 @@ +export default (text: string): string => { + return text.charAt(0).toUpperCase() + text.slice(1); +}; diff --git a/src/helpers/deferReply.ts b/src/helpers/deferReply/index.ts similarity index 91% rename from src/helpers/deferReply.ts rename to src/helpers/deferReply/index.ts index feec1a7..45d95ed 100644 --- a/src/helpers/deferReply.ts +++ b/src/helpers/deferReply/index.ts @@ -1,5 +1,5 @@ import { CommandInteraction, MessageEmbed } from "discord.js"; -import getEmbedConfig from "@helpers/getEmbedConfig"; +import getEmbedConfig from "../../helpers/getEmbedConfig"; export default async (interaction: CommandInteraction, ephemeral: boolean) => { if (interaction.guild == null) return; diff --git a/src/helpers/dropGuild.ts b/src/helpers/dropGuild/index.ts similarity index 82% rename from src/helpers/dropGuild.ts rename to src/helpers/dropGuild/index.ts index d69d09b..e0d8356 100644 --- a/src/helpers/dropGuild.ts +++ b/src/helpers/dropGuild/index.ts @@ -1,11 +1,11 @@ -import guildSchema from "@schemas/guild"; -import userSchema from "@schemas/user"; -import apiSchema from "@schemas/api"; -import counterSchema from "@schemas/counter"; -import shopRoleSchema from "@schemas/shopRole"; -import timeoutSchema from "@schemas/timeout"; +import guildSchema from "../../database/schemas/guild"; +import userSchema from "../../database/schemas/user"; +import apiSchema from "../../database/schemas/api"; +import counterSchema from "../../database/schemas/counter"; +import shopRoleSchema from "../../database/schemas/shopRole"; +import timeoutSchema from "../../database/schemas/timeout"; -import logger from "@logger"; +import logger from "../../logger"; import { Guild } from "discord.js"; diff --git a/src/helpers/dropUser.ts b/src/helpers/dropUser/index.ts similarity index 82% rename from src/helpers/dropUser.ts rename to src/helpers/dropUser/index.ts index 8306285..976cd6c 100644 --- a/src/helpers/dropUser.ts +++ b/src/helpers/dropUser/index.ts @@ -1,6 +1,6 @@ -import userSchema from "@schemas/user"; +import userSchema from "../../database/schemas/user"; -import logger from "@logger"; +import logger from "../../logger"; import { Guild, User } from "discord.js"; diff --git a/src/helpers/embedBuilder.ts b/src/helpers/embedBuilder/index.ts similarity index 74% rename from src/helpers/embedBuilder.ts rename to src/helpers/embedBuilder/index.ts index 8d15d90..d93cc5c 100644 --- a/src/helpers/embedBuilder.ts +++ b/src/helpers/embedBuilder/index.ts @@ -1,4 +1,4 @@ -import { footerText, footerIcon } from "@config/embed"; +import { footerText, footerIcon } from "../../config/embed"; import { MessageEmbed } from "discord.js"; export default new MessageEmbed() diff --git a/src/helpers/fetchGuild.ts b/src/helpers/fetchGuild/index.ts similarity index 86% rename from src/helpers/fetchGuild.ts rename to src/helpers/fetchGuild/index.ts index 4c8f107..bf4aff5 100644 --- a/src/helpers/fetchGuild.ts +++ b/src/helpers/fetchGuild/index.ts @@ -2,10 +2,10 @@ import { Guild } from "discord.js"; // Models -import guildSchema from "@schemas/guild"; +import guildSchema from "../../database/schemas/guild"; // Handlers -import logger from "@logger"; +import logger from "../../logger"; // Function export default async (guild: Guild) => { diff --git a/src/helpers/fetchUser.ts b/src/helpers/fetchUser/index.ts similarity index 89% rename from src/helpers/fetchUser.ts rename to src/helpers/fetchUser/index.ts index 96386ef..19b9f1f 100644 --- a/src/helpers/fetchUser.ts +++ b/src/helpers/fetchUser/index.ts @@ -2,10 +2,10 @@ import { Guild, User } from "discord.js"; // Models -import userSchema from "@schemas/user"; +import userSchema from "../../database/schemas/user"; // Handlers -import logger from "@logger"; +import logger from "../../logger"; // Function export default async (user: User, guild: Guild) => { diff --git a/src/helpers/getCommandMetadata.ts b/src/helpers/getCommandMetadata.ts deleted file mode 100644 index 7894c00..0000000 --- a/src/helpers/getCommandMetadata.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { CommandInteraction } from "discord.js"; - -export default async (interaction: CommandInteraction, currentCommand: any) => { - const subcommand = interaction.options.getSubcommand(); - const subcommandGroup = interaction.options.getSubcommandGroup(false); - - if (!subcommandGroup) { - return currentCommand.modules[subcommand].metadata; - } - - return currentCommand.modules[subcommandGroup].modules[subcommand].metadata; -}; diff --git a/src/helpers/getCommandMetadata/index.ts b/src/helpers/getCommandMetadata/index.ts new file mode 100644 index 0000000..647eb75 --- /dev/null +++ b/src/helpers/getCommandMetadata/index.ts @@ -0,0 +1,14 @@ +import { CommandInteraction } from "discord.js"; +import { ICommand } from "../../interfaces/Command"; + +export default async ( + interaction: CommandInteraction, + currentCommand: ICommand +) => { + const subcommand = interaction.options.getSubcommand(); + const subcommandGroup = interaction.options.getSubcommandGroup(false); + + return subcommandGroup + ? currentCommand.moduleData[subcommandGroup].moduleData[subcommand].metadata + : currentCommand.moduleData[subcommand].metadata; +}; diff --git a/src/helpers/getEmbedConfig.ts b/src/helpers/getEmbedConfig.ts deleted file mode 100644 index 3532542..0000000 --- a/src/helpers/getEmbedConfig.ts +++ /dev/null @@ -1,18 +0,0 @@ -import guildSchema from "@schemas/guild"; - -import { ColorResolvable, Guild } from "discord.js"; - -export default async (guild: Guild) => { - const guildConfig = await guildSchema.findOne({ guildId: guild.id }); - - if (guildConfig == null) - return { - successColor: "#22bb33" as ColorResolvable, - waitColor: "#f0ad4e" as ColorResolvable, - errorColor: "#bb2124" as ColorResolvable, - footerIcon: "https://github.com/ZynerOrg.png", - footerText: "https://github.com/ZynerOrg/xyter", - }; - - return guildConfig.embeds; -}; diff --git a/src/helpers/getEmbedConfig/index.ts b/src/helpers/getEmbedConfig/index.ts new file mode 100644 index 0000000..a52cbe5 --- /dev/null +++ b/src/helpers/getEmbedConfig/index.ts @@ -0,0 +1,20 @@ +import guildSchema from "../../database/schemas/guild"; +import * as embedConfig from "../../config/embed"; + +import { Guild } from "discord.js"; + +export default async (guild: Guild | null) => { + if (guild == null) + return { + ...embedConfig, + }; + + const guildConfig = await guildSchema.findOne({ guildId: guild.id }); + + if (guildConfig == null) + return { + ...embedConfig, + }; + + return guildConfig.embeds; +}; diff --git a/src/helpers/listDir/index.ts b/src/helpers/listDir/index.ts new file mode 100644 index 0000000..247fbe0 --- /dev/null +++ b/src/helpers/listDir/index.ts @@ -0,0 +1,10 @@ +import fs from "fs"; +const fsPromises = fs.promises; + +export default async (path: string) => { + try { + return await fsPromises.readdir(path); + } catch (err) { + console.error("Error occurred while reading directory!", err); + } +}; diff --git a/src/helpers/pluralize.ts b/src/helpers/pluralize/index.ts similarity index 86% rename from src/helpers/pluralize.ts rename to src/helpers/pluralize/index.ts index 3c5d55f..d6e266d 100644 --- a/src/helpers/pluralize.ts +++ b/src/helpers/pluralize/index.ts @@ -1,4 +1,4 @@ -import logger from "@root/logger"; +import logger from "../../logger"; export default (count: number, noun: string, suffix?: string): string => { const result = `${count} ${noun}${count !== 1 ? suffix || "s" : ""}`; diff --git a/src/helpers/saveUser.ts b/src/helpers/saveUser.ts deleted file mode 100644 index 8feb92e..0000000 --- a/src/helpers/saveUser.ts +++ /dev/null @@ -1,43 +0,0 @@ -import sleep from "@helpers/sleep"; -import logger from "@logger"; -import Chance from "chance"; - -export default async function saveUser(data: any, data2: any) { - process.nextTick( - async () => { - // Chance module - const chance = new Chance(); - - await sleep( - chance.integer({ - min: 0, - max: 1, - }) * - 10 + - 1 * 100 - ); // 100 - 1000 random Number generator - data.save((_: any) => - _ - ? logger?.error( - `ERROR Occurred while saving data (saveUser) \n${"=".repeat( - 50 - )}\n${`${_}\n${"=".repeat(50)}`}` - ) - : logger?.silly(`Saved user: ${data.id} (saveUser)`) - ); - if (data2) { - data2.save((_: any) => - _ - ? logger?.error( - `ERROR Occurred while saving data (saveUser) \n${"=".repeat( - 50 - )}\n${`${_}\n${"=".repeat(50)}`}` - ) - : logger?.silly(`Saved user: ${data2.id} (saveUser)`) - ); - } - }, - data, - data2 - ); -} diff --git a/src/helpers/sleep.ts b/src/helpers/sleep.ts deleted file mode 100644 index 792c81f..0000000 --- a/src/helpers/sleep.ts +++ /dev/null @@ -1,8 +0,0 @@ -import logger from "@logger"; - -export default function sleep(milliseconds: number) { - return new Promise((resolve) => { - setTimeout(resolve, milliseconds); - logger?.silly(`Sleeping for ${milliseconds} milliseconds`); - }); -} diff --git a/src/helpers/updatePresence.ts b/src/helpers/updatePresence.ts deleted file mode 100644 index 7f23885..0000000 --- a/src/helpers/updatePresence.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Dependencies -import { Client } from "discord.js"; -import logger from "@logger"; - -// Function -export default async (client: Client) => { - const status = `${client?.guilds?.cache?.size} guilds.`; - - client?.user?.setPresence({ - activities: [{ type: "WATCHING", name: status }], - status: "online", - }); - logger?.debug(`Updated client presence to: ${status}`); -}; diff --git a/src/helpers/updatePresence/index.ts b/src/helpers/updatePresence/index.ts new file mode 100644 index 0000000..a8c4a35 --- /dev/null +++ b/src/helpers/updatePresence/index.ts @@ -0,0 +1,23 @@ +// Dependencies +import { Client } from "discord.js"; +import logger from "../../logger"; + +// Function +export default async (client: Client) => { + if (!client?.user) throw new Error("Client's user is undefined."); + + const { guilds } = client; + + const memberCount = guilds.cache.reduce((a, g) => a + g.memberCount, 0); + + const guildCount = guilds.cache.size; + + const status = `${memberCount} users in ${guildCount} guilds.`; + + client.user.setPresence({ + activities: [{ type: "LISTENING", name: status }], + status: "online", + }); + + logger.info(`Client's presence is set to "${status}"`); +}; diff --git a/src/index.ts b/src/index.ts index eaef4db..31e3e40 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,13 @@ import "tsconfig-paths/register"; // Allows using tsconfig.json paths during runtime -import { token, intents } from "@config/discord"; +import { token, intents } from "./config/discord"; import { Client } from "discord.js"; // discord.js -import database from "@database"; -import schedules from "@handlers/schedules"; -import events from "@handlers/events"; -import commands from "@handlers/commands"; +import database from "./database"; +import schedules from "./handlers/schedules"; +import * as eventManager from "./managers/event"; +import * as commandManager from "./managers/command"; // Main process that starts all other sub processes const main = async () => { @@ -23,10 +23,10 @@ const main = async () => { await schedules(client); // Start command handler - await commands(client); + await commandManager.register(client); // Start event handler - await events(client); + await eventManager.register(client); // Authorize with Discord's API await client.login(token); diff --git a/src/interfaces/Command.ts b/src/interfaces/Command.ts new file mode 100644 index 0000000..f8a895a --- /dev/null +++ b/src/interfaces/Command.ts @@ -0,0 +1,7 @@ +import { SlashCommandBuilder } from "@discordjs/builders"; + +export interface ICommand { + builder: SlashCommandBuilder; + moduleData: any; + execute: Promise; +} diff --git a/src/interfaces/EncryptionData.ts b/src/interfaces/EncryptionData.ts new file mode 100644 index 0000000..ac41844 --- /dev/null +++ b/src/interfaces/EncryptionData.ts @@ -0,0 +1,4 @@ +export interface IEncryptionData { + iv: string; + content: string; +} diff --git a/src/interfaces/EventOptions.ts b/src/interfaces/EventOptions.ts new file mode 100644 index 0000000..7634394 --- /dev/null +++ b/src/interfaces/EventOptions.ts @@ -0,0 +1,3 @@ +export interface IEventOptions { + type: "on" | "once"; +} diff --git a/src/jobs/shopRoles.ts b/src/jobs/shopRoles.ts index b42a3f5..76ea653 100644 --- a/src/jobs/shopRoles.ts +++ b/src/jobs/shopRoles.ts @@ -1,12 +1,12 @@ // Dependencies import { Client } from "discord.js"; -import logger from "@logger"; +import logger from "../logger"; // Schemas -import userSchema from "@schemas/user"; -import shopRoleSchema from "@schemas/shopRole"; -import guildSchema from "@schemas/guild"; +import userSchema from "../database/schemas/user"; +import shopRoleSchema from "../database/schemas/shopRole"; +import guildSchema from "../database/schemas/guild"; export default async (client: Client) => { const roles = await shopRoleSchema.find(); diff --git a/src/logger/index.ts b/src/logger/index.ts index ae96924..1ffbceb 100644 --- a/src/logger/index.ts +++ b/src/logger/index.ts @@ -1,10 +1,12 @@ import winston from "winston"; import "winston-daily-rotate-file"; +import { logLevel } from "../config/other"; + const { combine, timestamp, printf, colorize, align, json } = winston.format; export default winston.createLogger({ - level: process.env.LOG_LEVEL || "silly", + level: logLevel || "info", transports: [ new winston.transports.DailyRotateFile({ filename: "logs/combined-%DATE%.log", diff --git a/src/managers/command/index.ts b/src/managers/command/index.ts new file mode 100644 index 0000000..3cf3316 --- /dev/null +++ b/src/managers/command/index.ts @@ -0,0 +1,30 @@ +import fs from "fs"; // fs +import { Collection, Client } from "discord.js"; // discord.js +import logger from "../../logger"; +import { ICommand } from "../../interfaces/Command"; +import listDir from "../../helpers/listDir"; + +export const register = async (client: Client) => { + client.commands = new Collection(); + + const commandNames = await listDir("commands"); + if (!commandNames) return; + + logger.info(`Loading ${commandNames.length} commands`); + + await Promise.all( + commandNames.map(async (commandName, index) => { + const command: ICommand = await import(`../../commands/${commandName}`); + + client.commands.set(command.builder.name, command); + + logger.verbose(`${command.builder.name} loaded`); + }) + ) + .then(async () => { + logger.info(`Finished loading commands.`); + }) + .catch(async (err) => { + logger.error(`${err}`); + }); +}; diff --git a/src/managers/event/index.ts b/src/managers/event/index.ts new file mode 100644 index 0000000..8a3a506 --- /dev/null +++ b/src/managers/event/index.ts @@ -0,0 +1,24 @@ +/* eslint-disable no-loops/no-loops */ +import { Client } from "discord.js"; +import listDir from "../../helpers/listDir"; + +export const register = async (client: Client) => { + const eventNames = await listDir("events"); + if (!eventNames) return; + + for await (const eventName of eventNames) { + const event = await import(`../../events/${eventName}`); + const eventExecutor = async (...args: any[]) => event.execute(...args); + if (!event.options?.type) return; + + switch (event.options.type) { + case "once": + client.once(eventName, eventExecutor); + break; + + case "on": + client.on(eventName, eventExecutor); + break; + } + } +}; diff --git a/src/plugins/config/index.ts b/src/plugins/config/index.ts deleted file mode 100644 index 9cf1ab4..0000000 --- a/src/plugins/config/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -// Dependencies -import { SlashCommandBuilder } from "@discordjs/builders"; -import { CommandInteraction } from "discord.js"; - -// Modules -import modules from "./modules"; - -// Handlers -import logger from "@logger"; - -// Function -export default { - modules, - - builder: new SlashCommandBuilder() - .setName("config") - .setDescription("Manage guild configurations.") - - .addSubcommand(modules.pterodactyl.builder) - .addSubcommand(modules.credits.builder) - .addSubcommand(modules.points.builder) - .addSubcommand(modules.welcome.builder) - .addSubcommand(modules.audits.builder) - .addSubcommand(modules.shop.builder) - .addSubcommand(modules.embeds.builder), - - async execute(interaction: CommandInteraction) { - // Destructure member - const { options } = interaction; - - switch (options?.getSubcommand()) { - case "pterodactyl": - logger?.silly(`Subcommand is pterodactyl`); - - return modules.pterodactyl.execute(interaction); - case "credits": - logger?.silly(`Subcommand is credits`); - - return modules.credits.execute(interaction); - case "points": - logger?.silly(`Subcommand is points`); - - return modules.points.execute(interaction); - case "welcome": - logger?.silly(`Subcommand is welcome`); - - return modules.welcome.execute(interaction); - case "audits": - logger?.silly(`Subcommand is audits`); - - return modules.audits.execute(interaction); - case "shop": - logger?.silly(`Subcommand is shop`); - - return modules.shop.execute(interaction); - case "embeds": - logger?.silly(`Subcommand is shop`); - - return modules.embeds.execute(interaction); - default: - logger?.silly(`Subcommand is not found`); - } - }, -}; diff --git a/src/plugins/config/modules/embeds.ts b/src/plugins/config/modules/embeds.ts deleted file mode 100644 index f4f3a15..0000000 --- a/src/plugins/config/modules/embeds.ts +++ /dev/null @@ -1,129 +0,0 @@ -// Dependencies -import { ColorResolvable, CommandInteraction, Permissions } from "discord.js"; - -//Handlers -import logger from "@logger"; - -// Models -import guildSchema from "@schemas/guild"; -import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; -import getEmbedConfig from "@helpers/getEmbedConfig"; - -// Function -export default { - metadata: { - guildOnly: true, - ephemeral: true, - permissions: [Permissions.FLAGS.MANAGE_GUILD], - }, - - builder: (command: SlashCommandSubcommandBuilder) => { - return command - .setName("embeds") - .setDescription(`Embeds`) - .addStringOption((option) => - option - .setName("success-color") - .setDescription("No provided description") - ) - .addStringOption((option) => - option.setName("wait-color").setDescription("No provided description") - ) - .addStringOption((option) => - option.setName("error-color").setDescription("No provided description") - ) - .addStringOption((option) => - option.setName("footer-icon").setDescription("No provided description") - ) - .addStringOption((option) => - option.setName("footer-text").setDescription("No provided description") - ); - }, - execute: async (interaction: CommandInteraction) => { - // Destructure member - const { guild, options } = interaction; - - if (guild == null) return; - - const embedConfig = await getEmbedConfig(guild); - - if (embedConfig == null) return; - - logger.info(embedConfig); - - // Get options - const successColor = options?.getString("success-color") as ColorResolvable; - const waitColor = options?.getString("wait-color") as ColorResolvable; - const errorColor = options?.getString("error-color") as ColorResolvable; - const footerIcon = options?.getString("footer-icon"); - const footerText = options?.getString("footer-text"); - - // Get guild object - const guildDB = await guildSchema?.findOne({ - guildId: guild?.id, - }); - - if (guildDB === null) { - return logger?.silly(`Guild is null`); - } - - // Modify values - guildDB.embeds.successColor = - successColor !== null ? successColor : guildDB?.embeds?.successColor; - guildDB.embeds.waitColor = - waitColor !== null ? waitColor : guildDB?.embeds?.waitColor; - guildDB.embeds.errorColor = - errorColor !== null ? errorColor : guildDB?.embeds?.errorColor; - guildDB.embeds.footerIcon = - footerIcon !== null ? footerIcon : guildDB?.embeds?.footerIcon; - guildDB.embeds.footerText = - footerText !== null ? footerText : guildDB?.embeds?.footerText; - - // Save guild - await guildDB?.save()?.then(async () => { - logger?.silly(`Guild saved`); - - return interaction?.editReply({ - embeds: [ - { - title: ":tools: Settings - Guild [Credits]", - description: `Credits settings updated.`, - color: successColor || embedConfig.successColor, - fields: [ - { - name: "🤖 Success Color", - value: `${guildDB?.embeds?.successColor}`, - inline: true, - }, - { - name: "📈 Wait Color", - value: `${guildDB?.embeds?.waitColor}`, - inline: true, - }, - { - name: "📈 Error Color", - value: `${guildDB?.embeds?.errorColor}`, - inline: true, - }, - { - name: "🔨 Footer Icon", - value: `${guildDB?.embeds?.footerIcon}`, - inline: true, - }, - { - name: "⏰ Footer Text", - value: `${guildDB?.embeds?.footerText}`, - inline: true, - }, - ], - timestamp: new Date(), - footer: { - iconURL: footerIcon || embedConfig.footerIcon, - text: footerText || embedConfig.footerText, - }, - }, - ], - }); - }); - }, -}; diff --git a/src/plugins/config/modules/index.ts b/src/plugins/config/modules/index.ts deleted file mode 100644 index e14701a..0000000 --- a/src/plugins/config/modules/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import audits from "@plugins/config/modules/audits"; -import credits from "@plugins/config/modules/credits"; -import points from "@plugins/config/modules/points"; -import pterodactyl from "@plugins/config/modules/pterodactyl"; -import shop from "@plugins/config/modules/shop"; -import welcome from "@plugins/config/modules/welcome"; -import embeds from "@plugins/config/modules/embeds"; - -export default { audits, credits, points, pterodactyl, shop, welcome, embeds }; diff --git a/src/plugins/counters/index.ts b/src/plugins/counters/index.ts deleted file mode 100644 index ca3fc56..0000000 --- a/src/plugins/counters/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { CommandInteraction } from "discord.js"; -import { SlashCommandBuilder } from "@discordjs/builders"; -import logger from "@logger"; - -import modules from "@plugins/counters/modules"; - -export default { - modules, - - builder: new SlashCommandBuilder() - .setName("counters") - .setDescription("View guild counters") - - .addSubcommand(modules.view.builder), - - async execute(interaction: CommandInteraction) { - const { options } = interaction; - - if (options.getSubcommand() === "view") { - logger.silly(`Executing view subcommand`); - return modules.view.execute(interaction); - } - - logger.silly(`Unknown subcommand ${options.getSubcommand()}`); - }, -}; diff --git a/src/plugins/counters/modules/index.ts b/src/plugins/counters/modules/index.ts deleted file mode 100644 index 8c5ea76..0000000 --- a/src/plugins/counters/modules/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import view from "@plugins/counters/modules/view"; - -export default { view }; diff --git a/src/plugins/credits/index.ts b/src/plugins/credits/index.ts deleted file mode 100644 index 5e8033f..0000000 --- a/src/plugins/credits/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { SlashCommandBuilder } from "@discordjs/builders"; -import { CommandInteraction } from "discord.js"; -import logger from "@logger"; - -import modules from "@plugins/credits/modules"; - -export default { - modules, - - builder: new SlashCommandBuilder() - .setName("credits") - .setDescription("Manage your credits.") - - .addSubcommand(modules.balance.builder) - .addSubcommand(modules.gift.builder) - .addSubcommand(modules.top.builder) - .addSubcommand(modules.work.builder), - - async execute(interaction: CommandInteraction) { - const { options } = interaction; - - switch (options.getSubcommand()) { - case "balance": - await modules.balance.execute(interaction); - break; - case "gift": - await modules.gift.execute(interaction); - break; - case "top": - await modules.top.execute(interaction); - break; - case "work": - await modules.work.execute(interaction); - break; - default: - logger.silly(`Unknown subcommand ${options.getSubcommand()}`); - } - }, -}; diff --git a/src/plugins/credits/modules/index.ts b/src/plugins/credits/modules/index.ts deleted file mode 100644 index 9b144f2..0000000 --- a/src/plugins/credits/modules/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import balance from "@plugins/credits/modules/balance"; -import gift from "@plugins/credits/modules/gift"; -import top from "@plugins/credits/modules/top"; -import work from "@plugins/credits/modules/work"; - -export default { balance, gift, top, work }; diff --git a/src/plugins/fun/index.ts b/src/plugins/fun/index.ts deleted file mode 100644 index 9ba8e81..0000000 --- a/src/plugins/fun/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { SlashCommandBuilder } from "@discordjs/builders"; -import { CommandInteraction } from "discord.js"; -import logger from "@logger"; - -import modules from "@plugins/fun/modules"; - -export default { - modules, - - builder: new SlashCommandBuilder() - .setName("fun") - .setDescription("Fun commands.") - - .addSubcommand(modules.meme.builder), - - async execute(interaction: CommandInteraction) { - const { options } = interaction; - - if (options.getSubcommand() === "meme") { - await modules.meme.execute(interaction); - } else { - logger.silly(`Unknown subcommand ${options.getSubcommand()}`); - } - }, -}; diff --git a/src/plugins/fun/modules/index.ts b/src/plugins/fun/modules/index.ts deleted file mode 100644 index 2b59097..0000000 --- a/src/plugins/fun/modules/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import meme from "@plugins/fun/modules/meme"; - -export default { - meme, -}; diff --git a/src/plugins/fun/modules/meme.ts b/src/plugins/fun/modules/meme.ts deleted file mode 100644 index be62672..0000000 --- a/src/plugins/fun/modules/meme.ts +++ /dev/null @@ -1,41 +0,0 @@ -import getEmbedConfig from "@helpers/getEmbedConfig"; - -import axios from "axios"; -import { CommandInteraction, MessageEmbed } from "discord.js"; -import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; -import logger from "@logger"; - -export default { - metadata: { guildOnly: false, ephemeral: false }, - - builder: (command: SlashCommandSubcommandBuilder) => { - return command.setName("meme").setDescription("Get a meme from r/memes)"); - }, - execute: async (interaction: CommandInteraction) => { - if (interaction.guild == null) return; - const { successColor, footerText, footerIcon } = await getEmbedConfig( - interaction.guild - ); - await axios - .get("https://www.reddit.com/r/memes/random/.json") - .then(async (res) => { - const response = res.data[0].data.children; - const content = response[0].data; - - const embed = new MessageEmbed() - .setTitle(content.title) - .setTimestamp(new Date()) - .setImage(content.url) - .setFooter({ - text: `👍 ${content.ups}︱👎 ${content.downs}\n${footerText}`, - iconURL: footerIcon, - }) - .setColor(successColor); - - return interaction.editReply({ embeds: [embed] }); - }) - .catch((error) => { - logger.error(`${error}`); - }); - }, -}; diff --git a/src/plugins/manage/index.ts b/src/plugins/manage/index.ts deleted file mode 100644 index 993ba9f..0000000 --- a/src/plugins/manage/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -//Dependencies -import { SlashCommandBuilder } from "@discordjs/builders"; -import { CommandInteraction } from "discord.js"; - -// Groups -import modules from "@plugins/manage/modules"; -import logger from "@logger"; - -// Function -export default { - modules, - - builder: new SlashCommandBuilder() - .setName("manage") - .setDescription("Manage the bot.") - .addSubcommandGroup(modules.counters.builder) - .addSubcommandGroup(modules.credits.builder), - - async execute(interaction: CommandInteraction) { - // Destructure - const { options } = interaction; - - if (options?.getSubcommandGroup() === "credits") { - logger?.silly(`Subcommand group is credits`); - - return modules.credits.execute(interaction); - } - - if (options?.getSubcommandGroup() === "counters") { - logger?.silly(`Subcommand group is counters`); - - return modules.counters.execute(interaction); - } - - logger?.silly(`Subcommand group is not credits or counters`); - }, -}; diff --git a/src/plugins/manage/modules/counters/index.ts b/src/plugins/manage/modules/counters/index.ts deleted file mode 100644 index 3fb9d3e..0000000 --- a/src/plugins/manage/modules/counters/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -// Dependencies -import { SlashCommandSubcommandGroupBuilder } from "@discordjs/builders"; -import { CommandInteraction } from "discord.js"; - -import logger from "@logger"; - -// Modules -import modules from "./modules"; - -// Function -export default { - modules, - - builder: (group: SlashCommandSubcommandGroupBuilder) => { - return group - .setName("counters") - .setDescription("Manage guild counters.") - .addSubcommand(modules.add.builder) - .addSubcommand(modules.remove.builder); - }, - - execute: async (interaction: CommandInteraction) => { - const { options } = interaction; - - if (options?.getSubcommand() === "add") { - logger?.silly(`Executing create subcommand`); - - return modules.add.execute(interaction); - } - - if (options?.getSubcommand() === "remove") { - logger?.silly(`Executing delete subcommand`); - - return modules.remove.execute(interaction); - } - - logger?.silly(`Unknown subcommand ${options?.getSubcommand()}`); - }, -}; diff --git a/src/plugins/manage/modules/counters/modules/index.ts b/src/plugins/manage/modules/counters/modules/index.ts deleted file mode 100644 index 2f55183..0000000 --- a/src/plugins/manage/modules/counters/modules/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import add from "@plugins/manage/modules/counters/modules/add"; -import remove from "@plugins/manage/modules/counters/modules/remove"; - -export default { add, remove }; diff --git a/src/plugins/manage/modules/credits/index.ts b/src/plugins/manage/modules/credits/index.ts deleted file mode 100644 index a12cf11..0000000 --- a/src/plugins/manage/modules/credits/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { CommandInteraction } from "discord.js"; -import { SlashCommandSubcommandGroupBuilder } from "@discordjs/builders"; -import logger from "@logger"; - -import modules from "./modules"; - -export default { - modules, - - builder: (group: SlashCommandSubcommandGroupBuilder) => { - return group - .setName("credits") - .setDescription("Manage the credits of a user.") - .addSubcommand(modules.give.builder) - .addSubcommand(modules.set.builder) - .addSubcommand(modules.take.builder) - .addSubcommand(modules.transfer.builder); - }, - execute: async (interaction: CommandInteraction) => { - const { options } = interaction; - - switch (options.getSubcommand()) { - case "give": - logger.silly(`Executing give subcommand`); - - return modules.give.execute(interaction); - case "set": - logger.silly(`Executing set subcommand`); - - return modules.set.execute(interaction); - case "take": - logger.silly(`Executing take subcommand`); - - return modules.take.execute(interaction); - case "transfer": - logger.silly(`Executing transfer subcommand`); - - return modules.transfer.execute(interaction); - default: - logger.silly(`Unknown subcommand ${options.getSubcommand()}`); - } - }, -}; diff --git a/src/plugins/manage/modules/credits/modules/index.ts b/src/plugins/manage/modules/credits/modules/index.ts deleted file mode 100644 index 1dd2f3d..0000000 --- a/src/plugins/manage/modules/credits/modules/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import give from "@plugins/manage/modules/credits/modules/give"; -import set from "@plugins/manage/modules/credits/modules/set"; -import take from "@plugins/manage/modules/credits/modules/take"; -import transfer from "@plugins/manage/modules/credits/modules/transfer"; - -export default { give, set, take, transfer }; diff --git a/src/plugins/manage/modules/index.ts b/src/plugins/manage/modules/index.ts deleted file mode 100644 index 61797b1..0000000 --- a/src/plugins/manage/modules/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import counters from "@plugins/manage/modules/counters"; -import credits from "@plugins/manage/modules/credits"; - -export default { counters, credits }; diff --git a/src/plugins/profile/index.ts b/src/plugins/profile/index.ts deleted file mode 100644 index d37ad1b..0000000 --- a/src/plugins/profile/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Dependencies -import { SlashCommandBuilder } from "@discordjs/builders"; -import { CommandInteraction } from "discord.js"; - -// Modules -import modules from "@plugins/profile/modules"; - -// Handlers -import logger from "@logger"; - -// Function -export default { - modules, - - builder: new SlashCommandBuilder() - .setName("profile") - .setDescription("Check a profile.") - .addSubcommand(modules.view.builder), - async execute(interaction: CommandInteraction) { - const { options } = interaction; - - if (options?.getSubcommand() === "view") { - logger?.silly(`Executing view subcommand`); - - return modules.view.execute(interaction); - } - - logger?.silly(`No subcommand found`); - }, -}; diff --git a/src/plugins/profile/modules/index.ts b/src/plugins/profile/modules/index.ts deleted file mode 100644 index 1dc8e1b..0000000 --- a/src/plugins/profile/modules/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import view from "@plugins/profile/modules/view"; - -export default { view }; diff --git a/src/plugins/reputation/index.ts b/src/plugins/reputation/index.ts deleted file mode 100644 index f5237ab..0000000 --- a/src/plugins/reputation/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Dependencies -import { SlashCommandBuilder } from "@discordjs/builders"; -import { CommandInteraction } from "discord.js"; - -// Modules -import modules from "./modules"; - -// Handlers -import logger from "@logger"; - -// Function -export default { - modules, - builder: new SlashCommandBuilder() - .setName("reputation") - .setDescription("Manage reputation.") - .addSubcommand(modules.give.builder), - async execute(interaction: CommandInteraction) { - const { options } = interaction; - - if (options?.getSubcommand() === "give") { - logger?.silly(`Executing give subcommand`); - - await modules.give.execute(interaction); - } - - logger?.silly(`No subcommand found`); - }, -}; diff --git a/src/plugins/reputation/modules/index.ts b/src/plugins/reputation/modules/index.ts deleted file mode 100644 index f6746fd..0000000 --- a/src/plugins/reputation/modules/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import give from "@plugins/reputation/modules/give"; - -export default { give }; diff --git a/src/plugins/shop/index.ts b/src/plugins/shop/index.ts deleted file mode 100644 index 330306e..0000000 --- a/src/plugins/shop/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Dependencies -import { SlashCommandBuilder } from "@discordjs/builders"; -import { CommandInteraction } from "discord.js"; - -// Modules -import modules from "./modules"; - -// Handlers -import logger from "../../logger"; - -// Function -export default { - modules, - - builder: new SlashCommandBuilder() - .setName("shop") - .setDescription("Shop for credits and custom roles.") - .addSubcommand(modules.pterodactyl.builder) - .addSubcommandGroup(modules.roles.builder), - async execute(interaction: CommandInteraction) { - const { options } = interaction; - - if (options?.getSubcommand() === "pterodactyl") { - logger.silly(`Executing pterodactyl subcommand`); - - return modules.pterodactyl.execute(interaction); - } - - if (options?.getSubcommandGroup() === "roles") { - logger?.silly(`Subcommand group is roles`); - - return modules.roles.execute(interaction); - } - - logger?.silly(`No subcommand found.`); - }, -}; diff --git a/src/plugins/shop/modules/index.ts b/src/plugins/shop/modules/index.ts deleted file mode 100644 index c356cae..0000000 --- a/src/plugins/shop/modules/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import pterodactyl from "@plugins/shop/modules/pterodactyl"; -import roles from "@plugins/shop/modules/roles"; - -export default { pterodactyl, roles }; diff --git a/src/plugins/shop/modules/roles/index.ts b/src/plugins/shop/modules/roles/index.ts deleted file mode 100644 index 33ece41..0000000 --- a/src/plugins/shop/modules/roles/index.ts +++ /dev/null @@ -1,70 +0,0 @@ -// Dependencies -import { SlashCommandSubcommandGroupBuilder } from "@discordjs/builders"; -import { CommandInteraction } from "discord.js"; - -// Handlers -import logger from "@logger"; - -import getEmbedConfig from "@helpers/getEmbedConfig"; - -// Modules -import modules from "./modules"; - -import guildSchema from "@schemas/guild"; - -// Function -export default { - modules, - - builder: (group: SlashCommandSubcommandGroupBuilder) => { - return group - .setName("roles") - .setDescription("Shop for custom roles.") - .addSubcommand(modules.buy.builder) - .addSubcommand(modules.cancel.builder); - }, - execute: async (interaction: CommandInteraction) => { - if (interaction.guild == null) return; - const { errorColor, footerText, footerIcon } = await getEmbedConfig( - interaction.guild - ); - const { options, guild } = interaction; - - const guildDB = await guildSchema?.findOne({ - guildId: guild?.id, - }); - - if (guildDB === null) return; - - if (!guildDB.shop.roles.status) { - logger.silly(`Shop roles disabled.`); - - return interaction?.editReply({ - embeds: [ - { - title: ":dollar: Shop - Roles", - description: "This server has disabled shop roles.", - color: errorColor, - timestamp: new Date(), - footer: { - iconURL: footerIcon, - text: footerText, - }, - }, - ], - }); - } - - if (options?.getSubcommand() === "buy") { - logger.silly(`Executing buy subcommand`); - - await modules.buy.execute(interaction); - } - - if (options?.getSubcommand() === "cancel") { - logger.silly(`Executing cancel subcommand`); - - await modules.cancel.execute(interaction); - } - }, -}; diff --git a/src/plugins/utility/index.ts b/src/plugins/utility/index.ts deleted file mode 100644 index 6dc6fff..0000000 --- a/src/plugins/utility/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Dependencies -import { SlashCommandBuilder } from "@discordjs/builders"; -import { CommandInteraction } from "discord.js"; - -// Modules -import modules from "@plugins/utility/modules"; - -// Handlers -import logger from "../../logger"; - -// Function -export default { - modules, - - builder: new SlashCommandBuilder() - .setName("utility") - .setDescription("Common utility.") - - .addSubcommand(modules.lookup.builder) - .addSubcommand(modules.about.builder) - .addSubcommand(modules.stats.builder) - .addSubcommand(modules.avatar.builder), - - async execute(interaction: CommandInteraction) { - const { options } = interaction; - - switch (options.getSubcommand()) { - case "lookup": - return modules.lookup.execute(interaction); - case "about": - return modules.about.execute(interaction); - case "stats": - return modules.stats.execute(interaction); - case "avatar": - return modules.avatar.execute(interaction); - default: - logger.error(`Unknown subcommand ${options.getSubcommand()}`); - } - }, -}; diff --git a/src/plugins/utility/modules/index.ts b/src/plugins/utility/modules/index.ts deleted file mode 100644 index 80c5a64..0000000 --- a/src/plugins/utility/modules/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import avatar from "@plugins/utility/modules/avatar"; -import about from "@plugins/utility/modules/about"; -import lookup from "@plugins/utility/modules/lookup"; -import stats from "@plugins/utility/modules/stats"; - -export default { - avatar, - about, - lookup, - stats, -}; diff --git a/src/types/common/discord.d.ts b/src/types/common/discord.d.ts index 68458e0..e83d22f 100644 --- a/src/types/common/discord.d.ts +++ b/src/types/common/discord.d.ts @@ -1,8 +1,9 @@ -import { Collection, Client as DJSClient } from "discord.js"; +import { Collection } from "discord.js"; +import ICommand from "../interfaces/Command"; declare module "discord.js" { export interface Client extends DJSClient { - commands: Collection; + commands: Collection; } } diff --git a/tsconfig.json b/tsconfig.json index 8f7076a..0879e1c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,7 @@ "baseUrl": "./src", "typeRoots": ["/types/common", "./node_modules/@types"], "paths": { - "@interface/*": ["Interfaces/*"], + "@interface/*": ["interfaces/*"], "@root/*": ["*"], "@config/*": ["config/*"], "@events/*": ["events/*"],