diff --git a/src/commands/admin/counter/addons/add.ts b/src/commands/admin/counter/addons/add.ts deleted file mode 100644 index 420dcd5..0000000 --- a/src/commands/admin/counter/addons/add.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; - -// Database models -import counters from '../../../../helpers/database/models/counterSchema'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: 'Admin', - color: config.colors.error as any, - description: 'You do not have permission to manage this!', - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get options - const channel = await interaction.options.getChannel('channel'); - const word = await interaction.options.getString('word'); - const start = await interaction.options.getNumber('start'); - - if (channel?.type !== 'GUILD_TEXT') { - // Create embed object - const embed = { - title: 'Admin - Counter', - description: `That channel is not supported, it needs to be a text channel.`, - timestamp: new Date(), - color: config.colors.error as any, - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - const counterExist = await counters.findOne({ - guildId: interaction?.guild?.id, - channelId: channel?.id, - word, - }); - - if (!counterExist) { - await counters.create({ - guildId: interaction?.guild?.id, - channelId: channel?.id, - word, - counter: start || 0, - }); - // Create embed object - const embed = { - title: 'Admin - Counter', - description: `${channel} is now counting when hearing word ${word} and it starts at number ${ - start || 0 - }.`, - timestamp: new Date(), - color: config.colors.success as any, - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${interaction?.user?.id} added ${channel.id} as a counter using word "${word}" for counting.` - ); - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - // Create embed object - const embed = { - title: 'Admin - Counter', - description: `${channel} is already a counting channel.`, - timestamp: new Date(), - color: config.colors.error as any, - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); -}; diff --git a/src/commands/admin/counter/addons/index.ts b/src/commands/admin/counter/addons/index.ts deleted file mode 100644 index 8b1faf0..0000000 --- a/src/commands/admin/counter/addons/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import add from './add'; -import remove from './remove'; - -export default { add, remove }; diff --git a/src/commands/admin/counter/addons/remove.ts b/src/commands/admin/counter/addons/remove.ts deleted file mode 100644 index 6d82c5f..0000000 --- a/src/commands/admin/counter/addons/remove.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; - -// Database models -import counters from '../../../../helpers/database/models/counterSchema'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: 'Admin', - color: config.colors.error as any, - description: 'You do not have permission to manage this!', - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get options - const channel = await interaction.options.getChannel('channel'); - - await counters - .deleteOne({ guildId: interaction?.guild?.id, channelId: channel?.id }) - .then(async () => { - interaction.editReply({ content: 'Removed' }); - }); - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${interaction?.user?.id} executed remove counter.` - ); -}; diff --git a/src/commands/admin/counter/index.ts b/src/commands/admin/counter/index.ts deleted file mode 100644 index 2e8668f..0000000 --- a/src/commands/admin/counter/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../config.json'; -import logger from '../../../handlers/logger'; -import add from './addons/add'; -import remove from './addons/remove'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Counter', - color: config.colors.error as any, - description: 'You do not have permission to manage this!', - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - } - - // If subcommand is give - if (interaction.options.getSubcommand() === 'add') { - // Execute give addon - await add(interaction); - } - - // If subcommand is take - else if (interaction.options.getSubcommand() === 'remove') { - // Execute take addon - await remove(interaction); - } - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${ - interaction?.user?.id - } executed /${ - interaction.commandName - } ${interaction.options.getSubcommandGroup()} ${interaction.options.getSubcommand()}` - ); -}; diff --git a/src/commands/admin/counters/index.ts b/src/commands/admin/counters/index.ts new file mode 100644 index 0000000..ea02b38 --- /dev/null +++ b/src/commands/admin/counters/index.ts @@ -0,0 +1,34 @@ +// Dependencies +import { CommandInteraction } from "discord.js"; + +// Handlers +import logger from "../../../handlers/logger"; + +// Modules +import add from "./modules/add"; +import remove from "./modules/remove"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure + const { options, guild, user, commandName } = interaction; + + // Module - Add + if (options?.getSubcommand() === "add") { + // Execute Module - Add + return await add(interaction); + } + + // Module - Remove + else if (options?.getSubcommand() === "remove") { + // Execute Module - Remove + return await remove(interaction); + } + + // Log debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); +}; diff --git a/src/commands/admin/counters/modules/add.ts b/src/commands/admin/counters/modules/add.ts new file mode 100644 index 0000000..c19514f --- /dev/null +++ b/src/commands/admin/counters/modules/add.ts @@ -0,0 +1,97 @@ +// Dependencies +import { ColorResolvable, CommandInteraction } from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +// Handlers +import logger from "../../../../handlers/logger"; + +// Models +import counterSchema from "../../../../helpers/database/models/counterSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure + const { options, guild, user } = interaction; + + // Channel option + const optionChannel = options?.getChannel("channel"); + + // Word option + const optionWord = options?.getString("word"); + + // Start option + const optionStart = options?.getNumber("start"); + + if (optionChannel?.type !== "GUILD_TEXT") { + // Embed object + const embed = { + title: ":toolbox: Admin - Counters [Add]" as string, + description: + "That channel is not supported, it needs to be a text channel." as string, + timestamp: new Date() as Date, + color: config?.colors?.error as ColorResolvable, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + const counterExist = await counterSchema?.findOne({ + guildId: guild?.id, + channelId: optionChannel?.id, + optionWord, + }); + + if (!counterExist) { + await counterSchema?.create({ + guildId: guild?.id, + channelId: optionChannel?.id, + optionWord, + counter: optionStart || 0, + }); + + // Embed object + const embed = { + title: ":toolbox: Admin - Counters [Add]" as string, + description: + `${optionChannel} is now counting when hearing word ${optionWord} and it starts at number ${ + optionStart || 0 + }.` as string, + timestamp: new Date() as Date, + color: config?.colors?.success as ColorResolvable, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Log debug message + logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} added ${optionChannel?.id} as a counter using word "${optionWord}" for counting.` + ); + + // Return interaction reply + return interaction?.editReply({ embeds: [embed] }); + } + + // Embed object + const embed = { + title: ":toolbox: Admin - Counters [Add]" as string, + description: `${optionChannel} is already a counting channel.` as string, + timestamp: new Date() as Date, + color: config?.colors?.error as ColorResolvable, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return interaction?.editReply({ embeds: [embed] }); +}; diff --git a/src/commands/admin/counters/modules/remove.ts b/src/commands/admin/counters/modules/remove.ts new file mode 100644 index 0000000..9664b7c --- /dev/null +++ b/src/commands/admin/counters/modules/remove.ts @@ -0,0 +1,48 @@ +// Dependencies +import { ColorResolvable, CommandInteraction } from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +// Handlers +import logger from "../../../../handlers/logger"; + +// Models +import counterSchema from "../../../../helpers/database/models/counterSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure + const { options, guild, user } = interaction; + + // Get options + const optionChannel = options?.getChannel("channel"); + + await counterSchema + ?.deleteOne({ + guildId: guild?.id, + channelId: optionChannel?.id, + }) + ?.then(async () => { + // Embed object + const embed = { + title: ":toolbox: Admin - Counters [Remove]" as string, + description: + `${optionChannel} is no longer an counting channel.` as string, + timestamp: new Date() as Date, + color: config?.colors?.success as ColorResolvable, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return interaction?.editReply({ embeds: [embed] }); + }); + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} removed ${optionChannel?.id} as a counter.` + ); +}; diff --git a/src/commands/admin/credits/addons/give.ts b/src/commands/admin/credits/addons/give.ts deleted file mode 100644 index b343b9a..0000000 --- a/src/commands/admin/credits/addons/give.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; - -// Database models -import users from '../../../../helpers/database/models/userSchema'; - -import creditNoun from '../../../../helpers/creditNoun'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { guild, user } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Give]', - color: config.colors.error as any, - description: 'You do not have permission to manage this!', - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get options - const userOption = await interaction.options.getUser('user'); - const amount = await interaction.options.getInteger('amount'); - - if (amount === null) return; - - if (amount <= 0) { - // If amount is zero or below - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Give]', - description: "You can't give zero or below.", - color: 0xbb2124, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get toUserDB object - const toUserDB = await users.findOne({ - userId: userOption?.id, - guildId: interaction?.guild?.id, - }); - - // If toUserDB has no credits - if (!toUserDB) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Give]', - description: - 'That userOption has no credits, I can not give credits to the userOption', - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Deposit amount to toUserDB - toUserDB.credits += amount; - - // Save toUserDB - await toUserDB - .save() - - // If successful - .then(async () => { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Give]', - description: `Gave ${creditNoun(amount)} to ${userOption}.`, - color: 0x22bb33, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send debug message - await logger.debug( - `Administrator: ${interaction.user.username} gave ${ - amount <= 1 ? `${amount} credit` : `${amount} credits` - } to ${userOption?.username}` - ); - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - - // Send debug message - await logger.debug( - `Guild: ${guild?.id} User: ${user?.id} gave ${ - userOption?.id - } ${creditNoun(amount)}.` - ); - }); -}; diff --git a/src/commands/admin/credits/addons/index.ts b/src/commands/admin/credits/addons/index.ts deleted file mode 100644 index 24e6e58..0000000 --- a/src/commands/admin/credits/addons/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import give from './give'; -import set from './set'; -import take from './take'; -import transfer from './transfer'; - -export default { - give, - set, - take, - transfer, -}; diff --git a/src/commands/admin/credits/addons/set.ts b/src/commands/admin/credits/addons/set.ts deleted file mode 100644 index b8df820..0000000 --- a/src/commands/admin/credits/addons/set.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; - -// Database models - -import users from '../../../../helpers/database/models/userSchema'; - -import creditNoun from '../../../../helpers/creditNoun'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Set]', - color: config.colors.error as any, - description: 'You do not have permission to manage this!', - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get options - const user = await interaction.options.getUser('user'); - const amount = await interaction.options.getInteger('amount'); - - if (amount === null) return; - - // If amount is zero or below - if (amount <= 0) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Set]', - description: "You can't give zero or below.", - color: 0xbb2124, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get toUserDB object - const toUserDB = await users.findOne({ - userId: user?.id, - guildId: interaction?.guild?.id, - }); - - // If toUserDB has no credits - if (!toUserDB) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Set]', - description: - 'That user has no credits, I can not set credits to the user', - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Set toUserDB with amount - toUserDB.credits = amount; - - // Save toUserDB - await toUserDB - .save() - - // If successful - .then(async () => { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Set]', - description: `You set ${creditNoun(amount)} on ${user}.`, - color: 0x22bb33, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send debug message - await logger.debug( - `Administrator: ${interaction.user.username} set ${ - amount <= 1 ? `${amount} credit` : `${amount} credits` - } on ${user?.username}` - ); - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${interaction?.user?.id} set ${ - user?.id - } to ${creditNoun(amount)}.` - ); - }); -}; diff --git a/src/commands/admin/credits/addons/take.ts b/src/commands/admin/credits/addons/take.ts deleted file mode 100644 index fa1b9a3..0000000 --- a/src/commands/admin/credits/addons/take.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; - -// Database models - -import users from '../../../../helpers/database/models/userSchema'; - -import creditNoun from '../../../../helpers/creditNoun'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { guild, user } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Take]', - color: config.colors.error as any, - description: 'You do not have permission to manage this!', - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get options - const userOption = await interaction.options.getUser('userOption'); - const amount = await interaction.options.getInteger('amount'); - - if (amount === null) return; - - // If amount is zero or below - if (amount <= 0) { - // Give embed object - const embed = { - title: ':toolbox: Admin - Credits [Take]', - description: "You can't take zero or below.", - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get toUser object - const toUser = await users.findOne({ - userId: userOption?.id, - guildId: interaction?.guild?.id, - }); - - // If toUser has no credits - if (!toUser) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Take]', - description: - 'That userOption has no credits, I can not take credits from the userOption', - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Withdraw amount from toUser - toUser.credits -= amount; - - // Save toUser - await toUser - .save() - - // If successful - .then(async () => { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Take]', - description: `You took ${creditNoun(amount)} to ${userOption}.`, - color: 0x22bb33, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send debug message - await logger.debug( - `Administrator: ${interaction.user.username} took ${ - amount <= 1 ? `${amount} credit` : `${amount} credits` - } from ${userOption?.username}` - ); - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - - // Send debug message - await logger.debug( - `Guild: ${guild?.id} User: ${user?.id} took ${creditNoun( - amount - )} from ${user.id}.` - ); - }); -}; diff --git a/src/commands/admin/credits/addons/transfer.ts b/src/commands/admin/credits/addons/transfer.ts deleted file mode 100644 index 1feb452..0000000 --- a/src/commands/admin/credits/addons/transfer.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; - -// Database models - -import users from '../../../../helpers/database/models/userSchema'; - -import creditNoun from '../../../../helpers/creditNoun'; -import saveUser from '../../../../helpers/saveUser'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Transfer]', - color: config.colors.error as any, - description: 'You do not have permission to manage this!', - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get options - const from = await interaction.options.getUser('from'); - const to = await interaction.options.getUser('to'); - const amount = await interaction.options.getInteger('amount'); - - // Get fromUser object - const fromUser = await users.findOne({ - userId: from?.id, - guildId: interaction?.guild?.id, - }); - - // Get toUser object - const toUser = await users.findOne({ - userId: to?.id, - guildId: interaction?.guild?.id, - }); - - // If fromUser has no credits - if (!fromUser) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Transfer]', - description: - 'That user has no credits, I can not transfer credits from the user', - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // If toUser has no credits - if (!toUser) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Transfer]', - description: - 'That user has no credits, I can not transfer credits to the user', - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - if (amount === null) return; - - // If amount is zero or below - if (amount <= 0) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Transfer]', - description: "You can't transfer zero or below.", - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Withdraw amount from fromUser - fromUser.credits -= amount; - - // Deposit amount to toUser - toUser.credits += amount; - - // Save users - await saveUser(fromUser, toUser) - // If successful - .then(async () => { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits [Transfer]', - description: `You sent ${creditNoun(amount)} from ${from} to ${to}.`, - color: config.colors.success as any, - fields: [ - { - name: `${from?.username} Balance`, - value: `${fromUser.credits}`, - inline: true, - }, - { - name: `${to?.username} Balance`, - value: `${toUser.credits}`, - inline: true, - }, - ], - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${ - interaction?.user?.id - } transferred ${creditNoun(amount)} from ${from?.id} to ${to?.id}.` - ); - }); -}; diff --git a/src/commands/admin/credits/index.ts b/src/commands/admin/credits/index.ts index 4739d25..e3a8c3d 100644 --- a/src/commands/admin/credits/index.ts +++ b/src/commands/admin/credits/index.ts @@ -1,61 +1,38 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../config.json'; -import logger from '../../../handlers/logger'; -import give from './addons/give'; -import take from './addons/take'; -import set from './addons/set'; -import transfer from './addons/transfer'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { user, guild } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: ':toolbox: Admin - Credits' as string, - color: config.colors.error as any, - description: 'You do not have permission to manage this!' as string, - timestamp: new Date(), - footer: { - iconURL: config.footer.icon as string, - text: config.footer.text as string, - }, - }; - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - } - - // If subcommand is give - if (interaction.options.getSubcommand() === 'give') { - // Execute give addon - await give(interaction); - } - - // If subcommand is take - else if (interaction.options.getSubcommand() === 'take') { - // Execute take addon - await take(interaction); - } - - // If subcommand is set - else if (interaction.options.getSubcommand() === 'set') { - // Execute set addon - await set(interaction); - } - - // If subcommand is transfer - else if (interaction.options.getSubcommand() === 'transfer') { - // Execute transfer addon - await transfer(interaction); - } - - // Send debug message - await logger.debug( - `Guild: ${guild?.id} User: ${user?.id} executed /${ - interaction.commandName - } ${interaction.options.getSubcommandGroup()} ${interaction.options.getSubcommand()}` - ); -}; +// Dependencies +import { CommandInteraction } from "discord.js"; + +// Modules +import give from "./modules/give"; +import take from "./modules/take"; +import set from "./modules/set"; +import transfer from "./modules/transfer"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure + const { user, guild, commandName, options } = interaction; + + // Module - Give + if (options?.getSubcommand() === "give") { + // Execute Module - Give + return await give(interaction); + } + + // Module - Take + else if (options?.getSubcommand() === "take") { + // Execute Module - Take + return await take(interaction); + } + + // Module - Set + else if (options?.getSubcommand() === "set") { + // Execute Module - Set + return await set(interaction); + } + + // Module - Transfer + else if (options?.getSubcommand() === "transfer") { + // Execute Module - Transfer + return await transfer(interaction); + } +}; diff --git a/src/commands/admin/credits/modules/give.ts b/src/commands/admin/credits/modules/give.ts new file mode 100644 index 0000000..bb4bd3d --- /dev/null +++ b/src/commands/admin/credits/modules/give.ts @@ -0,0 +1,135 @@ +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +// Handlers +import logger from "../../../../handlers/logger"; + +// Helpers +import creditNoun from "../../../../helpers/creditNoun"; + +// Models +import userSchema from "../../../../helpers/database/models/userSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure + const { guild, user, options } = interaction; + + // User option + const optionUser = options?.getUser("user"); + + // Amount option + const optionAmount = options?.getInteger("amount"); + + // If amount option is null + if (optionAmount === null) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Give]" as string, + description: "We could not read your requested amount." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If amount is zero or below + if (optionAmount <= 0) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Give]" as string, + description: "You can not give zero credits or below." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // toUser Information + const toUser = await userSchema?.findOne({ + userId: optionUser?.id, + guildId: guild?.id, + }); + + // If toUser does not exist + if (!toUser) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Give]" as string, + description: `We could not find ${optionUser} in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If toUser.credits does not exist + if (!toUser?.credits) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Give]" as string, + description: + `We could not find credits for ${optionUser} in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // Deposit amount to toUser + toUser.credits += optionAmount; + + // Save toUser + await toUser?.save()?.then(async () => { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Give]" as string, + description: `We have given ${optionUser}, ${creditNoun( + optionAmount + )}.` as string, + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Log debug message + logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} gave ${ + optionUser?.id + } ${creditNoun(optionAmount)}.` + ); + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + }); +}; diff --git a/src/commands/admin/credits/modules/set.ts b/src/commands/admin/credits/modules/set.ts new file mode 100644 index 0000000..c291f4a --- /dev/null +++ b/src/commands/admin/credits/modules/set.ts @@ -0,0 +1,117 @@ +// Dependencies +import { Permissions, CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +// Handlers +import logger from "../../../../handlers/logger"; + +// Helpers +import creditNoun from "../../../../helpers/creditNoun"; + +// Models +import userSchema from "../../../../helpers/database/models/userSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure + const { options, user, guild } = interaction; + + // User Option + const optionUser = options.getUser("user"); + + // Amount Option + const optionAmount = options.getInteger("amount"); + + // If amount is null + if (optionAmount === null) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Set]" as string, + description: "We could not read your requested amount." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // toUser Information + const toUser = await userSchema?.findOne({ + userId: optionUser?.id, + guildId: guild?.id, + }); + + // If toUser does not exist + if (!toUser) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Set]" as string, + description: `We could not find ${optionUser} in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If toUser.credits does not exist + if (!toUser?.credits) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Set]" as string, + description: + `We could not find credits for ${optionUser} in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // Set toUser with amount + toUser.credits = optionAmount; + + // Save toUser + await toUser?.save()?.then(async () => { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Set]" as string, + description: `We have set ${optionUser} to ${creditNoun( + optionAmount + )}` as string, + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Log debug message + logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} set ${ + optionUser?.id + } to ${creditNoun(optionAmount)}.` + ); + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + }); +}; diff --git a/src/commands/admin/credits/modules/take.ts b/src/commands/admin/credits/modules/take.ts new file mode 100644 index 0000000..f9680b7 --- /dev/null +++ b/src/commands/admin/credits/modules/take.ts @@ -0,0 +1,135 @@ +// Dependencies +import { Permissions, CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +// Handlers +import logger from "../../../../handlers/logger"; + +// Helpers +import creditNoun from "../../../../helpers/creditNoun"; + +// Models +import userSchema from "../../../../helpers/database/models/userSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure + const { guild, user, options } = interaction; + + // User option + const optionUser = options?.getUser("user"); + + // Amount option + const optionAmount = options?.getInteger("amount"); + + // If amount is null + if (optionAmount === null) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Take]" as string, + description: "We could not read your requested amount." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If amount is zero or below + if (optionAmount <= 0) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Take]" as string, + description: "You can not take zero credits or below." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // toUser Information + const toUser = await userSchema?.findOne({ + userId: optionUser?.id, + guildId: guild?.id, + }); + + // If toUser does not exist + if (!toUser) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Take]" as string, + description: `We could not find ${optionUser} in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If toUser.credits does not exist + if (!toUser?.credits) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Take]" as string, + description: + `We could not find credits for ${optionUser} in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // Withdraw amount from toUser + toUser.credits -= optionAmount; + + // Save toUser + await toUser?.save()?.then(async () => { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Set]" as string, + description: `We have taken ${creditNoun( + optionAmount + )} from ${optionUser}` as string, + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Log debug message + logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} set ${ + optionUser?.id + } to ${creditNoun(optionAmount)}.` + ); + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + }); +}; diff --git a/src/commands/admin/credits/modules/transfer.ts b/src/commands/admin/credits/modules/transfer.ts new file mode 100644 index 0000000..04a00cc --- /dev/null +++ b/src/commands/admin/credits/modules/transfer.ts @@ -0,0 +1,177 @@ +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +// Handlers +import logger from "../../../../handlers/logger"; + +// Helpers +import creditNoun from "../../../../helpers/creditNoun"; +import saveUser from "../../../../helpers/saveUser"; + +// Models +import userSchema from "../../../../helpers/database/models/userSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure member + const { guild, options, user } = interaction; + + // Get options + const optionFromUser = options?.getUser("from"); + const optionToUser = options?.getUser("to"); + const optionAmount = options?.getInteger("amount"); + + // If amount is null + if (optionAmount === null) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Transfer]" as string, + description: "We could not read your requested amount." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // Get fromUser object + const fromUser = await userSchema?.findOne({ + userId: optionFromUser?.id, + guildId: guild?.id, + }); + + // Get toUser object + const toUser = await userSchema.findOne({ + userId: optionToUser?.id, + guildId: guild?.id, + }); + + // If toUser does not exist + if (!fromUser) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Transfer]" as string, + description: + `We could not find ${optionFromUser} in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If toUser.credits does not exist + if (!fromUser?.credits) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Transfer]" as string, + description: + `We could not find credits for ${optionFromUser} in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If toUser does not exist + if (!toUser) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Transfer]" as string, + description: + `We could not find ${optionToUser} in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If toUser.credits does not exist + if (!toUser?.credits) { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Transfer]" as string, + description: + `We could not find credits for ${optionToUser} in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // Withdraw amount from fromUser + fromUser.credits -= optionAmount; + + // Deposit amount to toUser + toUser.credits += optionAmount; + + // Save users + await saveUser(fromUser, toUser)?.then(async () => { + // Embed object + const embed = { + title: ":toolbox: Admin - Credits [Transfer]" as string, + description: `You sent ${creditNoun( + optionAmount + )} from ${optionFromUser} to ${optionToUser}.` as string, + color: config?.colors?.success as ColorResolvable, + fields: [ + { + name: `${optionFromUser?.username as string} Balance`, + value: `${fromUser?.credits as string}`, + inline: true, + }, + { + name: `${optionToUser?.username as string} Balance`, + value: `${toUser?.credits as string}`, + inline: true, + }, + ], + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Log debug message + logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} transferred ${creditNoun( + optionAmount + )} from ${optionFromUser?.id} to ${optionToUser?.id}.` + ); + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + }); +}; diff --git a/src/commands/admin/index.ts b/src/commands/admin/index.ts index 43f0daa..ec80e42 100644 --- a/src/commands/admin/index.ts +++ b/src/commands/admin/index.ts @@ -1,139 +1,177 @@ -import { SlashCommandBuilder } from '@discordjs/builders'; -import credits from './credits'; -import counter from './counter'; - -import { CommandInteraction } from 'discord.js'; - -export default { - data: new SlashCommandBuilder() - .setName('admin') - .setDescription('Admin actions.') - .addSubcommandGroup((group) => - group - .setName('credits') - .setDescription('Manage credits.') - .addSubcommand((command) => - command - .setName('give') - .setDescription('Give credits to a user') - .addUserOption((option) => - option - .setName('user') - .setDescription('The user you want to pay.') - .setRequired(true) - ) - .addIntegerOption((option) => - option - .setName('amount') - .setDescription('The amount you will pay.') - .setRequired(true) - ) - ) - .addSubcommand((command) => - command - .setName('set') - .setDescription('Set credits to a user') - .addUserOption((option) => - option - .setName('user') - .setDescription('The user you want to set credits on.') - .setRequired(true) - ) - .addIntegerOption((option) => - option - .setName('amount') - .setDescription('The amount you will set.') - .setRequired(true) - ) - ) - .addSubcommand((command) => - command - .setName('take') - .setDescription('Take credits from a user') - .addUserOption((option) => - option - .setName('user') - .setDescription('The user you want to take credits from.') - .setRequired(true) - ) - .addIntegerOption((option) => - option - .setName('amount') - .setDescription('The amount you will take.') - .setRequired(true) - ) - ) - .addSubcommand((command) => - command - .setName('transfer') - .setDescription('Transfer credits from a user to another user.') - .addUserOption((option) => - option - .setName('from') - .setDescription('The user you want to take credits from.') - .setRequired(true) - ) - .addUserOption((option) => - option - .setName('to') - .setDescription('The user you want to give credits to.') - .setRequired(true) - ) - .addIntegerOption((option) => - option - .setName('amount') - .setDescription('The amount you will transfer.') - .setRequired(true) - ) - ) - ) - .addSubcommandGroup((group) => - group - .setName('counter') - .setDescription('Manage counters.') - .addSubcommand((command) => - command - .setName('add') - .setDescription('Add a counter') - .addChannelOption((option) => - option - .setName('channel') - .setDescription('The counter channel.') - .setRequired(true) - ) - .addStringOption((option) => - option - .setName('word') - .setDescription('The counter word.') - .setRequired(true) - ) - .addNumberOption((option) => - option.setName('start').setDescription('Start at number X.') - ) - ) - .addSubcommand((command) => - command - .setName('remove') - .setDescription('Remove a counter') - .addChannelOption((option) => - option - .setName('channel') - .setDescription('The counter channel.') - .setRequired(true) - ) - ) - ), - async execute(interaction: CommandInteraction) { - // If subcommand group is credits - if (interaction.options.getSubcommandGroup() === 'credits') { - // Execute credits group - await credits(interaction); - } - - // If subcommand group is credits - else if (interaction.options.getSubcommandGroup() === 'counter') { - // Execute credits group - await counter(interaction); - } - }, -}; +//Dependencies +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction, ColorResolvable, Permissions } from "discord.js"; + +// Configurations +import config from "../../../config.json"; + +// Handlers +import logger from "../../handlers/logger"; + +// Groups +import credits from "./credits"; +import counters from "./counters"; + +// Function +export default { + data: new SlashCommandBuilder() + .setName("admin") + .setDescription("Admin actions.") + .addSubcommandGroup((group) => + group + .setName("credits") + .setDescription("Manage credits.") + .addSubcommand((command) => + command + .setName("give") + .setDescription("Give credits to a user") + .addUserOption((option) => + option + .setName("user") + .setDescription("The user you want to pay.") + .setRequired(true) + ) + .addIntegerOption((option) => + option + .setName("amount") + .setDescription("The amount you will pay.") + .setRequired(true) + ) + ) + .addSubcommand((command) => + command + .setName("set") + .setDescription("Set credits to a user") + .addUserOption((option) => + option + .setName("user") + .setDescription("The user you want to set credits on.") + .setRequired(true) + ) + .addIntegerOption((option) => + option + .setName("amount") + .setDescription("The amount you will set.") + .setRequired(true) + ) + ) + .addSubcommand((command) => + command + .setName("take") + .setDescription("Take credits from a user") + .addUserOption((option) => + option + .setName("user") + .setDescription("The user you want to take credits from.") + .setRequired(true) + ) + .addIntegerOption((option) => + option + .setName("amount") + .setDescription("The amount you will take.") + .setRequired(true) + ) + ) + .addSubcommand((command) => + command + .setName("transfer") + .setDescription("Transfer credits from a user to another user.") + .addUserOption((option) => + option + .setName("from") + .setDescription("The user you want to take credits from.") + .setRequired(true) + ) + .addUserOption((option) => + option + .setName("to") + .setDescription("The user you want to give credits to.") + .setRequired(true) + ) + .addIntegerOption((option) => + option + .setName("amount") + .setDescription("The amount you will transfer.") + .setRequired(true) + ) + ) + ) + .addSubcommandGroup((group) => + group + .setName("counters") + .setDescription("Manage counters.") + .addSubcommand((command) => + command + .setName("add") + .setDescription("Add a counter") + .addChannelOption((option) => + option + .setName("channel") + .setDescription("The counter channel.") + .setRequired(true) + ) + .addStringOption((option) => + option + .setName("word") + .setDescription("The counter word.") + .setRequired(true) + ) + .addNumberOption((option) => + option.setName("start").setDescription("Start at number X.") + ) + ) + .addSubcommand((command) => + command + .setName("remove") + .setDescription("Remove a counter") + .addChannelOption((option) => + option + .setName("channel") + .setDescription("The counter channel.") + .setRequired(true) + ) + ) + ), + async execute(interaction: CommandInteraction) { + // Destructure + const { memberPermissions, options, user, commandName, guild } = + interaction; + + // Check permission + if (!memberPermissions?.has(Permissions?.FLAGS?.MANAGE_GUILD)) { + // Embed object + const embed = { + title: ":toolbox: Admin" as string, + color: config?.colors?.error as ColorResolvable, + description: "You do not have permission to manage this!" as string, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return interaction?.editReply({ embeds: [embed] }); + } + + // Group - Credits + if (options?.getSubcommandGroup() === "credits") { + // Execute Group - Credits + return await credits(interaction); + } + + // Group - Counters + else if (options?.getSubcommandGroup() === "counters") { + // Execute Group - Counters + return await counters(interaction); + } + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); + }, +}; diff --git a/src/commands/counter/addons/view.ts b/src/commands/counter/addons/view.ts deleted file mode 100644 index 78223d9..0000000 --- a/src/commands/counter/addons/view.ts +++ /dev/null @@ -1,47 +0,0 @@ -import config from '../../../../config.json'; -import logger from '../../../handlers/logger'; -import counters from '../../../helpers/database/models/counterSchema'; -import { CommandInteraction } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - try { - // Destructure member - const { member } = await interaction; - - // Get options - const channel = await interaction.options.getChannel('channel'); - - const counter = await counters.findOne({ - guildId: interaction?.guild?.id, - channelId: channel?.id, - }); - - if (!counter) { - // Create embed object - const embed = { - title: 'Counter - View', - description: `${channel} is not a counting channel.`, - timestamp: new Date(), - color: config.colors.error as any, - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return await interaction.editReply({ embeds: [embed] }); - } - - // Create embed object - const embed = { - title: 'Counter - View', - color: config.colors.success as any, - description: `${channel} is currently at number ${counter.counter}.`, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return await interaction.editReply({ embeds: [embed] }); - } catch (e) { - // Send debug message - await logger.error(e); - } -}; diff --git a/src/commands/counter/index.ts b/src/commands/counter/index.ts deleted file mode 100644 index 3c4f328..0000000 --- a/src/commands/counter/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { SlashCommandBuilder } from '@discordjs/builders'; -import view from './addons/view'; - -import { CommandInteraction } from 'discord.js'; - -export default { - data: new SlashCommandBuilder() - .setName('counter') - .setDescription('Manage counters.') - .addSubcommand((subcommand) => - subcommand - .setName('view') - .setDescription('View a counter.') - .addChannelOption((option) => - option - .setName('channel') - .setDescription('The counter channel you want to view') - .setRequired(true) - ) - ), - async execute(interaction: CommandInteraction) { - // If subcommand is view - if (interaction.options.getSubcommand() === 'view') { - // Execute view addon - await view(interaction); - } - }, -}; diff --git a/src/commands/counters/index.ts b/src/commands/counters/index.ts new file mode 100644 index 0000000..e061089 --- /dev/null +++ b/src/commands/counters/index.ts @@ -0,0 +1,43 @@ +// Dependencies +import { CommandInteraction } from "discord.js"; +import { SlashCommandBuilder } from "@discordjs/builders"; + +// Modules +import view from "./modules/view"; + +// Handlers +import logger from "../../handlers/logger"; + +// Function +export default { + data: new SlashCommandBuilder() + .setName("counters") + .setDescription("Manage counters.") + .addSubcommand((subcommand) => + subcommand + .setName("view") + .setDescription("View a counter.") + .addChannelOption((option) => + option + .setName("channel") + .setDescription("The counter channel you want to view") + .setRequired(true) + ) + ), + async execute(interaction: CommandInteraction) { + const { options, guild, user, commandName } = interaction; + + // Module - View + if (options?.getSubcommand() === "view") { + // Execute Module - View + return await view(interaction); + } + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); + }, +}; diff --git a/src/commands/counters/modules/view.ts b/src/commands/counters/modules/view.ts new file mode 100644 index 0000000..68e486e --- /dev/null +++ b/src/commands/counters/modules/view.ts @@ -0,0 +1,54 @@ +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../config.json"; + +// Models +import counterSchema from "../../../helpers/database/models/counterSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure member + const { options, guild } = interaction; + + // Get options + const optionChannel = options?.getChannel("channel"); + + const counter = await counterSchema?.findOne({ + guildId: guild?.id, + channelId: optionChannel?.id, + }); + + if (!counter) { + // Create embed object + const embed = { + title: ":1234: Counters [View]" as string, + description: `${optionChannel} is not a counting channel.` as string, + timestamp: new Date() as Date, + color: config?.colors?.error as ColorResolvable, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // Embed object + const embed = { + title: ":1234: Counters [View]" as string, + color: config.colors.success as ColorResolvable, + description: `${optionChannel} is currently at number ${counter?.counter}.`, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + return await interaction?.editReply({ embeds: [embed] }); +}; diff --git a/src/commands/credits/addons/balance.ts b/src/commands/credits/addons/balance.ts deleted file mode 100644 index 17c69cb..0000000 --- a/src/commands/credits/addons/balance.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { CommandInteraction } from 'discord.js'; -import config from '../../../../config.json'; -import logger from '../../../handlers/logger'; -import users from '../../../helpers/database/models/userSchema'; -import creditNoun from '../../../helpers/creditNoun'; - -export default async (interaction: CommandInteraction) => { - // Get options - const user = await interaction.options.getUser('user'); - - // Get credit object - const userDB = await users.findOne({ - userId: user ? user.id : interaction?.user?.id, - guildId: interaction?.guild?.id, - }); - - // Destructure balance - const { credits } = userDB; - - // If !userDB - if (!userDB) { - // Create embed object - const embed = { - title: ':dollar: Credits - Balance', - description: `${ - user ? `${user} is` : 'You are' - } not found in the database.`, - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // If !credits - if (!credits) { - // Create embed object - const embed = { - title: ':dollar: Credits - Balance', - description: `${user ? `${user} has` : 'You have'} no credits.`, - color: config.colors.success as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // If credits - if (credits) { - // Create embed object - const embed = { - title: ':dollar: Credits - Balance', - description: `${user ? `${user} has` : 'You have'} ${creditNoun( - credits - )}.`, - color: config.colors.success as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } -}; diff --git a/src/commands/credits/addons/gift.ts b/src/commands/credits/addons/gift.ts deleted file mode 100644 index 92690b8..0000000 --- a/src/commands/credits/addons/gift.ts +++ /dev/null @@ -1,140 +0,0 @@ -import config from '../../../../config.json'; -import logger from '../../../handlers/logger'; -import users from '../../../helpers/database/models/userSchema'; -import saveUser from '../../../helpers/saveUser'; -import creditNoun from '../../../helpers/creditNoun'; -import { CommandInteraction } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - // Get options - const user = await interaction.options.getUser('user'); - const amount = await interaction.options.getInteger('amount'); - const reason = await interaction.options.getString('reason'); - - const { member } = interaction; - - // Get fromUserDB object - const fromUserDB = await users.findOne({ - userId: interaction?.user?.id, - guildId: interaction?.guild?.id, - }); - - // Get toUserDB object - const toUserDB = await users.findOne({ - userId: user?.id, - guildId: interaction?.guild?.id, - }); - - // If receiver is same as sender - if (user?.id === interaction?.user?.id) { - // Create embed object - const embed = { - title: ':dollar: Credits - Gift', - description: "You can't pay yourself.", - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - if (amount === null) return; - - // If amount is zero or below - if (amount <= 0) { - // Create embed object - const embed = { - title: ':dollar: Credits - Gift', - description: "You can't pay zero or below.", - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // If user has below gifting amount - if (fromUserDB.credits < amount) { - // Create embed - const embed = { - title: ':dollar: Credits - Gift', - description: `You have insufficient credits. Your credits is ${fromUserDB.credits}`, - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // If toUserDB has no credits - if (!toUserDB) { - // Create embed object - const embed = { - title: ':dollar: Credits - Gift', - description: - 'That user has no credits, I can not gift credits to the user', - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Withdraw amount from fromUserDB - fromUserDB.credits -= amount; - - // Deposit amount to toUserDB - toUserDB.credits += amount; - - // Save users - await saveUser(fromUserDB, toUserDB).then(async () => { - // Create interaction embed object - const interactionEmbed = { - title: ':dollar: Credits - Gift', - description: `You sent ${creditNoun(amount)} to ${user}${ - reason ? ` with reason: ${reason}` : '' - }. Your new credits is ${creditNoun(fromUserDB.credits)}.`, - color: 0x22bb33, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Create DM embed object - const dmEmbed = { - title: ':dollar: Credits - Gift', - description: `You received ${creditNoun(amount)} from ${ - interaction.user - }${ - reason ? ` with reason: ${reason}` : '' - }. Your new credits is ${creditNoun(toUserDB.credits)}.`, - color: 0x22bb33, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Get DM user object - const dmUser = await interaction.client.users.cache.get( - interaction?.user?.id - ); - - // Send DM to user - await dmUser?.send({ embeds: [dmEmbed] }); - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${interaction?.user?.id} gift sent from: ${interaction?.user?.id} to: ${user?.id}` - ); - - // Send interaction reply - return interaction.editReply({ - embeds: [interactionEmbed], - }); - }); -}; diff --git a/src/commands/credits/addons/index.ts b/src/commands/credits/addons/index.ts deleted file mode 100644 index 9a61a6c..0000000 --- a/src/commands/credits/addons/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -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/commands/credits/addons/top.ts b/src/commands/credits/addons/top.ts deleted file mode 100644 index 175754f..0000000 --- a/src/commands/credits/addons/top.ts +++ /dev/null @@ -1,35 +0,0 @@ -import config from '../../../../config.json'; -import users from '../../../helpers/database/models/userSchema'; -import creditNoun from '../../../helpers/creditNoun'; -import { CommandInteraction } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - // Get all users in the guild - - const usersDB = await users.find({ guildId: interaction?.guild?.id }); - - const topTen = usersDB - - // Sort them after credits amount (ascending) - .sort((a, b) => (a.credits > b.credits ? -1 : 1)) - - // Return the top 10 - .slice(0, 10); - - // Create entry object - const entry = (x: any, index: any) => - `**Top ${index + 1}** - <@${x.userId}> ${creditNoun(x.credits)}`; - - // Create embed object - const embed = { - title: ':dollar: Credits - Top', - description: `Below are the top ten.\n${topTen - .map((x, index) => entry(x, index)) - .join('\n')}`, - color: config.colors.success as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); -}; diff --git a/src/commands/credits/addons/work.ts b/src/commands/credits/addons/work.ts deleted file mode 100644 index 77a4ebd..0000000 --- a/src/commands/credits/addons/work.ts +++ /dev/null @@ -1,96 +0,0 @@ -import config from '../../../../config.json'; -import logger from '../../../handlers/logger'; -import guilds from '../../../helpers/database/models/guildSchema'; -import users from '../../../helpers/database/models/userSchema'; -import timeouts from '../../../helpers/database/models/timeoutSchema'; -import creditNoun from '../../../helpers/creditNoun'; -import { CommandInteraction } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // Check if user has a timeout - const isTimeout = await timeouts.findOne({ - guildId: interaction?.guild?.id, - userId: interaction?.user?.id, - timeoutId: '2022-03-15-19-16', - }); - - const guildDB = await guilds.findOne({ - guildId: interaction?.guild?.id, - }); - - // If user is not on timeout - if (!isTimeout) { - // Make a variable of how much credits user will earn based on random multiplied with work rate - const creditsEarned = Math.floor(Math.random() * guildDB.credits.workRate); - - const userDB = await users.findOne({ - userId: interaction?.user?.id, - guildId: interaction?.guild?.id, - }); - - userDB.credits += creditsEarned; - - await userDB.save().then(async () => { - // Send debug message - await logger.debug(`Credits added to user: ${interaction?.user?.id}`); - - // Create embed object - const embed = { - title: ':dollar: Credits - Work', - description: `You have earned ${creditNoun(creditsEarned)}`, - color: config.colors.success as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - }); - - // Create a timeout for the user - await timeouts.create({ - guildId: interaction?.guild?.id, - userId: interaction?.user?.id, - timeoutId: '2022-03-15-19-16', - }); - - setTimeout(async () => { - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${ - interaction?.user?.id - } has not worked within the last ${ - guildDB.work.timeout / 1000 - } seconds, work can be done` - ); - - // When timeout is out, remove it from the database - await timeouts.deleteOne({ - guildId: interaction?.guild?.id, - userId: interaction?.user?.id, - timeoutId: '2022-03-15-19-16', - }); - }, guildDB.credits.workTimeout); - } else { - // Create embed object - const embed = { - title: ':dollar: Credits - Work', - description: `You have worked within the last ${ - guildDB.credits.workTimeout / 1000 - } seconds, you can not work now!`, - timestamp: new Date(), - color: config.colors.error as any, - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${interaction?.user?.id} has worked within last day, no work can be done` - ); - } -}; diff --git a/src/commands/credits/index.ts b/src/commands/credits/index.ts index d5fcc4a..b522c61 100644 --- a/src/commands/credits/index.ts +++ b/src/commands/credits/index.ts @@ -1,73 +1,90 @@ -import { SlashCommandBuilder } from '@discordjs/builders'; -import balance from './addons/balance'; -import gift from './addons/gift'; -import top from './addons/top'; -import work from './addons/work'; -import { CommandInteraction } from 'discord.js'; -export default { - data: new SlashCommandBuilder() - .setName('credits') - .setDescription('Manage your credits.') - .addSubcommand((subcommand) => - subcommand - .setName('balance') - .setDescription("Check a user's balance.") - .addUserOption((option) => - option - .setName('user') - .setDescription('The user whose balance you want to check.') - .setRequired(false) - ) - ) - .addSubcommand((subcommand) => - subcommand - .setName('gift') - .setDescription('Gift someone credits from your credits.') - .addUserOption((option) => - option - .setName('user') - .setDescription('The user you want to pay.') - .setRequired(true) - ) - .addIntegerOption((option) => - option - .setName('amount') - .setDescription('The amount you will pay.') - .setRequired(true) - ) - .addStringOption((option) => - option.setName('reason').setDescription('Your reason.') - ) - ) - .addSubcommand((subcommand) => - subcommand.setName('top').setDescription('Check the top balance.') - ) - .addSubcommand((subcommand) => - subcommand.setName('work').setDescription('Work for credits.') - ), - async execute(interaction: CommandInteraction) { - // If subcommand is balance - if (interaction.options.getSubcommand() === 'balance') { - // Execute balance addon - await balance(interaction); - } - - // If subcommand is gift - else if (interaction.options.getSubcommand() === 'gift') { - // Execute gift addon - await gift(interaction); - } - - // If subcommand is top - else if (interaction.options.getSubcommand() === 'top') { - // Execute top addon - await top(interaction); - } - - // If subcommand is work - else if (interaction.options.getSubcommand() === 'work') { - // Execute work addon - await work(interaction); - } - }, -}; +// Dependencies +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +// Handlers +import logger from "../../handlers/logger"; + +// Modules +import balance from "./modules/balance"; +import gift from "./modules/gift"; +import top from "./modules/top"; +import work from "./modules/work"; + +// Function +export default { + data: new SlashCommandBuilder() + .setName("credits") + .setDescription("Manage your credits.") + .addSubcommand((subcommand) => + subcommand + .setName("balance") + .setDescription("Check a user's balance.") + .addUserOption((option) => + option + .setName("user") + .setDescription("The user whose balance you want to check.") + .setRequired(false) + ) + ) + .addSubcommand((subcommand) => + subcommand + .setName("gift") + .setDescription("Gift someone credits from your credits.") + .addUserOption((option) => + option + .setName("user") + .setDescription("The user you want to pay.") + .setRequired(true) + ) + .addIntegerOption((option) => + option + .setName("amount") + .setDescription("The amount you will pay.") + .setRequired(true) + ) + .addStringOption((option) => + option.setName("reason").setDescription("Your reason.") + ) + ) + .addSubcommand((subcommand) => + subcommand.setName("top").setDescription("Check the top balance.") + ) + .addSubcommand((subcommand) => + subcommand.setName("work").setDescription("Work for credits.") + ), + async execute(interaction: CommandInteraction) { + const { options, user, guild, commandName } = interaction; + + // Module - Balance + if (options?.getSubcommand() === "balance") { + // Execute Module - Balance + return await balance(interaction); + } + + // Module - Gift + else if (options?.getSubcommand() === "gift") { + // Execute Module - Gift + return await gift(interaction); + } + + // Module - Top + else if (options?.getSubcommand() === "top") { + // Execute Module - Top + return await top(interaction); + } + + // Module - Work + else if (options?.getSubcommand() === "work") { + // Execute Module - Work + return await work(interaction); + } + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); + }, +}; diff --git a/src/commands/credits/modules/balance.ts b/src/commands/credits/modules/balance.ts new file mode 100644 index 0000000..e7d5e4d --- /dev/null +++ b/src/commands/credits/modules/balance.ts @@ -0,0 +1,83 @@ +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../config.json"; + +// Helpers +import creditNoun from "../../../helpers/creditNoun"; + +// Models +import userSchema from "../../../helpers/database/models/userSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure + const { options, user, guild } = interaction; + + // User option + const optionUser = options?.getUser("user"); + + // Get credit object + const userDB = await userSchema?.findOne({ + userId: optionUser ? optionUser?.id : user?.id, + guildId: guild?.id, + }); + + // If userDB does not exist + if (!userDB) { + // Embed object + const embed = { + title: ":dollar: Credits [Balance]" as string, + description: `We can not find ${ + optionUser || "you" + } in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return interaction?.editReply({ embeds: [embed] }); + } + + // If userDB.credits does not exist + if (!userDB.credits) { + // Embed object + const embed = { + title: ":dollar: Credits [Balance]" as string, + description: `We can not find credits for ${ + optionUser || "you" + } in our database.` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return interaction?.editReply({ embeds: [embed] }); + } else { + // Embed object + const embed = { + title: ":dollar: Credits [Balance]" as string, + description: `${ + optionUser ? `${optionUser} has` : "You have" + } ${creditNoun(userDB.credits)}.` as string, + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return interaction?.editReply({ embeds: [embed] }); + } +}; diff --git a/src/commands/credits/modules/gift.ts b/src/commands/credits/modules/gift.ts new file mode 100644 index 0000000..fb0313a --- /dev/null +++ b/src/commands/credits/modules/gift.ts @@ -0,0 +1,187 @@ +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../config.json"; + +// Handlers +import logger from "../../../handlers/logger"; + +// Helpers +import saveUser from "../../../helpers/saveUser"; +import creditNoun from "../../../helpers/creditNoun"; + +// Models +import userSchema from "../../../helpers/database/models/userSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure + const { options, user, guild, client } = interaction; + + // User option + const optionUser = options?.getUser("user"); + + // Amount option + const optionAmount = options?.getInteger("amount"); + + // Reason option + const optionReason = options?.getString("reason"); + + // Get fromUserDB object + const fromUserDB = await userSchema?.findOne({ + userId: user?.id, + guildId: guild?.id, + }); + + // Get toUserDB object + const toUserDB = await userSchema?.findOne({ + userId: optionUser?.id, + guildId: guild?.id, + }); + + // If receiver is same as sender + if (optionUser?.id === user?.id) { + // Create embed object + const embed = { + title: ":dollar: Credits [Gift]" as string, + description: "You can't pay yourself." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If amount is null + if (optionAmount === null) { + // Embed object + const embed = { + title: ":dollar: Credits [Gift]" as string, + description: "We could not read your requested amount." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If amount is zero or below + if (optionAmount <= 0) { + // Embed object + const embed = { + title: ":dollar: Credits [Gift]" as string, + description: "You can't pay zero or below." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If user has below gifting amount + if (fromUserDB?.credits < optionAmount) { + // Embed object + const embed = { + title: ":dollar: Credits [Gift]" as string, + description: + `You have insufficient credits. Your credits is ${fromUserDB?.credits}` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // If toUserDB has no credits + if (!toUserDB) { + // Embed object + const embed = { + title: ":dollar: Credits [Gift]" as string, + description: + `That user has no credits, I can not gift credits to ${optionUser}` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // Withdraw amount from fromUserDB + fromUserDB.credits -= optionAmount; + + // Deposit amount to toUserDB + toUserDB.credits += optionAmount; + + // Save users + await saveUser(fromUserDB, toUserDB)?.then(async () => { + // Interaction embed object + const interactionEmbed = { + title: ":dollar: Credits [Gift]", + description: `You sent ${creditNoun(optionAmount)} to ${optionUser}${ + optionReason ? ` with reason: ${optionReason}` : "" + }. Your new credits is ${creditNoun(fromUserDB?.credits)}.`, + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // DM embed object + const dmEmbed = { + title: ":dollar: Credits [Gift]" as string, + description: `You received ${creditNoun(optionAmount)} from ${user}${ + optionReason ? ` with reason: ${optionReason}` : "" + }. Your new credits is ${creditNoun(toUserDB?.credits)}.` as string, + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Get DM user object + const dmUser = client?.users?.cache?.get(interaction?.user?.id); + + // Send DM to user + await dmUser?.send({ embeds: [dmEmbed] }); + + // Send debug message + logger.debug( + `Guild: ${guild?.id} User: ${user?.id} gift sent from: ${user?.id} to: ${optionUser?.id}` + ); + + // Send interaction reply + return await interaction.editReply({ + embeds: [interactionEmbed], + }); + }); +}; diff --git a/src/commands/credits/modules/top.ts b/src/commands/credits/modules/top.ts new file mode 100644 index 0000000..7577f1f --- /dev/null +++ b/src/commands/credits/modules/top.ts @@ -0,0 +1,47 @@ +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../config.json"; + +// Models +import userSchema from "../../../helpers/database/models/userSchema"; + +// helpers +import creditNoun from "../../../helpers/creditNoun"; + +// Function +export default async (interaction: CommandInteraction) => { + // Get all users in the guild + + const usersDB = await userSchema.find({ guildId: interaction?.guild?.id }); + + const topTen = usersDB + + // Sort them after credits amount (ascending) + .sort((a, b) => (a?.credits > b?.credits ? -1 : 1)) + + // Return the top 10 + .slice(0, 10); + + // Create entry object + const entry = (x: any, index: number) => + `**Top ${index + 1}** - <@${x?.userId}> ${creditNoun(x?.credits)}`; + + // Create embed object + const embed = { + title: ":dollar: Credits [Top]" as string, + description: `Below are the top ten.\n${topTen + ?.map((x, index) => entry(x, index)) + ?.join("\n")}` as string, + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); +}; diff --git a/src/commands/credits/modules/work.ts b/src/commands/credits/modules/work.ts new file mode 100644 index 0000000..8029bb3 --- /dev/null +++ b/src/commands/credits/modules/work.ts @@ -0,0 +1,113 @@ +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../config.json"; + +// Handlers +import logger from "../../../handlers/logger"; + +// Models +import guildSchema from "../../../helpers/database/models/guildSchema"; +import userSchema from "../../../helpers/database/models/userSchema"; +import timeouts from "../../../helpers/database/models/timeoutSchema"; + +// Helpers +import creditNoun from "../../../helpers/creditNoun"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure member + const { guild, user } = interaction; + + // Check if user has a timeout + const isTimeout = await timeouts?.findOne({ + guildId: guild?.id, + userId: user?.id, + timeoutId: "2022-03-15-19-16", + }); + + const guildDB = await guildSchema?.findOne({ + guildId: guild?.id, + }); + + // If user is not on timeout + if (!isTimeout) { + // Make a variable of how much credits user will earn based on random multiplied with work rate + const creditsEarned = Math?.floor( + Math?.random() * guildDB?.credits?.workRate + ); + + const userDB = await userSchema?.findOne({ + userId: user?.id, + guildId: guild?.id, + }); + + userDB.credits += creditsEarned; + + await userDB?.save()?.then(async () => { + // Send debug message + logger?.debug(`Credits added to user: ${user?.id}`); + + // Create embed object + const embed = { + title: ":dollar: Credits [Work]" as string, + description: `You have earned ${creditNoun(creditsEarned)}` as string, + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + return await interaction?.editReply({ embeds: [embed] }); + }); + + // Create a timeout for the user + await timeouts?.create({ + guildId: guild?.id, + userId: user?.id, + timeoutId: "2022-03-15-19-16", + }); + + setTimeout(async () => { + // Send debug message + logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} has not worked within the last ${ + guildDB?.work?.timeout / 1000 + } seconds, work can be done` + ); + + // When timeout is out, remove it from the database + await timeouts?.deleteOne({ + guildId: guild?.id, + userId: user?.id, + timeoutId: "2022-03-15-19-16", + }); + }, guildDB?.credits?.workTimeout); + } else { + // Create embed object + const embed = { + title: ":dollar: Credits [Work]" as string, + description: `You have worked within the last ${ + guildDB?.credits?.workTimeout / 1000 + } seconds, you can not work now!` as string, + timestamp: new Date() as Date, + color: config?.colors?.error as ColorResolvable, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send debug message + logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} has worked within last day, no work can be done` + ); + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } +}; diff --git a/src/commands/profile/index.ts b/src/commands/profile/index.ts index e2a617a..cf867e0 100644 --- a/src/commands/profile/index.ts +++ b/src/commands/profile/index.ts @@ -5,6 +5,9 @@ import { CommandInteraction } from "discord.js"; // Modules import view from "./modules/view"; +// Handlers +import logger from "../../handlers/logger"; + // Function export default { data: new SlashCommandBuilder() @@ -21,10 +24,20 @@ export default { ) ), async execute(interaction: CommandInteraction) { + // Destructure + const { options, guild, user, commandName } = interaction; + // Module - View - if (interaction.options.getSubcommand() === "view") { + if (options?.getSubcommand() === "view") { // Execute Module - View - await view(interaction); + return await view(interaction); } + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); }, }; diff --git a/src/commands/profile/modules/view.ts b/src/commands/profile/modules/view.ts index 37cc0d5..e7cb8fd 100644 --- a/src/commands/profile/modules/view.ts +++ b/src/commands/profile/modules/view.ts @@ -1,8 +1,13 @@ -import i18next from "i18next"; +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations import config from "../../../../config.json"; -import logger from "../../../handlers/logger"; -import users from "../../../helpers/database/models/userSchema"; -import { CommandInteraction } from "discord.js"; + +// Models +import userSchema from "../../../helpers/database/models/userSchema"; + +// Function export default async (interaction: CommandInteraction) => { // Destructure const { client, options, user, guild } = interaction; @@ -11,12 +16,12 @@ export default async (interaction: CommandInteraction) => { const target = options?.getUser("target"); // Discord User Information - const discordUser = await client.users.fetch( + const discordUser = await client?.users?.fetch( `${target ? target?.id : user?.id}` ); // User Information - const userObj = await users.findOne({ + const userObj = await userSchema?.findOne({ userId: discordUser?.id, guildId: guild?.id, }); @@ -24,41 +29,44 @@ export default async (interaction: CommandInteraction) => { // Embed object const embed = { author: { - name: `${discordUser.username}#${discordUser.discriminator}`, - icon_url: discordUser.displayAvatarURL(), + name: `${discordUser?.username}#${discordUser?.discriminator}` as string, + icon_url: discordUser?.displayAvatarURL() as string, }, - color: config.colors.success as any, + color: config?.colors?.success as ColorResolvable, fields: [ { - name: `:dollar: Credits`, - value: `${userObj.credits || "Not found"}`, + name: `:dollar: Credits` as string, + value: `${userObj?.credits || "Not found"}` as string, inline: true, }, { - name: `:squeeze_bottle: Level`, - value: `${userObj.level || "Not found"}`, + name: `:squeeze_bottle: Level` as string, + value: `${userObj?.level || "Not found"}` as string, inline: true, }, { - name: `:squeeze_bottle: Points`, - value: `${userObj.points || "Not found"}`, + name: `:squeeze_bottle: Points` as string, + value: `${userObj?.points || "Not found"}` as string, inline: true, }, { - name: `:loudspeaker: Reputation`, - value: `${userObj.reputation || "Not found"}`, + name: `:loudspeaker: Reputation` as string, + value: `${userObj?.reputation || "Not found"}` as string, inline: true, }, { - name: `:rainbow_flag: Language`, - value: `${userObj.language || "Not found"}`, + name: `:rainbow_flag: Language` as string, + value: `${userObj?.language || "Not found"}` as string, inline: true, }, ], - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, }; - // Send interaction reply - return await interaction.editReply({ embeds: [embed] }); + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); }; diff --git a/src/commands/reputation/index.ts b/src/commands/reputation/index.ts index 2766fc6..93ff54c 100644 --- a/src/commands/reputation/index.ts +++ b/src/commands/reputation/index.ts @@ -5,6 +5,9 @@ import { CommandInteraction } from "discord.js"; // Modules import give from "./modules/give"; +// Handlers +import logger from "../../handlers/logger"; + // Function export default { data: new SlashCommandBuilder() @@ -31,12 +34,19 @@ export default { ), async execute(interaction: CommandInteraction) { // Destructure - const { options } = interaction; + const { options, guild, user, commandName } = interaction; // Module - Give - if (options.getSubcommand() === "give") { + if (options?.getSubcommand() === "give") { // Execute Module - Give await give(interaction); } + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); }, }; diff --git a/src/commands/reputation/modules/give.ts b/src/commands/reputation/modules/give.ts index 5919693..c188946 100644 --- a/src/commands/reputation/modules/give.ts +++ b/src/commands/reputation/modules/give.ts @@ -1,122 +1,138 @@ -import i18next from "i18next"; -import { CommandInteraction } from "discord.js"; -import config from "../../../../config.json"; -import logger from "../../../handlers/logger"; -import users from "../../../helpers/database/models/userSchema"; -import timeouts from "../../../helpers/database/models/timeoutSchema"; +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; +// Configurations +import config from "../../../../config.json"; + +// Handlers +import logger from "../../../handlers/logger"; + +// Models +import userSchema from "../../../helpers/database/models/userSchema"; +import timeoutSchema from "../../../helpers/database/models/timeoutSchema"; + +// Function export default async (interaction: CommandInteraction) => { // Destructure const { options, user, guild } = interaction; - // Target information - const target = options.getUser("target"); + // Target option + const optionTarget = options?.getUser("target"); // Type information - const type = options.getString("type"); + const optionType = options?.getString("type"); // User information - const userObj = await users.findOne({ + const userObj = await userSchema?.findOne({ userId: user?.id, guildId: guild?.id, }); // Check if user has a timeout - const isTimeout = await timeouts.findOne({ + const isTimeout = await timeoutSchema?.findOne({ guildId: guild?.id, userId: user?.id, - timeoutId: 2, + timeoutId: "2022-04-10-16-42", }); // If user is not on timeout if (!isTimeout) { // Do not allow self reputation - if (target?.id === user?.id) { + if (optionTarget?.id === user?.id) { // Embed object const embed = { - title: ":loudspeaker: Reputation - Give", - description: "You can not repute yourself.", - timestamp: new Date(), - color: config.colors.error as any, - footer: { iconURL: config.footer.icon, text: config.footer.text }, + title: ":loudspeaker: Reputation [Give]" as string, + description: "You can not repute yourself." as string, + timestamp: new Date() as Date, + color: config?.colors?.error as ColorResolvable, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, }; // Return interaction reply - return interaction.editReply({ embeds: [embed] }); + return await interaction?.editReply({ embeds: [embed] }); } // If type is positive - if (type === "positive") { + if (optionType === "positive") { userObj.reputation += 1; } // If type is negative - if (type === "negative") { + else if (optionType === "negative") { userObj.reputation -= 1; } // Save user - await userObj.save().then(async () => { + await userObj?.save()?.then(async () => { // Embed object const embed = { - title: ":loudspeaker: Reputation - Give", - description: `You have given ${target} a ${type} reputation!`, - timestamp: new Date(), - color: config.colors.success as any, - footer: { iconURL: config.footer.icon, text: config.footer.text }, + title: ":loudspeaker: Reputation [Give]" as string, + description: + `You have given ${optionTarget} a ${optionType} reputation!` as string, + timestamp: new Date() as Date, + color: config?.colors?.success as ColorResolvable, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, }; - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - // Log debug message - logger.debug( - `Guild: ${guild?.id} User: ${user?.id} has given ${target?.id} a ${type} reputation.` + logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} has given ${optionTarget?.id} a ${optionType} reputation.` ); // Create a timeout for the user - await timeouts.create({ + await timeoutSchema?.create({ guildId: guild?.id, userId: user?.id, - timeoutId: 2, + timeoutId: "2022-04-10-16-42", }); + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); }); setTimeout(async () => { // send debug message - logger.debug( + logger?.debug( `Guild: ${guild?.id} User: ${user?.id} has not repute within last ${ - config.reputation.timeout / 1000 + config?.reputation?.timeout / 1000 } seconds, reputation can be given` ); // When timeout is out, remove it from the database - await timeouts.deleteOne({ + await timeoutSchema?.deleteOne({ guildId: guild?.id, userId: user?.id, - timeoutId: 2, + timeoutId: "2022-04-10-16-42", }); - }, config.reputation.timeout); + }, config?.reputation?.timeout); } else { // Create embed object const embed = { - title: ":loudspeaker: Reputation - Give", + title: ":loudspeaker: Reputation [Give]" as string, description: `You have given reputation within the last ${ - config.reputation.timeout / 1000 - } seconds, you can not repute now!`, - timestamp: new Date(), - color: config.colors.error as any, - footer: { iconURL: config.footer.icon, text: config.footer.text }, + config?.reputation?.timeout / 1000 + } seconds, you can not repute now!` as string, + timestamp: new Date() as Date, + color: config.colors.error as ColorResolvable, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, }; - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - // Log debug message - logger.debug( + logger?.debug( `Guild: ${guild?.id} User: ${user?.id} has repute within last ${ - config.reputation.timeout / 1000 + config?.reputation?.timeout / 1000 } seconds, no reputation can be given` ); + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); } }; diff --git a/src/commands/settings/guild/addons/credits.ts b/src/commands/settings/guild/addons/credits.ts index cb5ebef..411ed20 100644 --- a/src/commands/settings/guild/addons/credits.ts +++ b/src/commands/settings/guild/addons/credits.ts @@ -1,95 +1,97 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; - -// Database models -import guilds from '../../../../helpers/database/models/guildSchema'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { guild, user } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: ':hammer: Settings - Guild [Credits]', - color: config.colors.error as any, - description: `You don't have permission to manage this!`, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get options - const status = await interaction.options.getBoolean('status'); - const rate = await interaction.options.getNumber('rate'); - const timeout = await interaction.options.getNumber('timeout'); - const minimumLength = await interaction.options.getNumber('minimum-length'); - const workRate = await interaction.options.getNumber('work-rate'); - const workTimeout = await interaction.options.getNumber('work-timeout'); - - // Get guild object - const guildDB = await guilds.findOne({ - guildId: guild?.id, - }); - - // Modify values - guildDB.credits.status = status !== null ? status : guildDB.credits.status; - guildDB.credits.rate = rate !== null ? rate : guildDB.credits.rate; - guildDB.credits.timeout = - timeout !== null ? timeout : guildDB.credits.timeout; - guildDB.credits.workRate = - workRate !== null ? workRate : guildDB.credits.workRate; - guildDB.credits.workTimeout = - workTimeout !== null ? workTimeout : guildDB.credits.workTimeout; - guildDB.credits.minimumLength = - minimumLength !== null ? minimumLength : guildDB.credits.minimumLength; - - // Save guild - await guildDB.save().then(async () => { - // Create embed object - const embed = { - title: ':hammer: Settings - Guild [Credits]', - description: 'Following settings is set!', - color: config.colors.success as any, - fields: [ - { name: '🤖 Status', value: `${guildDB.credits.status}`, inline: true }, - { name: '📈 Rate', value: `${guildDB.credits.rate}`, inline: true }, - { - name: '📈 Work Rate', - value: `${guildDB.credits.workRate}`, - inline: true, - }, - { - name: '🔨 Minimum Length', - value: `${guildDB.credits.minimumLength}`, - inline: true, - }, - { - name: '⏰ Timeout', - value: `${guildDB.credits.timeout}`, - inline: true, - }, - { - name: '⏰ Work Timeout', - value: `${guildDB.credits.workTimeout}`, - inline: true, - }, - ], - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - - // Send debug message - await logger.debug( - `Guild: ${guild?.id} User: ${user.id} has changed credit details.` - ); - }); -}; +// Dependencies +import { ColorResolvable, CommandInteraction } from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +//Handlers +import logger from "../../../../handlers/logger"; + +// Models +import guildSchema from "../../../../helpers/database/models/guildSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure member + const { guild, user, options } = interaction; + + // Get options + const status = options?.getBoolean("status"); + const rate = options?.getNumber("rate"); + const timeout = options?.getNumber("timeout"); + const minimumLength = options?.getNumber("minimum-length"); + const workRate = options?.getNumber("work-rate"); + const workTimeout = options?.getNumber("work-timeout"); + + // Get guild object + const guildDB = await guildSchema?.findOne({ + guildId: guild?.id, + }); + + // Modify values + guildDB.credits.status = status !== null ? status : guildDB?.credits?.status; + guildDB.credits.rate = rate !== null ? rate : guildDB?.credits?.rate; + guildDB.credits.timeout = + timeout !== null ? timeout : guildDB?.credits?.timeout; + guildDB.credits.workRate = + workRate !== null ? workRate : guildDB?.credits?.workRate; + guildDB.credits.workTimeout = + workTimeout !== null ? workTimeout : guildDB?.credits?.workTimeout; + guildDB.credits.minimumLength = + minimumLength !== null ? minimumLength : guildDB?.credits?.minimumLength; + + // Save guild + await guildDB?.save()?.then(async () => { + // Embed object + const embed = { + title: ":tools: Settings - Guild [Credits]" as string, + description: "Following settings is set!" as string, + color: config?.colors?.success as ColorResolvable, + fields: [ + { + name: "🤖 Status" as string, + value: `${guildDB?.credits?.status}` as string, + inline: true, + }, + { + name: "📈 Rate" as string, + value: `${guildDB?.credits?.rate}` as string, + inline: true, + }, + { + name: "📈 Work Rate" as string, + value: `${guildDB?.credits?.workRate}` as string, + inline: true, + }, + { + name: "🔨 Minimum Length" as string, + value: `${guildDB?.credits?.minimumLength}` as string, + inline: true, + }, + { + name: "⏰ Timeout" as string, + value: `${guildDB?.credits?.timeout}` as string, + inline: true, + }, + { + name: "⏰ Work Timeout" as string, + value: `${guildDB?.credits?.workTimeout}` as string, + inline: true, + }, + ], + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send debug message + logger?.debug( + `Guild: ${guild?.id} User: ${user.id} has changed credit details.` + ); + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + }); +}; diff --git a/src/commands/settings/guild/addons/index.ts b/src/commands/settings/guild/addons/index.ts deleted file mode 100644 index 52501a3..0000000 --- a/src/commands/settings/guild/addons/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import pterodactyl from './pterodactyl'; -import credits from './credits'; -import points from './points'; - -export default { pterodactyl, credits, points }; diff --git a/src/commands/settings/guild/addons/points.ts b/src/commands/settings/guild/addons/points.ts index 2fdfc43..9113d4b 100644 --- a/src/commands/settings/guild/addons/points.ts +++ b/src/commands/settings/guild/addons/points.ts @@ -1,79 +1,81 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; - -// Database models -import guilds from '../../../../helpers/database/models/guildSchema'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: ':hammer: Settings - Guild [Points]', - color: config.colors.error as any, - description: `You don't have permission to manage this!`, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get options - const status = await interaction.options.getBoolean('status'); - const rate = await interaction.options.getNumber('rate'); - const timeout = await interaction.options.getNumber('timeout'); - const minimumLength = await interaction.options.getNumber('minimum-length'); - - // Get guild object - const guildDB = await guilds.findOne({ - guildId: interaction?.guild?.id, - }); - - // Modify values - guildDB.credits.status = status !== null ? status : guildDB.credits.status; - guildDB.credits.rate = rate !== null ? rate : guildDB.credits.rate; - guildDB.credits.timeout = - timeout !== null ? timeout : guildDB.credits.timeout; - guildDB.credits.minimumLength = - minimumLength !== null ? minimumLength : guildDB.credits.minimumLength; - - // Save guild - await guildDB.save().then(async () => { - // Create embed object - const embed = { - title: ':hammer: Settings - Guild [Points]', - description: 'Following settings is set!', - color: config.colors.success as any, - fields: [ - { name: '🤖 Status', value: `${guildDB.credits.status}`, inline: true }, - { name: '📈 Rate', value: `${guildDB.credits.rate}`, inline: true }, - { - name: '🔨 Minimum Length', - value: `${guildDB.credits.minimumLength}`, - inline: true, - }, - { - name: '⏰ Timeout', - value: `${guildDB.credits.timeout}`, - inline: true, - }, - ], - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${interaction?.user?.id} has changed credit details.` - ); - }); -}; +// Dependencies +import { ColorResolvable, CommandInteraction } from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +// Handlers +import logger from "../../../../handlers/logger"; + +// Models +import guildSchema from "../../../../helpers/database/models/guildSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure member + const { options, guild, user } = interaction; + + // Get options + const status = options?.getBoolean("status"); + const rate = options?.getNumber("rate"); + const timeout = options?.getNumber("timeout"); + const minimumLength = options?.getNumber("minimum-length"); + + // Get guild object + const guildDB = await guildSchema?.findOne({ + guildId: guild?.id, + }); + + // Modify values + guildDB.points.status = status !== null ? status : guildDB?.points?.status; + guildDB.points.rate = rate !== null ? rate : guildDB?.points?.rate; + guildDB.points.timeout = + timeout !== null ? timeout : guildDB?.points?.timeout; + guildDB.points.minimumLength = + minimumLength !== null ? minimumLength : guildDB?.points?.minimumLength; + + // Save guild + await guildDB?.save()?.then(async () => { + // Create embed object + const embed = { + title: ":hammer: Settings - Guild [Points]" as string, + description: "Following settings is set!" as string, + color: config.colors.success as ColorResolvable, + fields: [ + { + name: "🤖 Status" as string, + value: `${guildDB?.points?.status}` as string, + inline: true, + }, + { + name: "📈 Rate" as string, + value: `${guildDB?.points?.rate}` as string, + inline: true, + }, + { + name: "🔨 Minimum Length" as string, + value: `${guildDB?.points?.minimumLength}` as string, + inline: true, + }, + { + name: "⏰ Timeout" as string, + value: `${guildDB?.points?.timeout}` as string, + inline: true, + }, + ], + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send debug message + logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} has changed credit details.` + ); + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + }); +}; diff --git a/src/commands/settings/guild/addons/pterodactyl.ts b/src/commands/settings/guild/addons/pterodactyl.ts index ffa564f..7bbae1a 100644 --- a/src/commands/settings/guild/addons/pterodactyl.ts +++ b/src/commands/settings/guild/addons/pterodactyl.ts @@ -1,62 +1,50 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; - -// Database models - -import apis from '../../../../helpers/database/models/apiSchema'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: ':hammer: Settings - Guild [Pterodactyl]', - color: config.colors.error as any, - description: 'You do not have permission to manage this!', - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - return interaction.editReply({ embeds: [embed] }); - } - - // Get options - - const url = await interaction.options.getString('url'); - const token = await interaction.options.getString('token'); - - // Update API credentials - - await apis - .findOneAndUpdate( - { guildId: interaction?.guild?.id }, - { url, token }, - { new: true, upsert: true } - ) - .then(async () => { - // Build embed - - const embed = { - title: ':hammer: Settings - Guild [Pterodactyl]', - color: config.colors.success as any, - description: 'Pterodactyl settings is saved!', - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send reply - - await interaction.editReply({ embeds: [embed] }); - - // Send debug message - - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${interaction?.user?.id} has changed api credentials.` - ); - }); -}; +// Dependencies +import { ColorResolvable, CommandInteraction } from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +// Handlers +import logger from "../../../../handlers/logger"; + +// Models +import apiSchema from "../../../../helpers/database/models/apiSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure member + const { options, guild, user } = interaction; + + // Get options + const url = options?.getString("url"); + const token = options?.getString("token"); + + // Update API credentials + await apiSchema + ?.findOneAndUpdate( + { guildId: guild?.id }, + { url, token }, + { new: true, upsert: true } + ) + .then(async () => { + // Embed object + const embed = { + title: ":hammer: Settings - Guild [Pterodactyl]" as string, + color: config?.colors?.success as ColorResolvable, + description: "Pterodactyl settings is saved!" as string, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send debug message + logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} has changed api credentials.` + ); + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + }); +}; diff --git a/src/commands/settings/guild/index.ts b/src/commands/settings/guild/index.ts index 876a49f..f03cde3 100644 --- a/src/commands/settings/guild/index.ts +++ b/src/commands/settings/guild/index.ts @@ -1,53 +1,62 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../config.json'; -import logger from '../../../handlers/logger'; -import pterodactyl from './addons/pterodactyl'; -import credits from './addons/credits'; -import points from './addons/points'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // Check permission - if (!interaction?.memberPermissions?.has(Permissions.FLAGS.MANAGE_GUILD)) { - // Create embed object - const embed = { - title: 'Settings - Guild', - color: config.colors.error as any, - description: 'You do not have permission to manage this!', - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - } - - // If subcommand is pterodactyl - if (interaction.options.getSubcommand() === 'pterodactyl') { - // Execute pterodactyl addon - await pterodactyl(interaction); - } - - // If subcommand is credits - else if (interaction.options.getSubcommand() === 'credits') { - // Execute credits addon - await credits(interaction); - } - - // If subcommand is points - else if (interaction.options.getSubcommand() === 'points') { - // Execute points addon - await points(interaction); - } - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${ - interaction?.user?.id - } executed /${ - interaction.commandName - } ${interaction.options.getSubcommandGroup()} ${interaction.options.getSubcommand()}` - ); -}; +// Dependencies +import { Permissions, ColorResolvable, CommandInteraction } from "discord.js"; + +// Configurations +import config from "../../../../config.json"; + +// Handlers +import logger from "../../../handlers/logger"; + +// Modules +import pterodactyl from "./addons/pterodactyl"; +import credits from "./addons/credits"; +import points from "./addons/points"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure member + const { memberPermissions, options, commandName, user, guild } = interaction; + + // Check permission + if (!memberPermissions?.has(Permissions?.FLAGS?.MANAGE_GUILD)) { + // Create embed object + const embed = { + title: ":tools: Settings - Guild" as string, + color: config?.colors?.error as ColorResolvable, + description: "You do not have permission to manage this!" as string, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // Module - Pterodactyl + if (options?.getSubcommand() === "pterodactyl") { + // Execute Module - Pterodactyl + return await pterodactyl(interaction); + } + + // Module - Credits + else if (options?.getSubcommand() === "credits") { + // Execute Module - Credits + return await credits(interaction); + } + + // Module - Points + else if (options?.getSubcommand() === "points") { + // Execute Module - Points + return await points(interaction); + } + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); +}; diff --git a/src/commands/settings/index.ts b/src/commands/settings/index.ts index e2a2c17..a0cdb0b 100644 --- a/src/commands/settings/index.ts +++ b/src/commands/settings/index.ts @@ -1,127 +1,144 @@ -import { SlashCommandBuilder } from '@discordjs/builders'; -import { Permissions, CommandInteraction } from 'discord.js'; -import guild from './guild'; -import user from './user'; - -export default { - data: new SlashCommandBuilder() - .setName('settings') - .setDescription('Manage settings.') - .addSubcommandGroup((group) => - group - .setName('guild') - .setDescription('Manage guild settings.') - .addSubcommand((command) => - command - .setName('pterodactyl') - .setDescription('Controlpanel.gg') - .addStringOption((option) => - option - .setName('url') - .setDescription('The api url') - .setRequired(true) - ) - .addStringOption((option) => - option - .setName('token') - .setDescription('The api token') - .setRequired(true) - ) - ) - .addSubcommand((command) => - command - .setName('credits') - .setDescription('Credits') - .addBooleanOption((option) => - option - .setName('status') - .setDescription('Should credits be enabled?') - ) - .addNumberOption((option) => - option - .setName('rate') - .setDescription('Amount of credits per message.') - ) - .addNumberOption((option) => - option - .setName('minimum-length') - .setDescription('Minimum length of message to earn credits.') - ) - .addNumberOption((option) => - option - .setName('work-rate') - .setDescription('Maximum amount of credits on work.') - ) - .addNumberOption((option) => - option - .setName('work-timeout') - .setDescription( - 'Timeout between work schedules (milliseconds).' - ) - ) - .addNumberOption((option) => - option - .setName('timeout') - .setDescription( - 'Timeout between earning credits (milliseconds).' - ) - ) - ) - .addSubcommand((command) => - command - .setName('points') - .setDescription('Points') - .addBooleanOption((option) => - option - .setName('status') - .setDescription('Should credits be enabled?') - ) - .addNumberOption((option) => - option - .setName('rate') - .setDescription('Amount of credits per message.') - ) - .addNumberOption((option) => - option - .setName('minimum-length') - .setDescription('Minimum length of message to earn credits.') - ) - .addNumberOption((option) => - option - .setName('timeout') - .setDescription( - 'Timeout between earning credits (milliseconds).' - ) - ) - ) - ) - .addSubcommandGroup((group) => - group - .setName('user') - .setDescription('Manage user settings.') - .addSubcommand((command) => - command - .setName('appearance') - .setDescription('Manage your appearance') - .addStringOption((option) => - option - .setName('language') - .setDescription('Configure your language') - .addChoice('English', 'en') - .addChoice('Swedish', 'sv') - ) - ) - ), - async execute(interaction: CommandInteraction) { - // If subcommand group is guild - if (interaction.options.getSubcommandGroup() === 'guild') { - // Execute guild group - await guild(interaction); - } - // If subcommand group is user - else if (interaction.options.getSubcommandGroup() === 'user') { - // Execute user group - await user(interaction); - } - }, -}; +// Dependencies +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +// Groups +import guildGroup from "./guild"; +import userGroup from "./user"; + +// Handlers +import logger from "../../handlers/logger"; + +// Function +export default { + data: new SlashCommandBuilder() + .setName("settings") + .setDescription("Manage settings.") + .addSubcommandGroup((group) => + group + .setName("guild") + .setDescription("Manage guild settings.") + .addSubcommand((command) => + command + .setName("pterodactyl") + .setDescription("Controlpanel.gg") + .addStringOption((option) => + option + .setName("url") + .setDescription("The api url") + .setRequired(true) + ) + .addStringOption((option) => + option + .setName("token") + .setDescription("The api token") + .setRequired(true) + ) + ) + .addSubcommand((command) => + command + .setName("credits") + .setDescription("Credits") + .addBooleanOption((option) => + option + .setName("status") + .setDescription("Should credits be enabled?") + ) + .addNumberOption((option) => + option + .setName("rate") + .setDescription("Amount of credits per message.") + ) + .addNumberOption((option) => + option + .setName("minimum-length") + .setDescription("Minimum length of message to earn credits.") + ) + .addNumberOption((option) => + option + .setName("work-rate") + .setDescription("Maximum amount of credits on work.") + ) + .addNumberOption((option) => + option + .setName("work-timeout") + .setDescription( + "Timeout between work schedules (milliseconds)." + ) + ) + .addNumberOption((option) => + option + .setName("timeout") + .setDescription( + "Timeout between earning credits (milliseconds)." + ) + ) + ) + .addSubcommand((command) => + command + .setName("points") + .setDescription("Points") + .addBooleanOption((option) => + option + .setName("status") + .setDescription("Should credits be enabled?") + ) + .addNumberOption((option) => + option + .setName("rate") + .setDescription("Amount of credits per message.") + ) + .addNumberOption((option) => + option + .setName("minimum-length") + .setDescription("Minimum length of message to earn credits.") + ) + .addNumberOption((option) => + option + .setName("timeout") + .setDescription( + "Timeout between earning credits (milliseconds)." + ) + ) + ) + ) + .addSubcommandGroup((group) => + group + .setName("user") + .setDescription("Manage user settings.") + .addSubcommand((command) => + command + .setName("appearance") + .setDescription("Manage your appearance") + .addStringOption((option) => + option + .setName("language") + .setDescription("Configure your language") + .addChoice("English", "en") + .addChoice("Swedish", "sv") + ) + ) + ), + async execute(interaction: CommandInteraction) { + // Destructure + const { options, commandName, user, guild } = interaction; + + // Group - Guild + if (options.getSubcommandGroup() === "guild") { + // Execute Group - Guild + await guildGroup(interaction); + } + // Group - User + else if (options.getSubcommandGroup() === "user") { + // Execute Group - User + await userGroup(interaction); + } + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); + }, +}; diff --git a/src/commands/settings/user/addons/appearance.ts b/src/commands/settings/user/addons/appearance.ts deleted file mode 100644 index de400c0..0000000 --- a/src/commands/settings/user/addons/appearance.ts +++ /dev/null @@ -1,49 +0,0 @@ -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; -import { CommandInteraction } from 'discord.js'; -// Database models -import users from '../../../../helpers/database/models/userSchema'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // Get options - const language = await interaction.options.getString('language'); - - // Get user object - const userDB = await users.findOne({ - userId: interaction?.user?.id, - guildId: interaction?.guild?.id, - }); - - // Modify values - userDB.language = language !== null ? language : userDB.language; - - // Save guild - await userDB.save().then(async () => { - // Create embed object - const embed = { - title: ':hammer: Settings - User [Appearance]', - description: 'Following settings is set!', - color: config.colors.success as any, - fields: [ - { - name: '🏳️‍🌈 Language', - value: `${userDB.language}`, - inline: true, - }, - ], - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${interaction?.user?.id} has changed appearance settings.` - ); - }); -}; diff --git a/src/commands/settings/user/addons/index.ts b/src/commands/settings/user/addons/index.ts deleted file mode 100644 index 5362aba..0000000 --- a/src/commands/settings/user/addons/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import appearance from './appearance'; - -export default { appearance }; diff --git a/src/commands/settings/user/index.ts b/src/commands/settings/user/index.ts index ba69eae..7797711 100644 --- a/src/commands/settings/user/index.ts +++ b/src/commands/settings/user/index.ts @@ -1,24 +1,27 @@ -import { Permissions, CommandInteraction } from 'discord.js'; -import config from '../../../../config.json'; -import logger from '../../../handlers/logger'; -import appearance from './addons/appearance'; - -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // If subcommand is appearance - if (interaction.options.getSubcommand() === 'appearance') { - // Execute appearance addon - await appearance(interaction); - } - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${ - interaction?.user?.id - } executed /${ - interaction.commandName - } ${interaction.options.getSubcommandGroup()} ${interaction.options.getSubcommand()}` - ); -}; +// Dependencies +import { CommandInteraction } from "discord.js"; + +// Handlers +import logger from "../../../handlers/logger"; + +// Modules +import appearance from "./modules/appearance"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure member + const { guild, user, options, commandName } = interaction; + + // Module - Appearance + if (options?.getSubcommand() === "appearance") { + // Execute Module - Appearance + await appearance(interaction); + } + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); +}; diff --git a/src/commands/settings/user/modules/appearance.ts b/src/commands/settings/user/modules/appearance.ts new file mode 100644 index 0000000..6fe7cec --- /dev/null +++ b/src/commands/settings/user/modules/appearance.ts @@ -0,0 +1,59 @@ +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +// Handlers +import logger from "../../../../handlers/logger"; + +// Models +import userSchema from "../../../../helpers/database/models/userSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure member + const { options, user, guild } = interaction; + + // Get options + const language = options?.getString("language"); + + // Get user object + const userDB = await userSchema?.findOne({ + userId: user?.id, + guildId: guild?.id, + }); + + // Modify values + userDB.language = language !== null ? language : userDB?.language; + + // Save guild + await userDB?.save()?.then(async () => { + // Embed object + const embed = { + title: ":hammer: Settings - User [Appearance]" as string, + description: "Following settings is set!" as string, + color: config?.colors?.success as ColorResolvable, + fields: [ + { + name: "🏳️‍🌈 Language" as string, + value: `${userDB?.language}` as string, + inline: true, + }, + ], + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send debug message + logger?.debug( + `Guild: ${guild?.id} User: ${user?.id} has changed appearance settings.` + ); + + // Return interaction reply + return await interaction?.editReply({ embeds: [embed] }); + }); +}; diff --git a/src/commands/shop/addons/pterodactyl.ts b/src/commands/shop/addons/pterodactyl.ts deleted file mode 100644 index 7d0c7ea..0000000 --- a/src/commands/shop/addons/pterodactyl.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { v4 as uuidv4 } from 'uuid'; -import axios from 'axios'; -import config from '../../../../config.json'; -import logger from '../../../handlers/logger'; -import apis from '../../../helpers/database/models/apiSchema'; -import users from '../../../helpers/database/models/userSchema'; -import creditNoun from '../../../helpers/creditNoun'; -import { CommandInteraction } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - const { member } = interaction; - - // Get options - const amount = await interaction.options.getInteger('amount'); - - if (amount === null) return; - - // Get user object - const userDB = await users.findOne({ - userId: interaction?.user?.id, - guildId: interaction?.guild?.id, - }); - - // Get DM user object - const dmUser = interaction.client.users.cache.get(interaction?.user?.id); - - // Stop if amount or user credits is below 100 - if ((amount || userDB.credits) < 100) { - const embed = { - title: ':shopping_cart: Shop - Pterodactyl', - description: `You **can't** withdraw for __Pterodactyl__ below **100**.`, - color: config.colors.error as any, - fields: [ - { name: 'Your balance', value: `${creditNoun(userDB.credits)}` }, - ], - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - return interaction.editReply({ embeds: [embed] }); - } - - // Stop if amount or user credits is above 1.000.000 - if ((amount || userDB.credits) > 1000000) { - const embed = { - title: ':shopping_cart: Shop - Pterodactyl', - description: `You **can't** withdraw for __Pterodactyl__ above **1.000.000**.`, - color: config.colors.error as any, - fields: [ - { name: 'Your balance', value: `${creditNoun(userDB.credits)}` }, - ], - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - return interaction.editReply({ embeds: [embed] }); - } - - // Stop if user credits is below amount - if (userDB.credits < amount) { - const embed = { - title: ':shopping_cart: Shop - Pterodactyl', - description: `You have **insufficient** credits.`, - color: config.colors.error as any, - fields: [ - { name: 'Your balance', value: `${creditNoun(userDB.credits)}` }, - ], - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - return interaction.editReply({ embeds: [embed] }); - } - - // Generate a unique voucher for the user - const code = uuidv4(); - - // Get api object - const apiCredentials = await apis.findOne({ - guildId: interaction?.guild?.id, - }); - - // Create a api instance - const api = axios.create({ - baseURL: apiCredentials.url, - headers: { Authorization: `Bearer ${apiCredentials.token}` }, - }); - - // Get shop URL - const shopUrl = apiCredentials.url.replace('/api', '/store'); - - // Make API request - await api - - // Make a post request to the API - .post('vouchers', { - uses: 1, - code, - credits: amount || userDB.credits, - memo: `${interaction.createdTimestamp} - ${interaction?.user?.id}`, - }) - - // If successful - .then(async () => { - // Create DM embed object - const dmEmbed = { - title: ':shopping_cart: Shop - Pterodactyl', - description: `Redeem this voucher [here](${shopUrl})!`, - fields: [ - { name: 'Code', value: `${code}`, inline: true }, - { - name: 'Credits', - value: `${amount || userDB.credits}`, - inline: true, - }, - ], - color: config.colors.success as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Create interaction embed object - const interactionEmbed = { - title: ':shopping_cart: Shop - Pterodactyl', - description: 'I have sent you the code in DM!', - color: config.colors.success as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Withdraw amount from user credits - userDB.credits -= amount || userDB.credits; - - // Save new credits - await userDB - .save() - // If successful - .then(async () => { - // Send debug message - await logger.debug( - `User: ${interaction?.user?.username} redeemed: ${creditNoun( - amount - )}` - ); - - // Send DM message - await dmUser?.send({ embeds: [dmEmbed] }); - - // Send interaction reply - await interaction.editReply({ - embeds: [interactionEmbed], - }); - }) - - // If error occurs - .catch(async (e: any) => { - await logger.error(e); - const embed = { - title: ':shopping_cart: Shop - Pterodactyl', - description: 'Something went wrong, please try again later.', - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - return interaction.editReply({ embeds: [embed] }); - }); - }) - - // If error occurs - .catch(async (e) => { - await logger.error(e); - const embed = { - title: ':shopping_cart: Shop - Pterodactyl', - description: 'Something went wrong, please try again later.', - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - return interaction.editReply({ embeds: [embed] }); - }); -}; diff --git a/src/commands/shop/addons/roles.ts b/src/commands/shop/addons/roles.ts deleted file mode 100644 index 08d1873..0000000 --- a/src/commands/shop/addons/roles.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { v4 as uuidv4 } from 'uuid'; -import axios from 'axios'; -import config from '../../../../config.json'; -import logger from '../../../handlers/logger'; -import guilds from '../../../helpers/database/models/guildSchema'; -import users from '../../../helpers/database/models/userSchema'; -import creditNoun from '../../../helpers/creditNoun'; -import { CommandInteraction, RoleManager } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - const name = interaction.options.getString('name'); - - const { member } = interaction; - - const guildDB = await guilds.findOne({ guildId: interaction?.guild?.id }); - const userDB = await users.findOne({ - userId: interaction?.user?.id, - guildId: interaction?.guild?.id, - }); - - if (name === null) return; - - (interaction?.guild?.roles as RoleManager) - .create({ - name, - color: 'BLUE', - reason: `${interaction?.user?.id} bought from shop`, - }) - .then(async (role) => { - console.log(role); - userDB.credits -= guildDB.shop.roles.pricePerHour; - await userDB.save().then(async () => { - const embed = { - title: ':shopping_cart: Shop - Roles', - description: `You have bought ${role.name} for ${guildDB.shop.roles.pricePerHour} per hour.`, - color: config.colors.error as any, - fields: [ - { name: 'Your balance', value: `${creditNoun(userDB.credits)}` }, - ], - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - return interaction.editReply({ - embeds: [embed], - }); - }); - }) - .catch(console.error); -}; diff --git a/src/commands/shop/index.ts b/src/commands/shop/index.ts index 74a870e..47bad3a 100644 --- a/src/commands/shop/index.ts +++ b/src/commands/shop/index.ts @@ -1,59 +1,77 @@ -import { SlashCommandBuilder } from '@discordjs/builders'; -import { Permissions, CommandInteraction } from 'discord.js'; -import guilds from '../../helpers/database/models/guildSchema'; -import pterodactyl from './addons/pterodactyl'; -import roles from './roles'; - -export default { - data: new SlashCommandBuilder() - .setName('shop') - .setDescription('Open our shop.') - .addSubcommand((subcommand) => - subcommand - .setName('pterodactyl') - .setDescription('Buy pterodactyl power.') - .addIntegerOption((option) => - option - .setName('amount') - .setDescription('How much credits you want to withdraw.') - ) - ) - .addSubcommandGroup((group) => - group - .setName('roles') - .setDescription('Manage custom roles.') - .addSubcommand((command) => - command - .setName('buy') - .setDescription('Buy a custom role') - .addStringOption((option) => - option - .setName('name') - .setDescription('Name of the role you wish to purchase.') - ) - ) - .addSubcommand((command) => - command - .setName('cancel') - .setDescription('Cancel a custom role') - .addRoleOption((option) => - option - .setName('role') - .setDescription('Name of the role you wish to cancel.') - ) - ) - ), - async execute(interaction: CommandInteraction) { - // If subcommand is pterodactyl - if (interaction.options.getSubcommand() === 'pterodactyl') { - // Execute pterodactyl addon - await pterodactyl(interaction); - } - - // If subcommand group is roles - else if (interaction.options.getSubcommandGroup() === 'roles') { - // Execute roles addon - await roles(interaction); - } - }, -}; +// Dependencies +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +// Modules +import pterodactyl from "./modules/pterodactyl"; + +// Groups +import roles from "./roles"; + +// Handlers +import logger from "../../handlers/logger"; + +// Function +export default { + data: new SlashCommandBuilder() + .setName("shop") + .setDescription("Open our shop.") + .addSubcommand((subcommand) => + subcommand + .setName("pterodactyl") + .setDescription("Buy pterodactyl power.") + .addIntegerOption((option) => + option + .setName("amount") + .setDescription("How much credits you want to withdraw.") + ) + ) + .addSubcommandGroup((group) => + group + .setName("roles") + .setDescription("Manage custom roles.") + .addSubcommand((command) => + command + .setName("buy") + .setDescription("Buy a custom role") + .addStringOption((option) => + option + .setName("name") + .setDescription("Name of the role you wish to purchase.") + ) + ) + .addSubcommand((command) => + command + .setName("cancel") + .setDescription("Cancel a custom role") + .addRoleOption((option) => + option + .setName("role") + .setDescription("Name of the role you wish to cancel.") + ) + ) + ), + async execute(interaction: CommandInteraction) { + // Destructure + const { options, commandName, user, guild } = interaction; + + // Module - Pterodactyl + if (options?.getSubcommand() === "pterodactyl") { + // Execute Module - Pterodactyl + return await pterodactyl(interaction); + } + + // Group - Roles + else if (options?.getSubcommandGroup() === "roles") { + // Execute Group - Roles + return await roles(interaction); + } + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); + }, +}; diff --git a/src/commands/shop/modules/pterodactyl.ts b/src/commands/shop/modules/pterodactyl.ts new file mode 100644 index 0000000..6c865bc --- /dev/null +++ b/src/commands/shop/modules/pterodactyl.ts @@ -0,0 +1,235 @@ +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; +import { v4 as uuidv4 } from "uuid"; +import axios from "axios"; + +// Configurations +import config from "../../../../config.json"; + +// Handlers +import logger from "../../../handlers/logger"; + +// Helpers +import creditNoun from "../../../helpers/creditNoun"; + +// Models +import apiSchema from "../../../helpers/database/models/apiSchema"; +import userSchema from "../../../helpers/database/models/userSchema"; + +// Function +export default async (interaction: CommandInteraction) => { + const { options, guild, user, client } = interaction; + + // Get options + const optionAmount = options?.getInteger("amount"); + + // If amount is null + if (optionAmount === null) { + // Embed object + const embed = { + title: ":dollar: Credits [Gift]" as string, + description: "We could not read your requested amount." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + // Get user object + const userDB = await userSchema?.findOne({ + userId: user?.id, + guildId: guild?.id, + }); + + // Get DM user object + const dmUser = client?.users?.cache?.get(user?.id); + + // Stop if amount or user credits is below 100 + if ((optionAmount || userDB?.credits) < 100) { + const embed = { + title: ":shopping_cart: Shop [Pterodactyl]" as string, + description: + `You **can't** withdraw for __Pterodactyl__ below **100**.` as string, + color: config?.colors?.error as ColorResolvable, + fields: [ + { + name: "Your balance" as string, + value: `${creditNoun(userDB?.credits)}` as string, + }, + ], + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + return interaction?.editReply({ embeds: [embed] }); + } + + // Stop if amount or user credits is above 1.000.000 + if ((optionAmount || userDB?.credits) > 1000000) { + const embed = { + title: ":shopping_cart: Shop [Pterodactyl]" as string, + description: + `You **can't** withdraw for __Pterodactyl__ above **1.000.000**.` as string, + color: config?.colors?.error as ColorResolvable, + fields: [ + { + name: "Your balance" as string, + value: `${creditNoun(userDB?.credits)}` as string, + }, + ], + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + return interaction?.editReply({ embeds: [embed] }); + } + + // Stop if user credits is below amount + if (userDB?.credits < optionAmount) { + const embed = { + title: ":shopping_cart: Shop [Pterodactyl]" as string, + description: `You have **insufficient** credits.` as string, + color: config.colors.error as ColorResolvable, + fields: [ + { + name: "Your balance" as string, + value: `${creditNoun(userDB?.credits)}` as string, + }, + ], + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + return interaction?.editReply({ embeds: [embed] }); + } + + // Generate a unique voucher for the user + const code = uuidv4(); + + // Get api object + const apiCredentials = await apiSchema?.findOne({ + guildId: guild?.id, + }); + + // Create a api instance + const api = axios?.create({ + baseURL: apiCredentials?.url, + headers: { Authorization: `Bearer ${apiCredentials?.token}` }, + }); + + // Get shop URL + const shopUrl = apiCredentials?.url?.replace("/api", "/store"); + + // Make API request + await api + + // Make a post request to the API + ?.post("vouchers", { + uses: 1, + code, + credits: optionAmount || userDB?.credits, + memo: `${interaction?.createdTimestamp} - ${interaction?.user?.id}`, + }) + + // If successful + ?.then(async () => { + // Create DM embed object + const dmEmbed = { + title: ":shopping_cart: Shop [Pterodactyl]" as string, + description: `Redeem this voucher [here](${shopUrl})!` as string, + fields: [ + { name: "Code" as string, value: `${code}` as string, inline: true }, + { + name: "Credits" as string, + value: `${optionAmount || userDB?.credits}` as string, + inline: true, + }, + ], + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Create interaction embed object + const interactionEmbed = { + title: ":shopping_cart: Shop [Pterodactyl]" as string, + description: "I have sent you the code in DM!" as string, + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Withdraw amount from user credits + userDB.credits -= optionAmount || userDB?.credits; + + // Save new credits + await userDB + ?.save() + // If successful + ?.then(async () => { + // Send debug message + logger?.debug( + `User: ${user?.username} redeemed: ${creditNoun(optionAmount)}` + ); + + // Send DM message + await dmUser?.send({ embeds: [dmEmbed] }); + + // Send interaction reply + await interaction?.editReply({ + embeds: [interactionEmbed], + }); + }) + + // If error occurs + .catch(async (e: any) => { + logger?.error(e); + const embed = { + title: ":shopping_cart: Shop [Pterodactyl]" as string, + description: + "Something went wrong, please try again later." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + return interaction?.editReply({ embeds: [embed] }); + }); + }) + + // If error occurs + .catch(async (e) => { + logger?.error(e); + const embed = { + title: ":shopping_cart: Shop [Pterodactyl]" as string, + description: "Something went wrong, please try again later." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + return interaction?.editReply({ embeds: [embed] }); + }); +}; diff --git a/src/commands/shop/roles/addons/buy.ts b/src/commands/shop/roles/addons/buy.ts deleted file mode 100644 index eeca6c4..0000000 --- a/src/commands/shop/roles/addons/buy.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { v4 as uuidv4 } from 'uuid'; -import axios from 'axios'; -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; -import users from '../../../../helpers/database/models/userSchema'; -import shopRoles from '../../../../helpers/database/models/shopRolesSchema'; -import guilds from '../../../../helpers/database/models/guildSchema'; -import creditNoun from '../../../../helpers/creditNoun'; -import { CommandInteraction, GuildMemberRoleManager } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - const { member } = interaction; - - const name = await interaction.options.getString('name'); - - if (name === null) return; - - await interaction?.guild?.roles - .create({ - name, - color: 'RED', - reason: `${interaction?.user?.id} bought from shop`, - }) - .then(async (role) => { - // Get guild object - const guildDB = await guilds.findOne({ - guildId: interaction?.guild?.id, - }); - const userDB = await users.findOne({ - userId: interaction?.user?.id, - guildId: interaction?.guild?.id, - }); - const { pricePerHour } = guildDB.shop.roles; - - userDB.credits -= pricePerHour; - - await userDB.save(); - - await shopRoles.create({ - roleId: role?.id, - userId: interaction?.user?.id, - guildId: interaction?.guild?.id, - pricePerHour, - lastPayed: new Date(), - }); - - await (interaction?.member?.roles as GuildMemberRoleManager)?.add( - role?.id - ); - await shopRoles.find().then((role: any) => console.log(role)); - - const embed = { - title: ':shopping_cart: Shop - Roles [Buy]', - description: `You have bought ${role.name} for ${guildDB.shop.roles.pricePerHour} per hour.`, - color: config.colors.success as any, - fields: [ - { name: 'Your balance', value: `${creditNoun(userDB.credits)}` }, - ], - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - return interaction.editReply({ - embeds: [embed], - }); - }) - .catch(console.error); -}; diff --git a/src/commands/shop/roles/addons/cancel.ts b/src/commands/shop/roles/addons/cancel.ts deleted file mode 100644 index 5b9d90c..0000000 --- a/src/commands/shop/roles/addons/cancel.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { v4 as uuidv4 } from 'uuid'; -import axios from 'axios'; -import config from '../../../../../config.json'; -import logger from '../../../../handlers/logger'; -import users from '../../../../helpers/database/models/userSchema'; -import shopRoles from '../../../../helpers/database/models/shopRolesSchema'; -import guilds from '../../../../helpers/database/models/guildSchema'; -import creditNoun from '../../../../helpers/creditNoun'; -import { CommandInteraction, GuildMemberRoleManager } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - const { member } = interaction; - - const role = await interaction.options.getRole('role'); - - if (role === null) return; - - const roleExist = await shopRoles.find({ - guildId: interaction?.guild?.id, - userId: interaction?.user?.id, - roleId: role?.id, - }); - - if (roleExist) { - await (interaction?.member?.roles as GuildMemberRoleManager).remove( - role?.id - ); - - await interaction?.guild?.roles - .delete(role?.id, `${interaction?.user?.id} canceled from shop`) - .then(async () => { - // Get guild object - const guildDB = await guilds.findOne({ - guildId: interaction?.guild?.id, - }); - - const userDB = await users.findOne({ - userId: interaction?.user?.id, - guildId: interaction?.guild?.id, - }); - - await shopRoles.deleteOne({ - roleId: role?.id, - userId: interaction?.user?.id, - guildId: interaction?.guild?.id, - }); - - const embed = { - title: ':shopping_cart: Shop - Roles [Buy]', - description: `You have canceled ${role.name}.`, - color: config.colors.success as any, - fields: [ - { name: 'Your balance', value: `${creditNoun(userDB.credits)}` }, - ], - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - return interaction.editReply({ - embeds: [embed], - }); - }) - .catch(console.error); - } -}; diff --git a/src/commands/shop/roles/addons/index.ts b/src/commands/shop/roles/addons/index.ts deleted file mode 100644 index 12e3413..0000000 --- a/src/commands/shop/roles/addons/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import buy from './buy'; -import cancel from './cancel'; - -export default { buy, cancel }; diff --git a/src/commands/shop/roles/index.ts b/src/commands/shop/roles/index.ts index 67f136d..5103fd6 100644 --- a/src/commands/shop/roles/index.ts +++ b/src/commands/shop/roles/index.ts @@ -1,29 +1,34 @@ -import logger from '../../../handlers/logger'; -import buy from './addons/buy'; -import cancel from './addons/cancel'; -import { CommandInteraction } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - // Destructure member - const { member } = interaction; - - // If subcommand is buy - if (interaction.options.getSubcommand() === 'buy') { - // Execute buy addon - await buy(interaction); - } - - // If subcommand is cancel - if (interaction.options.getSubcommand() === 'cancel') { - // Execute cancel addon - await cancel(interaction); - } - - // Send debug message - await logger.debug( - `Guild: ${interaction?.guild?.id} User: ${ - interaction?.user?.id - } executed /${ - interaction.commandName - } ${interaction.options.getSubcommandGroup()} ${interaction.options.getSubcommand()}` - ); -}; +// Dependencies +import { CommandInteraction } from "discord.js"; + +// Handlers +import logger from "../../../handlers/logger"; + +// Modules +import buy from "./modules/buy"; +import cancel from "./modules/cancel"; + +// Function +export default async (interaction: CommandInteraction) => { + // Destructure member + const { options, commandName, guild, user } = interaction; + + // Module - Buy + if (options?.getSubcommand() === "buy") { + // Execute Module - Buy + await buy(interaction); + } + + // Module - Cancel + if (options?.getSubcommand() === "cancel") { + // Execute Module - Cancel + await cancel(interaction); + } + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); +}; diff --git a/src/commands/shop/roles/modules/buy.ts b/src/commands/shop/roles/modules/buy.ts new file mode 100644 index 0000000..8ec08da --- /dev/null +++ b/src/commands/shop/roles/modules/buy.ts @@ -0,0 +1,99 @@ +// Dependencies +import { + CommandInteraction, + ColorResolvable, + GuildMemberRoleManager, +} from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +// Models +import userSchema from "../../../../helpers/database/models/userSchema"; +import shopRolesSchema from "../../../../helpers/database/models/shopRolesSchema"; +import guildSchema from "../../../../helpers/database/models/guildSchema"; + +// Helpers +import creditNoun from "../../../../helpers/creditNoun"; + +// Function +export default async (interaction: CommandInteraction) => { + const { options, guild, user, member } = interaction; + + const optionName = options?.getString("name"); + + // If amount is null + if (optionName === null) { + // Embed object + const embed = { + title: ":dollar: Shop - Roles [Buy]" as string, + description: "We could not read your requested name." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + await guild?.roles + .create({ + name: optionName, + color: "RED", + reason: `${user?.id} bought from shop`, + }) + .then(async (role) => { + // Get guild object + const guildDB = await guildSchema?.findOne({ + guildId: guild?.id, + }); + + const userDB = await userSchema?.findOne({ + userId: user?.id, + guildId: guild?.id, + }); + + const { pricePerHour } = guildDB?.shop?.roles; + + userDB.credits -= pricePerHour; + + await userDB?.save(); + + await shopRolesSchema?.create({ + roleId: role?.id, + userId: user?.id, + guildId: guild?.id, + pricePerHour, + lastPayed: new Date(), + }); + + await (member?.roles as GuildMemberRoleManager)?.add(role?.id); + await shopRolesSchema?.find()?.then((role: any) => console.log(role)); + + const embed = { + title: ":shopping_cart: Shop - Roles [Buy]" as string, + description: + `You have bought ${role?.name} for ${guildDB?.shop?.roles?.pricePerHour} per hour.` as string, + color: config?.colors?.success as ColorResolvable, + fields: [ + { + name: "Your balance" as string, + value: `${creditNoun(userDB?.credits)}` as string, + }, + ], + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + return interaction?.editReply({ + embeds: [embed], + }); + }) + .catch(console.error); +}; diff --git a/src/commands/shop/roles/modules/cancel.ts b/src/commands/shop/roles/modules/cancel.ts new file mode 100644 index 0000000..c8d637d --- /dev/null +++ b/src/commands/shop/roles/modules/cancel.ts @@ -0,0 +1,87 @@ +// Dependencies +import { + CommandInteraction, + ColorResolvable, + GuildMemberRoleManager, +} from "discord.js"; + +// Configurations +import config from "../../../../../config.json"; + +// Models +import userSchema from "../../../../helpers/database/models/userSchema"; +import shopRolesSchema from "../../../../helpers/database/models/shopRolesSchema"; + +// Helpers +import creditNoun from "../../../../helpers/creditNoun"; + +// Function +export default async (interaction: CommandInteraction) => { + const { options, guild, user, member } = interaction; + + const optionRole = options.getRole("role"); + + // If amount is null + if (optionRole === null) { + // Embed object + const embed = { + title: ":dollar: Shop - Roles [Cancel]" as string, + description: "We could not read your requested role." as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + return await interaction?.editReply({ embeds: [embed] }); + } + + const roleExist = await shopRolesSchema?.find({ + guildId: guild?.id, + userId: user?.id, + roleId: optionRole?.id, + }); + + if (roleExist) { + await (member?.roles as GuildMemberRoleManager)?.remove(optionRole?.id); + + await guild?.roles + .delete(optionRole?.id, `${user?.id} canceled from shop`) + .then(async () => { + const userDB = await userSchema?.findOne({ + userId: user?.id, + guildId: guild?.id, + }); + + await shopRolesSchema?.deleteOne({ + roleId: optionRole?.id, + userId: user?.id, + guildId: guild?.id, + }); + + const embed = { + title: ":shopping_cart: Shop - Roles [Cancel]" as string, + description: `You have canceled ${optionRole.name}.` as string, + color: config?.colors?.success as ColorResolvable, + fields: [ + { + name: "Your balance" as string, + value: `${creditNoun(userDB?.credits)}` as string, + }, + ], + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + return interaction?.editReply({ + embeds: [embed], + }); + }) + .catch(console.error); + } +}; diff --git a/src/commands/utilities/addons/about.ts b/src/commands/utilities/addons/about.ts deleted file mode 100644 index d0d4d48..0000000 --- a/src/commands/utilities/addons/about.ts +++ /dev/null @@ -1,18 +0,0 @@ -import config from '../../../../config.json'; -import { CommandInteraction } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - const interactionEmbed = { - title: ':hammer: Utilities - About', - description: `This bot is hosted by ${ - config.hoster.url - ? `[${config.hoster.name}](${config.hoster.url})` - : `${config.hoster.name}` - }, the bot is developed by [Zyner](https://github.com/ZynerOrg)! - - If you are interested in contributing, then just [fork it](https://github.com/ZynerOrg/xyter) yourself, we :heart: Open Source.`, - color: config.colors.success as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - interaction.editReply({ embeds: [interactionEmbed] }); -}; diff --git a/src/commands/utilities/addons/index.ts b/src/commands/utilities/addons/index.ts deleted file mode 100644 index 1eb5b45..0000000 --- a/src/commands/utilities/addons/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import lookup from './lookup'; -import about from './about'; -import stats from './stats'; - -export default { lookup, about, stats }; diff --git a/src/commands/utilities/addons/lookup.ts b/src/commands/utilities/addons/lookup.ts deleted file mode 100644 index 4183509..0000000 --- a/src/commands/utilities/addons/lookup.ts +++ /dev/null @@ -1,87 +0,0 @@ -import axios from 'axios'; -import config from '../../../../config.json'; -import logger from '../../../handlers/logger'; -import { CommandInteraction } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - try { - // Get lookup query - const query = await interaction.options.getString('query'); - - // Make API request - await axios - // Make a get request - .get(`http://ip-api.com/json/${query}`) - - // If successful - .then(async (res) => { - // If query failed - if (res.data.status === 'fail') { - // Create embed object - const embed = { - title: ':hammer: Utilities - Lookup', - description: `${res.data.message}: ${res.data.query}`, - color: config.colors.error as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - } - - // If query is successful - else if (res.data.status === 'success') { - // Create embed object - const embed = { - title: ':hammer: Utilities - Lookup', - fields: [ - { name: 'AS', value: `${res.data.as || 'Not available'}` }, - { - name: 'Country', - value: `${res.data.country || 'Not available'}`, - }, - { - name: 'Country Code', - value: `${res.data.countryCode || 'Not available'}`, - }, - { - name: 'Region', - value: `${res.data.region || 'Not available'}`, - }, - { - name: 'Region Name', - value: `${res.data.regionName || 'Not available'}`, - }, - { name: 'City', value: `${res.data.city || 'Not available'}` }, - { name: 'ZIP Code', value: `${res.data.zip || 'Not available'}` }, - { name: 'Latitude', value: `${res.data.lat || 'Not available'}` }, - { - name: 'Longitude', - value: `${res.data.lon || 'Not available'}`, - }, - { - name: 'Timezone', - value: `${res.data.timezone || 'Not available'}`, - }, - { name: 'ISP', value: `${res.data.isp || 'Not available'}` }, - { - name: 'Organization', - value: `${res.data.org || 'Not available'}`, - }, - ], - color: config.colors.success as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - - // Send interaction reply - await interaction.editReply({ embeds: [embed] }); - } - }) - .catch(async (e) => { - await logger.error(e); - }); - } catch (e) { - await logger.error(e); - } -}; diff --git a/src/commands/utilities/addons/stats.ts b/src/commands/utilities/addons/stats.ts deleted file mode 100644 index d73139f..0000000 --- a/src/commands/utilities/addons/stats.ts +++ /dev/null @@ -1,53 +0,0 @@ -import config from '../../../../config.json'; -import { CommandInteraction } from 'discord.js'; -export default async (interaction: CommandInteraction) => { - if (interaction?.client?.uptime === null) return; - let totalSeconds = interaction?.client?.uptime / 1000; - const days = Math.floor(totalSeconds / 86400); - totalSeconds %= 86400; - const hours = Math.floor(totalSeconds / 3600); - totalSeconds %= 3600; - const minutes = Math.floor(totalSeconds / 60); - const seconds = Math.floor(totalSeconds % 60); - - const uptime = `${days} days, ${hours} hours, ${minutes} minutes and ${seconds} seconds`; - - const interactionEmbed = { - title: ':hammer: Utilities - Stats', - description: 'Below you can see a list of statistics about the bot.', - fields: [ - { - name: '⏰ Latency', - value: `${Date.now() - interaction.createdTimestamp} ms`, - inline: true, - }, - { - name: '⏰ API Latency', - value: `${Math.round(interaction.client.ws.ping)} ms`, - inline: true, - }, - { - name: '⏰ Uptime', - value: `${uptime}`, - inline: false, - }, - { - name: '📈 Guilds', - value: `${interaction.client.guilds.cache.size}`, - inline: true, - }, - { - name: '📈 Users (non-unique)', - value: `${interaction.client.guilds.cache.reduce( - (acc, guild) => acc + guild.memberCount, - 0 - )}`, - inline: true, - }, - ], - color: config.colors.success as any, - timestamp: new Date(), - footer: { iconURL: config.footer.icon, text: config.footer.text }, - }; - interaction.editReply({ embeds: [interactionEmbed] }); -}; diff --git a/src/commands/utilities/index.ts b/src/commands/utilities/index.ts index cbb3723..4170650 100644 --- a/src/commands/utilities/index.ts +++ b/src/commands/utilities/index.ts @@ -1,46 +1,64 @@ -import { SlashCommandBuilder } from '@discordjs/builders'; -import lookup from './addons/lookup'; -import about from './addons/about'; -import stats from './addons/stats'; -import { CommandInteraction } from 'discord.js'; -export default { - data: new SlashCommandBuilder() - .setName('utilities') - .setDescription('Common utilities.') - .addSubcommand((subcommand) => - subcommand - .setName('lookup') - .setDescription( - 'Lookup a domain or ip. (Request sent over HTTP, proceed with caution!)' - ) - .addStringOption((option) => - option - .setName('query') - .setDescription('The query you want to look up.') - .setRequired(true) - ) - ) - .addSubcommand((subcommand) => - subcommand.setName('about').setDescription('About this bot!)') - ) - .addSubcommand((subcommand) => - subcommand.setName('stats').setDescription('Check bot statistics!)') - ), - async execute(interaction: CommandInteraction) { - // If subcommand is lookup - if (interaction.options.getSubcommand() === 'lookup') { - // Execute lookup addon - await lookup(interaction); - } - // If subcommand is about - else if (interaction.options.getSubcommand() === 'about') { - // Execute about addon - await about(interaction); - } - // If subcommand is stats - else if (interaction.options.getSubcommand() === 'stats') { - // Execute stats addon - await stats(interaction); - } - }, -}; +// Dependencies +import { SlashCommandBuilder } from "@discordjs/builders"; +import { CommandInteraction } from "discord.js"; + +// Modules +import lookup from "./modules/lookup"; +import about from "./modules/about"; +import stats from "./modules/stats"; + +// Handlers +import logger from "../../handlers/logger"; + +// Function +export default { + data: new SlashCommandBuilder() + .setName("utilities") + .setDescription("Common utilities.") + .addSubcommand((subcommand) => + subcommand + .setName("lookup") + .setDescription( + "Lookup a domain or ip. (Request sent over HTTP, proceed with caution!)" + ) + .addStringOption((option) => + option + .setName("query") + .setDescription("The query you want to look up.") + .setRequired(true) + ) + ) + .addSubcommand((subcommand) => + subcommand.setName("about").setDescription("About this bot!)") + ) + .addSubcommand((subcommand) => + subcommand.setName("stats").setDescription("Check bot statistics!)") + ), + async execute(interaction: CommandInteraction) { + // Destructure + const { options, guild, user, commandName } = interaction; + + // Module - Lookup + if (options?.getSubcommand() === "lookup") { + // Execute Module - Lookup + return await lookup(interaction); + } + // Module - About + else if (options?.getSubcommand() === "about") { + // Execute Module - About + return await about(interaction); + } + // Module - Stats + else if (options?.getSubcommand() === "stats") { + // Execute Module - Stats + return await stats(interaction); + } + + // Send debug message + return logger?.debug( + `Guild: ${guild?.id} User: ${ + user?.id + } executed /${commandName} ${options?.getSubcommandGroup()} ${options?.getSubcommand()}` + ); + }, +}; diff --git a/src/commands/utilities/modules/about.ts b/src/commands/utilities/modules/about.ts new file mode 100644 index 0000000..40f4e9b --- /dev/null +++ b/src/commands/utilities/modules/about.ts @@ -0,0 +1,26 @@ +// Dependencies +import { CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../config.json"; + +// Function +export default async (interaction: CommandInteraction) => { + const interactionEmbed = { + title: ":hammer: Utilities [About]" as string, + description: `This bot is hosted by ${ + config?.hoster?.url + ? `[${config?.hoster?.name}](${config?.hoster?.url})` + : `${config?.hoster?.name}` + }, the bot is developed by [Zyner](https://github.com/ZynerOrg)! + + If you are interested in contributing, then just [fork it](https://github.com/ZynerOrg/xyter) yourself, we :heart: Open Source.` as string, + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + interaction?.editReply({ embeds: [interactionEmbed] }); +}; diff --git a/src/commands/utilities/modules/lookup.ts b/src/commands/utilities/modules/lookup.ts new file mode 100644 index 0000000..0a12893 --- /dev/null +++ b/src/commands/utilities/modules/lookup.ts @@ -0,0 +1,112 @@ +// Dependencies +import axios from "axios"; +import { CommandInteraction, ColorResolvable } from "discord.js"; + +// Configurations +import config from "../../../../config.json"; + +// Handlers +import logger from "../../../handlers/logger"; + +// Function +export default async (interaction: CommandInteraction) => { + const { options } = interaction; + // Get lookup query + const query = options?.getString("query"); + + // Make API request + await axios + // Make a get request + ?.get(`http://ip-api.com/json/${query}`) + + // If successful + ?.then(async (res) => { + // If query failed + if (res?.data?.status === "fail") { + // Create embed object + const embed = { + title: ":hammer: Utilities - Lookup" as string, + description: `${res?.data?.message}: ${res?.data?.query}` as string, + color: config?.colors?.error as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + await interaction?.editReply({ embeds: [embed] }); + } + + // If query is successful + else if (res?.data?.status === "success") { + // Create embed object + const embed = { + title: ":hammer: Utilities - Lookup" as string, + fields: [ + { + name: "AS" as string, + value: `${res?.data?.as || "Not available"}` as string, + }, + { + name: "Country" as string, + value: `${res?.data?.country || "Not available"}` as string, + }, + { + name: "Country Code" as string, + value: `${res?.data?.countryCode || "Not available"}` as string, + }, + { + name: "Region" as string, + value: `${res?.data?.region || "Not available"}` as string, + }, + { + name: "Region Name" as string, + value: `${res?.data?.regionName || "Not available"}` as string, + }, + { + name: "City" as string, + value: `${res?.data?.city || "Not available"}` as string, + }, + { + name: "ZIP Code" as string, + value: `${res?.data?.zip || "Not available"}` as string, + }, + { + name: "Latitude" as string, + value: `${res?.data?.lat || "Not available"}` as string, + }, + { + name: "Longitude" as string, + value: `${res?.data?.lon || "Not available"}` as string, + }, + { + name: "Timezone" as string, + value: `${res?.data?.timezone || "Not available"}` as string, + }, + { + name: "ISP" as string, + value: `${res?.data?.isp || "Not available"}` as string, + }, + { + name: "Organization" as string, + value: `${res?.data?.org || "Not available"}` as string, + }, + ], + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + + // Send interaction reply + await interaction?.editReply({ embeds: [embed] }); + } + }) + .catch(async (e) => { + logger?.error(e); + }); +}; diff --git a/src/commands/utilities/modules/stats.ts b/src/commands/utilities/modules/stats.ts new file mode 100644 index 0000000..bba06ba --- /dev/null +++ b/src/commands/utilities/modules/stats.ts @@ -0,0 +1,58 @@ +import config from "../../../../config.json"; +import { CommandInteraction, ColorResolvable } from "discord.js"; +export default async (interaction: CommandInteraction) => { + const { client } = interaction; + if (client?.uptime === null) return; + let totalSeconds = client?.uptime / 1000; + const days = Math?.floor(totalSeconds / 86400); + totalSeconds %= 86400; + const hours = Math?.floor(totalSeconds / 3600); + totalSeconds %= 3600; + const minutes = Math?.floor(totalSeconds / 60); + const seconds = Math?.floor(totalSeconds % 60); + + const uptime = `${days} days, ${hours} hours, ${minutes} minutes and ${seconds} seconds`; + + const interactionEmbed = { + title: ":hammer: Utilities - Stats" as string, + description: + "Below you can see a list of statistics about the bot." as string, + fields: [ + { + name: "⏰ Latency" as string, + value: `${Date?.now() - interaction?.createdTimestamp} ms` as string, + inline: true, + }, + { + name: "⏰ API Latency" as string, + value: `${Math?.round(client?.ws?.ping)} ms` as string, + inline: true, + }, + { + name: "⏰ Uptime" as string, + value: `${uptime}` as string, + inline: false, + }, + { + name: "📈 Guilds" as string, + value: `${client?.guilds?.cache?.size}` as string, + inline: true, + }, + { + name: "📈 Users (non-unique)" as string, + value: `${client?.guilds?.cache?.reduce( + (acc, guild) => acc + guild?.memberCount, + 0 + )}` as string, + inline: true, + }, + ], + color: config?.colors?.success as ColorResolvable, + timestamp: new Date() as Date, + footer: { + iconURL: config?.footer?.icon as string, + text: config?.footer?.text as string, + }, + }; + interaction?.editReply({ embeds: [interactionEmbed] }); +};