diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 37df8be..cd33b64 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -5,9 +5,9 @@ name: Node.js CI on: push: - branches: [master] + branches: [dev, release] pull_request: - branches: [master] + branches: [dev, release] jobs: build: @@ -25,4 +25,4 @@ jobs: with: node-version: ${{ matrix.node-version }} - run: npm ci - - run: node index.js + - run: npm test diff --git a/Addons/hello.js b/Addons/hello.js index e87b181..3d696f5 100644 --- a/Addons/hello.js +++ b/Addons/hello.js @@ -10,24 +10,36 @@ const supportbot = yaml.load( ); const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); -// Your Addon Config file! Saved in /Addons/Settings/YourAddonConfig.yml -// const exampleaddon = yaml.load(fs.readFileSync('./Addons/Settings/YourAddonConfig.yml', 'utf8')); +// Your Addon Config file! Saved in /Addons/Configs/YourAddonConfig.yml +// const config = yaml.load(fs.readFileSync('./Addons/Configs/YourAddonConfig.yml', 'utf8')); -const Command = require("../Structures/Command.js"); +const { Command, Event } = require("../Structures/Addon"); -module.exports = new Command({ - name: "hello", - description: "hello", - slashCommandOptions: [], - permission: "SEND_MESSAGES", +module.exports.commands = [ + /* + // EXAMPLE COMMAND + new Command({ + name: "hello", + description: "hello", + options: [], + permissions: ["SEND_MESSAGES"], + async run(interaction) { + const Embed = new Discord.MessageEmbed() + .setDescription("Hello World!") + .setColor(supportbot.InfoColour); - async run(interaction) { - const Embed = new Discord.MessageEmbed() - .setDescription("Hello World!") - .setColor(supportbot.InfoColour); - - interaction.reply({ - embeds: [Embed], - }); - }, -}); + interaction.reply({ + embeds: [Embed], + }); + }, + }), + */ +]; +module.exports.events = [ + /* + // EXAMPLE EVENT + new Event("ready", async (client) => { + console.log("Bot started!"); + }), + */ +]; diff --git a/Commands/add.js b/Commands/add.js index 5aee916..b011048 100644 --- a/Commands/add.js +++ b/Commands/add.js @@ -12,16 +12,10 @@ const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); const Command = require("../Structures/Command.js"); -async function asyncForEach(array, callback) { - for (let index = 0; index < array.length; index++) { - await callback(array[index], index, array); - } -} - module.exports = new Command({ name: cmdconfig.TicketAdd, description: cmdconfig.TicketAddDesc, - slashCommandOptions: [ + options: [ { name: "user", description: "User to add", @@ -29,22 +23,15 @@ module.exports = new Command({ required: true, }, ], - permission: "SEND_MESSAGES", + permissions: ["SEND_MESSAGES"], async run(interaction) { - let SupportStaff = - interaction.guild.roles.cache.find( - (SupportTeam) => SupportTeam.name === supportbot.Staff - ) || - interaction.guild.roles.cache.find( - (SupportTeam) => SupportTeam.id === supportbot.Staff - ); - let Admins = - interaction.guild.roles.cache.find( - (AdminUser) => AdminUser.name === supportbot.Admin - ) || - interaction.guild.roles.cache.find( - (AdminUser) => AdminUser.id === supportbot.Admin + const { getRole, getChannel, getCategory } = interaction.client; + let SupportStaff = await getRole(supportbot.Staff, interaction.guild); + let Admin = await getRole(supportbot.Admin, interaction.guild); + if (!SupportStaff || !Admin) + return interaction.reply( + "Some roles seem to be missing!\nPlease check for errors when starting the bot." ); const NoPerms = new Discord.MessageEmbed() @@ -55,41 +42,51 @@ module.exports = new Command({ .setColor(supportbot.WarningColour); if ( - interaction.member.roles.cache.has(SupportStaff.id) || - interaction.member.roles.cache.has(Admins.id) - ) { - if (!interaction.channel.name.startsWith(`${supportbot.TicketPrefix}`)) { - const Exists = new Discord.MessageEmbed() - .setTitle("No Ticket Found!") - .setDescription(`${supportbot.NoValidTicket}`) - .setColor(supportbot.WarningColour); - return interaction.reply({ embeds: [Exists] }); - } - - let uMember = interaction.options.getUser("user"); - const UserNotExist = new Discord.MessageEmbed() - .setTitle("User Not Found!") - .setDescription( - `${supportbot.UserNotFound}\n\nTry Again:\`/${cmdconfig.TicketAdd} \`` - ) - .setColor(supportbot.ErrorColour); - - if (!uMember) return interaction.reply({ embeds: [UserNotExist] }); - - interaction.channel.permissionOverwrites.edit(uMember, { - VIEW_CHANNEL: true, - READ_MESSAGE_HISTORY: true, - SEND_MESSAGES: true, - }); - - const Complete = new Discord.MessageEmbed() - .setTitle("User Added!") - .setDescription(supportbot.AddedUser.replace(/%user%/g, uMember.id)) - .setTimestamp() - .setColor(supportbot.EmbedColour); - interaction.reply({ embeds: [Complete] }); - } else { + !interaction.member.roles.cache.has(SupportStaff.id) && + !interaction.member.roles.cache.has(Admin.id) + ) return interaction.reply({ embeds: [NoPerms] }); + + let TicketData = await JSON.parse( + fs.readFileSync("./Data/TicketData.json", "utf8") + ); + let ticket = await TicketData.tickets.findIndex( + (t) => t.id == interaction.channel.id + ); + if (ticket == -1) { + const Exists = new Discord.MessageEmbed() + .setTitle("No Ticket Found!") + .setDescription(`${supportbot.NoValidTicket}`) + .setColor(supportbot.WarningColour); + return interaction.reply({ embeds: [Exists] }); } + + let uMember = interaction.options.getUser("user"); + const UserNotExist = new Discord.MessageEmbed() + .setTitle("User Not Found!") + .setDescription( + `${supportbot.UserNotFound}\n\nTry Again:\`/${cmdconfig.TicketAdd} \`` + ) + .setColor(supportbot.ErrorColour); + + if (!uMember) return interaction.reply({ embeds: [UserNotExist] }); + + interaction.channel.permissionOverwrites.edit(uMember.id, { + VIEW_CHANNEL: true, + }); + const Complete = new Discord.MessageEmbed() + .setTitle("User Added!") + .setDescription(supportbot.AddedUser.replace(/%user%/g, uMember.id)) + .setTimestamp() + .setColor(supportbot.EmbedColour); + interaction.reply({ embeds: [Complete] }); + TicketData.tickets[ticket].subUsers.push(uMember.id); + fs.writeFileSync( + "./Data/TicketData.json", + JSON.stringify(TicketData, null, 4), + (err) => { + if (err) console.error(err); + } + ); }, }); diff --git a/Commands/close.js b/Commands/close.js index 2a29c8a..22a251d 100644 --- a/Commands/close.js +++ b/Commands/close.js @@ -11,35 +11,66 @@ const supportbot = yaml.load( const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); const Command = require("../Structures/Command.js"); -const TicketNumberID = require("../Structures/TicketID.js"); - -async function asyncForEach(array, callback) { - for (let index = 0; index < array.length; index++) { - await callback(array[index], index, array); - } -} module.exports = new Command({ name: cmdconfig.CloseTicket, description: cmdconfig.CloseTicketDesc, - slashCommandOptions: [ + options: [ { name: "reason", description: "Ticket Close Reason", type: "STRING", }, ], - permission: "SEND_MESSAGES", + permissions: ["SEND_MESSAGES"], async run(interaction) { - if (!interaction.channel.name.startsWith(`${supportbot.TicketPrefix}`)) { + const { getRole, getChannel, getCategory } = interaction.client; + if (supportbot.StaffOnly) { + let SupportStaff = await getRole(supportbot.Staff, interaction.guild); + let Admin = await getRole(supportbot.Admin, interaction.guild); + if (!SupportStaff || !Admin) + return interaction.reply( + "Some roles seem to be missing!\nPlease check for errors when starting the bot." + ); + const NoPerms = new Discord.MessageEmbed() + .setTitle("Invalid Permissions!") + .setDescription( + `${supportbot.IncorrectPerms}\n\nRole Required: \`${supportbot.Staff}\` or \`${supportbot.Admin}\`` + ) + .setColor(supportbot.WarningColour); + + if ( + !interaction.member.roles.cache.has(SupportStaff.id) && + !interaction.member.roles.cache.has(Admin.id) + ) + return interaction.reply({ embeds: [NoPerms] }); + } + await interaction.deferReply(); + let tickets = await JSON.parse( + fs.readFileSync("./Data/TicketData.json", "utf8") + ).tickets.find((t) => t.id === interaction.channel.id); + let TicketData = await tickets.tickets.findIndex( + (t) => t.id == ticketChannel.id + ); + if (!TicketData) { const Exists = new Discord.MessageEmbed() .setTitle("No Ticket Found!") .setDescription(`${supportbot.NoValidTicket}`) .setColor(supportbot.WarningColour); - return interaction.reply({ embed: Exists }); + return interaction.followUp({ embeds: [Exists] }); } + let tUser = interaction.client.users.cache.get(TicketData.user); + let transcriptChannel = await getChannel( + supportbot.TranscriptLog, + interaction.guild + ); + let logChannel = await getChannel(supportbot.TicketLog, interaction.guild); + let reason = + (await interaction.options?.getString("reason")) || "No Reason Provided."; + if (!transcriptChannel || !logChannel) + return interaction.followUp("Some Channels seem to be missing!"); if (supportbot.CloseConfirmation) { const CloseTicketRequest = new Discord.MessageEmbed() .setTitle(`**${supportbot.ClosingTicket}**`) @@ -47,185 +78,105 @@ module.exports = new Command({ `Please confirm by repeating the following word.. \`${supportbot.ClosingConfirmation_Word}\` ` ) .setColor(supportbot.EmbedColour); - - interaction - .reply(CloseTicketRequest) - .then((m) => { - interaction.channel - .awaitMessages( - (response) => - response.content.toLowerCase() === - supportbot.ClosingConfirmation_Word, - { - max: 1, - time: 20000, - errors: ["time"], - } - ) - .then((collected) => { - let logChannel = - interaction.guild.channels.cache.find( - (channel) => channel.name === supportbot.TranscriptLog - ) || - interaction.guild.channels.cache.find( - (channel) => channel.id === supportbot.TranscriptLog - ); - let user = interaction.user; - let reason = - interaction.options.getString("reason") || - "No Reason Provided."; - - let name = interaction.channel.name; - let ticketChannel = interaction.channel; - - interaction - .reply(`**${supportbot.ClosingTicket}**`) - - .then(() => { - const logEmbed = new Discord.MessageEmbed() - .setTitle(supportbot.TranscriptTitle) - .setColor(supportbot.EmbedColour) - .setFooter(supportbot.EmbedFooter) - .addField("Closed By", interaction.user.tag) - .addField("Reason", reason); - - interaction.channel.interactions - .fetch({ limit: 100 }) - .then((msgs) => { - let html = ""; - - msgs = msgs.sort( - (a, b) => a.createdTimestamp - b.createdTimestamp - ); - html += ``; - html += `Server Name: ${interaction.guild.name}
`; - html += `Ticket: ${ticketChannel.name}
`; - html += `Message: ${msgs.size} Messages


