diff --git a/events/interactions/logBtnsCmds.js b/events/interactions/logBtnsCmds.js new file mode 100644 index 0000000..fa946d0 --- /dev/null +++ b/events/interactions/logBtnsCmds.js @@ -0,0 +1,21 @@ +module.exports = { + name: "logBtnsCmds", + description: "Logs all button and command interactions", + type: "interaction", + + /** @param { import('discord.js').ChatInputCommandInteraction } interaction */ + + execute(interaction) { + if (interaction.isCommand()) { + console.log(interaction.user.username + "#" + + interaction.user.discriminator + " ran " + + interaction.commandName + ); + } else if (interaction.isButton()) { + console.log(interaction.user.username + "#" + + interaction.user.discriminator + " clicked " + + interaction.customId + ); + } + } +} diff --git a/events/ready/consolelog.js b/events/ready/consolelog.js new file mode 100644 index 0000000..45e3ea4 --- /dev/null +++ b/events/ready/consolelog.js @@ -0,0 +1,10 @@ +module.exports = { + name: 'conolelog', + description: "console log", + type: 'ready', + + /** @param { import('discord.js').Client } client */ + execute(client) { + console.log("Logged in as " + client.user.tag + "!"); + } +} diff --git a/events/ready/sendOnlineMessage.js b/events/ready/sendOnlineMessage.js new file mode 100644 index 0000000..f3b6283 --- /dev/null +++ b/events/ready/sendOnlineMessage.js @@ -0,0 +1,27 @@ +const { Events } = require('discord.js'); +const { botLogChannel, color } = require('../../config/options.json'); + +module.exports = { + name: 'sendonlinemessage', + description: "send an online message", + type: 'ready', + + execute(client) { + if (process.env.NODE_ENV !== 'dev') { + console.log("Logged in as " + client.user.tag + "!"); + const channel = client.channels.cache.get(botLogChannel); + const embedColor = Number(color.replace('#', '0x')) + + if (!channel) { + return; + } + + channel.send({ + embeds: [{ + description: `Bot is online!`, + color: embedColor + }] + }); + } + } +} diff --git a/events/ready/status.js b/events/ready/status.js new file mode 100644 index 0000000..e361d25 --- /dev/null +++ b/events/ready/status.js @@ -0,0 +1,36 @@ +const { Events, ActivityType } = require('discord.js'); + +module.exports = { + name: 'status', + description: 'Sets the status of the bot', + type: 'ready', + + /** @param { import('discord.js').Client } client */ + execute(client) { + client.user.setActivity( + { name: "over the Illegitimate Server", type: ActivityType.Watching } + ); + + const activities = [ + { name: "for Martina's return", type: ActivityType.Watching }, + { name: "w vri's feelings", type: ActivityType.Playing }, + { name: "urCryhard steal finals again", type: ActivityType.Watching }, + { name: "with Perlcence the AI", type: ActivityType.Playing }, + { name: "with ur mom in my bed", type: ActivityType.Playing }, + { name: "with Jone the idiot", type: ActivityType.Playing }, + { name: "over the Illegitimate Server", type: ActivityType.Watching } + ]; + + let i = 0; + setInterval(() => + client.user.setActivity( + activities[i++ % activities.length] + ), + 1000 * 60 * 30 + ) + + client.on(Events.ClientReady, () => { + client.user.setStatus('dnd'); + }); + } +} diff --git a/index.js b/index.js index a5a466b..e8958bb 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,8 @@ const { Client, GatewayIntentBits, Partials, ActivityType, Events, Collection } = require('discord.js'); -const { botLogChannel, color } = require('./config/options.json'); +const { loadSlashCommands, loadMessageEvents, loadContextMenu, loadModalEvents, loadButtonEvents, loadReadyEvents, loadInteractionEvents } = require('./utils/eventHandler.js') require('dotenv').config(); const mongoURI = process.env.MONGOURI; const { connect } = require('mongoose'); -const path = require('path'); -const fs = require('fs'); if (process.env.NODE_ENV === 'dev') { console.log("Running in development mode."); @@ -34,231 +32,13 @@ client.commands = new Collection(); client.events = new Collection(); client.modals = new Collection(); -//! commands -const cmdPath = path.join(__dirname, 'commands'); -const cmdFiles = fs.readdirSync(cmdPath).filter(file => file.endsWith('.js')); - -for (const file of cmdFiles) { - - const filePath = path.join(cmdPath, file); - const cmd = require(filePath); - - if ('data' in cmd && 'execute' in cmd && cmd.type === 'slash') { - client.commands.set(cmd.data.name, cmd); - } else { - console.log(`[WARNING] The command at ${filePath} is missing a required "data", "execute" or "type" property.`); - } -} - -//! commands testing -const cmdTestPath = path.join(__dirname, 'commands-testing'); -const cmdTestFiles = fs.readdirSync(cmdTestPath).filter(file => file.endsWith('.js')); - -for (const file of cmdTestFiles) { - - const filePath = path.join(cmdTestPath, file); - const cmd = require(filePath); - - if ('data' in cmd && 'execute' in cmd && cmd.type === 'slash') { - client.commands.set(cmd.data.name, cmd); - } else { - console.log(`[WARNING] The command at ${filePath} is missing a required "data", "execute" or "type" property.`); - } -} - -//! command handler -client.on(Events.InteractionCreate, async interaction => { - if (!interaction.isChatInputCommand()) - return; - - const command = interaction.client.commands.get(interaction.commandName); - - if (!command) { - console.error(`No command matching ${interaction.commandName} was found.`); - return; - } - - try { - await command.execute(interaction); - } catch (error) { - console.error(error); - await interaction.reply({ - content: 'There was an error while executing this command!', - ephemeral: true - }) - } -}); - -//! commands -const contextMenuPath = path.join(__dirname, 'commands-contextmenu'); -const contextMenuFiles = fs.readdirSync(contextMenuPath).filter(file => file.endsWith('.js')); - -for (const file of contextMenuFiles) { - - const filePath = path.join(contextMenuPath, file); - const cmd = require(filePath); - - if ('data' in cmd && 'execute' in cmd && cmd.type === 'contextmenu') { - client.commands.set(cmd.data.name, cmd); - } else { - console.log(`[WARNING] The command at ${filePath} is missing a required "data", "execute" or "type" property.`); - } -} - -//! context menu command handler -client.on(Events.InteractionCreate, async interaction => { - if (!interaction.isContextMenuCommand()) - return; - - const command = interaction.client.commands.get(interaction.commandName); - - if (!command) { - console.error(`No command matching ${interaction.commandName} was found.`); - return; - } - - try { - await command.execute(interaction); - } catch (error) { - console.error(error); - await interaction.reply({ - content: 'There was an error while executing this command!', - ephemeral: true - }) - } -}); - -//! button events -const btnPath = path.join(__dirname, 'events', 'buttons'); -const btnFiles = fs.readdirSync(btnPath).filter(file => file.endsWith('.js')); - -for (const file of btnFiles) { - - const filePath = path.join(btnPath, file); - const btn = require(filePath); - - if ('name' in btn && 'execute' in btn && btn.type === 'button') { - client.events.set(btn.name, btn); - } else { - console.log(`[WARNING] The button at ${filePath} is missing a required "name", "execute" or "type" property.`); - } -} - -//! button event handler -client.on(Events.InteractionCreate, async event => { - if (!event.isButton()) - return; - - const event2 = event.client.events.get(event.customId); - - if (!event2) { - console.error(`No event matching ${event.customId} was found.`); - return; - } - - try { - await event2.execute(event); - } catch (error) { - console.error(error); - await event.reply({ - content: 'There was an error while executing this event!', - ephemeral: true - }) - } -}) - -//! modals -const modalPath = path.join(__dirname, 'events', 'modals'); -const modalFiles = fs.readdirSync(modalPath).filter(file => file.endsWith('.js')); - -for (const file of modalFiles) { - - const filePath = path.join(modalPath, file); - const modal = require(filePath); - - if ('name' in modal && 'execute' in modal && modal.type === 'modal') { - client.on(Events.InteractionCreate, modal.execute); - } else { - console.log(`[WARNING] The modal at ${filePath} is missing a required "name", "execute" or "type" property.`); - } -} - -client.on(Events.InteractionCreate, async interaction => { - if (interaction.isCommand()) { - console.log(interaction.user.username + "#" + - interaction.user.discriminator + " ran " + - interaction.commandName - ); - } else if (interaction.isButton()) { - console.log(interaction.user.username + "#" + - interaction.user.discriminator + " clicked " + - interaction.customId - ); - } -}); - -client.on(Events.ClientReady, () => { - if (process.env.NODE_ENV !== 'dev') { - console.log("Logged in as " + client.user.tag + "!"); - const channel = client.channels.cache.get(botLogChannel); - const embedColor = Number(color.replace('#', '0x')) - - if (!channel) { - return; - } - - channel.send({ - embeds: [{ - description: `Bot is online!`, - color: embedColor - }] - }); - } -}); - -// message files -const messagePath = path.join(__dirname, 'events', 'messages'); -const messageFiles = fs.readdirSync(messagePath).filter(file => file.endsWith('.js')); - -for (const file of messageFiles) { - - const filePath = path.join(messagePath, file); - const message = require(filePath); - - if (message.type === 'message') { - client.on(Events.MessageCreate, message.execute); - } else { - console.log(`[WARNING] The message at ${filePath} is missing a required "type" property.`); - } -} - -client.on(Events.ClientReady, () => { - client.user.setActivity( - { name: "over the Illegitimate Server", type: ActivityType.Watching } - ); - - const activities = [ - { name: "for Martina's return", type: ActivityType.Watching }, - { name: "w vri's feelings", type: ActivityType.Playing }, - { name: "urCryhard steal finals again", type: ActivityType.Watching }, - { name: "with Perlcence the AI", type: ActivityType.Playing }, - { name: "with ur mom in my bed", type: ActivityType.Playing }, - { name: "with Jone the idiot", type: ActivityType.Playing }, - { name: "over the Illegitimate Server", type: ActivityType.Watching } - ]; - - let i = 0; - setInterval(() => - client.user.setActivity( - activities[i++ % activities.length] - ), - 1000 * 60 * 30 - ) -}); - -client.on(Events.ClientReady, () => { - client.user.setStatus('dnd'); -}); +loadSlashCommands(client); +loadContextMenu(client); +loadButtonEvents(client); +loadModalEvents(client); +loadMessageEvents(client); +loadReadyEvents(client) +loadInteractionEvents(client); client.login(token); diff --git a/utils/eventHandler.js b/utils/eventHandler.js new file mode 100644 index 0000000..990ebc7 --- /dev/null +++ b/utils/eventHandler.js @@ -0,0 +1,9 @@ +const { loadButtonEvents } = require('./eventHandlers/button.js') +const { loadSlashCommands } = require('./eventHandlers/command.js') +const { loadContextMenu } = require('./eventHandlers/contextmenu.js') +const { loadMessageEvents } = require('./eventHandlers/message.js') +const { loadModalEvents } = require('./eventHandlers/modal.js') +const { loadReadyEvents } = require('./eventHandlers/ready.js') +const { loadInteractionEvents } = require('./eventHandlers/interaction.js') + +module.exports = { loadSlashCommands, loadButtonEvents, loadContextMenu, loadMessageEvents, loadModalEvents, loadReadyEvents, loadInteractionEvents } diff --git a/utils/eventHandlers/button.js b/utils/eventHandlers/button.js new file mode 100644 index 0000000..4b7b58c --- /dev/null +++ b/utils/eventHandlers/button.js @@ -0,0 +1,46 @@ +const { Events } = require('discord.js') +const path = require('path'); +const fs = require('fs'); + +/** @param { import('discord.js').Client } client */ + +function loadButtonEvents(client) { + const btnPath = path.join(__dirname, '..', '..', 'events', 'buttons'); + const btnFiles = fs.readdirSync(btnPath).filter(file => file.endsWith('.js')); + + for (const file of btnFiles) { + + const filePath = path.join(btnPath, file); + const btn = require(filePath); + + if ('name' in btn && 'execute' in btn && btn.type === 'button') { + client.events.set(btn.name, btn); + } else { + console.log(`[WARNING] The button at ${filePath} is missing a required "name", "execute" or "type" property.`); + } + } + + client.on(Events.InteractionCreate, async event => { + if (!event.isButton()) + return; + + const event2 = event.client.events.get(event.customId); + + if (!event2) { + console.error(`No event matching ${event.customId} was found.`); + return; + } + + try { + await event2.execute(event); + } catch (error) { + console.error(error); + await event.reply({ + content: 'There was an error while executing this event!', + ephemeral: true + }) + } + }) +} + +module.exports = { loadButtonEvents } diff --git a/utils/eventHandlers/command.js b/utils/eventHandlers/command.js new file mode 100644 index 0000000..60830e1 --- /dev/null +++ b/utils/eventHandlers/command.js @@ -0,0 +1,63 @@ +const { Events } = require('discord.js') +const path = require('path'); +const fs = require('fs'); + +/** @param { import('discord.js').Client } client */ + +function loadSlashCommands(client) { + const cmdPath = path.join(__dirname, '..', '..', 'commands'); + const cmdFiles = fs.readdirSync(cmdPath).filter(file => file.endsWith('.js')); + + for (const file of cmdFiles) { + + const filePath = path.join(cmdPath, file); + const cmd = require(filePath); + + if ('data' in cmd && 'execute' in cmd && cmd.type === 'slash') { + client.commands.set(cmd.data.name, cmd); + } else { + console.log(`[WARNING] The command at ${filePath} is missing a required "data", "execute" or "type" property.`); + } + } + + //! commands testing + const cmdTestPath = path.join(__dirname, '..', '..', 'commands-testing'); + const cmdTestFiles = fs.readdirSync(cmdTestPath).filter(file => file.endsWith('.js')); + + for (const file of cmdTestFiles) { + + const filePath = path.join(cmdTestPath, file); + const cmd = require(filePath); + + if ('data' in cmd && 'execute' in cmd && cmd.type === 'slash') { + client.commands.set(cmd.data.name, cmd); + } else { + console.log(`[WARNING] The command at ${filePath} is missing a required "data", "execute" or "type" property.`); + } + } + + //! command handler + client.on(Events.InteractionCreate, async interaction => { + if (!interaction.isChatInputCommand()) + return; + + const command = interaction.client.commands.get(interaction.commandName); + + if (!command) { + console.error(`No command matching ${interaction.commandName} was found.`); + return; + } + + try { + await command.execute(interaction); + } catch (error) { + console.error(error); + await interaction.reply({ + content: 'There was an error while executing this command!', + ephemeral: true + }) + } + }) +} + +module.exports = { loadSlashCommands } diff --git a/utils/eventHandlers/contextmenu.js b/utils/eventHandlers/contextmenu.js new file mode 100644 index 0000000..5ed8fe7 --- /dev/null +++ b/utils/eventHandlers/contextmenu.js @@ -0,0 +1,47 @@ +const { Events } = require('discord.js') +const path = require('path'); +const fs = require('fs'); + +/** @param { import('discord.js').Client } client */ + +function loadContextMenu(client) { + const contextMenuPath = path.join(__dirname, '..', '..', 'commands-contextmenu'); + const contextMenuFiles = fs.readdirSync(contextMenuPath).filter(file => file.endsWith('.js')); + + for (const file of contextMenuFiles) { + + const filePath = path.join(contextMenuPath, file); + const cmd = require(filePath); + + if ('data' in cmd && 'execute' in cmd && cmd.type === 'contextmenu') { + client.commands.set(cmd.data.name, cmd); + } else { + console.log(`[WARNING] The command at ${filePath} is missing a required "data", "execute" or "type" property.`); + } + } + + //! context menu command handler + client.on(Events.InteractionCreate, async interaction => { + if (!interaction.isContextMenuCommand()) + return; + + const command = interaction.client.commands.get(interaction.commandName); + + if (!command) { + console.error(`No command matching ${interaction.commandName} was found.`); + return; + } + + try { + await command.execute(interaction); + } catch (error) { + console.error(error); + await interaction.reply({ + content: 'There was an error while executing this command!', + ephemeral: true + }) + } + }) +} + +module.exports = { loadContextMenu } diff --git a/utils/eventHandlers/interaction.js b/utils/eventHandlers/interaction.js new file mode 100644 index 0000000..1af8b5b --- /dev/null +++ b/utils/eventHandlers/interaction.js @@ -0,0 +1,23 @@ +const { Events } = require('discord.js') +const path = require('path'); +const fs = require('fs'); + +/** @param { import('discord.js').Client } client */ + +function loadInteractionEvents(client) { + const interactionsPath = path.join(__dirname, '..', '..', 'events', 'interactions') + const interactionsFiles = fs.readdirSync(interactionsPath).filter(file => file.endsWith('.js')); + + for (const file of interactionsFiles) { + const filePath = path.join(interactionsPath, file); + const interactionFile = require(filePath); + + if ('name' in interactionFile && 'execute' in interactionFile && interactionFile.type === 'interaction') { + client.on(Events.InteractionCreate, interactionFile.execute) + } else { + console.log(`[WARNING] The interactions event at ${filePath} is missing a required "name", "execute" or "type" property.`); + } + } +} + +module.exports = { loadInteractionEvents } diff --git a/utils/eventHandlers/message.js b/utils/eventHandlers/message.js new file mode 100644 index 0000000..249b5ed --- /dev/null +++ b/utils/eventHandlers/message.js @@ -0,0 +1,24 @@ +const { Events } = require('discord.js') +const path = require('path'); +const fs = require('fs'); + +/** @param { import('discord.js').Client } client */ + +function loadMessageEvents(client) { + const messagePath = path.join(__dirname, '..', '..', 'events', 'messages'); + const messageFiles = fs.readdirSync(messagePath).filter(file => file.endsWith('.js')); + + for (const file of messageFiles) { + + const filePath = path.join(messagePath, file); + const message = require(filePath); + + if (message.type === 'message') { + client.on(Events.MessageCreate, message.execute); + } else { + console.log(`[WARNING] The message at ${filePath} is missing a required "type" property.`); + } + } +} + +module.exports = { loadMessageEvents } diff --git a/utils/eventHandlers/modal.js b/utils/eventHandlers/modal.js new file mode 100644 index 0000000..5c2bd56 --- /dev/null +++ b/utils/eventHandlers/modal.js @@ -0,0 +1,24 @@ +const { Events } = require('discord.js') +const path = require('path'); +const fs = require('fs'); + +/** @param { import('discord.js').Client } client */ + +function loadModalEvents(client) { + const modalPath = path.join(__dirname, '..', '..', 'events', 'modals'); + const modalFiles = fs.readdirSync(modalPath).filter(file => file.endsWith('.js')); + + for (const file of modalFiles) { + + const filePath = path.join(modalPath, file); + const modal = require(filePath); + + if ('name' in modal && 'execute' in modal && modal.type === 'modal') { + client.on(Events.InteractionCreate, modal.execute); + } else { + console.log(`[WARNING] The modal at ${filePath} is missing a required "name", "execute" or "type" property.`); + } + } +} + +module.exports = { loadModalEvents } diff --git a/utils/eventHandlers/ready.js b/utils/eventHandlers/ready.js new file mode 100644 index 0000000..282ba72 --- /dev/null +++ b/utils/eventHandlers/ready.js @@ -0,0 +1,23 @@ +const { Events } = require('discord.js') +const path = require('path'); +const fs = require('fs'); + +/** @param { import('discord.js').Client } client */ + +function loadReadyEvents(client) { + const readyPath = path.join(__dirname, '..', '..', 'events', 'ready') + const readyFiles = fs.readdirSync(readyPath).filter(file => file.endsWith('.js')); + + for (const file of readyFiles) { + const filePath = path.join(readyPath, file); + const ready = require(filePath); + + if ('name' in ready && 'execute' in ready && ready.type === 'ready') { + client.on(Events.ClientReady, ready.execute) + } else { + console.log(`[WARNING] The ready event at ${filePath} is missing a required "name", "execute" or "type" property.`); + } + } +} + +module.exports = { loadReadyEvents }