diff --git a/bot/base/Command.js b/bot/base/Command.js deleted file mode 100644 index f8573bc..0000000 --- a/bot/base/Command.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = class Command { - constructor (name, category) { - // Gateway stuff - this.name = name, - this.description = "No description provided.", - this.options = [], - this.permissions = { - DEFAULT_MEMBER_PERMISSIONS: "SendMessages" - } - this.dm_permission = false, - // Extra stuff Woomy uses internally - this.category = category, - this.usage = "No usage information provided.", - this.friendlyOptions = "No options provided." - this.enabled = true, - this.devOnly = false, - this.cooldown = 2000 - } - - run (client, interaction, data) { //eslint-disable-line no-unused-vars - - } -}; \ No newline at end of file diff --git a/bot/commands/Bot/ping.js b/bot/commands/Bot/ping.js deleted file mode 100644 index 9bce46a..0000000 --- a/bot/commands/Bot/ping.js +++ /dev/null @@ -1,14 +0,0 @@ -const Command = require("../../base/Command.js"); - -module.exports = class Ping extends Command { - constructor (name, category) { - super (name, category) - this.name = name, - this.description = 'Check response time between Woomy and Discord', - this.category = category - } - - run (client, interaction, data) { //eslint-disable-line no-unused-vars - return interaction.reply('Pong! Did I do this right?'); - } -}; \ No newline at end of file diff --git a/bot/commands/Utility/avatar.js.du b/bot/commands/Utility/avatar.js similarity index 100% rename from bot/commands/Utility/avatar.js.du rename to bot/commands/Utility/avatar.js diff --git a/bot/commands/Utility/serverinfo.js b/bot/commands/Utility/serverinfo.js new file mode 100644 index 0000000..17dac6d --- /dev/null +++ b/bot/commands/Utility/serverinfo.js @@ -0,0 +1,34 @@ +module.exports = class { + constructor (name, category) { + this.name = name, + this.category = category, + this.enabled = true, + this.devOnly = false, + this.aliases = [], + this.userPerms = [], + this.botPerms = [], + this.cooldown = 2000, + this.help = { + description: '', + arguments: '', + details: '', + examples: '' + }; + } + + run (client, message, args, data) { //eslint-disable-line no-unused-vars + const guild = message.guild; + + const embed = new client.MessageEmbed() + .setColor(client.functions.embedColor(message.guild)) + .setTitle(guild.name) + .setThumbnail(guild.iconURL) + .addField('ID', guild.id, true) + .addField('Owner', `<@${guild.ownerId}>`, true) + .addField('Region', guild.region.toProperCase(), true) + .addField('Boosts', `${guild.premiumSubscriptionCount} (Level ${guild.premiumTier})`, true) + .addField('Member Count (Approximate)', `${guild.memberCount} (${guild.memberCount - guild.members.filter(member => member.user.bot).length} humans, ${guild.members.filter(member => member.user.bot).length} bots)`, true) + .addField('Channels', `${guild.channels.size} ()`) + message.channel.send({ embeds: [embed] }); + } +}; \ No newline at end of file diff --git a/bot/commands/Utility/userinfo.js b/bot/commands/Utility/userinfo.js new file mode 100644 index 0000000..69ca67d --- /dev/null +++ b/bot/commands/Utility/userinfo.js @@ -0,0 +1,78 @@ +const dayjs = require('dayjs'); +dayjs.extend(require('dayjs/plugin/relativeTime')); + +module.exports = class { + constructor (name, category) { + this.name = name, + this.category = category, + this.enabled = true, + this.devOnly = false, + this.aliases = ['user'], + this.userPerms = [], + this.botPerms = [], + this.cooldown = 2000, + this.help = { + description: 'Get information on a user.', + arguments: '[user]', + details: '', + examples: 'userinfo\nuserinfo Octavia\nuserinfo @Animals' + }; + } + + async run (client, message, args, data) { //eslint-disable-line no-unused-vars + let member = message.member; + + if (args[0]) { + if (message.mentions.length > 0) { + member = await message.guild.members.fetch(message.mentions[0].id) + } else { + member = await client.functions.validateUserID(message.guild, args[0]); + + if (!member) { + member = await message.guild.searchMembers(args.join(' '), 2); + + if (member.length === 0) return message.channel.send( + `${client.config.emojis.userError} No users found. Check for mispellings, or ping the user instead.` + ); + + if (member.length > 1) return message.channel.send( + `${client.config.emojis.userError} Found more than one user, try refining your search or pinging the user instead.` + ); + + member = member[0]; + } + } + } + + const badges = []; + + if (client.config.ownerIDs.includes(member.id)) badges.push('<:Woomy_Developer:816822318289518622> '); + if (member.id === member.guild.ownerId) badges.push('<:owner:685703193694306331>'); + if (member.bot) badges.push('<:bot:686489601678114859>'); + + const roles = []; + + for (const roleID of member.roles) { + if (roles.length === 45) { + roles.push(`and ${member.roles.length - 45} more`); + break; + } + + roles.push(`<@&${roleID}>`); + } + + const embed = new client.MessageEmbed() + .setTitle(member.user.username + '#' + member.user.discriminator) + .setColor(client.functions.embedColor(message.guild, member)) + .setThumbnail(member.user.avatarURL || member.user.defaultAvatarURL) + .addField('Display Name', member.nick || member.user.username, true) + .addField('User ID', member.id, true) + .addField('Highest Role', `<@&${client.functions.highestRole(member).id}>`, true) + .addField('Roles:', roles.join(' ')) + .addField('Joined Server', `${dayjs(member.joinedAt).format('D/M/YYYY HH:mm (UTCZ)')}\n*${dayjs().to(member.joinedAt)}*`, true) + .addField('Joined Discord', `${dayjs(member.user.createdAt).format('D/M/YYYY HH:mm (UTCZ)')}\n*${dayjs().to(member.user.createdAt)}*`, true); + if (badges.length > 0) embed.setDescription(badges.join(' ')); + + message.channel.send({ embeds: [embed] }); + } +}; \ No newline at end of file diff --git a/bot/commands/Utility/weather.js b/bot/commands/Utility/weather.js new file mode 100644 index 0000000..21d7f33 --- /dev/null +++ b/bot/commands/Utility/weather.js @@ -0,0 +1,85 @@ +const fetch = require('node-fetch'); +const windrose = require('windrose'); +const ISO2 = require('../../assets/ISO2.json'); + + +module.exports = class { + constructor (name, category) { + this.name = name, + this.category = category, + this.enabled = true, + this.devOnly = false, + this.aliases = [], + this.userPerms = [], + this.botPerms = [], + this.cooldown = 2000, + this.help = { + description: 'Gives you the weather for the specified city. You can also specify a country code with a comma.', + arguments: ', [code]', + details: '`` - name of a city\n`[code]` - country code (USA = US, Australia = AU, etc.)', + examples: 'w!weather Minneapolis\nw!weather Melbourne, AU' + }; + } + + async run (client, message, args, data) { //eslint-disable-line no-unused-vars + if (!args[0]) return; + + let city = args.join(' ').toProperCase(); + let countryCode = ','; + + if (args.join(' ').indexOf(',') > -1) { + const params = city.split(','); + city = params[0].trim().toProperCase(); + if (ISO2.country[params[1].toProperCase().trim()]) { + countryCode += ISO2.country[params[1].toProperCase().trim()]; + } else { + countryCode += params[1].trim(); + } + } + + const editMessage = await message.channel.send(`${client.config.emojis.loading} Please wait...`); + fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city + countryCode}&appid=${client.config.keys.weather}`, { headers: { 'User-Agent': client.config.userAgent }}) + .then(res => res.json()) + .then(json => { + if (json.cod >= 200 && json.cod <= 299) { + const tempCelcius = Math.round(json.main.temp - 273.15); + let embedColour; + if (tempCelcius < 0) { + embedColour = '#addeff'; + } else if (tempCelcius < 20) { + embedColour = '#4fb8ff'; + } else if (tempCelcius < 26) { + embedColour = '#ffea4f'; + } else if (tempCelcius < 31) { + embedColour = '#ffa14f'; + } else { + embedColour = '#ff614f'; + } + + const embed = new client.MessageEmbed() + .setTitle(`Weather for ${city + ', ' + ISO2.code[json.sys.country]}`) + .setThumbnail(`https://openweathermap.org/img/wn/${json.weather[0].icon}@4x.png`) + .setColor(embedColour) + .addField('Condition:', json.weather[0].main, true) + .addField('Temperature:', `${tempCelcius}°C | ${Math.round(json.main.temp * 9/5 - 459.67)}°F`, true) + .addField('Min/Max:', ` + ${Math.round(json.main.temp_min - 273.15)}°C - ${Math.round(json.main.temp_max - 273.15)}°C + ${Math.round(json.main.temp_min * 9/5 - 459.67)}°F - ${Math.round(json.main.temp_max * 9/5 - 459.67)}°F + `, true) + .addField('Humidity:', `${json.main.humidity}%`, true) + .addField('Wind Speed:', `${Math.round(json.wind.speed * 10) / 10}km/h | ${Math.round(json.wind.speed * 10 / 1.609344)}mi/h`, true) + .addField('Wind Direction:', windrose.getPoint(json.wind.deg).name, true) + .setFooter('Powered by openweathermap.org'); + return editMessage.edit({ content: null, embeds: [embed] }); + } else { + if (json.message && json.message === 'city not found') { + return message.channel.send(`${client.config.emojis.userError} You provided an invalid city name. Maybe check your spelling?`); + } + return message.channel.send(`${client.config.emojis.botError} API error occured: \`code ${json.cod}: ${json.message}\``); + } + }) + .catch(err => { + return message.channel.send(`${client.config.emojis.botError} An error has occured: \`${err.stack}\``); + }); + } +}; \ No newline at end of file diff --git a/bot/deploy.js b/bot/deploy.js deleted file mode 100644 index 6407f6b..0000000 --- a/bot/deploy.js +++ /dev/null @@ -1,36 +0,0 @@ -// taken from https://discordjs.guide/ - -const { REST, Routes } = require('discord.js'); -const { clientId, token } = require('../botconfig.json'); -const guildId = "413591792185769984"; -const read = require('fs-readdir-recursive'); -const commands = []; -const commandFiles = read('./commands').filter(file => file.endsWith('.js')); - -for (const file of commandFiles) { - const command = new (require(__dirname + '/commands/' + file))(file.substr(file.indexOf('/') + 1).slice(0, -3), file.substr(0, file.indexOf('/'))); - commands.push({ - name: command.name, - description: command.description, - options: command.options, - permissions: command.permissions, - dm_permission: command.dm_permission - }); -} - -const rest = new REST({ version: '10' }).setToken(token); - -(async () => { - try { - console.log(`Started refreshing ${commands.length} application (/) commands.`); - - const data = await rest.put( - Routes.applicationGuildCommands(clientId, guildId), - { body: commands }, - ); - - console.log(`Successfully reloaded ${data.length} application (/) commands.`); - } catch (error) { - console.error(error); - } -})(); diff --git a/bot/event_modules/eventHandler.js b/bot/event_modules/eventHandler.js index a0faafe..eb8f53e 100644 --- a/bot/event_modules/eventHandler.js +++ b/bot/event_modules/eventHandler.js @@ -15,49 +15,43 @@ class EventHandler { case 'error': { const errorModules = this.client.eventModules.filter(module => module.wsEvent === 'error'); - errorModules.forEach(module => module.run(this.client, param_1)); + errorModules.forEach(module => module.run(this.client, error)); break; } case 'messageCreate': { const mCreateModules = this.client.eventModules.filter(module => module.wsEvent === 'messageCreate'); - mCreateModules.forEach(module => module.run(this.client, param_1)); - break; - } - - case 'interactionCreate': { - const iCreateModules = this.client.eventModules.filter(module => module.wsEvent === 'interactionCreate'); - iCreateModules.forEach(module => module.run(this.client, param_1)); + mCreateModules.forEach(module => module.run(this.client, message)); break; } case 'guildCreate': { const gCreateModules = this.client.eventModules.filter(module => module.wsEvent === 'guildCreate'); - gCreateModules.forEach(module => module.run(this.client, param_1)); + gCreateModules.forEach(module => module.run(this.client, guild)); break; } case 'guildDelete': { const gDeleteModules = this.client.eventModules.filter(module => module.wsEvent === 'guildDelete'); - gDeleteModules.forEach(module => module.run(this.client, param_1)); + gDeleteModules.forEach(module => module.run(this.client, guild)); break; } case 'guildMemberAdd': { const gMemberAddModules = this.client.eventModules.filter(module => module.wsEvent === 'guildMemberAdd'); - gMemberAddModules.forEach(module => module.run(this.client, param_1, param_2)); + gMemberAddModules.forEach(module => module.run(this.client, guild, member)); break; } case 'guildMemberRemove': { const gMemberRemoveModules = this.client.eventModules.filter(module => module.wsEvent === 'guildMemberRemove'); - gMemberRemoveModules.forEach(module => module.run(this.client, param_1, param_2)); + gMemberRemoveModules.forEach(module => module.run(this.client, guild, member)); break; } case 'voiceStateUpdate': { const vStateUpdateModules = this.client.eventModules.filter(module => module.wsEvent === 'voiceStateUpdate'); - vStateUpdateModules.forEach(module => module.run(this.client, param_1, param_2)); + vStateUpdateModules.forEach(module => module.run(this.client, oVoiceState, nVoiceState)); break; } } diff --git a/bot/event_modules/interactionCreate/interactionHandler.js b/bot/event_modules/interactionCreate/interactionHandler.js index 50dc4ab..29da3c1 100644 --- a/bot/event_modules/interactionCreate/interactionHandler.js +++ b/bot/event_modules/interactionCreate/interactionHandler.js @@ -1,53 +1,121 @@ -module.exports = class { - constructor (wsEvent) { - this.wsEvent = wsEvent; +class MessageHandler { + constructor (client) { + this.client = client; } - async run (client, interaction) { - if (!interaction.isChatInputCommand()) return; + async handle (message) { + // Ignore messages from bots, and messages in DM's + if (message.author.bot) return; + if (!message.guild) return; // Request all the data we need from the database const data = {}; - data.user = await client.db.getUser(interaction.user.id); - data.guild = await client.db.getGuild(interaction.guild.id); - data.member = await client.db.getMember(interaction.guild.id, interaction.user.id); + data.user = await this.client.db.getUser(message.author.id); + data.guild = await this.client.db.getGuild(message.guild.id); + data.member = await this.client.db.getMember(message.guild.id, message.author.id); - const command = client.commands.get(interaction.commandName); + // Ignore users on the guild blocklist + if (data.guild.blocklist.includes(message.author.id)) return; - // Return if the command is disabled globally - if (command.enabled === false) interaction.reply( - client.config.emojis.permError + ' This command has been disabled by my developers.' - ); - - // Return if the command is restricted to developers (and the user is not a developer) - if (command.devOnly === true && client.config.devIds.includes(interaction.user.id) !== true) { - return interaction.reply( - `${client.config.emojis.permError} ${interaction.user.username} is not in the sudoers file. This incident will be reported.` + // If a user pings Woomy, respond to them with the prefixes they can use + if (message.content === `<@${this.client.user.id}>` || message.content === `<@!${this.client.user.id}>`) { + return message.channel.send( + `Hi! The prefix for this server is \`${data.guild.prefix}\`, and your personal prefix is \`${data.user.prefix}\`. You can also ping me ^-^` ); } + // All the prefixes Woomy will respond to + const prefixes = [ + data.user.prefix, + data.guild.prefix, + `<@${this.client.user.id}> `, + `<@!${this.client.user.id}> ` + ]; + + let prefix; + + // Check the message content to see if it starts with one of our prefixes + for (const thisPrefix of prefixes) { + if (message.content.startsWith(thisPrefix)) { + prefix = thisPrefix; + break; + } + } + + // Ignore the message if it doesn't start with a valid prefix + if (!prefix) return; + + // Save prefix so we can use it later (mostly for help command) + if (prefix === `<@${this.client.user.id}> ` || prefix === `<@!${this.client.user.id}> `) { + message.prefix = '@Woomy '; + } else (message.prefix = prefix); + + // Turn the message content into an array (excluding the prefix) + const args = message.content.slice(prefix.length).trim().split(/ +/g); + + // Find the command + const commandName = args.shift().toLowerCase(); + const command = this.client.commands.get(commandName) || this.client.commands.get(this.client.aliases.get(commandName)); + + // Return if a command (or its aliases) are not found + if (!command) return; + + // Both of these blocks check if the command is disabled/in a disabled category + if (data.guild.disabledcommands.includes(command.name)) return message.channel.send( + this.client.config.emojis.permError + ' This command has been disabled by a server administrator.' + ); + + if (data.guild.disabledcategories.includes(command.category)) return message.channel.send( + this.client.config.emojis.permError + ' The category this command is apart of has been disabled by a server administrator.' + ); + + // Both of these blocks check the permissions of the user, and reply with missing perms if any are found + const missingUserPerms = this.client.functions.checkPermissions(message.channel, message.author.id, command.userPerms); + if (missingUserPerms) return message.channel.send( + `${this.client.config.emojis.permError} You can't use this command because you lack these permissions: \`${missingUserPerms.join('`, `')}\`` + ); + + const missingBotPerms = this.client.functions.checkPermissions(message.channel, this.client.user.id, command.botPerms); + if (missingBotPerms) return message.channel.send( + `${this.client.config.emojis.permError} I can't run this command because I lack these permissions: \`${missingBotPerms.join('`, `')}\`` + ); + + // Return if the command is disabled globally + if (command.enabled === false) return message.channel.send( + this.client.config.emojis.permError + ' This command has been disabled by my developers.' + ); + + // Return if the command is restricted to developers (and the user is not a developer) + if (command.devOnly === true && this.client.config.ownerIDs.includes(message.author.id) !== true) { + return message.channel.send( + `${this.client.config.emojis.permError} ${message.author.username} is not in the sudoers file. This incident will be reported.` + ); + } + // Cooldown - if (client.cooldowns.get(command.name).has(interaction.user.id)) { - const timestamp = client.cooldowns.get(command.name).get(interaction.user.id); + if (this.client.cooldowns.get(command.name).has(message.author.id)) { + const timestamp = this.client.cooldowns.get(command.name).get(message.author.id); const currentTime = Date.now(); const cooldown = command.cooldown / 1000; const timePassed = Math.floor((currentTime - timestamp) / 1000); - return interaction.reply( - `${client.config.emojis.wait} ${message.author.mention}, you need to wait ${cooldown - timePassed} seconds before using this command again.` + return message.channel.send( + `${this.client.config.emojis.wait} ${message.author.mention}, you need to wait ${cooldown - timePassed} seconds before using this command again.` ); } else { - client.cooldowns.get(command.name).set(interaction.user.id, new Date()); + this.client.cooldowns.get(command.name).set(message.author.id, new Date()); setTimeout(() => { - client.cooldowns.get(command.name).delete(interaction.user.id); - }, client.commands.get(command.name).cooldown); - } + this.client.cooldowns.get(command.name).delete(message.author.id); + }, this.client.commands.get(command.name).cooldown); + } try { - command.run(client, interaction, data); - client.logger.command(`Ran ${command.name}`); + command.run(this.client, message, args, data); + this.client.logger.command(`Ran ${command.name}`); } catch (error) { - client.logger.error('COMMAND_EXECUTION_ERROR', `${command.name}: ${error.stack}`); - interaction.reply(`${client.config.emojis.botError} An error occurred when I was trying to run this command. I've sent through the details of the error to my developers.`); + this.client.logger.error('COMMAND_EXECUTION_ERROR', `${command.name}: ${error.stack}`); + message.channel.send(`${this.client.config.emojis.botError} An error occured when I was trying to run this command. I've sent through the details of the error to my developers.`); } } -}; \ No newline at end of file +} + +module.exports = MessageHandler; \ No newline at end of file diff --git a/bot/event_modules/messageCreate/messageHandler.js b/bot/event_modules/messageCreate/messageHandler.js new file mode 100644 index 0000000..29da3c1 --- /dev/null +++ b/bot/event_modules/messageCreate/messageHandler.js @@ -0,0 +1,121 @@ +class MessageHandler { + constructor (client) { + this.client = client; + } + + async handle (message) { + // Ignore messages from bots, and messages in DM's + if (message.author.bot) return; + if (!message.guild) return; + + // Request all the data we need from the database + const data = {}; + data.user = await this.client.db.getUser(message.author.id); + data.guild = await this.client.db.getGuild(message.guild.id); + data.member = await this.client.db.getMember(message.guild.id, message.author.id); + + // Ignore users on the guild blocklist + if (data.guild.blocklist.includes(message.author.id)) return; + + // If a user pings Woomy, respond to them with the prefixes they can use + if (message.content === `<@${this.client.user.id}>` || message.content === `<@!${this.client.user.id}>`) { + return message.channel.send( + `Hi! The prefix for this server is \`${data.guild.prefix}\`, and your personal prefix is \`${data.user.prefix}\`. You can also ping me ^-^` + ); + } + + // All the prefixes Woomy will respond to + const prefixes = [ + data.user.prefix, + data.guild.prefix, + `<@${this.client.user.id}> `, + `<@!${this.client.user.id}> ` + ]; + + let prefix; + + // Check the message content to see if it starts with one of our prefixes + for (const thisPrefix of prefixes) { + if (message.content.startsWith(thisPrefix)) { + prefix = thisPrefix; + break; + } + } + + // Ignore the message if it doesn't start with a valid prefix + if (!prefix) return; + + // Save prefix so we can use it later (mostly for help command) + if (prefix === `<@${this.client.user.id}> ` || prefix === `<@!${this.client.user.id}> `) { + message.prefix = '@Woomy '; + } else (message.prefix = prefix); + + // Turn the message content into an array (excluding the prefix) + const args = message.content.slice(prefix.length).trim().split(/ +/g); + + // Find the command + const commandName = args.shift().toLowerCase(); + const command = this.client.commands.get(commandName) || this.client.commands.get(this.client.aliases.get(commandName)); + + // Return if a command (or its aliases) are not found + if (!command) return; + + // Both of these blocks check if the command is disabled/in a disabled category + if (data.guild.disabledcommands.includes(command.name)) return message.channel.send( + this.client.config.emojis.permError + ' This command has been disabled by a server administrator.' + ); + + if (data.guild.disabledcategories.includes(command.category)) return message.channel.send( + this.client.config.emojis.permError + ' The category this command is apart of has been disabled by a server administrator.' + ); + + // Both of these blocks check the permissions of the user, and reply with missing perms if any are found + const missingUserPerms = this.client.functions.checkPermissions(message.channel, message.author.id, command.userPerms); + if (missingUserPerms) return message.channel.send( + `${this.client.config.emojis.permError} You can't use this command because you lack these permissions: \`${missingUserPerms.join('`, `')}\`` + ); + + const missingBotPerms = this.client.functions.checkPermissions(message.channel, this.client.user.id, command.botPerms); + if (missingBotPerms) return message.channel.send( + `${this.client.config.emojis.permError} I can't run this command because I lack these permissions: \`${missingBotPerms.join('`, `')}\`` + ); + + // Return if the command is disabled globally + if (command.enabled === false) return message.channel.send( + this.client.config.emojis.permError + ' This command has been disabled by my developers.' + ); + + // Return if the command is restricted to developers (and the user is not a developer) + if (command.devOnly === true && this.client.config.ownerIDs.includes(message.author.id) !== true) { + return message.channel.send( + `${this.client.config.emojis.permError} ${message.author.username} is not in the sudoers file. This incident will be reported.` + ); + } + + // Cooldown + if (this.client.cooldowns.get(command.name).has(message.author.id)) { + const timestamp = this.client.cooldowns.get(command.name).get(message.author.id); + const currentTime = Date.now(); + const cooldown = command.cooldown / 1000; + const timePassed = Math.floor((currentTime - timestamp) / 1000); + return message.channel.send( + `${this.client.config.emojis.wait} ${message.author.mention}, you need to wait ${cooldown - timePassed} seconds before using this command again.` + ); + } else { + this.client.cooldowns.get(command.name).set(message.author.id, new Date()); + setTimeout(() => { + this.client.cooldowns.get(command.name).delete(message.author.id); + }, this.client.commands.get(command.name).cooldown); + } + + try { + command.run(this.client, message, args, data); + this.client.logger.command(`Ran ${command.name}`); + } catch (error) { + this.client.logger.error('COMMAND_EXECUTION_ERROR', `${command.name}: ${error.stack}`); + message.channel.send(`${this.client.config.emojis.botError} An error occured when I was trying to run this command. I've sent through the details of the error to my developers.`); + } + } +} + +module.exports = MessageHandler; \ No newline at end of file diff --git a/bot/index.js b/bot/index.js index 340a4fc..a1c0286 100644 --- a/bot/index.js +++ b/bot/index.js @@ -4,6 +4,7 @@ const Discord = require('discord.js'); const CommandLoader = require('./util/commandLoader'); const EventLoader = require('./util/eventLoader'); const EventHandler = require('./event_modules/eventHandler'); +const MessageHandler = require('./event_modules/messageCreate/messageHandler'); const Functions = require('./util/functions'); const Database = require('./util/database'); const Logger = require('./util/logger'); @@ -27,6 +28,7 @@ class WoomyClient extends Discord.Client { this.commandLoader = new CommandLoader(this); this.eventLoader = new EventLoader(this); this.eventHandler = new EventHandler(this); + this.messageHandler = new MessageHandler(this); // Collections to store our successfully loaded events and commands in, as well as cooldowns. this.commands = new Discord.Collection(); @@ -40,6 +42,7 @@ class WoomyClient extends Discord.Client { this.on('ready', this.runReadyModules); this.on('error', this.runErrorModules); this.on('interactionCreate', this.runInteractionCreateModules); + this.on('messageCreate', this.runMessageCreateModules); this.on('guildCreate', this.runGuildCreateModules); this.on('guildDelete', this.runGuildDeleteModules); this.on('guildMemberAdd', this.runGuildMemberAddModules); @@ -69,6 +72,11 @@ class WoomyClient extends Discord.Client { this.mainEventListener('interactionCreate', interaction); } + runMessageCreateModules (message) { + this.messageHandler.handle(message); + this.mainEventListener('messageCreate', message); + } + runGuildCreateModules (guild) { this.mainEventListener('guildCreate', guild); } @@ -93,11 +101,17 @@ class WoomyClient extends Discord.Client { // Initialize our client const client = new WoomyClient({ shards: 'auto', + partials: [ + Discord.Partials.Reaction + ], intents: [ Discord.GatewayIntentBits.Guilds, Discord.GatewayIntentBits.GuildMembers, Discord.GatewayIntentBits.GuildEmojisAndStickers, Discord.GatewayIntentBits.GuildVoiceStates, + Discord.GatewayIntentBits.GuildMessages, + Discord.GatewayIntentBits.MessageContent, + Discord.GatewayIntentBits.GuildMessageReactions ], allowedMentions: { parse: [ diff --git a/bot/util/commandLoader.js b/bot/util/commandLoader.js index e7d77dd..3560425 100644 --- a/bot/util/commandLoader.js +++ b/bot/util/commandLoader.js @@ -13,8 +13,12 @@ class CommandLoader { const name = file.substr(file.indexOf('/') + 1).slice(0, -3); const category = file.substr(0, file.indexOf('/')); const command = new (require(this.client.path + '/commands/' + file))(name, category); + this.client.commands.set(command.name, command); this.client.cooldowns.set(command.name, new Map()); + command.aliases.forEach(alias => { + this.client.aliases.set(alias, command.name); + }); } catch (error) { this.client.logger.error('COMMAND_LOADER_ERROR', `Failed to load ${file}: ${error}`); } diff --git a/botconfig.json.example b/botconfig.json.example index 96a9682..1fb7e72 100644 --- a/botconfig.json.example +++ b/botconfig.json.example @@ -5,9 +5,7 @@ "userAgent": "", - "devIds": [""], - - "clientId": "", + "ownerIDs": [""], "keys": { "sentry": "", diff --git a/templates/exampleCommand.js b/templates/exampleCommand.js new file mode 100644 index 0000000..8f5bbf8 --- /dev/null +++ b/templates/exampleCommand.js @@ -0,0 +1,22 @@ +module.exports = class { + constructor (name, category) { + this.name = name, + this.category = category, + this.enabled = true, + this.devOnly = false, + this.aliases = [], + this.userPerms = [], + this.botPerms = [], + this.cooldown = 2000, + this.help = { + description: '', + arguments: '', + details: '', + examples: '' + }; + } + + run (client, message, args, data) { //eslint-disable-line no-unused-vars + + } +}; \ No newline at end of file diff --git a/bot/base/Event.js b/templates/exampleEvent.js similarity index 100% rename from bot/base/Event.js rename to templates/exampleEvent.js diff --git a/schemas/guilds.sql b/templates/schemas/guilds.sql similarity index 100% rename from schemas/guilds.sql rename to templates/schemas/guilds.sql diff --git a/schemas/members.sql b/templates/schemas/members.sql similarity index 100% rename from schemas/members.sql rename to templates/schemas/members.sql diff --git a/schemas/users.sql b/templates/schemas/users.sql similarity index 100% rename from schemas/users.sql rename to templates/schemas/users.sql