`; - - msgs.forEach((msg) => { - if (msg.content) { - html += `User: ${msg.author.tag}
`; - html += `Message: ${msg.content}
`; - html += `-----

`; - } - }); - - logChannel.send({ embeds: [logEmbed] }).catch((err) => { - interaction.reply(err); - }); - - let file = new Discord.MessageAttachment( - Buffer.from(html), - `${name}.html` - ); - logChannel - .send({ embeds: [logEmbed], files: [file] }) - .catch((err) => { - interaction.reply(err); - }); - - interaction.channel.delete().catch((error) => { - if ( - error.code !== - Discord.Constants.APIErrors.UNKNOWN_CHANNEL - ) { - console.error( - "Failed to delete the interaction:", - error - ); - } - }); - }); - }); - }); - }) - .catch(() => { - interaction - .followUp({ - content: "The request to close the ticket has timed out.", - }) - .then((m2) => setTimeout(() => interaction.channel.delete(3000))); - }); + await interaction.followUp({ embeds: [CloseTicketRequest] }); + let filter = (m) => + m.content.toLowerCase() == supportbot.ClosingConfirmation_Word && + m.author.id == interaction.user.id; + await interaction.channel.awaitMessages({ + filter, + max: 1, + time: 20000, + errors: ["time"], + }); } + try { + tickets.tickets[TicketData].open = false; + fs.writeFileSync( + "./Data/TicketData.json", + JSON.stringify(tickets, null, 4), + (err) => { + if (err) console.error(err); + } + ); + await interaction.followUp(`**${supportbot.ClosingTicket}**`); + const transcriptEmbed = new Discord.MessageEmbed() + .setTitle(supportbot.TranscriptTitle) + .setColor(supportbot.EmbedColour) + .setFooter(supportbot.EmbedFooter) + .addField( + "Ticket", + `${interaction.channel.name} (${interaction.channel.id})` + ) + .addField( + "User", + `${tUser.username}#${tUser.discriminator} (${tUser.id})` + ) + .addField("Closed By", interaction.user.tag) + .addField("Reason", reason); + const logEmbed = new Discord.MessageEmbed() + .setTitle(supportbot.TicketLog_Title) + .setColor(supportbot.EmbedColour) + .setFooter(supportbot.EmbedFooter) + .addField( + "Ticket", + `${interaction.channel.name} (${interaction.channel.id})` + ) + .addField( + "User", + `${tUser.username}#${tUser.discriminator} (${tUser.id})` + ) + .addField("Closed By", interaction.user.tag) + .addField("Reason", reason); + let msgs = await interaction.channel.messages.fetch(); + let html = ""; - if (!supportbot.CloseConfirmation) { - let logChannel = - interaction.guild.channels.cache.find( - (channel) => channel.name === supportbot.TranscriptLog - ) || - interaction.guild.channels.cache.find( - (channel) => channel.id === supportbot.TranscriptLog - ); - let user = interaction.user; - let reason = - (await interaction.options.getString("reason")) || - "No Reason Provided."; + msgs = msgs.sort((a, b) => a.createdTimestamp - b.createdTimestamp); + html += ``; + html += `Server Name: ${interaction.guild.name}
`; + html += `Ticket: ${interaction.channel.name}
`; + html += `Message: ${msgs.size} Messages


`; - let name = interaction.channel.name; - let ticketChannel = interaction.channel; + await msgs.forEach((msg) => { + if (msg.content) { + html += `User: ${msg.author.tag}
`; + html += `Message: ${msg.content}
`; + html += `-----

`; + } + }); - interaction - .reply(`**${supportbot.ClosingTicket}**`) + await logChannel.send({ embeds: [logEmbed] }).catch((err) => { + console.error(err); + }); - .then(() => { - const logEmbed = new Discord.MessageEmbed() - .setTitle(supportbot.TranscriptTitle) - .setColor(supportbot.EmbedColour) - .setFooter(supportbot.EmbedFooter) - .addField("Closed By", interaction.user.tag) - .addField("Reason", reason); - - interaction.channel.interactions - .fetch({ limit: 100 }) - .then((msgs) => { - let html = ""; - - msgs = msgs.sort( - (a, b) => a.createdTimestamp - b.createdTimestamp - ); - html += ``; - html += `Server Name: ${interaction.guild.name}
`; - html += `Ticket: ${ticketChannel.name}
`; - html += `Message: ${msgs.size} Messages


`; - - msgs.forEach((msg) => { - if (msg.content) { - html += `User: ${msg.author.tag}
`; - html += `Message: ${msg.content}
`; - html += `-----

`; - } - }); - - logChannel.send({ embeds: [logEmbed] }).catch((err) => { - interaction.reply(err); - }); - - let file = new Discord.MessageAttachment( - Buffer.from(html), - `${name}.html` - ); - logChannel - .send({ embeds: [logEmbed], files: [file] }) - .catch((err) => { - interaction.reply(err); - }); - - interaction.channel.delete().catch((error) => { - if ( - error.code !== Discord.Constants.APIErrors.UNKNOWN_CHANNEL - ) { - console.error("Failed to delete the interaction:", error); - } - }); - }); - }) - .catch(() => { - interaction - .followUp({ - content: "The request to close the ticket has timed out.", - }) - .then((m2) => setTimeout(() => interaction.channel.delete(3000))); + let file = new Discord.MessageAttachment( + Buffer.from(html), + `${interaction.channel.name}.html` + ); + await transcriptChannel + .send({ embeds: [transcriptEmbed], files: [file] }) + .catch(async (err) => { + console.error(err); }); + await tUser + .send({ embeds: [transcriptEmbed], files: [file] }) + .catch(async (err) => { + console.error(err); + }); + if (TicketData.subUsers) { + TicketData.subUsers.forEach(async (subUser) => { + interaction.client.users.cache + .get(subUser) + .send({ embeds: [transcriptEmbed], files: [file] }); + }); + } + await interaction.channel.delete().catch(async (error) => { + console.error(error); + if (error.code !== Discord.Constants.APIErrors.UNKNOWN_CHANNEL) { + console.error("Failed to delete the interaction:", error); + } + }); + } catch (error) { + console.error(error); } }, }); diff --git a/Commands/embed.js b/Commands/embed.js index 9bff3a8..c9083ff 100644 --- a/Commands/embed.js +++ b/Commands/embed.js @@ -15,7 +15,7 @@ const Command = require("../Structures/Command.js"); module.exports = new Command({ name: cmdconfig.EmbedCommand, description: cmdconfig.EmbedCommandDesc, - slashCommandOptions: [ + options: [ { name: "title", description: "Embed Title", @@ -28,24 +28,17 @@ module.exports = new Command({ type: "STRING", }, ], - permission: "SEND_MESSAGES", + permissions: ["SEND_MESSAGES"], async run(interaction) { - let SupportStaff = - interaction.guild.roles.cache.find( - (SupportTeam) => SupportTeam.name === supportbot.Staff - ) || - interaction.guild.roles.cache.find( - (SupportTeam) => SupportTeam.id === supportbot.Staff - ); - let Admins = - interaction.guild.roles.cache.find( - (AdminUser) => AdminUser.name === supportbot.Admin - ) || - interaction.guild.roles.cache.find( - (AdminUser) => AdminUser.id === supportbot.Admin - ); + const { getRole, getChannel, getCategory } = interaction.client; + let SupportStaff = await getRole(supportbot.Staff, interaction.guild); + let Admin = await getRole(supportbot.Admin, interaction.guild); + if (!SupportStaff || !Admin) + return interaction.reply( + "Some roles seem to be missing!\nPlease check for errors when starting the bot." + ); const NoPerms = new Discord.MessageEmbed() .setTitle("Invalid Permissions!") .setDescription( @@ -55,7 +48,7 @@ module.exports = new Command({ if ( interaction.member.roles.cache.has(SupportStaff.id) || - interaction.member.roles.cache.has(Admins.id) + interaction.member.roles.cache.has(Admin.id) ) { const EmbedTitle = interaction.options.getString("title"); const EmbedSubject = interaction.options.getString("message"); diff --git a/Commands/help.js b/Commands/help.js index bc02091..9b3e595 100644 --- a/Commands/help.js +++ b/Commands/help.js @@ -21,86 +21,72 @@ async function asyncForEach(array, callback) { module.exports = new Command({ name: cmdconfig.HelpCommand, description: cmdconfig.HelpCommandDesc, - slashCommandOptions: [], - permission: "SEND_MESSAGES", + options: [], + permissions: ["SEND_MESSAGES"], async run(interaction) { - let SupportStaff = - interaction.guild.roles.cache.find( - (adminRole) => adminRole.name === supportbot.Staff - ) || - interaction.guild.roles.cache.find( - (staffRole) => staffRole.id === supportbot.Staff - ); - let AdminStaff = - interaction.guild.roles.cache.find( - (adminRole) => adminRole.name === supportbot.Admin - ) || - interaction.guild.roles.cache.find( - (adminRole) => adminRole.id === supportbot.Admin + const { getRole, getChannel, getCategory } = interaction.client; + let SupportStaff = await getRole(supportbot.Staff, interaction.guild); + let Admin = await getRole(supportbot.Admin, interaction.guild); + if (!SupportStaff || !Admin) + return interaction.reply( + "Some roles seem to be missing!\nPlease check for errors when starting the bot." ); - if (supportbot.HelpMenu) { - let botCommands = ""; - botCommands += `**/${cmdconfig.HelpCommand}** ${cmdconfig.HelpCommandDesc}\n`; - botCommands += `**/${cmdconfig.InfoCommand}** ${cmdconfig.InfoCommandDesc}\n`; - botCommands += `**/${cmdconfig.PingCommand}** ${cmdconfig.PingCommandDesc}\n`; + let botCommands = ""; + botCommands += `**/${cmdconfig.HelpCommand}** ${cmdconfig.HelpCommandDesc}\n`; + botCommands += `**/${cmdconfig.InfoCommand}** ${cmdconfig.InfoCommandDesc}\n`; + botCommands += `**/${cmdconfig.PingCommand}** ${cmdconfig.PingCommandDesc}\n`; - let ticketCommands = ""; - ticketCommands += `**/${cmdconfig.OpenTicket}** ${cmdconfig.OpenTicketDesc}\n`; - ticketCommands += `**/${cmdconfig.CloseTicket}** ${cmdconfig.CloseTicketDesc}\n`; + let ticketCommands = ""; + ticketCommands += `**/${cmdconfig.OpenTicket}** ${cmdconfig.OpenTicketDesc}\n`; + ticketCommands += `**/${cmdconfig.CloseTicket}** ${cmdconfig.CloseTicketDesc}\n`; - let staffCommands = ""; - staffCommands += `**/${cmdconfig.TicketAdd}** ${cmdconfig.TicketAddDesc}\n`; - staffCommands += `**/${cmdconfig.TicketRemove}** ${cmdconfig.TicketRemoveDesc}\n`; + let staffCommands = ""; + staffCommands += `**/${cmdconfig.TicketAdd}** ${cmdconfig.TicketAddDesc}\n`; + staffCommands += `**/${cmdconfig.TicketRemove}** ${cmdconfig.TicketRemoveDesc}\n`; - const HelpEmbed1 = new Discord.MessageEmbed() - .setTitle(supportbot.Name + " Commands") - .setThumbnail(interaction.user.displayAvatarURL()) + const HelpEmbed1 = new Discord.MessageEmbed() + .setTitle(supportbot.Name + " Commands") + .setThumbnail(interaction.user.displayAvatarURL()) - .addFields( - { - name: "🖥️ General Commands\n", - value: `${botCommands}\n`, - inline: false, - }, - { - name: "🎫 Support Commands\n", - value: `${ticketCommands}\n`, - inline: false, - } - ) - - .setColor(supportbot.EmbedColour) - .setFooter(supportbot.EmbedFooter, interaction.user.displayAvatarURL()); - - if (interaction.member.roles.cache.has(SupportStaff.id)) { - HelpEmbed1.addFields({ - name: "🔐 Staff Commands\n", - value: `${staffCommands}\n`, + .addFields( + { + name: "🖥️ General Commands\n", + value: `${botCommands}\n`, + inline: false, + }, + { + name: "🎫 Support Commands\n", + value: `${ticketCommands}\n`, inline: false, - }); - } else { - if (interaction.member.roles.cache.has(AdminStaff.id)) { - HelpEmbed1.addFields({ - name: "🔐 Staff Commands\n", - value: `${staffCommands}\n`, - inline: false, - }); } - } + ) - if (supportbot.SendHelpPage === "dm") { - interaction.user.reply({ - embeds: [HelpEmbed1], - }); - } + .setColor(supportbot.EmbedColour) + .setFooter(supportbot.EmbedFooter, interaction.user.displayAvatarURL()); - if (supportbot.SendHelpPage === "channel") { - interaction.reply({ - embeds: [HelpEmbed1], - }); - } + if ( + interaction.member.roles.cache.has(SupportStaff.id) || + interaction.member.roles.cache.has(Admin.id) + ) { + HelpEmbed1.addFields({ + name: "🔐 Staff Commands\n", + value: `${staffCommands}\n`, + inline: false, + }); + } + + if (supportbot.SendHelpPage === "dm") { + interaction.user.reply({ + embeds: [HelpEmbed1], + }); + } + + if (supportbot.SendHelpPage === "channel") { + interaction.reply({ + embeds: [HelpEmbed1], + }); } }, }); diff --git a/Commands/info.js b/Commands/info.js index b93dcf9..51ad789 100644 --- a/Commands/info.js +++ b/Commands/info.js @@ -15,8 +15,8 @@ const Command = require("../Structures/Command.js"); module.exports = new Command({ name: cmdconfig.InfoCommand, description: cmdconfig.InfoCommandDesc, - slashCommandOptions: [], - permission: "SEND_MESSAGES", + options: [], + permissions: ["SEND_MESSAGES"], async run(interaction) { const InfoButton = new Discord.MessageButton() diff --git a/Commands/ping.js b/Commands/ping.js index edf812d..74637bb 100644 --- a/Commands/ping.js +++ b/Commands/ping.js @@ -15,8 +15,8 @@ const Command = require("../Structures/Command.js"); module.exports = new Command({ name: cmdconfig.PingCommand, description: cmdconfig.PingCommandDesc, - slashCommandOptions: [], - permission: "SEND_MESSAGES", + options: [], + permissions: ["SEND_MESSAGES"], async run(interaction) { const PingEmbed = new Discord.MessageEmbed() diff --git a/Commands/remove.js b/Commands/remove.js index d062584..5084835 100644 --- a/Commands/remove.js +++ b/Commands/remove.js @@ -21,7 +21,7 @@ async function asyncForEach(array, callback) { module.exports = new Command({ name: cmdconfig.TicketRemove, description: cmdconfig.TicketRemoveDesc, - slashCommandOptions: [ + options: [ { name: "user", description: "User to remove", @@ -29,22 +29,15 @@ module.exports = new Command({ required: true, }, ], - permission: "SEND_MESSAGES", + permissions: ["SEND_MESSAGES"], async run(interaction) { - let SupportStaff = - interaction.guild.roles.cache.find( - (SupportTeam) => SupportTeam.name === supportbot.Staff - ) || - interaction.guild.roles.cache.find( - (SupportTeam) => SupportTeam.id === supportbot.Staff - ); - let Admins = - interaction.guild.roles.cache.find( - (AdminUser) => AdminUser.name === supportbot.Admin - ) || - interaction.guild.roles.cache.find( - (AdminUser) => AdminUser.id === supportbot.Admin + const { getRole, getChannel, getCategory } = interaction.client; + let Staff = await getRole(supportbot.Staff, interaction.guild); + let Admin = await getRole(supportbot.Admin, interaction.guild); + if (!Staff || !Admin) + return interaction.reply( + "Some roles seem to be missing!\nPlease check for errors when starting the bot." ); const NoPerms = new Discord.MessageEmbed() @@ -55,41 +48,53 @@ module.exports = new Command({ .setColor(supportbot.WarningColour); if ( - interaction.member.roles.cache.has(SupportStaff.id) || - interaction.member.roles.cache.has(Admins.id) - ) { - if (!interaction.channel.name.startsWith(`${supportbot.TicketPrefix}`)) { - const Exists = new Discord.MessageEmbed() - .setTitle("No Ticket Found!") - .setDescription(`${supportbot.NoValidTicket}`) - .setColor(supportbot.WarningColour); - return interaction.reply({ embeds: [Exists] }); - } - - let uMember = interaction.options.getUser("user"); - const UserNotExist = new Discord.MessageEmbed() - .setTitle("User Not Found!") - .setDescription( - `${supportbot.UserNotFound}\n\nTry Again:\`/${cmdconfig.TicketRemove} \`` - ) - .setColor(supportbot.ErrorColour); - - if (!uMember) return interaction.reply({ embeds: [UserNotExist] }); - - interaction.channel.permissionOverwrites.edit(uMember, { - VIEW_CHANNEL: false, - READ_MESSAGE_HISTORY: false, - SEND_MESSAGES: false, - }); - - const Complete = new Discord.MessageEmbed() - .setTitle("User Removed!") - .setDescription(supportbot.RemovedUser.replace(/%user%/g, uMember.id)) - .setTimestamp() - .setColor(supportbot.EmbedColour); - interaction.reply({ embeds: [Complete] }); - } else { + !interaction.member.roles.cache.has(Staff.id) && + !interaction.member.roles.cache.has(Admin.id) + ) return interaction.reply({ embeds: [NoPerms] }); + let TicketData = await JSON.parse( + fs.readFileSync("./Data/TicketData.json", "utf8") + ); + let ticket = await TicketData.tickets.findIndex( + (t) => t.id == interaction.channel.id + ); + if (ticket == -1) { + const Exists = new Discord.MessageEmbed() + .setTitle("No Ticket Found!") + .setDescription(`${supportbot.NoValidTicket}`) + .setColor(supportbot.WarningColour); + return interaction.reply({ embeds: [Exists] }); } + + let uMember = interaction.options.getUser("user"); + const UserNotExist = new Discord.MessageEmbed() + .setTitle("User Not Found!") + .setDescription( + `${supportbot.UserNotFound}\n\nTry Again:\`/${cmdconfig.TicketRemove} \`` + ) + .setColor(supportbot.ErrorColour); + + if (!uMember) return interaction.reply({ embeds: [UserNotExist] }); + + interaction.channel.permissionOverwrites.edit(uMember.id, { + VIEW_CHANNEL: false, + }); + + const Complete = new Discord.MessageEmbed() + .setTitle("User Removed!") + .setDescription(supportbot.RemovedUser.replace(/%user%/g, uMember.id)) + .setTimestamp() + .setColor(supportbot.EmbedColour); + interaction.reply({ embeds: [Complete] }); + TicketData.tickets[ticket].subUsers = TicketData.tickets[ + ticket + ].subUsers.filter((u) => u != uMember.id); + fs.writeFileSync( + "./Data/TicketData.json", + JSON.stringify(TicketData, null, 4), + (err) => { + if (err) console.error(err); + } + ); }, }); diff --git a/Commands/suggest.js b/Commands/suggest.js index 99a99bc..e29ac30 100644 --- a/Commands/suggest.js +++ b/Commands/suggest.js @@ -15,23 +15,21 @@ const Command = require("../Structures/Command.js"); module.exports = new Command({ name: cmdconfig.SuggestCommand, description: cmdconfig.SuggestCommandDesc, - slashCommandOptions: [ + options: [ { name: "suggestion", description: "Create a Suggestion", type: "STRING", }, ], - permission: "SEND_MESSAGES", + permissions: ["SEND_MESSAGES"], async run(interaction) { - const suggestChannel = - interaction.guild.channels.cache.find( - (channel) => channel.name === supportbot.SuggestionChannel - ) || - interaction.guild.channels.cache.find( - (channel) => channel.id === supportbot.SuggestionChannel - ); + const { getRole, getChannel, getCategory } = interaction.client; + const suggestChannel = await getChannel( + supportbot.SuggestionChannel, + interaction.guild + ); const NoChannel = new Discord.MessageEmbed() .setTitle("Missing Channel!") diff --git a/Commands/ticket.js b/Commands/ticket.js index 27329fd..99fbd54 100644 --- a/Commands/ticket.js +++ b/Commands/ticket.js @@ -3,7 +3,12 @@ const fs = require("fs"); -const Discord = require("discord.js"); +const { + MessageEmbed, + Permissions, + MessageButton, + MessageActionRow, +} = require("discord.js"); const yaml = require("js-yaml"); const supportbot = yaml.load( fs.readFileSync("./Configs/supportbot.yml", "utf8") @@ -13,52 +18,60 @@ const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); const Command = require("../Structures/Command.js"); const TicketNumberID = require("../Structures/TicketID.js"); -async function asyncForEach(array, callback) { - for (let index = 0; index < array.length; index++) { - await callback(array[index], index, array); - } -} - module.exports = new Command({ name: cmdconfig.OpenTicket, description: cmdconfig.OpenTicketDesc, - slashCommandOptions: [ + options: [ { name: "reason", description: "Ticket Reason", type: "STRING", }, ], - permission: "SEND_MESSAGES", + permissions: ["SEND_MESSAGES"], async run(interaction) { - let reactionUser = interaction.guild.members.cache.get(interaction.user.id); + let TicketData = await JSON.parse( + fs.readFileSync("./Data/TicketData.json", "utf8") + ); + const { getRole, getChannel, getCategory } = interaction.client; + let User = interaction.guild.members.cache.get(interaction.user.id); if ( - reactionUser.roles.cache.find( - (role) => role.name === supportbot.TicketBlackListRole - ) || - reactionUser.roles.cache.find( - (role) => role.id === supportbot.TicketBlackListRole + supportbot.MaxAllowedTickets && + TicketData.tickets.filter((t) => t.user == interaction.user.id && t.open) + .length >= supportbot.MaxAllowedTickets + ) { + return interaction.reply({ + embeds: [ + { + title: "Too Many Tickets!", + description: `You can't have more than ${supportbot.MaxAllowedTickets} open tickets!`, + color: supportbot.WarningColour, + }, + ], + ephemeral: true, + }); + } + if ( + User.roles.cache.has( + getRole(supportbot.TicketBlackListRole, interaction.guild).id ) ) { - return interaction - .reply({ - content: `<@${interaction.user.id}> ${supportbot.TicketBlackListMessage}`, - }) - .then((msg) => { - setTimeout(() => msg.delete(), 3500); - }); + return interaction.reply({ + content: supportbot.TicketBlackListMessage, + ephemeral: true, + }); } // Ticket ID - let ticketNumberID = TicketNumberID.pad(interaction.guild.id); + let ticketNumberID = await TicketNumberID.pad(); // Ticket Subject const TicketSubject = interaction.options?.getString("reason") || supportbot.NoTicketSubject; - const TicketExists = new Discord.MessageEmbed() + const TicketExists = new MessageEmbed() .setTitle("Ticket Exists!") .setDescription(`${supportbot.TicketExists}`) .setColor(supportbot.WarningColour); @@ -68,112 +81,94 @@ module.exports = new Command({ ticketChannel.name === `${supportbot.TicketPrefix}${ticketNumberID}`; }) ) { - return interaction.reply({ embeds: [TicketExists] }); + return await interaction.reply({ embeds: [TicketExists] }); } - const Staff = - interaction.guild.roles.cache.find( - (SupportTeam) => SupportTeam.name === supportbot.Staff - ) || - interaction.guild.roles.cache.find( - (SupportTeam) => SupportTeam.id === supportbot.Staff - ); - const Admins = - interaction.guild.roles.cache.find( - (AdminUser) => AdminUser.name === supportbot.Admin - ) || - interaction.guild.roles.cache.find( - (AdminUser) => AdminUser.id === supportbot.Admin - ); - const DeptRole1 = - interaction.guild.roles.cache.find( - (DepartmentRole) => - DepartmentRole.name === `${supportbot.DepartmentRole_1}` - ) || - interaction.guild.roles.cache.find( - (DepartmentRole) => - DepartmentRole.id === `${supportbot.DepartmentRole_1}` - ); - const DeptRole2 = - interaction.guild.roles.cache.find( - (DepartmentRole) => - DepartmentRole.name === `${supportbot.DepartmentRole_2}` - ) || - interaction.guild.roles.cache.find( - (DepartmentRole) => - DepartmentRole.id === `${supportbot.DepartmentRole_2}` - ); - const DeptRole3 = - interaction.guild.roles.cache.find( - (DepartmentRole) => - DepartmentRole.name === `${supportbot.DepartmentRole_3}` - ) || - interaction.guild.roles.cache.find( - (DepartmentRole) => - DepartmentRole.id === `${supportbot.DepartmentRole_3}` - ); + const Staff = await getRole(supportbot.Staff, interaction.guild); + const Admin = await getRole(supportbot.Admin, interaction.guild); + const DeptRole1 = await getRole( + supportbot.DepartmentRole_1, + interaction.guild + ); + const DeptRole2 = await getRole( + supportbot.DepartmentRole_2, + interaction.guild + ); + const DeptRole3 = await getRole( + supportbot.DepartmentRole_3, + interaction.guild + ); + if (!Staff || !Admin || !DeptRole1 || !DeptRole2 || !DeptRole3) + return interaction.reply({ + content: + "Some roles seem to be missing!\nPlease check for errors when starting the bot.", + ephemeral: true, + }); const Author = interaction.user; - const Everyone = interaction.guild.id; + let TicketCategory = await getCategory( + supportbot.TicketCategory, + interaction.guild + ); const ticketChannel = await interaction.guild.channels.create( `${supportbot.TicketPrefix}${ticketNumberID}`, { type: "GUILD_TEXT", + parent: TicketCategory.id, + permissionOverwrites: [ + { + id: Admin.id, + allow: [Permissions.FLAGS.VIEW_CHANNEL], + }, + { + id: Author.id, + allow: [Permissions.FLAGS.VIEW_CHANNEL], + deny: [Permissions.FLAGS.SEND_MESSAGES], + }, + { + id: interaction.guild.id, + deny: [Permissions.FLAGS.VIEW_CHANNEL], + }, + ], + } + ); + if (supportbot.AllowStaff) { + ticketChannel.permissionOverwrites.edit(Staff.id, { + VIEW_CHANNEL: true, + }); + } + await TicketData.tickets.push({ + id: ticketChannel.id, + name: ticketChannel.name, + user: Author.id, + number: ticketNumberID, + reason: TicketSubject, + open: true, + subUsers: [], + }); + fs.writeFileSync( + "./Data/TicketData.json", + JSON.stringify(TicketData, null, 4), + (err) => { + if (err) console.error(err); } ); - if ( - interaction.channel.name === supportbot.ReactionChannel || - interaction.channel.id === supportbot.ReactionChannel - ) { - const CreatedTicket = new Discord.MessageEmbed() - .setDescription( - supportbot.TicketCreatedAlert.replace( - /%ticketauthor%/g, - interaction.user.id - ) - .replace(/%ticketid%/g, ticketChannel.id) - .replace(/%ticketusername%/g, interaction.user.username) + const CreatedTicket = new MessageEmbed() + .setDescription( + supportbot.TicketCreatedAlert.replace( + /%ticketauthor%/g, + interaction.user.id ) - .setColor(supportbot.EmbedColour); - interaction.reply({ embeds: [CreatedTicket], ephemeral: true }); - } else { - const CreatedTicket = new Discord.MessageEmbed() - .setDescription( - supportbot.TicketCreatedAlert.replace( - /%ticketauthor%/g, - interaction.user.id - ) - .replace(/%ticketid%/g, ticketChannel.id) - .replace(/%ticketusername%/g, interaction.user.username) - ) - .setColor(supportbot.EmbedColour); - interaction.reply({ embeds: [CreatedTicket], ephemeral: true }); - } - let AllowArr = [Staff, Staff, Admins, Author]; - await asyncForEach(AllowArr, (index) => { - ticketChannel.permissionOverwrites.create(index, { VIEW_CHANNEL: true }); - }); - - let DenyArr = [Everyone]; - await asyncForEach(DenyArr, (index) => { - ticketChannel.permissionOverwrites.create(index, { VIEW_CHANNEL: false }); - }); - - let TicketCategory = - interaction.guild.channels.cache.find( - (category) => category.name === supportbot.TicketCategory - ) || - interaction.guild.channels.cache.find( - (category) => category.id === supportbot.TicketCategory - ); - if (TicketCategory) { - ticketChannel.setParent(TicketCategory.id); - } + .replace(/%ticketid%/g, ticketChannel.id) + .replace(/%ticketusername%/g, interaction.user.username) + ) + .setColor(supportbot.EmbedColour); + await interaction.reply({ embeds: [CreatedTicket], ephemeral: true }); if (supportbot.AllowTicketMentions) { - ticketChannel.send({ content: `${interaction.user}` }); + await ticketChannel.send(`${interaction.user}`); } - const TicketMessage = new Discord.MessageEmbed() + const TicketMessage = new MessageEmbed() .setTitle( supportbot.Ticket_Title.replace(/%ticketauthor%/g, interaction.user.id) .replace(/%ticketid%/g, ticketChannel.id) @@ -194,7 +189,7 @@ module.exports = new Command({ if (supportbot.TicketSubject === "description") { if (TicketSubject != "No Reason Provided.") { - ticketChannel.setTopic( + await ticketChannel.setTopic( `Reason: ${TicketSubject} - User ID: ${interaction.user.id} - Ticket: ${ticketChannel.name}` ); } @@ -206,157 +201,121 @@ module.exports = new Command({ value: ` **${supportbot.DepartmentTitle_1}**\n **${supportbot.DepartmentTitle_2}**\n **${supportbot.DepartmentTitle_3}**`, }); } - const CloseButton = new Discord.MessageButton() + const CloseButton = new MessageButton() .setCustomId("ticketclose") .setLabel("Close") .setStyle(supportbot.TicketCloseColour) .setEmoji(supportbot.TicketCloseEmoji); - const LockButton = new Discord.MessageButton() + const LockButton = new MessageButton() .setCustomId("ticketlock") .setLabel("Lock") .setStyle(supportbot.TicketLockColour) .setEmoji(supportbot.TicketLockEmoji); - const row2 = new Discord.MessageActionRow().addComponents( - CloseButton, - LockButton - ); + const row2 = new MessageActionRow().addComponents(CloseButton, LockButton); if (supportbot.TicketDepartments) { - let DenyArr = [DeptRole1, DeptRole2, DeptRole3]; - await asyncForEach(DenyArr, (index) => { - ticketChannel.permissionOverwrites.create(index, { - VIEW_CHANNEL: false, + try { + const Department1Button = new MessageButton() + .setCustomId("Department1") + .setLabel(supportbot.DepartmentTitle_1) + .setStyle(supportbot.TicketDept1Colour) + .setEmoji(supportbot.TicketDept1Emoji); + + const Department2Button = new MessageButton() + .setCustomId("Department2") + .setLabel(supportbot.DepartmentTitle_2) + .setStyle(supportbot.TicketDept2Colour) + .setEmoji(supportbot.TicketDept2Emoji); + + const Department3Button = new MessageButton() + .setCustomId("Department3") + .setLabel(supportbot.DepartmentTitle_3) + .setStyle(supportbot.TicketDept3Colour) + .setEmoji(supportbot.TicketDept3Emoji); + + const row = new MessageActionRow().addComponents( + Department1Button, + Department2Button, + Department3Button + ); + + const m = await ticketChannel.send({ + embeds: [TicketMessage], + components: [row], }); - }); - const Department1Button = new Discord.MessageButton() - .setCustomId("Department1") - .setLabel(`${supportbot.DepartmentTitle_1}`) - .setStyle(supportbot.TicketDept1Colour) - .setEmoji(supportbot.TicketDept1Emoji); - const Department2Button = new Discord.MessageButton() - .setCustomId("Department2") - .setLabel(`${supportbot.DepartmentTitle_2}`) - .setStyle(supportbot.TicketDept2Colour) - .setEmoji(supportbot.TicketDept2Emoji); - - const Department3Button = new Discord.MessageButton() - .setCustomId("Department3") - .setLabel(`${supportbot.DepartmentTitle_3}`) - .setStyle(supportbot.TicketDept3Colour) - .setEmoji(supportbot.TicketDept3Emoji); - - const row = new Discord.MessageActionRow().addComponents( - Department1Button, - Department2Button, - Department3Button - ); - - const m = await ticketChannel.send({ - embeds: [TicketMessage], - components: [row], - }); - - const filter = (i) => { - i.deferUpdate(); - return i.user.id === interaction.user.id; - }; - const collector = m.createMessageComponentCollector({ - filter, - max: 1, - componentType: "BUTTON", - time: 60000, - }); - - collector.on("collect", async (i) => { - if (i.customId === "Department1") { - ticketChannel.permissionOverwrites.edit(DeptRole1, { - VIEW_CHANNEL: true, - READ_MESSAGE_HISTORY: true, - SEND_MESSAGES: true, + const filter = (i) => i.user.id === interaction.user.id; + let collector; + try { + collector = await m.awaitMessageComponent({ + filter, + max: 1, + componentType: "BUTTON", + time: supportbot.Timeout * 60000, }); - - if (!supportbot.AllowStaff) { - ticketChannel.permissionOverwrites.edit(Staff, { - VIEW_CHANNEL: false, - READ_MESSAGE_HISTORY: false, - SEND_MESSAGES: false, - }); - } - - const Department1 = new Discord.MessageEmbed() - .setDescription( - `> Thank for reaching out to the **${supportbot.DepartmentTitle_1} Department**. Please provide us information regarding your query.` - ) - .setColor(supportbot.EmbedColour); - ticketChannel.send({ embeds: [Department1] }); - - if (supportbot.AllowTicketMentions) { - ticketChannel.send({ content: `@here` }); - } + } catch (e) { + if (e.code == "INTERACTION_COLLECTOR_ERROR") + try { + let ticket = await TicketData.tickets.findIndex( + (t) => t.id == ticketChannel.id + ); + TicketData.tickets[ticket].open = false; + fs.writeFileSync( + "./Data/TicketData.json", + JSON.stringify(TicketData, null, 4), + (err) => { + if (err) console.error(err); + } + ); + interaction.user.send( + "Your ticket has timed out. Please open a new one, and select a department." + ); + } catch (e) {} + return await ticketChannel.delete(); } - i.message.edit({ embeds: [TicketMessage], components: [row2] }); - - if (i.customId === "Department2") { - ticketChannel.permissionOverwrites.edit(DeptRole2, { - VIEW_CHANNEL: true, - READ_MESSAGE_HISTORY: true, - SEND_MESSAGES: true, - }); - - if (!supportbot.AllowStaff) { - ticketChannel.permissionOverwrites.edit(Staff, { - VIEW_CHANNEL: false, - READ_MESSAGE_HISTORY: false, - SEND_MESSAGES: false, - }); - } - - const Department2 = new Discord.MessageEmbed() - .setDescription( - `> Thank for reaching out to the **${supportbot.DepartmentTitle_2} Department**. Please provide us information regarding your query.` - ) - .setColor(supportbot.EmbedColour); - ticketChannel.send({ embeds: [Department2] }); - - if (supportbot.AllowTicketMentions) { - ticketChannel.send({ content: `@here` }); - } - - i.message.edit({ embeds: [TicketMessage], components: [row2] }); + let role; + let title; + if (collector.customId === "Department1") { + role = DeptRole1; + title = supportbot.DepartmentTitle_1; } - if (i.customId === "Department3") { - ticketChannel.permissionOverwrites.edit(DeptRole3, { - VIEW_CHANNEL: true, - READ_MESSAGE_HISTORY: true, - SEND_MESSAGES: true, - }); - - if (!supportbot.AllowStaff) { - ticketChannel.permissionOverwrites.edit(Staff, { - VIEW_CHANNEL: false, - READ_MESSAGE_HISTORY: false, - SEND_MESSAGES: false, - }); - } - - const Department3 = new Discord.MessageEmbed() - .setDescription( - `> Thank for reaching out to the **${supportbot.DepartmentTitle_3} Department**. Please provide us information regarding your query.` - ) - .setColor(supportbot.EmbedColour); - ticketChannel.send({ embeds: [Department3] }); - - if (supportbot.AllowTicketMentions) { - ticketChannel.send({ content: `@here` }); - } - i.message.edit({ embeds: [TicketMessage], components: [row2] }); + if (collector.customId === "Department2") { + role = DeptRole2; + title = supportbot.DepartmentTitle_2; } - }); + if (collector.customId === "Department3") { + role = DeptRole3; + title = supportbot.DepartmentTitle_3; + } + + ticketChannel.permissionOverwrites.edit(role.id, { + VIEW_CHANNEL: true, + }); + ticketChannel.permissionOverwrites.edit(Author.id, { + SEND_MESSAGES: true, + }); + + await collector.reply({ + embeds: [ + { + description: `> Thank for reaching out to the **${title} Department**. Please provide us information regarding your query.`, + color: supportbot.EmbedColour, + }, + ], + }); + + if (supportbot.AllowTicketMentions) { + await ticketChannel.send("@here"); + } + await collector.message.edit({ + embeds: [TicketMessage], + components: [row2], + }); + } catch (error) {} } else { - ticketChannel.send({ embeds: [TicketMessage], components: [row2] }); + await ticketChannel.send({ embeds: [TicketMessage], components: [row2] }); } }, }); diff --git a/Configs/supportbot.yml b/Configs/supportbot.yml index 24cc931..762c84b 100644 --- a/Configs/supportbot.yml +++ b/Configs/supportbot.yml @@ -10,15 +10,16 @@ # Discord Support: https://emeraldsrv.dev/discord # Community Resources: https://emeraldsrv.dev/resources -SupportBot_Version: "7.3.1" +SupportBot_Version: "7.4.0" # ------------------------- # General Configuration # ------------------------- Name: "SupportBot" -# No Prefix, as everything uses the new Slash (/) Commands feature! Token: "BOT_TOKEN" +# Guild ID Ex: 123456789123456789 +Guild: "" # ------------------------- # Activity Configuration @@ -58,7 +59,6 @@ InfoColour: "#f74343" # Help Configuration # ------------------------- -HelpMenu: true # Do not change! SendHelpPage: "channel" # Set to channel or dm # ------------------------- @@ -67,7 +67,6 @@ SendHelpPage: "channel" # Set to channel or dm AutoRole: true AutoRole_Role: "Member" -LockdownRole: "@everyone" Staff: "Staff" Admin: "Admin" @@ -92,9 +91,11 @@ TicketLog: "logs" TranscriptLog: "transcripts" TranscriptTitle: "Ticket Transcript" -TicketLog_Title: "Ticket Log" +TicketLog_Title: "Ticket Closed" TicketBlackListMessage: "You are not allowed to open a ticket" +MaxAllowedTickets: 2 + TicketSubject: "description" # "description" will displays the ticket reason within the channel description # "embed" will displays the ticket reason within the ticket embed @@ -127,13 +128,11 @@ RemovedUser: "👍 <@%user%> has been removed from this ticket" # --- Start --- # Discord Button Colour Selection -# PRIMARY - Blurple +# PRIMARY - Blue +# SECONDARY - Grey # DANGER - Red # SUCCESS - Green -# Secondary - Grey -TicketLockReaction: "🔒" -TicketDeleteReaction: "⛔" LockTicketCategory: "Archive" TicketCloseEmoji: "❌" @@ -155,13 +154,13 @@ TicketDept3Emoji: "3️⃣" TranscriptSavedMessage: "📝 **Transcript Saved!**" TicketLockMessage: "❌ **Ticket Locked!**" TicketDeleteMessage: "⚠ **Ticket Deleting!**" # Tickets deleting after 5 seconds by default. -TicketDeleteTime: 5000 # Time must be set in milliseconds. # --- Departments Config --- # --- Start --- TicketDepartments: true - +# Delete the ticket if no department selected. TIME IN MINUTES +Timeout: 5 AllowStaff: true # If set to false users with the "Staff" role will not be able to view tickets # without a valid department role set below. @@ -181,6 +180,7 @@ DepartmentRole_3: "Admin" # --- Closing Config --- # --- Start --- +StaffOnly: true ClosingTicket: ":warning: You have requested to close your support ticket." ClosingConfirmation_Word: "confirm" CloseConfirmation: false diff --git a/Data/TicketData.json b/Data/TicketData.json index cf23c47..f97612b 100644 --- a/Data/TicketData.json +++ b/Data/TicketData.json @@ -1,5 +1,4 @@ { - "854057237495676938": { - "id": 2 - } -} \ No newline at end of file + "id": 0, + "tickets": [] +} diff --git a/Data/ticket-panel-id.json b/Data/ticket-panel-id.json index b2367c6..ad5728f 100644 --- a/Data/ticket-panel-id.json +++ b/Data/ticket-panel-id.json @@ -1,3 +1 @@ -{ - "TicketPanelID": "" -} +{"TicketPanelID":""} \ No newline at end of file diff --git a/Events/guildCreate.js b/Events/guildCreate.js new file mode 100644 index 0000000..fb1f1b3 --- /dev/null +++ b/Events/guildCreate.js @@ -0,0 +1,9 @@ +const Event = require("../Structures/Event.js"); +module.exports = new Event("guildCreate", async (client, guild) => { + console.log( + `\u001b[31m`, + `${client.user.username} is not in the correct server set in your config. Please leave all other servers and restart the bot.` + ); + console.log(`\u001b[31m`, `${client.user.username} will now exit.`); + return process.exit(1); +}); diff --git a/Events/guildDelete.js b/Events/guildDelete.js new file mode 100644 index 0000000..f1b5ca1 --- /dev/null +++ b/Events/guildDelete.js @@ -0,0 +1,10 @@ +const Event = require("../Structures/Event.js"); + +module.exports = new Event("guildDelete", async (client, guild) => { + console.log( + `\u001b[31m`, + `${client.user.username} is not in the correct server set in your config. Please join the server and restart the bot.` + ); + console.log(`\u001b[31m`, `${client.user.username} will now exit.`); + return process.exit(1); +}); diff --git a/Events/interactionCreate.js b/Events/interactionCreate.js index d7e67a1..32672e3 100644 --- a/Events/interactionCreate.js +++ b/Events/interactionCreate.js @@ -12,14 +12,13 @@ const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); const Event = require("../Structures/Event.js"); -module.exports = new Event("interactionCreate", (client, interaction) => { +module.exports = new Event("interactionCreate", async (client, interaction) => { if (interaction.isCommand()) { const command = client.commands.find( (cmd) => cmd.name.toLowerCase() == interaction.commandName ); - if (interaction.user.bot || !interaction.isCommand() || !interaction.guild) - return; + if (interaction.user.bot || !interaction.guild) return; const NotValid = new Discord.MessageEmbed() .setDescription(`:x: \`Invalid Command\` `) @@ -57,79 +56,17 @@ module.exports = new Event("interactionCreate", (client, interaction) => { } if (interaction.customId === "ticketclose") { - if (interaction.channel.name.startsWith(`${supportbot.TicketPrefix}`)) { - interaction.message.fetch(); - interaction.deferUpdate(); - const DeleteTicketEmbed = new Discord.MessageEmbed() - .setDescription(supportbot.TicketDeleteMessage) - .setColor(supportbot.EmbedColour); - interaction.channel.send({ embeds: [DeleteTicketEmbed] }); - - let logChannel = - interaction.guild.channels.cache.find( - (channel) => channel.name === supportbot.TranscriptLog - ) || - interaction.guild.channels.cache.find( - (channel) => channel.id === supportbot.TranscriptLog - ); - - let user = interaction.user; - let name = interaction.channel.name; - let ticketChannel = interaction.channel; - let reason = "No Reason Provided."; - - interaction.channel - .send({ content: `**${supportbot.ClosingTicket}**` }) - .then(() => { - const logEmbed = new Discord.MessageEmbed() - .setTitle(supportbot.TranscriptTitle) - .setColor(supportbot.EmbedColour) - .setFooter(supportbot.EmbedFooter) - .addField("Closed By", user.username) - .addField("Reason", reason); - - interaction.channel.messages.fetch({ limit: 100 }).then((msgs) => { - let html = ""; - - msgs = msgs.sort( - (a, b) => a.createdTimestamp - b.createdTimestamp - ); - html += ``; - html += `Server Name: ${interaction.guild.name}
`; - html += `Ticket: ${ticketChannel.name}
`; - html += `Message: ${msgs.size} Messages


`; - - msgs.forEach((msg) => { - if (msg.content) { - html += `User: ${msg.author.tag}
`; - html += `Message: ${msg.content}
`; - html += `-----

`; - } - }); - - const TranscriptSavedEmbed = new Discord.MessageEmbed() - .setDescription(supportbot.TranscriptSavedMessage) - .setColor(supportbot.SuccessColour); - interaction.channel.send({ embeds: [TranscriptSavedEmbed] }); - - let file = new Discord.MessageAttachment( - Buffer.from(html), - `${name}.html` - ); - logChannel.send({ embeds: [logEmbed], files: [file] }); - - setTimeout( - () => interaction.channel.delete(), - supportbot.TicketDeleteTime - ); - }); - }); + try { + const cmd = client.commands.get(cmdconfig.CloseTicket); + if (!cmd) return; + cmd.run(interaction); + } catch (error) { + console.error(error); } } if (interaction.customId === "ticketlock") { if (interaction.channel.name.startsWith(`${supportbot.TicketPrefix}`)) { interaction.message.fetch(); - interaction.deferUpdate(); let Admin = interaction.guild.roles.cache.find( (AdminUser) => AdminUser.name === supportbot.Admin @@ -137,6 +74,12 @@ module.exports = new Event("interactionCreate", (client, interaction) => { interaction.guild.roles.cache.find( (AdminUser) => AdminUser.id === supportbot.Admin ); + if (!interaction.member.roles.cache.has(Admin.id)) { + return await interaction.reply({ + content: "You don't have permission to do that.", + ephemeral: true, + }); + } let all = interaction.channel.permissionOverwrites.cache; let parent = @@ -175,7 +118,7 @@ module.exports = new Event("interactionCreate", (client, interaction) => { .setDescription(`Archived ${interaction.channel.name}`) .setColor(`${supportbot.SuccessColour}`); - interaction.channel.send({ embeds: [ArchiveEmbed] }); + interaction.reply({ embeds: [ArchiveEmbed] }); interaction.message.edit({ components: [row] }); } } diff --git a/Events/ready.js b/Events/ready.js index 24bfa7f..9c304bc 100644 --- a/Events/ready.js +++ b/Events/ready.js @@ -14,7 +14,8 @@ const panelconfig = yaml.load( const Event = require("../Structures/Event.js"); -module.exports = new Event("ready", (client) => { +module.exports = new Event("ready", async (client) => { + const { getRole, getChannel, getCategory } = client; client.user.setActivity(supportbot.BotActivity, { type: supportbot.ActivityType, url: supportbot.StreamingURL, @@ -65,7 +66,76 @@ module.exports = new Event("ready", (client) => { console.log(`\u001b[37m`, `SupportBot proudly created by Emerald Services`); console.log(` `); console.log(`\u001b[31m`, `――――――――――――――――――――――――――――――――――――――――――――`); + if ( + !supportbot.Guild || + (await client.guilds.cache.size) !== 1 || + (await client.guilds.cache.first().id) !== supportbot.Guild + ) { + console.log( + `\u001b[31m`, + `${client.user.username} is not in the correct server set in your config. Please join the server and restart the bot.` + ); + console.log(`\u001b[31m`, `${client.user.username} will now exit.`); + return process.exit(1); + } + const roles = [ + supportbot.Admin, + supportbot.Staff, + supportbot.TicketBlackListRole, + supportbot.DepartmentRole_1, + supportbot.DepartmentRole_2, + supportbot.DepartmentRole_3, + ]; + if (supportbot.AutoRole) roles.push(supportbot.AutoRole_Role); + const channels = [ + supportbot.SuggestionChannel, + supportbot.TicketLog, + supportbot.TranscriptLog, + panelconfig.Channel, + ]; + const categories = [supportbot.TicketCategory]; + const missingC = []; + const missingR = []; + const missingCat = []; + for (let c of channels) { + const find = await getChannel(c, client.guilds.cache.first()); + if (!find) missingC.push(c); + } + for (let r of roles) { + const find = await getRole(r, client.guilds.cache.first()); + if (!find) missingR.push(r); + } + for (let cat of categories) { + const find = await getCategory(cat, client.guilds.cache.first()); + if (!find) missingCat.push(cat); + } + + if (missingR.length > 0) { + console.log( + "\u001b[33m", + `[WARN] The following Roles could not be found! Please check your configs!\n${missingR.join( + ", " + )}` + ); + } + + if (missingC.length > 0) { + console.log( + "\u001b[33m", + `[WARN] The following Channels could not be found! Please check your configs!\n${missingC.join( + ", " + )}` + ); + } + if (missingCat.length > 0) { + console.log( + "\u001b[33m", + `[WARN] The following Categories could not be found! Please check your configs!\n${missingCat.join( + ", " + )}` + ); + } if (panelconfig.TicketPanel) { let chan1 = client.channels.cache.find( (channel) => channel.name === panelconfig.Channel @@ -104,7 +174,8 @@ module.exports = new Event("ready", (client) => { let button = new Discord.MessageButton() .setLabel(panelconfig.ButtonLabel) .setCustomId("openticket") - .setStyle(panelconfig.ButtonColour); + .setStyle(panelconfig.ButtonColour) + .setEmoji(panelconfig.ButtonEmoji); let row = new Discord.MessageActionRow().addComponents(button); diff --git a/README.md b/README.md index 01cd9e6..8e9e13e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## What is SupportBot? -SupportBot is an open-sourced support system for discord. It's completely free to use with high amounts of customisation to match your own brand. +SupportBot is an open-sourced support system for discord. It's completely free to use with high amounts of customization to match your own brand. ## Quick Links diff --git a/Structures/Addon.js b/Structures/Addon.js new file mode 100644 index 0000000..a64b4ae --- /dev/null +++ b/Structures/Addon.js @@ -0,0 +1,21 @@ +// SupportBot | Emerald Services +// Addon Structure + +class Command { + constructor(options) { + this.name = options.name; + this.description = options.description; + this.permissions = options.permissions; + this.options = options.options || []; + this.run = options.run; + this.defaultPermission = true; + } +} +class Event { + constructor(event, run) { + this.event = event; + this.run = run; + } +} + +module.exports = { Command, Event }; diff --git a/Structures/Addons.js b/Structures/Addons.js deleted file mode 100644 index 95b24f7..0000000 --- a/Structures/Addons.js +++ /dev/null @@ -1,25 +0,0 @@ -// SupportBot | Emerald Services -// Addon Structure - -const fs = require("fs"); - -const Discord = require("discord.js"); - -const yaml = require("js-yaml"); -const supportbot = yaml.load( - fs.readFileSync("./Configs/supportbot.yml", "utf8") -); - -function RunFunction(interaction) {} - -class Addon { - constructor(options) { - this.name = options.name; - this.description = options.description; - this.permission = options.permission; - this.slashCommandOptions = options.slashCommandOptions || []; - this.run = options.run; - } -} - -module.exports = Addon; diff --git a/Structures/Client.js b/Structures/Client.js index e70422d..a0db27f 100644 --- a/Structures/Client.js +++ b/Structures/Client.js @@ -4,8 +4,6 @@ const fs = require("fs"); const Discord = require("discord.js"); -const Command = require("./Command.js"); -const Event = require("./Event.js"); const intents = new Discord.Intents(32767); const yaml = require("js-yaml"); @@ -19,6 +17,25 @@ class Client extends Discord.Client { this.commands = new Discord.Collection(); } + async getChannel(channel, guild) { + return guild.channels.cache.find( + (c) => + (c.type === "GUILD_TEXT" || c.type === "GUILD_NEWS") && + (c.id === channel || c.name.toLowerCase() === channel.toLowerCase()) + ); + } + async getRole(role, guild) { + return guild.roles.cache.find( + (r) => r.id === role || r.name.toLowerCase() === role.toLowerCase() + ); + } + async getCategory(category, guild) { + return guild.channels.cache.find( + (c) => + c.type === "GUILD_CATEGORY" && + (c.id === category || c.name.toLowerCase() === category.toLowerCase()) + ); + } start(token) { const commandFiles = fs @@ -29,10 +46,15 @@ class Client extends Discord.Client { .readdirSync("./Addons") .filter((file) => file.endsWith(".js")); - const addons = addonFiles.map((file) => require(`../Addons/${file}`)); + const addons = addonFiles.map((file) => { + let addon = require(`../Addons/${file}`); + addon.name = file.split(".")[0]; + return addon; + }); const commands = commandFiles.map((file) => require(`../Commands/${file}`)); + // Commands console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Commands ▬▬▬▬▬▬▬"); commands.forEach((cmd) => { @@ -40,6 +62,11 @@ class Client extends Discord.Client { this.commands.set(cmd.name, cmd); }); + console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Commands ▬▬▬▬▬▬▬"); + // Addons + console.log(" "); + console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Addons ▬▬▬▬▬▬▬"); + addons.forEach((addon) => { console.log( `\u001b[33m`, @@ -49,57 +76,23 @@ class Client extends Discord.Client { `\u001b[32;1m`, "Loaded" ); - this.commands.set(addon.name, addon); + addon.commands.forEach((command) => { + this.commands.set(command.name, command); + }); + addon.events.forEach((event) => { + this.on(event.event, (...args) => event.run(this, ...args)); + }); }); - console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Commands ▬▬▬▬▬▬▬"); + console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Addons ▬▬▬▬▬▬▬"); // Slash Commands - const slashCommands = commands.map((cmd) => ({ - name: cmd.name.toLowerCase(), - description: cmd.description, - permissions: [], - options: cmd.slashCommandOptions, - defaultPermission: true, - })); - - const slashCommands1 = addons.map((addon) => ({ - name: addon.name.toLowerCase(), - description: addon.description, - permissions: [], - options: addon.slashCommandOptions, - defaultPermission: true, - })); - - this.removeAllListeners(); - - this.on("ready", async () => { - const allCommands = slashCommands.concat(slashCommands1); - await this.application?.commands.set(allCommands); - - console.log(" "); - console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Slash Command ▬▬▬▬▬▬▬"), - console.log(" "); - - slashCommands.forEach((cmd) => - console.log( - `\u001b[31;1m`, - `${cmd.name}`, - `\u001b[32;1m`, - `| Slash Command Registered` - ) - ); - - slashCommands1.forEach((addon) => - console.log( - `\u001b[33m`, - `[ADDON]`, - `\u001b[31;1m`, - `${addon.name}`, - `\u001b[32;1m`, - `| Slash Command Registered` - ) + this.once("ready", async () => { + await this.application?.commands.set(this.commands, supportbot.Guild); + console.log( + `\u001b[32;1m`, + `Slash Commands Registered for ${this.guilds.cache.first().name}` ); }); @@ -111,14 +104,18 @@ class Client extends Discord.Client { .forEach((file) => { const event = require(`../Events/${file}`); console.log(`\u001b[31;1m`, `${event.event}`, `\u001b[32;1m`, "Loaded"); - - this.on(event.event, event.run.bind(null, this)); + this.on(event.event, (...args) => event.run(this, ...args)); }); console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Events ▬▬▬▬▬▬▬"); - console.log(" "); - - this.login(token); + if (process.argv[2] != "test") { + this.login(token); + } else { + console.log( + `\u001b[31;1m`, + "RUNNING IN TEST MODE, IF NOT INTENDED, PLEASE USE npm start" + ); + } } } diff --git a/Structures/Command.js b/Structures/Command.js index ba663b5..1dfaffe 100644 --- a/Structures/Command.js +++ b/Structures/Command.js @@ -3,22 +3,16 @@ const fs = require("fs"); -const Discord = require("discord.js"); - const yaml = require("js-yaml"); -const supportbot = yaml.load( - fs.readFileSync("./Configs/supportbot.yml", "utf8") -); - -function RunFunction(interaction) {} class Command { constructor(options) { this.name = options.name; this.description = options.description; - this.permission = options.permission; - this.slashCommandOptions = options.slashCommandOptions || []; + this.permissions = options.permissions; + this.options = options.options || []; this.run = options.run; + this.defaultPermission = true; } } diff --git a/Structures/Event.js b/Structures/Event.js index 61e4381..d644b72 100644 --- a/Structures/Event.js +++ b/Structures/Event.js @@ -1,21 +1,9 @@ // SupportBot | Emerald Services // Event Structure - -const fs = require("fs"); - -const Discord = require("discord.js"); - -const yaml = require("js-yaml"); -const supportbot = yaml.load( - fs.readFileSync("./Configs/supportbot.yml", "utf8") -); - -function RunFunction(client, ...eventArgs) {} - class Event { - constructor(event, runFunction) { + constructor(event, run) { this.event = event; - this.run = runFunction; + this.run = run; } } diff --git a/Structures/TicketID.js b/Structures/TicketID.js index 11c9d9f..4e5bb24 100644 --- a/Structures/TicketID.js +++ b/Structures/TicketID.js @@ -3,85 +3,67 @@ const fs = require("fs"); -const Discord = require("discord.js"); -const Command = require("./Command.js"); -const Client = require("./Client.js"); -const Event = require("./Event.js"); - -const yaml = require("js-yaml"); -const supportbot = yaml.load( - fs.readFileSync("./Configs/supportbot.yml", "utf8") -); - class TicketNumberID { - static pad(guildId) { - let n = this.get(guildId) + ""; + static async pad() { + let n = this.get() + ""; let z = "0"; let width = 4; - setTimeout(() => { - this.set(guildId, this.get(guildId) + 1); - }, 50); + await this.set(this.get() + 1); return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; } - static get(guildId) { + static get() { let ticketnumberID = JSON.parse( fs.readFileSync("./Data/TicketData.json", "utf8") ); - if (!ticketnumberID[guildId]) { - ticketnumberID[guildId] = { - id: 0, - }; + if (!ticketnumberID.id) { + ticketnumberID.id = 0; fs.writeFileSync( "./Data/TicketData.json", JSON.stringify(ticketnumberID, null, 4), (err) => { - if (err) console.log(err); + if (err) console.error(err); } ); return 0; } else { - return ticketnumberID[guildId].id; + return ticketnumberID.id; } } - static set(guildId, value) { + static set(value) { let ticketnumberID = JSON.parse( fs.readFileSync("./Data/TicketData.json", "utf8") ); - ticketnumberID[guildId] = { - id: value, - }; + ticketnumberID.id = value; fs.writeFileSync( "./Data/TicketData.json", JSON.stringify(ticketnumberID, null, 4), (err) => { - if (err) console.log(err); + if (err) console.error(err); } ); return value; } - static reset(guildId) { + static reset() { let ticketnumberID = JSON.parse( fs.readFileSync("./Data/TicketData.json", "utf8") ); - ticketnumberID[guildId] = { - id: 0, - }; + ticketnumberID.id = 0; fs.writeFileSync( "./Data/TicketData.json", JSON.stringify(ticketnumberID, null, 4), (err) => { - if (err) console.log(err); + if (err) console.error(err); } ); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ae72152 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,555 @@ +{ + "name": "supportbot", + "version": "7.4.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "supportbot", + "version": "7.4.0", + "license": "MIT", + "dependencies": { + "discord.js": "^13.3.1", + "js-yaml": "^4.1.0" + } + }, + "node_modules/@discordjs/builders": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.8.2.tgz", + "integrity": "sha512-/YRd11SrcluqXkKppq/FAVzLIPRVlIVmc6X8ZklspzMIHDtJ+A4W37D43SHvLdH//+NnK+SHW/WeOF4Ts54PeQ==", + "dependencies": { + "@sindresorhus/is": "^4.2.0", + "discord-api-types": "^0.24.0", + "ow": "^0.27.0", + "ts-mixer": "^6.0.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@discordjs/collection": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.3.2.tgz", + "integrity": "sha512-dMjLl60b2DMqObbH1MQZKePgWhsNe49XkKBZ0W5Acl5uVV43SN414i2QfZwRI7dXAqIn8pEWD2+XXQFn9KWxqg==", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@discordjs/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.9.tgz", + "integrity": "sha512-CbXaGwwlEMq+l1TRu01FJCvySJ1CEFKFclHT48nIfNeZXaAAmmwwy7scUKmYHPUa3GhoMp6Qr1B3eAJux6XgOQ==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", + "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@types/node": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.0.tgz", + "integrity": "sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==" + }, + "node_modules/@types/node-fetch": { + "version": "2.5.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz", + "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==", + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@types/ws": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz", + "integrity": "sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/discord-api-types": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.24.0.tgz", + "integrity": "sha512-X0uA2a92cRjowUEXpLZIHWl4jiX1NsUpDhcEOpa1/hpO1vkaokgZ8kkPtPih9hHth5UVQ3mHBu/PpB4qjyfJ4A==", + "engines": { + "node": ">=12" + } + }, + "node_modules/discord.js": { + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.3.1.tgz", + "integrity": "sha512-zn4G8tL5+tMV00+0aSsVYNYcIfMSdT2g0nudKny+Ikd+XKv7m6bqI7n3Vji0GIRqXDr5ArPaw+iYFM2I1Iw3vg==", + "dependencies": { + "@discordjs/builders": "^0.8.1", + "@discordjs/collection": "^0.3.2", + "@discordjs/form-data": "^3.0.1", + "@sapphire/async-queue": "^1.1.8", + "@types/node-fetch": "^2.5.12", + "@types/ws": "^8.2.0", + "discord-api-types": "^0.24.0", + "node-fetch": "^2.6.1", + "ws": "^8.2.3" + }, + "engines": { + "node": ">=16.6.0", + "npm": ">=7.0.0" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", + "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/ow": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", + "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", + "dependencies": { + "@sindresorhus/is": "^4.0.1", + "callsites": "^3.1.0", + "dot-prop": "^6.0.1", + "lodash.isequal": "^4.5.0", + "type-fest": "^1.2.1", + "vali-date": "^1.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "node_modules/ts-mixer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", + "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" + }, + "node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vali-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", + "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/ws": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.3.0.tgz", + "integrity": "sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + }, + "dependencies": { + "@discordjs/builders": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.8.2.tgz", + "integrity": "sha512-/YRd11SrcluqXkKppq/FAVzLIPRVlIVmc6X8ZklspzMIHDtJ+A4W37D43SHvLdH//+NnK+SHW/WeOF4Ts54PeQ==", + "requires": { + "@sindresorhus/is": "^4.2.0", + "discord-api-types": "^0.24.0", + "ow": "^0.27.0", + "ts-mixer": "^6.0.0", + "tslib": "^2.3.1" + } + }, + "@discordjs/collection": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.3.2.tgz", + "integrity": "sha512-dMjLl60b2DMqObbH1MQZKePgWhsNe49XkKBZ0W5Acl5uVV43SN414i2QfZwRI7dXAqIn8pEWD2+XXQFn9KWxqg==" + }, + "@discordjs/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "@sapphire/async-queue": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.9.tgz", + "integrity": "sha512-CbXaGwwlEMq+l1TRu01FJCvySJ1CEFKFclHT48nIfNeZXaAAmmwwy7scUKmYHPUa3GhoMp6Qr1B3eAJux6XgOQ==" + }, + "@sindresorhus/is": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", + "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==" + }, + "@types/node": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.0.tgz", + "integrity": "sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==" + }, + "@types/node-fetch": { + "version": "2.5.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz", + "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==", + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "@types/ws": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz", + "integrity": "sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==", + "requires": { + "@types/node": "*" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "discord-api-types": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.24.0.tgz", + "integrity": "sha512-X0uA2a92cRjowUEXpLZIHWl4jiX1NsUpDhcEOpa1/hpO1vkaokgZ8kkPtPih9hHth5UVQ3mHBu/PpB4qjyfJ4A==" + }, + "discord.js": { + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.3.1.tgz", + "integrity": "sha512-zn4G8tL5+tMV00+0aSsVYNYcIfMSdT2g0nudKny+Ikd+XKv7m6bqI7n3Vji0GIRqXDr5ArPaw+iYFM2I1Iw3vg==", + "requires": { + "@discordjs/builders": "^0.8.1", + "@discordjs/collection": "^0.3.2", + "@discordjs/form-data": "^3.0.1", + "@sapphire/async-queue": "^1.1.8", + "@types/node-fetch": "^2.5.12", + "@types/ws": "^8.2.0", + "discord-api-types": "^0.24.0", + "node-fetch": "^2.6.1", + "ws": "^8.2.3" + } + }, + "dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "requires": { + "mime-db": "1.51.0" + } + }, + "node-fetch": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", + "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "ow": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", + "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", + "requires": { + "@sindresorhus/is": "^4.0.1", + "callsites": "^3.1.0", + "dot-prop": "^6.0.1", + "lodash.isequal": "^4.5.0", + "type-fest": "^1.2.1", + "vali-date": "^1.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "ts-mixer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", + "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" + }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==" + }, + "vali-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", + "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "ws": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.3.0.tgz", + "integrity": "sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw==", + "requires": {} + } + } +} diff --git a/package.json b/package.json index d7e99f0..c24ff2e 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "supportbot", - "version": "7.3.0", + "version": "7.4.0", "description": "SupportBot is an open-sourced support system for discord. It's completely free to use with high amounts of customization to match your own brand.", "main": "index.js", "scripts": { - "start": "npm i && node index.js" + "start": "npm i && node index.js", + "test": "node index.js test" }, "repository": { "type": "git", @@ -17,7 +18,7 @@ }, "homepage": "https://github.com/Emerald-Services/SupportBot#readme", "dependencies": { - "discord.js": "^13.2.0", + "discord.js": "^13.3.1", "js-yaml": "^4.1.0" } }