diff --git a/Addons/.DS_Store b/Addons/.DS_Store deleted file mode 100644 index ceaaab3..0000000 Binary files a/Addons/.DS_Store and /dev/null differ diff --git a/Addons/Readme.md b/Addons/Readme.md deleted file mode 100644 index cf5930e..0000000 --- a/Addons/Readme.md +++ /dev/null @@ -1,2 +0,0 @@ -## SupportBot Addons -This is a developer version of SupportBot, Addons are not yet supported. \ No newline at end of file diff --git a/Commands/add.js b/Commands/add.js deleted file mode 100644 index 039f0aa..0000000 --- a/Commands/add.js +++ /dev/null @@ -1,104 +0,0 @@ -// SupportBot | Emerald Services -// Ticket Add Command - -const fs = require("fs"); - -const Discord = require("discord.js"); -const yaml = require("js-yaml"); - -const supportbot = yaml.load( - fs.readFileSync("./Configs/supportbot.yml", "utf8") -); - -const cmdconfig = yaml.load( - fs.readFileSync("./Configs/commands.yml", "utf8") -); - -const msgconfig = yaml.load( - fs.readFileSync("./Configs/messages.yml", "utf8") -); - -const Command = require("../Structures/Command.js"); - -module.exports = new Command({ - name: cmdconfig.TicketAdd.Command, - description: cmdconfig.TicketAdd.Description, - type: Discord.ApplicationCommandType.ChatInput, - options: [ - { - name: "user", - description: "User to add", - type: Discord.ApplicationCommandOptionType.User, - required: true, - }, - ], - permissions: cmdconfig.TicketAdd.Permission, - - async run(interaction) { - let disableCommand = true; - - const { getRole } = interaction.client; - let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild); - let Admin = await getRole(supportbot.Roles.StaffMember.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.EmbedBuilder() - .setTitle("Invalid Permissions!") - .setDescription( - `${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\`` - ) - .setColor(supportbot.Embed.Colours.Warn); - - if ( - !interaction.member.roles.cache.has(SupportStaff.id) && - !interaction.member.roles.cache.has(Admin.id) - ) - return interaction.reply({ ephemeral: true, 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.EmbedBuilder() - .setTitle("No Ticket Found!") - .setDescription(msgconfig.Error.NoValidTicket) - .setColor(supportbot.Embed.Colours.Warn); - return interaction.reply({ ephemeral: true, embeds: [Exists] }); - } - - let uMember = interaction.options.getUser("user"); - const UserNotExist = new Discord.EmbedBuilder() - .setTitle("User Not Found!") - .setDescription( - `${msgconfig.Error.UserNotFound}\n\nTry Again:\`/${cmdconfig.TicketAdd} \`` - ) - .setColor(supportbot.Embed.Colours.Error); - - if (!uMember) return interaction.reply({ embeds: [UserNotExist] }); - - await interaction.channel.permissionOverwrites.edit(uMember.id, { - ViewChannel: true, - }); - const Complete = new Discord.EmbedBuilder() - .setTitle("User Added!") - .setDescription(msgconfig.Ticket.AddedUser.replace(/%user%/g, uMember.id)) - .setTimestamp() - .setColor(supportbot.Embeds.Colours.General); - 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 5bb91f6..dc497ab 100644 --- a/Commands/close.js +++ b/Commands/close.js @@ -1,19 +1,13 @@ -// SupportBot | Emerald Services -// Close Ticket Command - const fs = require("fs"); - const Discord = require("discord.js"); const yaml = require("js-yaml"); const supportbot = yaml.load( fs.readFileSync("./Configs/supportbot.yml", "utf8") ); - const cmdconfig = yaml.load( fs.readFileSync("./Configs/commands.yml", "utf8") ); - const msgconfig = yaml.load( fs.readFileSync("./Configs/messages.yml", "utf8") ); @@ -34,24 +28,23 @@ module.exports = new Command({ permissions: cmdconfig.CloseTicket.Permission, async run(interaction) { - let disableCommand = true; - const { getRole, getChannel } = interaction.client; + if (supportbot.Ticket.Close.StaffOnly) { let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild); let Admin = await getRole(supportbot.Roles.StaffMember.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.EmbedBuilder() - .setTitle("Invalid Permissions!") - .setDescription( - `${supportbot.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\`` - ) - .setColor(supportbot.Embed.Colours.Warn); - + const NoPerms = new Discord.EmbedBuilder() + .setTitle("Invalid Permissions!") + .setDescription( + `${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\`` + ) + .setColor(supportbot.Embed.Colours.Warn); if ( !interaction.member.roles.cache.has(SupportStaff.id) && @@ -59,14 +52,22 @@ module.exports = new Command({ ) return interaction.reply({ embeds: [NoPerms] }); } + + if (interaction.channel.type !== Discord.ChannelType.PrivateThread) { + const NotTicketChannel = new Discord.EmbedBuilder() + .setTitle("Invalid Channel!") + .setDescription("This command can only be used in a ticket thread.") + .setColor(supportbot.Embed.Colours.Warn); + + return interaction.reply({ embeds: [NotTicketChannel], ephemeral: true }); + } + await interaction.deferReply(); - let tickets = await JSON.parse( - fs.readFileSync("./Data/TicketData.json", "utf8") - ); - let TicketData = await tickets.tickets.findIndex( - (t) => t.id === interaction.channel.id - ); + + let tickets = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8")); + let TicketData = tickets.tickets.findIndex((t) => t.id === interaction.channel.id); let ticket = tickets.tickets[TicketData]; + if (TicketData === -1) { const Exists = new Discord.EmbedBuilder() .setTitle("No Ticket Found!") @@ -74,121 +75,217 @@ module.exports = new Command({ .setColor(supportbot.Embed.Colours.Warn); return interaction.followUp({ embeds: [Exists] }); } - let tUser = interaction.client.users.cache.get(ticket.user); - let transcriptChannel = await getChannel( - supportbot.Ticket.Log.TranscriptLog, - interaction.guild - ); - let logChannel = await getChannel(supportbot.Log.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.Ticket.Close.CloseConfirmation) { - const CloseTicketRequest = new Discord.EmbedBuilder() - .setTitle(`**${supportbot.ClosingTicket}**`) - .setDescription( - `Please confirm by repeating the following word.. \`${supportbot.Ticket.Close.ClosingConfirmation_Word}\` ` - ) - .setColor(supportbot.Embed.Colours.General); - await interaction.followUp({ embeds: [CloseTicketRequest] }); - let filter = (m) => - m.content.toLowerCase() === supportbot.Ticket.Close.ClosingConfirmation_Word && - m.author.id === interaction.user.id; - await interaction.channel.awaitMessages({ - filter, - max: 1, - time: 20000, - errors: ["time"], + let reason = interaction.options?.getString("reason") || "No Reason Provided."; + + const CloseButton = new Discord.ButtonBuilder() + .setCustomId("confirmCloseTicket") + .setLabel(supportbot.Ticket.Close.Confirmation_Button) + .setStyle(Discord.ButtonStyle.Danger); + + const row = new Discord.ActionRowBuilder().addComponents(CloseButton); + + const CloseTicketRequest = new Discord.EmbedBuilder() + .setTitle(`**${supportbot.Ticket.Close.Title}**`) + .setDescription( + `${msgconfig.Ticket.ConfirmClose}` + ) + .setColor(supportbot.Embed.Colours.General); + + await interaction.followUp({ + embeds: [CloseTicketRequest], + components: [row], + }); + + const filter = (btnInteraction) => btnInteraction.customId === "confirmCloseTicket" && btnInteraction.user.id === interaction.user.id; + + interaction.channel.awaitMessageComponent({ filter, time: 20000 }) + .then(async (btnInteraction) => { + await handleCloseTicket(interaction, reason, ticket, TicketData); + await btnInteraction.reply({ content: "Ticket successfully closed.", ephemeral: true }); + }) + .catch((err) => { + interaction.followUp(`${msgconfig.Ticket.CloseTimeout}`); + console.error(err); + }); + }, +}); + +async function handleCloseTicket(interaction, reason, ticket, TicketData) { + const { getChannel } = interaction.client; + + let tickets = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8")); + let tUser = interaction.client.users.cache.get(ticket.user); + let transcriptChannel = await getChannel(supportbot.Ticket.Log.TranscriptLog, interaction.guild); + let logChannel = await getChannel(supportbot.Ticket.Log.TicketLog, interaction.guild); + + if (!transcriptChannel || !logChannel) + return interaction.followUp("Some Channels seem to be missing!"); + + try { + tickets.tickets[TicketData].open = false; + fs.writeFileSync( + "./Data/TicketData.json", + JSON.stringify(tickets, null, 4), + (err) => { + if (err) console.error(err); + } + ); + + const transcriptEmbed = new Discord.EmbedBuilder() + .setTitle(supportbot.Ticket.Log.TranscriptTitle) + .setColor(supportbot.Embed.Colours.General) + .setFooter({ + text: supportbot.Embed.Footer, + iconURL: interaction.user.displayAvatarURL(), + }) + .addFields( + { name: "Ticket", value: `${interaction.channel.name} (${interaction.channel.id})` }, + { name: "User", value: `${tUser?.username || "N/A"}#${tUser?.discriminator || "N/A"} (${tUser?.id || ticket.user})` }, + { name: "Closed By", value: interaction.user.tag }, + { name: "Reason", value: reason } + ); + + const logEmbed = new Discord.EmbedBuilder() + .setTitle(supportbot.Ticket.Log.TicketLog_Title) + .setColor(supportbot.Embed.Colours.General) + .setFooter({ + text: supportbot.Embed.Footer, + iconURL: interaction.user.displayAvatarURL(), + }) + .addFields( + { name: "Ticket", value: `${interaction.channel.name} (${interaction.channel.id})` }, + { name: "User", value: `${tUser?.username || "N/A"}#${tUser?.discriminator || "N/A"} (${tUser?.id || ticket.user})` }, + { name: "Closed By", value: interaction.user.tag }, + { name: "Reason", value: reason } + ); + + let msgs = await interaction.channel.messages.fetch({ limit: 100 }); + let html = ` + + + + + + +
+

Ticket Transcript

+

Server Name: ${interaction.guild.name}

+

Ticket: ${interaction.channel.name}

+

Messages: ${msgs.size} Messages

+
+ `; + + msgs = msgs.sort((a, b) => a.createdTimestamp - b.createdTimestamp); + msgs.forEach((msg) => { + if (msg.content) { + html += ` +
+ Avatar +
+

${msg.author.tag}

+

${msg.createdAt.toLocaleString()}

+

${convertMarkdownToHTML(msg.content)}

+
+
+ `; + } + }); + + const fileName = `${interaction.channel.name}.html`; + + html += ` +
+ Download Transcript +
+ + + `; + + if (!supportbot.Ticket.Log.DisableTicketLogChannel) { + await logChannel.send({ embeds: [logEmbed] }).catch((err) => { + console.error(err); }); } - 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(`**${msgconfig.Ticket.ClosingTicket}**`); - const transcriptEmbed = new Discord.EmbedBuilder() - .setTitle(supportbot.Ticket.Log.TranscriptTitle) - .setColor(supportbot.Embed.Colours.General) - .setFooter({ - text: supportbot.Embed.Footer, - iconURL: interaction.user.displayAvatarURL(), - }) - .addField( - "Ticket", - `${interaction.channel.name} (${interaction.channel.id})` - ) - .addField( - "User", - `${tUser?.username || "N/A"}#${tUser?.discriminator || "N/A"} (${ - tUser?.id || ticket.user - })` - ) - .addField("Closed By", interaction.user.tag) - .addField("Reason", reason); - const logEmbed = new Discord.EmbedBuilder() - .setTitle(supportbot.Ticket.Log.TicketLog_Title) - .setColor(supportbot.Embed.Colours.General) - .setFooter({ - text: supportbot.Embed.Footer, - iconURL: interaction.user.displayAvatarURL(), - }) - .addField( - "Ticket", - `${interaction.channel.name} (${interaction.channel.id})` - ) - .addField( - "User", - `${tUser?.username || "N/A"}#${tUser?.discriminator || "N/A"} (${ - tUser?.id || ticket.user - })` - ) - .addField("Closed By", interaction.user.tag) - .addField("Reason", reason); - let msgs = await interaction.channel.messages.fetch({ limit: 100 }); - let html = ""; - 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 file = new Discord.AttachmentBuilder( + Buffer.from(html), + { name: fileName } + ); - await msgs.forEach((msg) => { - if (msg.content) { - html += `User: ${msg.author.tag}
`; - html += `Message: ${msg.content}
`; - html += `-----

`; - } + await transcriptChannel + .send({ embeds: [transcriptEmbed], files: [file] }) + .catch((err) => { + console.error(err); }); - if (!(supportbot.Ticket.Log.DisableTicketLogChannel)) { - await logChannel.send({ embeds: [logEmbed] }).catch((err) => { - console.error(err); - }); - } - 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); - }); - if (supportbot.Ticket.DMTranscripts) { - - await tUser + if (supportbot.Ticket.DMTranscripts) { + await tUser ?.send({ embeds: [transcriptEmbed], files: [file] }) - .catch(async (err) => { + .catch((err) => { console.error(err); }); + if (ticket.subUsers) { ticket.subUsers.forEach(async (subUser) => { await interaction.client.users.cache @@ -196,17 +293,43 @@ module.exports = new Command({ ?.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); } - }, -}); + + await interaction.channel.delete().catch((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); + } +} + +function convertMarkdownToHTML(text) { + // Convert **bold** to bold + text = text.replace(/\*\*(.*?)\*\*/g, '$1'); + + // Convert *italic* to italic + text = text.replace(/\*(.*?)\*/g, '$1'); + + // Convert __underline__ to underline + text = text.replace(/__(.*?)__/g, '$1'); + + // Convert ~~strikethrough~~ to strikethrough + text = text.replace(/~~(.*?)~~/g, '$1'); + + // Convert inline code `code` to code + text = text.replace(/`(.*?)`/g, '$1'); + + // Convert blockquotes > quote to
quote
+ text = text.replace(/^> (.*?$)/gm, '
$1
'); + + // Convert multiline code blocks ```code``` to
code
+ text = text.replace(/```(.*?)```/gs, '
$1
'); + + // Convert line breaks to
+ text = text.replace(/\n/g, '
'); + + return text; +} diff --git a/Commands/embed.js b/Commands/embed.js index 3e4a8bd..1f4d447 100644 --- a/Commands/embed.js +++ b/Commands/embed.js @@ -1,22 +1,12 @@ -// SupportBot | Emerald Services -// Embed Command +// File path: ./commands/embed.js const fs = require("fs"); - const Discord = require("discord.js"); const yaml = require("js-yaml"); -const supportbot = yaml.load( - fs.readFileSync("./Configs/supportbot.yml", "utf8") -); - -const cmdconfig = yaml.load( - fs.readFileSync("./Configs/commands.yml", "utf8") -); - -const msgconfig = yaml.load( - fs.readFileSync("./Configs/messages.yml", "utf8") -) +const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8")); +const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); +const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8")); const Command = require("../Structures/Command.js"); @@ -44,21 +34,14 @@ module.exports = new Command({ required: false, }, { - name: "fieldtitle", - description: "Add an additional Embed Field", - type: Discord.ApplicationCommandOptionType.String, - required: false, - }, - { - name: "fieldcontent", - description: "Add an additional Embed Field", + name: "fields", + description: "Embed Fields (title|content;title|content;...)", type: Discord.ApplicationCommandOptionType.String, required: false, }, { name: "thumbnail", description: "Embed Thumbnail URL", - type: Discord.ApplicationCommandOptionType.String, required: false, }, @@ -68,47 +51,111 @@ module.exports = new Command({ type: Discord.ApplicationCommandOptionType.String, required: false, }, + { + name: "footer", + description: "Embed Footer Text", + type: Discord.ApplicationCommandOptionType.String, + required: false, + }, + { + name: "footericon", + description: "Embed Footer Icon URL", + type: Discord.ApplicationCommandOptionType.String, + required: false, + }, + { + name: "author", + description: "Embed Author Name", + type: Discord.ApplicationCommandOptionType.String, + required: false, + }, + { + name: "authoricon", + description: "Embed Author Icon URL", + type: Discord.ApplicationCommandOptionType.String, + required: false, + }, + { + name: "authorurl", + description: "Embed Author URL", + type: Discord.ApplicationCommandOptionType.String, + required: false, + }, + { + name: "timestamp", + description: "Include Timestamp", + type: Discord.ApplicationCommandOptionType.Boolean, + required: false, + }, + { + name: "inline", + description: "Make Fields Inline", + type: Discord.ApplicationCommandOptionType.Boolean, + required: false, + } ], permissions: cmdconfig.Embed.Permission, async run(interaction) { - let disableCommand = true; - const { getRole } = interaction.client; let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild); let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild); - if (!SupportStaff || !Admin) - return interaction.reply( - "Some roles seem to be missing!\nPlease check for errors when starting the bot." - ); + if (!SupportStaff || !Admin) { + return interaction.reply("Some roles seem to be missing!\nPlease check for errors when starting the bot."); + } - const NoPerms = new Discord.EmbedBuilder() + const NoPerms = new Discord.EmbedBuilder() .setTitle("Invalid Permissions!") - .setDescription( - `${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\`` - ) + .setDescription(`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``) .setColor(supportbot.Embed.Colours.Warn); if ( interaction.member.roles.cache.has(SupportStaff.id) || interaction.member.roles.cache.has(Admin.id) ) { - const EmbedTitle = interaction.options.getString("title"); - const EmbedSubject = interaction.options.getString("message"); - const GeneralColour = interaction.options.getString("color"); + const EmbedTitle = interaction.options.getString("title").replace(/\\n/g, '\n'); + const EmbedSubject = interaction.options.getString("message").replace(/\\n/g, '\n'); + const GeneralColour = interaction.options.getString("color") || supportbot.Embed.Colours.Default; const EmbedThumbnail = interaction.options.getString("thumbnail"); const EmbedImage = interaction.options.getString("image"); - const EmbedFieldContent = interaction.options.getString("fieldcontent"); - const EmbedFieldTitle = interaction.options.getString("fieldtitle"); + const EmbedFields = interaction.options.getString("fields"); + const EmbedFooter = interaction.options.getString("footer")?.replace(/\\n/g, '\n'); + const EmbedFooterIcon = interaction.options.getString("footericon"); + const EmbedAuthor = interaction.options.getString("author")?.replace(/\\n/g, '\n'); + const EmbedAuthorIcon = interaction.options.getString("authoricon"); + const EmbedAuthorURL = interaction.options.getString("authorurl"); + const EmbedTimestamp = interaction.options.getBoolean("timestamp"); + const InlineFields = interaction.options.getBoolean("inline"); const EmbedMsg = new Discord.EmbedBuilder() .setTitle(EmbedTitle) .setDescription(EmbedSubject) .setColor(GeneralColour) .setThumbnail(EmbedThumbnail) - .setImage(EmbedImage) - if (EmbedFieldTitle && EmbedFieldContent) { EmbedMsg.addField(EmbedFieldTitle, EmbedFieldContent) }; + .setImage(EmbedImage); + + if (EmbedFields) { + const fieldsArray = EmbedFields.split(';'); + fieldsArray.forEach(field => { + const [title, value] = field.split('|'); + if (title && value) { + EmbedMsg.addFields({ name: title.replace(/\\n/g, '\n'), value: value.replace(/\\n/g, '\n'), inline: InlineFields || false }); + } + }); + } + + if (EmbedFooter) { + EmbedMsg.setFooter({ text: EmbedFooter, iconURL: EmbedFooterIcon }); + } + + if (EmbedAuthor) { + EmbedMsg.setAuthor({ name: EmbedAuthor, iconURL: EmbedAuthorIcon, url: EmbedAuthorURL }); + } + + if (EmbedTimestamp) { + EmbedMsg.setTimestamp(); + } interaction.reply({ embeds: [EmbedMsg], diff --git a/Commands/help.js b/Commands/help.js index 17578e1..edea11b 100644 --- a/Commands/help.js +++ b/Commands/help.js @@ -2,7 +2,6 @@ // Help Command const fs = require("fs"); - const Discord = require("discord.js"); const yaml = require("js-yaml"); @@ -24,62 +23,51 @@ module.exports = new Command({ permissions: cmdconfig.Help.Permission, async run(interaction) { - let disableCommand = true; - const { getRole } = interaction.client; let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild); let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild); - if (!SupportStaff || !Admin) - + if (!SupportStaff || !Admin) { return interaction.reply( "Some roles seem to be missing!\nPlease check for errors when starting the bot." ); - - let botCommands = ""; - botCommands += ` \`${cmdconfig.Help.Command}\` `; - botCommands += `\`${cmdconfig.Ping.Command}\` `; - botCommands += `\`${cmdconfig.Info.Command}\` `; - - if (supportbot.DisableSuggestions === false) { - botCommands += `\`${cmdconfig.Suggestion.Command}\` `; } - let ticketCommands = ""; - ticketCommands += ` \`${cmdconfig.OpenTicket.Command}\` `; - ticketCommands += `\`${cmdconfig.CloseTicket.Command}\` `; - - let staffCommands = ""; - staffCommands += ` \`${cmdconfig.TicketAdd.Command}\` `; - staffCommands += `\`${cmdconfig.TicketRemove.Command}\` `; - staffCommands += `\`${cmdconfig.UserInfo.Command}\` `; - staffCommands += `\`${cmdconfig.Translate.Command}\` `; + // Fetch all commands from the client's commands collection + let botCommands = ""; + interaction.client.commands.forEach((command) => { + if (command.permissions) { + botCommands += `\`${command.name}\` `; + } + }); + // Create embed const HelpEmbed1 = new Discord.EmbedBuilder() .setTitle(supportbot.General.Name + " Commands") .setThumbnail(interaction.user.displayAvatarURL()) .setColor(supportbot.Embed.Colours.General) - .addFields( - { - name: "🖥️ Commands\n", - value: `${botCommands} ${ticketCommands} ${staffCommands}\n`, - inline: false, - }, - { - name: "🖥️ Addons\n", - value: `\`hello\`\n`, - inline: false, - } - ) - - .setColor(supportbot.Embed.Colours.General) - .setFooter({ - text: supportbot.Embed.Footer, - iconURL: interaction.user.displayAvatarURL(), + .addFields({ + name: "🖥️ Commands\n", + value: botCommands || "No commands available.", + inline: false, }); - interaction.reply({ - ephemeral: true, - embeds: [HelpEmbed1], + // Conditionally add Addons section + if (supportbot.General.Addons.Enabled) { + HelpEmbed1.addFields({ + name: "🛠️ Addons\n", + value: "No addons available.", + inline: false, }); + } + + HelpEmbed1.setFooter({ + text: supportbot.Embed.Footer, + iconURL: interaction.user.displayAvatarURL(), + }); + + interaction.reply({ + ephemeral: true, + embeds: [HelpEmbed1], + }); }, }); diff --git a/Commands/remove.js b/Commands/remove.js deleted file mode 100644 index 5c1951a..0000000 --- a/Commands/remove.js +++ /dev/null @@ -1,107 +0,0 @@ -// SupportBot | Emerald Services -// Ticket Remove Command - -const fs = require("fs"); - -const Discord = require("discord.js"); -const yaml = require("js-yaml"); - -const supportbot = yaml.load( - fs.readFileSync("./Configs/supportbot.yml", "utf8") -); - -const cmdconfig = yaml.load( - fs.readFileSync("./Configs/commands.yml", "utf8") -); - -const msgconfig = yaml.load( - fs.readFileSync("./Configs/messages.yml", "utf8") -); - -const Command = require("../Structures/Command.js"); - -module.exports = new Command({ - name: cmdconfig.TicketRemove.Command, - description: cmdconfig.TicketRemove.Description, - type: Discord.ApplicationCommandType.ChatInput, - options: [ - { - name: "user", - description: "User to remove", - type: Discord.ApplicationCommandOptionType.User, - required: true, - }, - ], - permissions: cmdconfig.TicketRemove.Permission, - - async run(interaction) { - let disableCommand = true; - - const { getRole } = interaction.client; - let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild); - let Admin = await getRole(supportbot.Roles.StaffMember.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.EmbedBuilder() - .setTitle("Invalid Permissions!") - .setDescription( - `${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\`` - ) - .setColor(supportbot.Embed.Colours.Warn); - - if ( - !interaction.member.roles.cache.has(SupportStaff.id) && - !interaction.member.roles.cache.has(Admin.id) - ) - return interaction.reply({ ephemeral: true, 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.EmbedBuilder() - .setTitle("No Ticket Found!") - .setDescription(msgconfig.Error.NoValidTicket) - .setColor(supportbot.Embed.Colours.Warn); - return interaction.reply({ ephemeral: true, embeds: [Exists] }); - } - - let uMember = interaction.options.getUser("user"); - const UserNotExist = new Discord.EmbedBuilder() - .setTitle("User Not Found!") - .setDescription( - `${msgconfig.Error.UserNotFound}\n\nTry Again:\`/${cmdconfig.TicketRemove} \`` - ) - .setColor(supportbot.Embed.Colours.Error); - - if (!uMember) return interaction.reply({ ephemeral: true, embeds: [UserNotExist] }); - - await interaction.channel.permissionOverwrites.edit(uMember.id, { - ViewChannel: false, - }); - - const Complete = new Discord.EmbedBuilder() - .setTitle("User Removed!") - .setDescription(msgconfig.Ticket.RemovedUser.replace(/%user%/g, uMember.id)) - .setTimestamp() - .setColor(supportbot.Embed.Colours.General); - 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 c05aca4..65f1c2d 100644 --- a/Commands/suggest.js +++ b/Commands/suggest.js @@ -1,25 +1,21 @@ -// SupportBot | Emerald Services -// Suggest Command - const fs = require("fs"); - const Discord = require("discord.js"); const yaml = require("js-yaml"); -const supportbot = yaml.load( - fs.readFileSync("./Configs/supportbot.yml", "utf8") -); - -const cmdconfig = yaml.load( - fs.readFileSync("./Configs/commands.yml", "utf8") -); - -const msgconfig = yaml.load( - fs.readFileSync("./Configs/messages.yml", "utf8") -); +// Load configurations +const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8")); +const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); +const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8")); const Command = require("../Structures/Command.js"); -const { channel } = require("diagnostics_channel"); + +// Ensure suggestions file exists and is correctly loaded +let suggestions; +try { + suggestions = require("../Data/SuggestionData.json"); +} catch (error) { + suggestions = {}; +} module.exports = new Command({ name: cmdconfig.Suggestion.Command, @@ -36,8 +32,6 @@ module.exports = new Command({ permissions: cmdconfig.Suggestion.Permission, async run(interaction) { - let disableCommand = true; - const { getChannel } = interaction.client; const suggestChannel = await getChannel( @@ -56,10 +50,11 @@ module.exports = new Command({ const SuggestEmbed = new Discord.EmbedBuilder() .addFields( - { name: "Suggestion", value: suggestion, inline: true}, - { name: "From", value: `<@${interaction.user.id}>`}, + { name: "Suggestion", value: suggestion, inline: true }, + { name: "From", value: `<@${interaction.user.id}>` }, + { name: `${supportbot.Suggestions.UpvoteEmoji} ${supportbot.Suggestions.UpvoteTitle}`, value: "0", inline: true }, + { name: `${supportbot.Suggestions.DownvoteEmoji} ${supportbot.Suggestions.DownvoteTitle}`, value: "0", inline: true } ) - .setThumbnail(interaction.user.displayAvatarURL()) .setFooter({ text: supportbot.Embed.Footer, @@ -67,35 +62,54 @@ module.exports = new Command({ }) .setColor(supportbot.Embed.Colours.General); - const suggestionMsg = await suggestChannel.send({ embeds: [SuggestEmbed] }); + const UpvoteButton = new Discord.ButtonBuilder() + .setCustomId("upvote") + .setEmoji(supportbot.Suggestions.UpvoteEmoji) + .setStyle(supportbot.Suggestions.Buttons.Upvote); - if (supportbot.Suggestions.UpvoteEmoji && supportbot.Suggestions.DownvoteEmoji) { - await suggestionMsg.react(supportbot.Suggestions.UpvoteEmoji); - await suggestionMsg.react(supportbot.Suggestions.DownvoteEmoji); + const DownvoteButton = new Discord.ButtonBuilder() + .setCustomId("downvote") + .setEmoji(supportbot.Suggestions.DownvoteEmoji) + .setStyle(supportbot.Suggestions.Buttons.Downvote); - if (supportbot.Suggestions.Threads.Enabled) { - await suggestionMsg.startThread({ - name: supportbot.Suggestions.Threads.Title, - autoArchiveDuration: 60, - type: Discord.ChannelType.GuildPublicThread, - reason: supportbot.Suggestions.Threads.Reason, - }) - - } + const RemoveVoteButton = new Discord.ButtonBuilder() + .setCustomId("removevote") + .setLabel(supportbot.Suggestions.Buttons.RemoveVote_Title) + .setStyle(supportbot.Suggestions.Buttons.RemoveVote); // Red button + + const row = new Discord.ActionRowBuilder().addComponents(UpvoteButton, DownvoteButton, RemoveVoteButton); + + const suggestionMsg = await suggestChannel.send({ embeds: [SuggestEmbed], components: [row] }); + + suggestions[suggestionMsg.id] = { + suggestion: suggestion, + author: interaction.user.id, + upvotes: [], + downvotes: [] + }; + + fs.writeFileSync("./Data/SuggestionData.json", JSON.stringify(suggestions, null, 2)); + + if (supportbot.Suggestions.Threads.Enabled) { + await suggestionMsg.startThread({ + name: supportbot.Suggestions.Threads.Title, + autoArchiveDuration: 60, + type: Discord.ChannelType.PublicThread, + reason: supportbot.Suggestions.Threads.Reason, + }); } const Submitted = new Discord.EmbedBuilder() - .setTitle("Suggestion Submitted!") - .setDescription(`:white_check_mark: You have successfully submitted a suggestion.`) + .setTitle(`${msgconfig.Suggestions.Sent_Title}`) + .setDescription(`${msgconfig.Suggestions.Sent}`) .addFields( - { name: "Sent to:", value: `<#${suggestChannel.id}>`}, + { name: "Sent to:", value: `<#${suggestChannel.id}>` }, ) .setColor(supportbot.Embed.Colours.Success); - return interaction.reply({ + await interaction.reply({ ephemeral: true, embeds: [Submitted] - }) - + }); }, }); diff --git a/Commands/ticket.js b/Commands/ticket.js index a45ddf5..c540958 100644 --- a/Commands/ticket.js +++ b/Commands/ticket.js @@ -1,35 +1,21 @@ -// SupportBot | Emerald Services -// Ticket Command - const fs = require("fs"); - const { EmbedBuilder, - Permissions, - MessageButton, - MessageActionRow, ApplicationCommandOptionType, ApplicationCommandType, - ButtonStyle, - InteractionType, - DiscordAPIError, ChannelType, - InteractionCollector + ActionRowBuilder, + ButtonBuilder, + StringSelectMenuBuilder, + StringSelectMenuOptionBuilder, + GuildMemberRoleManager, } = require("discord.js"); - const yaml = require("js-yaml"); -const supportbot = yaml.load( - fs.readFileSync("./Configs/supportbot.yml", "utf8") -); - -const cmdconfig = yaml.load( - fs.readFileSync("./Configs/commands.yml", "utf8") -); - -const msgconfig = yaml.load( - fs.readFileSync("./Configs/messages.yml", "utf8") -) +const panelconfig = yaml.load(fs.readFileSync("./Configs/ticket-panel.yml", "utf8")); +const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8")); +const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); +const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8")); const Command = require("../Structures/Command.js"); const TicketNumberID = require("../Structures/TicketID.js"); @@ -44,28 +30,18 @@ module.exports = new Command({ description: "Ticket Reason", type: ApplicationCommandOptionType.String, }, - ], permissions: cmdconfig.OpenTicket.Permission, async run(interaction) { - let disableCommand = true; - - - let department = interaction.customId?.split("-")[1] || null; - let TicketData = await JSON.parse( - fs.readFileSync("./Data/TicketData.json", "utf8") - ); - const { getRole, getCategory } = interaction.client; + let TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8")); + const { getRole, getChannel } = interaction.client; let User = interaction.guild.members.cache.get(interaction.user.id); - - if ( supportbot.Ticket.TicketsPerUser && - TicketData.tickets.filter((t) => t.user === interaction.user.id && t.open) - .length >= supportbot.Ticket.TicketsPerUser + TicketData.tickets.filter((t) => t.user === interaction.user.id && t.open).length >= supportbot.Ticket.TicketsPerUser ) { return interaction.reply({ embeds: [ @@ -78,26 +54,23 @@ module.exports = new Command({ ephemeral: true, }); } + if (User.roles.cache.has(supportbot.Roles.ModRoles.Blacklisted)) { return interaction.reply({ content: msgconfig.Ticket.Blacklisted, ephemeral: true, - }) - }; + }); + } if (User.roles.cache.has(supportbot.Roles.ModRoles.Muted)) { return interaction.reply({ content: msgconfig.Ticket.Muted, ephemeral: true, - }) - }; + }); + } - // Ticket ID let ticketNumberID = await TicketNumberID.pad(); - - // Ticket Subject - const TicketSubject = - interaction.options?.getString("reason") || msgconfig.Ticket.InvalidSubject; + const TicketSubject = interaction.options?.getString("reason") || msgconfig.Ticket.InvalidSubject; const TicketExists = new EmbedBuilder() .setTitle("Ticket Exists!") @@ -105,8 +78,7 @@ module.exports = new Command({ if ( await interaction.guild.channels.cache.find( - (ticketChannel) => - ticketChannel.name === `${supportbot.Ticket.Channel}${ticketNumberID}` + (ticketChannel) => ticketChannel.name === `${supportbot.Ticket.Channel}${ticketNumberID}` ) ) { return await interaction.reply({ @@ -119,49 +91,75 @@ module.exports = new Command({ const Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild); if (!Staff || !Admin) - return interaction.reply({ - content: - "Some roles seem to be missing!\nPlease check for errors when starting the bot.", + content: "Some roles seem to be missing!\nPlease check for errors when starting the bot.", ephemeral: true, }); - let TicketCategory = await getCategory( - supportbot.Departments[department].category, - interaction.guild + const TicketCategory = interaction.guild.channels.cache.find( + (c) => c.name === supportbot.Ticket.TicketCategory || c.id === supportbot.Ticket.TicketCategory ); - const ticketChannel = await interaction.guild.channels.create( - `${supportbot.TicketPrefix}${ticketNumberID}`, - { - type: ChannelType.GuildText, - parent: TicketCategory.id, - permissionOverwrites: [ - { - id: Admin.id, - allow: [PermissionsBitField.Flags.ViewChannel], - }, - { - id: interaction.user.id, - allow: [PermissionsBitField.Flags.ViewChannel], - }, - { - id: interaction.guild.id, - deny: [PermissionsBitField.Flags.ViewChannel], - }, - ], - } - ); - if (supportbot.Ticket.AllowAllStaff) { - await ticketChannel.permissionOverwrites.edit(Staff.id, { - ViewChannel: true, - }); + + const channel = await getChannel(panelconfig.Channel, interaction.guild); + const ticketChannel = await channel.threads.create({ + name: `${supportbot.Ticket.Channel}${ticketNumberID}`, + type: ChannelType.PrivateThread, + parent: TicketCategory, + autoArchiveDuration: 60, + reason: 'support ticket', + }); + + if (supportbot.Ticket.ClaimTickets.Enabled === false) { + const InvStaff = await ticketChannel.send(`<@&${Staff.id}> <@&${Admin.id}>`) + + setTimeout(() => { + InvStaff.delete(); + }, 2000) } + + // TICKET CLAIMING SYSTEM [START] + + if (supportbot.Ticket.ClaimTickets.Enabled) { + const InvStaff1 = await ticketChannel.send(`<@&${Admin.id}>`) + + setTimeout(() => { + InvStaff1.delete(); + }, 2000) + + const claimChannel = await getChannel( + supportbot.Ticket.ClaimTickets.Channel, + interaction.guild + ); + + const claimEmbed = new EmbedBuilder() + .setTitle(msgconfig.Ticket.ClaimTickets.ClaimTitle) + .setDescription(msgconfig.Ticket.ClaimTickets.ClaimMessage + .replace('%user%', interaction.user.id) + ) + .setColor(supportbot.Embed.Colours.General); + + const claimButton = new ButtonBuilder() + .setCustomId(`claimticket-${ticketChannel.id}`) + .setLabel(supportbot.Ticket.ClaimTickets.ButtonTitle) + .setStyle(supportbot.Ticket.ClaimTickets.Button); + + const row = new ActionRowBuilder().addComponents(claimButton); + + await claimChannel.send({ + content: `<@&${Staff.id}>`, + embeds: [claimEmbed], + components: [row] + }); + + } + + // TICKET CLAIMING SYSTEM [END] + if (!department) { - await ticketChannel.permissionOverwrites.edit(interaction.user.id, { - SendMessages: false, - }); + await ticketChannel.members.add(interaction.user.id); } - await TicketData.tickets.push({ + + TicketData.tickets.push({ id: ticketChannel.id, name: ticketChannel.name, user: interaction.user.id, @@ -169,7 +167,10 @@ module.exports = new Command({ reason: TicketSubject, open: true, subUsers: [], + createdAt: new Date().toISOString(), + claimedAt: null, // Will be updated when claimed }); + fs.writeFileSync( "./Data/TicketData.json", JSON.stringify(TicketData, null, 4), @@ -180,10 +181,7 @@ module.exports = new Command({ const CreatedTicket = new EmbedBuilder() .setDescription( - msgconfig.Ticket.TicketCreatedAlert.replace( - /%ticketauthor%/g, - interaction.user.id - ) + msgconfig.Ticket.TicketCreatedAlert.replace(/%ticketauthor%/g, interaction.user.id) .replace(/%ticketid%/g, ticketChannel.id) .replace(/%ticketusername%/g, interaction.user.username) ) @@ -195,6 +193,12 @@ module.exports = new Command({ } const TicketMessage = new EmbedBuilder() + .setAuthor({ + name: msgconfig.Ticket.TicketAuthorTitle.replace(/%ticketauthor%/g, interaction.user.id) + .replace(/%ticketid%/g, ticketChannel.id) + .replace(/%ticketusername%/g, interaction.user.username), + iconURL: interaction.user.displayAvatarURL(), + }) .setTitle( msgconfig.Ticket.TicketTitle.replace(/%ticketauthor%/g, interaction.user.id) .replace(/%ticketid%/g, ticketChannel.id) @@ -207,72 +211,71 @@ module.exports = new Command({ ) .setColor(supportbot.Embed.Colours.General); - if (supportbot.Ticket.TicketSubject === "embed") { - if (TicketSubject !== "No Reason Provided.") { - TicketMessage.addFields({ name: "Reason", value: TicketSubject }); - } - } + const SelectMenus = new StringSelectMenuBuilder() + .setCustomId("ticketcontrolpanel") + .setPlaceholder("Ticket Control Panel") + .addOptions( + new StringSelectMenuOptionBuilder() + .setLabel("Add User") + .setDescription("Add a user to the ticket.") + .setEmoji(supportbot.SelectMenus.Tickets.AddUserEmoji) + .setValue("ticketadduser"), + new StringSelectMenuOptionBuilder() + .setLabel("Remove User") + .setDescription("Remove a user from the ticket.") + .setEmoji(supportbot.SelectMenus.Tickets.RemoveUserEmoji) + .setValue("ticketremoveuser"), + new StringSelectMenuOptionBuilder() + .setLabel("Close") + .setDescription("Close the ticket.") + .setEmoji(supportbot.SelectMenus.Tickets.CloseEmoji) + .setValue("ticketclose"), + new StringSelectMenuOptionBuilder() + .setLabel("Enable Invites") + .setDescription("Enable invites.") + .setEmoji(supportbot.SelectMenus.Tickets.EnableInvitesEmoji) + .setValue("enableinvites"), + new StringSelectMenuOptionBuilder() + .setLabel("Disable Invites") + .setDescription("Disable invites.") + .setEmoji(supportbot.SelectMenus.Tickets.DisableInvitesEmoji) + .setValue("disableinvites"), + ); - if (supportbot.Ticket.TicketSubject === "description") { - if (TicketSubject !== "No Reason Provided.") { - await ticketChannel.setTopic( - `Reason: ${TicketSubject} - User ID: ${interaction.user.id} - Ticket: ${ticketChannel.name}` - ); - } - } + const row2 = new ActionRowBuilder().addComponents(SelectMenus); - if (!department) { - TicketMessage.addFields({ - name: "Departments", - value: ` **${supportbot.Departments.map((X) => X.title).join("\n")}**`, - }); - } - const CloseButton = new MessageButton() - .setCustomId("ticketclose") - .setLabel("Close") - .setStyle(supportbot.Buttons.Tickets.CloseStyle) - .setEmoji(supportbot.Buttons.Tickets.CloseEmoji); - - const LockButton = new MessageButton() - .setCustomId("ticketlock") - .setLabel("Lock") - .setStyle(supportbot.Buttons.Tickets.LockStyle) - .setEmoji(supportbot.Buttons.Tickets.LockEmoji); - - const row2 = new MessageActionRow().addComponents(CloseButton, LockButton); if (!department) { try { - let buttons = await supportbot.Departments.map((x) => - new MessageButton() + let buttons = supportbot.Departments.map((x) => + new ButtonBuilder() .setCustomId("Department" + supportbot.Departments.indexOf(x)) .setLabel(x.title) .setStyle(x.color) .setEmoji(x.emoji) ); - const row = new MessageActionRow().addComponents(buttons); + + if (supportbot.Ticket.AllowMentions) { + await ticketChannel.send("<@&" + supportbot.Ticket.RoleMention + ">"); + } + + const row = new ActionRowBuilder().addComponents(buttons); const m = await ticketChannel.send({ embeds: [TicketMessage], - components: [row], + components: [row2], }); - let collector; try { const filter = (i) => i.user.id === interaction.user.id; - collector = await m.awaitMessageComponent({ + await m.awaitMessageComponent({ filter, max: 1, componentType: "BUTTON", time: supportbot.Ticket.Timeout * 60000, }); } catch (e) { - if (e.code === "INTERACTION_COLLECTOR_ERROR") { + if (e.code === "COLLECTOR_ERROR") { try { - TicketData = await JSON.parse( - fs.readFileSync("./Data/TicketData.json", "utf8") - ); - let ticket = await TicketData.tickets.findIndex( - (t) => t.id === ticketChannel.id - ); + let ticket = TicketData.tickets.findIndex((t) => t.id === ticketChannel.id); TicketData.tickets[ticket].open = false; fs.writeFileSync( "./Data/TicketData.json", @@ -284,71 +287,22 @@ module.exports = new Command({ interaction.user.send( "Your ticket has timed out. Please open a new one, and select a department." ); - } catch (e) {} + } catch (error) { + console.error("An error occurred while handling collector:", error); + } return await ticketChannel.delete(); } } - let num = collector.customId.split("Department")[1]; - let role = getRole(supportbot.Departments[num].role, interaction.guild); - let title = supportbot.Departments[num].title; - - await ticketChannel.permissionOverwrites.edit(role.id, { - ViewChannel: true, - }); - await ticketChannel.permissionOverwrites.edit(interaction.user.id, { - SendMessages: true, - }); - - await collector.reply({ - embeds: [ - { - description: `> Thank for reaching out to the **${title} Department**. Please provide us information regarding your query.`, - color: supportbot.Embed.Colours.General, - }, - ], - }); - - if (supportbot.Ticket.AllowMentions) { - await ticketChannel.send("@here"); - } - await collector.message.edit({ - embeds: [TicketMessage], - components: [row2], - }); - } catch (error) {} + } catch (error) { + console.error("Error sending message:", error); + } } else { await ticketChannel.send({ embeds: [TicketMessage], components: [row2], }); - if (department) { - let role = await getRole( - supportbot.Departments[department].role, - interaction.guild - ); - let title = supportbot.Departments[department].title; - await ticketChannel.permissionOverwrites.edit(role.id, { - ViewChannel: true, - }); - let TicketCat = await getCategory( - supportbot.Departments[department].category, - interaction.guild - ); - await ticketChannel.setParent(TicketCat.id, { lockPermissions: false }); - if (supportbot.TicketAllowThanksForReachingOutMessage) { - await ticketChannel.send({ - embeds: [ - { - description: `> Thank for reaching out to the **${title} Department**. Please provide us information regarding your query.`, - color: supportbot.Embed.Colours.General, - }, - ], - }); - } - } - if (supportbot.Ticket.AllowMentions) { - await ticketChannel.send(supportbot.Ticket.RoleMention); - } + } + }, }); diff --git a/Commands/ticketpanel.js b/Commands/ticketpanel.js new file mode 100644 index 0000000..aa459f0 --- /dev/null +++ b/Commands/ticketpanel.js @@ -0,0 +1,115 @@ +// ticketpanel.js +const fs = require("fs"); +const { + EmbedBuilder, + ApplicationCommandType, + ActionRowBuilder, + ButtonBuilder, +} = require("discord.js"); +const yaml = require("js-yaml"); + +const panelconfig = yaml.load(fs.readFileSync("./Configs/ticket-panel.yml", "utf8")); +const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8")); +const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); + +const Command = require("../Structures/Command.js"); + +module.exports = new Command({ + name: cmdconfig.TicketPanel.Command, + description: cmdconfig.TicketPanel.Description, + type: ApplicationCommandType.ChatInput, + options: [], + permissions: cmdconfig.TicketPanel.Permission, + + async run(interaction) { + if (!panelconfig.Panel) { + console.log( + "\u001b[31m", + `[TICKET PANEL]`, + "\u001b[33m", + "Ticket Panel is not setup, You can set this in", `\u001b[31m`, '/Configs/ticket-panel.yml', `\n `, + ); + return interaction.reply({ + content: "Ticket Panel is not set up. Please configure it in `/Configs/ticket-panel.yml`.", + ephemeral: true, + }); + } + + const channelName = panelconfig.TicketCategory; + const channel = interaction.guild.channels.cache.find(ch => ch.name === channelName); + if (!channel) { + console.log(`[TICKET PANEL] ${channelName} channel not found. Please check your config file.`); + return interaction.reply({ + content: `${channelName} channel not found. Please check your config file.`, + ephemeral: true, + }); + } + + const panelid = JSON.parse(fs.readFileSync("./Data/ticket-panel-id.json", "utf8")); + + try { + await channel.messages.fetch(panelid.TicketPanelID); + return interaction.reply({ + content: "Ticket panel message already exists.", + ephemeral: true, + }); + } catch (error) { + let embed = new EmbedBuilder() + .setTitle(panelconfig.PanelTitle) + .setColor(panelconfig.PanelColour) + .setFooter({ + text: supportbot.Embed.Footer, + iconURL: interaction.user.displayAvatarURL(), + }); + + if (panelconfig.TicketPanel_Description) { + embed.setDescription(panelconfig.PanelMessage); + } + + if (panelconfig.TicketPanel_Thumbnail) { + embed.setThumbnail(panelconfig.PanelThumbnail); + } + + if (panelconfig.TicketPanel_Image) { + embed.setImage(panelconfig.PanelImage); + } + + const createTicketButton = new ButtonBuilder() + .setCustomId("createticket") + .setLabel(panelconfig.Button.Text) + .setEmoji(panelconfig.Button.Emoji) + .setStyle(panelconfig.Button.Color); + + let row = new ActionRowBuilder().addComponents(createTicketButton); + + try { + const message = await channel.send({ + embeds: [embed], + components: [row], + }); + + let data = { + id: panelid.id, + TicketPanelID: message.id, + }; + + fs.writeFileSync( + "./Data/ticket-panel-id.json", + JSON.stringify(data), + "utf8" + ); + + return interaction.reply({ + content: "Ticket panel message has been sent!", + ephemeral: true, + }); + } catch (e) { + console.log("Error sending message:", e); + return interaction.reply({ + content: "An error occurred while sending the ticket panel message.", + ephemeral: true, + }); + } + } + }, +}); \ No newline at end of file diff --git a/Commands/ticketstats.js b/Commands/ticketstats.js new file mode 100644 index 0000000..1afea81 --- /dev/null +++ b/Commands/ticketstats.js @@ -0,0 +1,56 @@ +const { EmbedBuilder, ApplicationCommandType } = require("discord.js"); +const fs = require("fs"); +const yaml = require("js-yaml"); + +const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8")); +const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); +const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8")); + +const Command = require("../Structures/Command.js"); + +module.exports = new Command({ + name: cmdconfig.TicketStats.Command, + description: cmdconfig.TicketStats.Description, + type: ApplicationCommandType.ChatInput, + permissions: ["SendMessages"], // Adjust permissions as needed + + async run(interaction) { + + if (supportbot.Ticket.ClaimTickets.Enabled) { + + const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8")); + const userId = interaction.user.id; + + const ticketsClaimed = TicketData.tickets.filter(t => t.claimedBy === userId); + const ticketsOpen = ticketsClaimed.filter(t => t.open); + const totalTickets = ticketsClaimed.length; + + let totalResponseTime = 0; + let responseCount = 0; + + ticketsClaimed.forEach(ticket => { + if (ticket.claimedAt && ticket.createdAt) { + const responseTime = new Date(ticket.claimedAt) - new Date(ticket.createdAt); + totalResponseTime += responseTime; + responseCount++; + } + }); + + const averageResponseTime = responseCount ? totalResponseTime / responseCount : 0; + const averageResponseTimeMinutes = Math.round(averageResponseTime / 60000); // Convert to minutes + + const statsEmbed = new EmbedBuilder() + .setTitle(msgconfig.TicketStats.Title) + .setDescription(`> Ticket stats for <@${interaction.user.id}>`) + .setColor(supportbot.Embed.Colours.General) + .addFields( + { name: msgconfig.TicketStats.OpenTickets, value: `${ticketsOpen.length}`, inline: true }, + { name: msgconfig.TicketStats.TotalTickets, value: `${totalTickets}`, inline: true }, + { name: msgconfig.TicketStats.ResponseTime, value: `${averageResponseTimeMinutes} minutes`, inline: false } + ); + + await interaction.reply({ embeds: [statsEmbed], ephemeral: true }); + } + + } +}); diff --git a/Configs/commands.yml b/Configs/commands.yml index 83549a5..c8aaa6b 100644 --- a/Configs/commands.yml +++ b/Configs/commands.yml @@ -19,23 +19,29 @@ Help: Permission: ["SendMessages"] Enabled: true +EnableAI: + Command: "enableai" + Description: "Talk with SupportBot" + Permission: ["SendMessages"] + Enabled: true + Info: Command: "info" Description: "Get information about the **ServerName**." Permission: ["SendMessages"] Enabled: true -TicketAdd: - Command: "add" - Description: "Add a user to a ticket." - Permission: ["SendMessages"] - Enabled: false +TicketPanel: + Command: "ticketpanel" + Description: "Create the ticket creation panel" + Permission: ["Administrator"] + Enabled: true -TicketRemove: - Command: "remove" - Description: "Remove a user from a ticket." +TicketStats: + Command: "ticketstats" + Description: "Shows staff members their ticket statistics" Permission: ["SendMessages"] - Enabled: true + # Command is automatically disabled when the TicketClaims is disabled. OpenTicket: Command: "ticket" @@ -43,6 +49,12 @@ OpenTicket: Permission: ["SendMessages"] Enabled: true +Add: + Command: "add" + Description: "Add a user to the ticket." + Permission: ["SendMessages"] + Enabled: true + CloseTicket: Command: "close" Description: "Close a support ticket" diff --git a/Configs/messages.yml b/Configs/messages.yml index 5b47c21..ce83f5a 100644 --- a/Configs/messages.yml +++ b/Configs/messages.yml @@ -8,8 +8,8 @@ # Installed with MIT License # # Discord Support: https://dsc.gg/emerald-dev -# Official Documentation: https://emeraldsrv.dev/wiki -# Third-Party Documentation: https://emeraldsrv.dev/third-party +# Official Documentation: https://emeraldsrv.com/wiki +# Third-Party Documentation: https://emeraldsrv.com/third-party # # Messages Configuration @@ -17,7 +17,7 @@ Info: Title: "About Us" 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." Button: "Visit Site" - URL: "https://emeraldsrv.dev" + URL: "https://emeraldsrv.com" Colour: "#f74343" Welcome: @@ -40,6 +40,12 @@ Leave: ImageEnabled: false ImageURL: "https://animagelink.png/" +Suggestions: + Sent_Title: "Suggestion Sent!" + Sent: "> :white_check_mark: **You have successfully sent a suggestion.**" + NoSelfVote: "> :x: **You cannot vote on your own suggestion.**" + RemoveVoteButton: "Remove Vote" + Ticket: # Available Placeholders: @@ -48,18 +54,27 @@ Ticket: # <@%ticketauthor%> - Tags the user who created the ticket. # <#%ticketid%> - Mentions the ticket channel. - TicketTitle: "Server Support | %ticketusername%" + TicketAuthorTitle: "%ticketusername%'s Ticket" + TicketTitle: "Support Ticket" TicketMessage: "> Hello <@%ticketauthor%>, Thank you for creating a support ticket\nPlease wait patiently whilst a member of our team reaches out to you." TicketThumbnail: "https://images.emojiterra.com/google/android-pie/512px/1f39f.png" TicketCreatedAlert: "> :ticket: Ticked Created: <#%ticketid%>" TicketExists: "> ❌ Ticket already exists" + TicketClaim: "> :white_check_mark: Ticket claimed by" #The user who claimed the ticket will be added to the end of this message + TicketUnclaim: "> :white_check_mark: Ticket unclaimed by" #The user who claimed the ticket will be added to the end of this message + + DisableInvites: "> 🔒 Invites have been disabled for this ticket." + EnableInvites: "> 🔓 Invites have been enabled for this ticket." # Available Placeholders: # <@%user%> - Tags the user who was added to the ticket. - AddedUser: "> 👍 <@%user%> has been `Added` to the ticket" - RemovedUser: "> 👍 <@%user%> has been `Removed` from this ticket" + AddUserToTicket_Title: "➕ Add User!" + AddUserToTicket: "> To add a user to this ticket, Tag them." + + RemovedUserFromTicket_Title: "➖ Removed User!" + RemovedUserFromTicket: "> <@%user%> has been `Removed` from this ticket" Blacklisted: "> :x: You are not allowed to open a ticket" Muted: "> :x: You are `Muted` and therefore not allowed to open any tickets" @@ -70,9 +85,28 @@ Ticket: TicketDeleteMessage: "⚠ **Ticket Deleting!**" ClosingTicket: "> :warning: You have requested to close your support ticket." + ConfirmClose: "> Please confirm closing the ticket by clicking the button below." + CloseTimeout: "> Ticket close confirmation timed out." + + ClaimTickets: + ClaimTitle: "Incoming Support Request!" + ClaimMessage: "> A new ticket has been created by <@!%user%>. Click the button below to claim this ticket." + ClaimMessage_Edit: "> <#%channel%> was claimed by <@!%user%>." + + ClaimedTitle: "Ticket Claimed!" + Claimed: "> You have successfully claimed this ticket. <#%channel%>" + NoPermsToClaimTitle: "Error, no permissions!" + NoPermsToClaim: "> :x: **Err!** You do not permissions to claim this ticket." + +TicketStats: + OpenTickets: "✅ Open Tickets" + TotalTickets: "🎫 Total Tickets" + ResponseTime: "⏱️ Average Response Time" + + Title: "Your Ticket Stats" Error: - IncorrectPerms: "> :x: **Err!** You do not have the correct permissions to use this command." + IncorrectPerms: "> :x: **Err!** You do not have the correct permissions to use this." InvalidChannel: "> :x: **Err!** Channel not found. Please create it!" UserNotFound: "> :x: **Err!** This user doesn't exist, Are they in this server?" NoValidTicket: "> :warning: You cannot execute this command here." diff --git a/Configs/supportbot-ai.yml b/Configs/supportbot-ai.yml new file mode 100644 index 0000000..60beab5 --- /dev/null +++ b/Configs/supportbot-ai.yml @@ -0,0 +1,40 @@ +# ------------------------- +# SupportBot AI +# +# In order to use the SupportBot AI, You need to setup an OpenAI Account. +# this can be done at https://platform.openai.com/ +# ------------------------- + +Enabled: true + +General: + Name: "SupportBot AI" + # What would you like to call your AI + Model: "gpt-4o" + # You can see a list of OpenAI Models here: https://platform.openai.com/docs/models + + Tokens: 400 + # Max tokens you can set is 400 + # For more information about tokens, go to https://openai.com/api/pricing/ + + OpenAI_Key: "OPEN_AI_APIKEY_HERE" + # To create an OpenAI API key, go to https://platform.openai.com/api-keys + + + PastebinAPI_Key: "PASTEBIN_API_KEY" + # You can get your Pastebin API Key from https://pastebin.com + PastebinAPI_URL: "https://pastebin.com/api/api_post.php" + +Channels: + AIChannel: "1250190338954498048" + # This is the channel where AI will respond in without needing to mention the bot. + +Embed: + Color: 0x0cc559 # 0x + Footer: "SupportBot | Developed by Emerald Development" + +Messages: + MessageTooLong: "The response was too long, so I've posted it here: {pastebin}" + ErrorResponse: "I didn't receive a proper response from OpenAI. Please try again later." + OpenAIError: "I'm having some trouble talking to SupportBot AI's Model, OpenAI. Please try again later." + AIDisabled: "I am disabled, You have enable me in `supportbot-ai.yml`" \ No newline at end of file diff --git a/Configs/supportbot.yml b/Configs/supportbot.yml index bc7cd40..169ffe6 100644 --- a/Configs/supportbot.yml +++ b/Configs/supportbot.yml @@ -8,10 +8,10 @@ # Installed with MIT License # # Discord Support: https://dsc.gg/emerald-dev -# Official Documentation: https://emeraldsrv.dev/wiki -# Third-Party Documentation: https://emeraldsrv.dev/third-party +# Official Documentation: https://github.com/Emerald-Services/SupportBot/wiki +# Third-Party Documentation: COMING SOON -SupportBot_Version: "v8.0 DEV-v1.2" +SupportBot_Version: "v8.0" # Do not change the version number # ------------------------- @@ -20,19 +20,20 @@ SupportBot_Version: "v8.0 DEV-v1.2" General: Name: "SupportBot" - Token: "BOT TOKEN" + Token: "BOT_TOKEN_HERE" + # To get your Discord Bot Token, Go to https://discord.com/developers/applications Addons: Enabled: false - + # ------------------------- # Activity # ------------------------- Activity: Status: "SupportBot v8" - Type: "Watching" - # The Type can either be Playing, Watching, Listenin or Streaming. + Type: "Competing" + # The Type can either be Playing, Watching, Listening or Competing StreamingURL: "https://www.twitch.tv/YOUR_TWITCH_NAME" # Set The Type to "Streaming" for a streaming status! @@ -42,10 +43,10 @@ Activity: Embed: Colours: - General: "#f74343" - Success: "#04b545" - Error: "#d12519" - Warn: "#fca117" + General: 0x0cc559 # 0x + Success: 0x04b545 # 0x + Error: 0xd13030 # 0x + Warn: 0xfca117 # 0x Footer: "SupportBot | Developed by Emerald Development" @@ -56,11 +57,11 @@ Embed: Roles: AutoRole: Enabled: true - Role: "SupportBot Member" + Role: "Member" StaffMember: - Staff: "SupportBot Staff" - Admin: "SupportBot Admin" + Staff: "Staff" + Admin: "Admin" ModRoles: Muted: "Muted" @@ -72,115 +73,144 @@ Roles: Welcome: Enabled: true - Channel: "welcome" + Channel: "🚨┃join-leave-logs" Leave: Enabled: true - Channel: "leave" + Channel: "🚨┃join-leave-logs" # ---------------------------- # Suggestions # ---------------------------- Suggestions: - Channel: "suggestions" + Channel: "📗┃suggestions" UpvoteEmoji: "✅" DownvoteEmoji: "❌" + + UpvoteTitle: "Yes" + DownvoteTitle: "No" + + OwnSuggestion: true + # If false this will not allow the user to vote for a suggestion they created + # If true this will allow the user to vote for a suggestion they created + + ShowUsers: true Threads: Enabled: true Title: "Suggestion-releated Thread" Reason: "A thread releted to this suggestion" + Buttons: + Upvote: "2" + Downvote: "2" + RemoveVote: "4" + RemoveVote_Title: "Remove Vote" + + # Available Button Styles + # 1 - Blurple + # 2 - Grey + # 3 - Green + # 4 - Red + # ------------------------- # Tickets # ------------------------- Ticket: + TicketCategory: "📗┃tickets" #Where tickets normally go with the /ticket command + # This is the channel name for the ticket threads to be created, NOT A DISCORD CATEGORY! + Channel: "ticket-" # The prefix for ticket channel names - TicketsPerUser: 2 - RoleMention: "@here" - AllowMentions: true + TicketsPerUser: 100 DMTranscripts: true - # Set to true to allow the ticket to mention the author and the support team. - # Set false to dis-allow mentions within tickets. + TicketReason: true + # If ticket reason is set to false, It will not prompt to create a reason TicketSubject: "description" # "description" will display the ticket reason within the channel description # "embed" will display the ticket reason within the ticket embed - AllowThanksForReachingOutMessage: true - # Set to true to allow the "Thanks for reaching out Message" to be sent when the ticket is created Timeout: 5 - AllowAllStaff: false # Set to true to allow all staff to access the ticket - LockTicketCategory: "Archive" Log: - TicketLog: "ticket-data" + TicketLog: "🚨┃ticket-data" TicketLog_Title: "Ticket Closed" DisableTicketLogChannel: false - TranscriptLog: "ticket-data" + TranscriptLog: "🚨┃ticket-data" TranscriptTitle: "Ticket Transcript" Close: StaffOnly: true # Set to false is anyone is able to close a ticket. - CloseConfirmation: true - Confirmation_Word: "confirm" + Confirmation_Button: "Confirm Close" + Title: "Are you sure you want to close this ticket?" + + Invites: + StaffOnly: true + + ClaimTickets: + Enabled: true + Channel: "0000000000000000000" + # Channel name or Channel ID + + ButtonTitle: "Claim Ticket" + Button: "1" + + # Available Button Styles + # 1 - Blurple + # 2 - Grey + # 3 - Green + # 4 - Red + # ------------------------- -# Departments +# Departments - NOT IN THIS UPDATE # ------------------------- Departments: - - title: "Support" - role: "SupportBot Staff" - color: "Secondary" - emoji: "1️⃣" - category: "Tickets" - - - title: "Billing Support" - role: "SupportBot Staff" - color: "Secondary" - emoji: "2️⃣" - category: "Tickets" - - - title: "Admin Team" - role: "SupportBot Admin" - color: "Secondary" - emoji: "3️⃣" - category: "Tickets" - -# - title: "Other" -# role: "Staff" -# color: "Secondary" -# emoji: "3️⃣" -# category: "Tickets" + - title: "Create Ticket" + role: "Staff" + color: "2" + emoji: "🎫" + category: "TICKETS" # ------------------------- # Buttons # ------------------------- - Buttons: Tickets: - CloseEmoji: "❌" - CloseStyle: "Danger" + ClaimEmoji: "🧑‍💻" + ClaimStyle: "1" - DeleteEmoji: "⛔" - DeleteStyle: "Danger" + # Available Button Styles + # 1 - Blurple + # 2 - Grey + # 3 - Green + # 4 - Red - LockEmoji: "🔒" - LockStyle: "Primary" -# Available Button Styles -# Primary - Blurple -# Secondary- Grey -# Danger - Red -# Success - Green +# ------------------------- +# Select Menus +# ------------------------- + +SelectMenus: + Tickets: + PanelEmoji: "⚙️" + CloseEmoji: "🗑️" + ArchiveEmoji: "♻️" + LockTicketEmoji: "🔒" + UnLockTicketEmoji: "🔓" + EnableInvitesEmoji: "🔒" + DisableInvitesEmoji: "🔓" + AddUserEmoji: "➕" + RemoveUserEmoji: "➖" + # ------------------------- # Misc # ------------------------- Translate: - Log: "translations-log" + Log: "🚨┃logs" diff --git a/Configs/ticket-panel.yml b/Configs/ticket-panel.yml index 61312e9..f285673 100644 --- a/Configs/ticket-panel.yml +++ b/Configs/ticket-panel.yml @@ -14,21 +14,33 @@ # Ticket Panel Configuration # ------------------------------- -TicketPanel: true +Panel: true # ---------------------------------------- -# Ticket Panel Message Configuration +# Ticket Panel Message Configuration #2b2d31 # ---------------------------------------- -Channel: "create-ticket" +TicketCategory: "📗┃tickets" +# This is the channel name for the ticket threads to be created, NOT A DISCORD CATEGORY! -PanelTitle: "Need Help? Create a Support Ticket." -PanelColour: "#f74343" +PanelTitle: "SupportBot" +PanelColour: "#0cc559" + +Button: + Text: "Create Ticket" + Emoji: "🎫" + Color: "2" + +# Available Button Styles +# 1 - Blurple +# 2 - Grey +# 3 - Red +# 4 - Green TicketPanel_Description: true -TicketPanel_Thumbnail: true +TicketPanel_Thumbnail: false TicketPanel_Image: true -PanelMessage: "Click the button to open a new support ticket." +PanelMessage: "Click on the button to file a `Ticket` and our team will try their best to assist you in the best way we can!" PanelThumbnail: "https://i.imgur.com/ieeZejl.png" -PanelImage: "https://i.imgur.com/5NkcmDq.png" \ No newline at end of file +PanelImage: "https://i.imgur.com/dejQvkg.png" \ No newline at end of file diff --git a/Data/.DS_Store b/Data/.DS_Store deleted file mode 100644 index 23c4cb2..0000000 Binary files a/Data/.DS_Store and /dev/null differ diff --git a/Data/SuggestionData.json b/Data/SuggestionData.json new file mode 100644 index 0000000..776e35d --- /dev/null +++ b/Data/SuggestionData.json @@ -0,0 +1,16 @@ +{ + "1249719789069402180": { + "suggestion": "test", + "author": "419821884431925260", + "upvotes": [ + "419821884431925260" + ], + "downvotes": [] + }, + "1249762468360884290": { + "suggestion": "test", + "author": "419821884431925260", + "upvotes": [], + "downvotes": [] + } +} \ No newline at end of file diff --git a/Data/SupportBot-AI.json b/Data/SupportBot-AI.json new file mode 100644 index 0000000..544b7b4 --- /dev/null +++ b/Data/SupportBot-AI.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/Data/TicketData.json b/Data/TicketData.json index d62d909..987b7f9 100644 --- a/Data/TicketData.json +++ b/Data/TicketData.json @@ -1 +1,5 @@ -{"tickets": [{}]} \ No newline at end of file +{ + "tickets": [ + {} + ] +} \ No newline at end of file diff --git a/Data/ticket-panel-id.json b/Data/ticket-panel-id.json index 46a3c59..b0b4882 100644 --- a/Data/ticket-panel-id.json +++ b/Data/ticket-panel-id.json @@ -1,4 +1,4 @@ { - "id": 4, - "TicketPanelID": "" + "id": 0, + "TicketPanelID": "0000000000000000000" } \ No newline at end of file diff --git a/Events/interactionCreate.js b/Events/interactionCreate.js index 3bbd7f3..db61e76 100644 --- a/Events/interactionCreate.js +++ b/Events/interactionCreate.js @@ -1,22 +1,10 @@ -// SupportBot | Emerald Services -// Interaction Create Event - const fs = require("fs"); - const Discord = require("discord.js"); const yaml = require("js-yaml"); -const supportbot = yaml.load( - fs.readFileSync("./Configs/supportbot.yml", "utf8") -); - -const cmdconfig = yaml.load( - fs.readFileSync("./Configs/commands.yml", "utf8") -); - -const msgconfig = yaml.load( - fs.readFileSync("./Configs/messages.yml", "utf8") -); +const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8")); +const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); +const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8")); const Event = require("../Structures/Event.js"); @@ -51,89 +39,186 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { }); command.run(interaction); } + + if (interaction.isStringSelectMenu()) { + if (interaction.customId === "ticketcontrolpanel") { + const selectedOption = interaction.values[0]; + const { getRole, getChannel } = interaction.client; + switch (selectedOption) { + case "ticketadduser": + const AddUserThreadTicket = new Discord.EmbedBuilder() + .setTitle(`${msgconfig.Ticket.AddUserToTicket}`) + .setDescription(`${msgconfig.Ticket.AddUserToTicket}`) + .setColor(supportbot.Embed.Colours.General); + + await interaction.reply({ + embeds: [AddUserThreadTicket], + ephemeral: true, + }); + break; + + case "ticketremoveuser": + await removeUserFromThread(interaction); + break; + + case "ticketclose": + const closeCommand = client.commands.get(cmdconfig.CloseTicket.Command); + if (closeCommand) { + closeCommand.run(interaction); + } else { + console.error("[X] Close Command Not Found"); + } + break; + + case "ticketremoveuser": + await removeUserFromThread(interaction); + break; + + case "enableinvites": + await handleInvites(interaction, true); + break; + + case "disableinvites": + await handleInvites(interaction, false); + break; + } + } + } + if (interaction.isButton()) { - if ( - interaction.customId === "openticket" || - interaction.customId.includes("department-") - ) { + if (interaction.customId === 'createticket') { try { const cmd = client.commands.get(cmdconfig.OpenTicket.Command); if (!cmd) return; cmd.run(interaction); } catch (error) { - console.error(error); + console.error("Error executing the ticket command:", error); + await interaction.reply({ + content: "An error occurred while creating the ticket.", + ephemeral: true, + }); } } - if (interaction.customId === "ticketclose") { + if (interaction.customId === "openticket") { try { - const cmd = client.commands.get(cmdconfig.CloseTicket.Command); + const cmd = client.commands.get(cmdconfig.OpenTicket); if (!cmd) return; cmd.run(interaction); } catch (error) { console.error(error); } } - if (interaction.customId === "ticketlock") { - if (interaction.channel.name.startsWith(supportbot.Ticket.Channel)) { - interaction.message.fetch(); - let Admin = - interaction.guild.roles.cache.find( - (AdminUser) => AdminUser.name === supportbot.Roles.StaffMember.Admin - ) || - interaction.guild.roles.cache.find( - (AdminUser) => AdminUser.id === supportbot.Roles.StaffMember.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 = - interaction.guild.channels.cache.find( - (c) => c.name === supportbot.Ticket.LockTicketCategory - ) || - interaction.guild.channels.cache.find( - (c) => c.id === supportbot.Ticket.LockTicketCategory - ); - if (parent) { - await interaction.channel.setParent(parent.id); - } - - all.forEach((perm) => { - interaction.channel.permissionOverwrites.delete(perm.id); + if (interaction.customId.startsWith('claimticket-')) { + const ticketChannelId = interaction.customId.split('-')[1]; + const ticketChannel = interaction.guild.channels.cache.get(ticketChannelId); + if (!ticketChannel) { + return interaction.reply({ + content: "Ticket channel not found.", + ephemeral: true, }); - await interaction.channel.permissionOverwrites.create(Admin.id, { - VIEW_CHANNEL: true, - }); - - await interaction.channel.permissionOverwrites.create( - interaction.guild.id, - { - VIEW_CHANNEL: false, - } - ); - - const ticketDeleteButton = new Discord.ButtonBuilder() - .setCustomId("ticketclose") - .setLabel("Close") - .setStyle(supportbot.Buttons.Tickets.DeleteStyle) - .setEmoji(supportbot.Buttons.Tickets.DeleteEmoji); - - const row = new Discord.ActionRowBuilder().addComponents( - ticketDeleteButton - ); - const ArchiveEmbed = new Discord.EmbedBuilder() - .setTitle("Archived") - .setDescription(`Archived ${interaction.channel.name}`) - .setColor(supportbot.Embed.Colours.Success); - - interaction.reply({ embeds: [ArchiveEmbed] }); - interaction.message.edit({ components: [row] }); } + + const { getRole, getChannel } = interaction.client; + const Staff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild); + const Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild); + + const RolePerms = new Discord.EmbedBuilder() + .setTitle("Invalid Permissions!") + .setDescription( + `${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\`` + ) + .setColor(supportbot.Embed.Colours.Warn); + + if (!Staff || !Admin) { + return interaction.reply({ + embeds: [RolePerms], + ephemeral: true, + }); + } + + const NoPermsClaim = new Discord.EmbedBuilder() + .setTitle(msgconfig.Ticket.ClaimTickets.NoPermsToClaimTitle) + .setDescription( + msgconfig.Ticket.ClaimTickets.NoPermsToClaim.replace('%channel%', ticketChannel.name) + ) + .setColor(supportbot.Embed.Colours.Error); + + if (!interaction.member.roles.cache.has(Staff.id) && !interaction.member.roles.cache.has(Admin.id)) { + return interaction.reply({ + embeds: [NoPermsClaim], + ephemeral: true, + }); + } + + await ticketChannel.members.add(interaction.user.id); + const pingclaimedstaff = await ticketChannel.send(`<@${interaction.user.id}>`); + + setTimeout(() => { + pingclaimedstaff.delete(); + }, 2000) + + const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8")); + const ticketIndex = TicketData.tickets.findIndex((t) => t.id === ticketChannelId); + if (ticketIndex !== -1) { + TicketData.tickets[ticketIndex].claimedBy = interaction.user.id; + TicketData.tickets[ticketIndex].claimedAt = new Date().toISOString(); + fs.writeFileSync("./Data/TicketData.json", JSON.stringify(TicketData, null, 4)); + } + + const claimMessage = await interaction.message.fetch(); + const claimedEmbed = new Discord.EmbedBuilder(claimMessage.embeds[0].data) + .setTitle(msgconfig.Ticket.ClaimTickets.ClaimedTitle) + .setDescription( + msgconfig.Ticket.ClaimTickets.ClaimMessage_Edit.replace('%user%', interaction.user.id).replace('%channel%', ticketChannel.id) + ) + .setColor(supportbot.Embed.Colours.Success); + + const successfullyClaimed = new Discord.EmbedBuilder() + .setTitle(msgconfig.Ticket.ClaimTickets.ClaimedTitle) + .setDescription(msgconfig.Ticket.ClaimTickets.Claimed.replace('%channel%', ticketChannel.id)) + .setColor(supportbot.Embed.Colours.Success); + + await claimMessage.edit({ embeds: [claimedEmbed], components: [] }); + await interaction.reply({ + embeds: [successfullyClaimed], + ephemeral: true, + }); } } -}); + + async function handleInvites(interaction, enable) { + if (supportbot.Ticket.Invites.StaffOnly) { + const SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild); + const Admin = await getRole(supportbot.Roles.StaffMember.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.EmbedBuilder() + .setTitle("Invalid Permissions!") + .setDescription( + `${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\`` + ) + .setColor(supportbot.Embed.Colours.Warn); + + if (!interaction.member.roles.cache.has(SupportStaff.id) && !interaction.member.roles.cache.has(Admin.id)) { + return interaction.reply({ embeds: [NoPerms] }); + } + } + + await interaction.channel.setInvitable(enable); + + const message = enable ? msgconfig.Ticket.EnableInvites : msgconfig.Ticket.DisableInvites; + const embed = new Discord.EmbedBuilder() + .setDescription(message) + .setColor(supportbot.Embed.Colours.General); + + await interaction.reply({ + embeds: [embed], + ephemeral: true, + }); + } +}); \ No newline at end of file diff --git a/Events/messageCreate.js b/Events/messageCreate.js new file mode 100644 index 0000000..537efdd --- /dev/null +++ b/Events/messageCreate.js @@ -0,0 +1,166 @@ +const fs = require("fs"); +const Discord = require("discord.js"); +const yaml = require("js-yaml"); +const axios = require("axios"); +const { OpenAI } = require('openai'); + +// Load configuration files with validation +function loadConfig(path) { + try { + return yaml.load(fs.readFileSync(path, "utf8")); + } catch (error) { + console.error(`Error loading config file at ${path}:`, error); + throw error; + } +} + +const supportbotai = yaml.load(fs.readFileSync("./Configs/supportbot-ai.yml")); +const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8")); +const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); +const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8")); +// Validate configuration values +function validateConfig(config, keys) { + keys.forEach(key => { + if (!config[key]) { + throw new Error(`Missing configuration key: ${key}`); + } + }); +} + +const CHANNELS = [supportbotai.Channels.AIChannel]; + +// Initialize Discord client +const client = new Discord.Client({ + intents: ['Guilds', 'GuildMembers', 'GuildMessages'] +}); + +// Load custom Event structure +const Event = require("../Structures/Event.js"); + +// Initialize OpenAI client +const openai = new OpenAI({ + apiKey: supportbotai.General.OpenAI_Key, +}); + +const PASTEBIN_API_KEY = supportbotai.General.PastebinAPI_Key; +const PASTEBIN_API_URL = supportbotai.General.PastebinAPI_URL; + +// Function to create a paste on Pastebin +async function createPaste(content) { + try { + const response = await axios.post(PASTEBIN_API_URL, new URLSearchParams({ + api_dev_key: PASTEBIN_API_KEY, + api_option: 'paste', + api_paste_code: content, + api_paste_private: 1, // 0 = public, 1 = unlisted, 2 = private + api_paste_expire_date: '1D', // Expire in 1 day + api_paste_format: 'text' + })); + return response.data; + } catch (error) { + console.error('Pastebin Error:', error); + throw error; + } +} + +// Event handler for message creation +module.exports = new Event("messageCreate", async (client, message) => { + if (message.author.bot || !message.guild) return; + if (!CHANNELS.includes(message.channelId) && !message.mentions.users.has(client.user.id)) return; + +if (supportbotai.Enabled) { + + const sendTypingInterval = setInterval(() => { + message.channel.sendTyping(); + }, 5000); + + let conversation = [{ + role: "system", + content: "SupportBot is your friendly neighbourhood support bot." + }]; + + let prevMessages = await message.channel.messages.fetch({ limit: 10 }); + prevMessages = prevMessages.reverse().filter(msg => !msg.author.bot || msg.author.id === client.user.id); + + prevMessages.forEach((msg) => { + const username = msg.author.username.replace(/\s+/g, '_').replace(/[^\w\s]/gi, ''); + + conversation.push({ + role: msg.author.id === client.user.id ? "assistant" : "user", + name: username, + content: msg.content, + }); + }); + + try { + const response = await openai.chat.completions.create({ + model: supportbotai.General.Model, + messages: conversation, + max_tokens: supportbotai.General.Tokens, + }); + + clearInterval(sendTypingInterval); + + if (response.choices && response.choices.length > 0) { + const replyContent = response.choices[0].message.content; + + const SupportBotAI = new Discord.EmbedBuilder() + .setAuthor({ name: supportbotai.General.Name, iconURL: client.user.displayAvatarURL() }) + .setDescription(replyContent) + .setColor(supportbotai.Embed.Color) + .setFooter({ text: supportbotai.Embed.Footer, iconURL: message.author.displayAvatarURL() }) + .setTimestamp(); + + if (replyContent.length > 2000) { + const pasteLink = await createPaste(replyContent); + + const SupportBotAIPastebin = new Discord.EmbedBuilder() + .setAuthor({ name: supportbotai.General.Name, iconURL: client.user.displayAvatarURL() }) + .setDescription(supportbotai.Messages.MessageTooLong.replace("{pastebin}", pasteLink)) + .setColor(supportbotai.Embed.Color) + .setFooter({ text: supportbotai.Embed.Footer, iconURL: message.author.displayAvatarURL() }) + .setTimestamp(); + + message.reply({ embeds: [SupportBotAIPastebin] }); + } else { + message.reply({ embeds: [SupportBotAI] }); + } + } else { + const SupportBotAIErrorResponse = new Discord.EmbedBuilder() + .setAuthor({ name: supportbotai.General.Name, iconURL: client.user.displayAvatarURL() }) + .setDescription(supportbotai.Messages.ErrorResponse) + .setColor(supportbotai.Embed.Color) + .setFooter({ text: supportbotai.Embed.Footer, iconURL: message.author.displayAvatarURL() }) + .setTimestamp(); + + message.reply({ embeds: [SupportBotAIErrorResponse], ephemeral: true }); + } + } catch (error) { + clearInterval(sendTypingInterval); + + const SupportBotAIErrorResponse = new Discord.EmbedBuilder() + .setAuthor({ name: supportbotai.General.Name, iconURL: client.user.displayAvatarURL() }) + .setDescription(supportbotai.Messages.OpenAIError) + .setColor(supportbot.Embed.Colours.Error) + .setFooter({ text: supportbotai.Embed.Footer, iconURL: message.author.displayAvatarURL() }) + .setTimestamp(); + + console.error('OpenAI Error:', error); + message.reply({ embeds: [SupportBotAIErrorResponse], ephemeral: true }); + } + +} + +if (supportbotai.Enabled === false) { + const AIDisabled = new Discord.EmbedBuilder() + .setAuthor({ name: supportbotai.General.Name, iconURL: client.user.displayAvatarURL() }) + .setDescription(supportbotai.Messages.AIDisabled) + .setColor(supportbot.Embed.Colours.Error) + .setFooter({ text: supportbotai.Embed.Footer, iconURL: message.author.displayAvatarURL() }) + .setTimestamp(); + + message.reply({ embeds: [AIDisabled], ephemeral: true }) + return; +} + +}); \ No newline at end of file diff --git a/Events/ready.js b/Events/ready.js index 1ac6d73..8d228c6 100644 --- a/Events/ready.js +++ b/Events/ready.js @@ -4,6 +4,9 @@ const fs = require("fs"); const Discord = require("discord.js"); +const { Client, GatewayIntentBits, ActivityType } = require('discord.js'); +const client = new Discord.Client({intents: 32767}) + const yaml = require("js-yaml"); const supportbot = yaml.load( @@ -23,12 +26,38 @@ const msgconfig = yaml.load( const Event = require("../Structures/Event.js"); +let chan1 = client.channels.cache.get(panelconfig.Channel); + module.exports = new Event("ready", async (client, interaction) => { const { getRole, getChannel, getCategory } = client; - client.user.setActivity(supportbot.Activity.Status, { - type: supportbot.Activity.Type, - url: supportbot.Activity.StreamingURL, - }); + + if (supportbot.Activity.Type === "Playing", "playing") { + client.user.setPresence({ + activities: [{ name: supportbot.Activity.Status, type: Discord.ActivityType.Playing }], + status: supportbot.Activity.Type, + }); + } + + if (supportbot.Activity.Type === "Watching", "watching") { + client.user.setPresence({ + activities: [{ name: supportbot.Activity.Status, type: Discord.ActivityType.Watching }], + status: supportbot.Activity.Type, + }); + } + + if (supportbot.Activity.Type === "Listening", "listening") { + client.user.setPresence({ + activities: [{ name: supportbot.Activity.Status, type: Discord.ActivityType.Listening }], + status: supportbot.Activity.Type, + }); + } + + if (supportbot.Activity.Type === "Competing", "competing") { + client.user.setPresence({ + activities: [{ name: supportbot.Activity.Status, type: Discord.ActivityType.Competing }], + status: supportbot.Activity.Type, + }); + } console.log(`\u001b[32m`, `――――――――――――――――――――――――――――――――――――――――――――`); console.log(` `); @@ -63,23 +92,23 @@ module.exports = new Event("ready", async (client, interaction) => { console.log( `\u001b[31m`, - `Resources`, + `Website`, `\u001b[32m`, - `https://emeraldsrv.dev`, + `https://emeraldsrv.com`, + ); + + console.log( + `\u001b[31m`, + `Marketplace`, + `\u001b[32m`, + `https://market.emeraldsrv.com`, ); console.log( `\u001b[31m`, `Documentation`, `\u001b[32m`, - `https://emeraldsrv.dev/wiki`, - ); - - console.log( - `\u001b[31m`, - `Third-Party Documentation`, - `\u001b[32m`, - `https://emeraldsrv.dev/third-party`, + `https://emeraldsrv.com/third-party`, ); console.log(` `); @@ -107,29 +136,29 @@ module.exports = new Event("ready", async (client, interaction) => { if (supportbot.Roles.AutoRole.Role) roles.push(supportbot.Roles.AutoRole.Role); - // const channels = [ - // supportbot.Suggestions.Channel, - // supportbot.Ticket.Log.TicketLog, - // supportbot.Ticket.Log.TranscriptLog, - // panelconfig.Channel, - // supportbot.Welcome.Channel, - // supportbot.Leave.Channel, - // supportbot.Translate.Log - // ]; + const channels = [ + supportbot.Suggestions.Channel, + supportbot.Ticket.Log.TicketLog, + supportbot.Ticket.Log.TranscriptLog, + panelconfig.Channel, + supportbot.Welcome.Channel, + supportbot.Leave.Channel, + supportbot.Translate.Log + ]; //const categories = [supportbot.TicketCategory]; + if (!channels) { + console.log("\u001b[31m", `[MISSING CHANNEL]`, `\u001b[37;1m`, `${channels}`, "\u001b[31m", `channel not found. Please check your config file.`); + return; + } +// else { +// console.log(`\u001b[32m`, `[CHANNEL LOCATED]`, `\u001b[37;1m`, `${channels}`, `\u001b[32;1m`, `channel has been found.`); +// } + const missingC = []; const missingR = []; const missingCat = []; - // for (let c of channels) { - // if ((c === supportbot.Suggestion.Channel && cmdconfig.Suggestion.Enabled) || c === supportbot.Ticket.Log.TicketLog && supportbot.Ticket.Log.DisableTicketLogChannel) { - // continue; - // } - // 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); @@ -170,77 +199,4 @@ module.exports = new Event("ready", async (client, interaction) => { )}]`, `\n `, ); } - if (panelconfig.TicketPanel) { - let chan1 = await client.getChannel( - panelconfig.Channel, - client.guilds.cache.first() - ); - - if (!chan1) { - console.log( - "\u001b[31m", - `[TICKET PANEL]`, - "\u001b[33m", - "Ticket Panel is not setup, You can set this in", `\u001b[31m`, '/Configs/Ticket-Panel.yml', `\n `, - ); - return false; - } - - const panelid = JSON.parse( - fs.readFileSync("./Data/ticket-panel-id.json", "utf8") - ); - - chan1.messages.fetch(panelid.TicketPanelID).catch(async () => { - let embed = new Discord.EmbedBuilder() - .setTitle(panelconfig.PanelTitle) - .setColor(panelconfig.PanelColour) - .setFooter({ - text: supportbot.Embed.Footer, - iconURL: interaction.user.displayAvatarURL(), - }); - - if (panelconfig.TicketPanel_Description) { - embed.setDescription(panelconfig.PanelMessage); - } - - if (panelconfig.TicketPanel_Thumbnail) { - embed.setThumbnail(panelconfig.PanelThumbnail); - } - - if (panelconfig.TicketPanel_Image) { - embed.setImage(panelconfig.PanelImage); - } - let button; - - button = supportbot.Departments.map((x) => - new Discord.ButtonBuilder() - .setCustomId("department-" + supportbot.Departments.indexOf(x)) - .setLabel(x.title) - .setStyle(x.color) - .setEmoji(x.emoji) - ); - - let row = new Discord.ActionRowBuilder().addComponents(button); - - await chan1 - .send({ - embeds: [embed], - components: [row], - }) - .then((r) => { - let data = { - id: panelid.id, - TicketPanelID: r.id, - }; - fs.writeFileSync( - "./Data/ticket-panel-id.json", - JSON.stringify(data), - "utf8" - ); - }) - .catch((e) => { - console.log("Raw: " + e); - }); - }); - } }); \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index 7e88a21..0000000 --- a/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018-2022 Emerald Development - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index 3e56285..0000000 --- a/README.md +++ /dev/null @@ -1,75 +0,0 @@ -

-
- -
- SupportBot -
-

- -
- - - shield.png - - - - shield.png - - - - shield.png - - - - shield.png - - -
- -

- Website - • - Wiki -
- About - • - Support - • - License - • - Third-Party - • - Contributors -

- -## About - -SupportBot is an Open-Source discord bot built with [discord.js](https://github.com/discordjs/discord.js). It's primarily focused to help servers organise and manage their support system in a unique way with full customisation to match your brand. - -## Support - - - Discord - - - -## License - -Released under the [MIT](https://opensource.org/licenses/MIT) license. - - -## Third-Party - -- [Syphers Addons](https://github.com/SypherRed/SB_Addons_Unofficial) -- [MC-Market](https://www.mc-market.org/supportbot) -- [Polymart](https://polymart.org/resource/supportbot-1-discord-ticket-bot.518) - - -## Contributors - - - - - - - diff --git a/Structures/Client.js b/Structures/Client.js index f75774d..074d382 100644 --- a/Structures/Client.js +++ b/Structures/Client.js @@ -18,10 +18,18 @@ const cmdconfig = yaml.load( class Client extends Discord.Client { constructor() { - super({ intents: [GatewayIntentBits.Guilds], partials: [Partials.Channel] }); + super({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildMessages + ], + partials: [Partials.Channel] + }); this.commands = new Discord.Collection(); } + async getChannel(channel, guild) { return guild.channels.cache.find( (c) => @@ -57,14 +65,6 @@ class Client extends Discord.Client { tempCommandFiles = tempCommandFiles.filter(item => item !== "info.js"); } - if (cmdconfig.TicketAdd.Enabled === false) { - tempCommandFiles = tempCommandFiles.filter(item => item !== "add.js"); - } - - if (cmdconfig.TicketRemove.Enabled === false) { - tempCommandFiles = tempCommandFiles.filter(item => item !== "remove.js"); - } - if (cmdconfig.OpenTicket.Enabled === false) { tempCommandFiles = tempCommandFiles.filter(item => item !== "ticket.js"); } @@ -89,6 +89,14 @@ class Client extends Discord.Client { tempCommandFiles = tempCommandFiles.filter(item => item !== "Ping.js"); } + if (cmdconfig.Ping.Enabled === false) { + tempCommandFiles = tempCommandFiles.filter(item => item !== "Ping.js"); + } + + if (supportbot.Ticket.ClaimTickets.Enabled === false) { + tempCommandFiles = tempCommandFiles.filter(item => item !== "ticketstats.js"); + } + const commandFiles = tempCommandFiles; const commands = commandFiles.map((file) => require(`../Commands/${file}`)); diff --git a/index.js b/index.js index 85468b8..b2f9578 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,27 @@ const supportbot = yaml.load( ); const Client = require("./Structures/Client.js"); -const client = new Client({}); +const client = new Client({ + intents: ['Guilds', 'GuildMembers', 'GuildMessages'] +}); client.start(supportbot.General.Token); + + + + + + + + + + + + + + + + + + + diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 10da0ef..0000000 --- a/package-lock.json +++ /dev/null @@ -1,1245 +0,0 @@ -{ - "name": "supportbot", - "version": "7.7b", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "supportbot", - "version": "7.7b", - "license": "MIT", - "dependencies": { - "@vitalets/google-translate-api": "^8.0.0", - "discord.js": "^14.0.3", - "js-yaml": "^4.1.0", - "moment": "^2.29.3" - } - }, - "node_modules/@discordjs/builders": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.0.0.tgz", - "integrity": "sha512-8y91ZfpOHubiGJu5tVyGI9tQCEyHZDTeqUWVcJd0dq7B96xIf84S0L4fwmD1k9zTe1eqEFSk0gc7BpY+FKn7Ww==", - "dependencies": { - "@sapphire/shapeshift": "^3.5.1", - "discord-api-types": "^0.36.2", - "fast-deep-equal": "^3.1.3", - "ts-mixer": "^6.0.1", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/@discordjs/collection": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.0.0.tgz", - "integrity": "sha512-nAxDQYE5dNAzEGQ7HU20sujDsG5vLowUKCEqZkKUIlrXERZFTt/60zKUj/g4+AVCGeq+pXC5hivMaNtiC+PY5Q==", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/@discordjs/rest": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.0.0.tgz", - "integrity": "sha512-uDAvnE0P2a8axMdD4C51EGjvCRQ2HZk2Yxf6vHWZgIqG87D8DGKMPwmquIxrrB07MjV+rwci2ObU+mGhGP+bJg==", - "dependencies": { - "@discordjs/collection": "^1.0.0", - "@sapphire/async-queue": "^1.3.2", - "@sapphire/snowflake": "^3.2.2", - "discord-api-types": "^0.36.2", - "file-type": "^17.1.2", - "tslib": "^2.4.0", - "undici": "^5.7.0" - }, - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/@sapphire/async-queue": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.3.2.tgz", - "integrity": "sha512-rUpMLATsoAMnlN3gecAcr9Ecnw1vG7zi5Xr+IX22YzRzi1k9PF9vKzoT8RuEJbiIszjcimu3rveqUnvwDopz8g==", - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@sapphire/shapeshift": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.5.1.tgz", - "integrity": "sha512-7JFsW5IglyOIUQI1eE0g6h06D/Far6HqpcowRScgCiLSqTf3hhkPWCWotVTtVycnDCMYIwPeaw6IEPBomKC8pA==", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "lodash.uniqwith": "^4.5.0" - }, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@sapphire/snowflake": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.2.2.tgz", - "integrity": "sha512-ula2O0kpSZtX9rKXNeQMrHwNd7E4jPDJYUXmEGTFdMRfyfMw+FPyh04oKMjAiDuOi64bYgVkOV3MjK+loImFhQ==", - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dependencies": { - "defer-to-connect": "^1.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" - }, - "node_modules/@types/node": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", - "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==" - }, - "node_modules/@types/ws": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", - "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@vitalets/google-translate-api": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@vitalets/google-translate-api/-/google-translate-api-8.0.0.tgz", - "integrity": "sha512-CHOi8DRgDAoLlFQy9pm1KHUauIk5ZXys3+Eh0aSYxzJSuxAE7Z2UL8+5MgNdl1oX7t/O7u+SwGhkhu6+U1bNcg==", - "dependencies": { - "configstore": "^5.0.1", - "got": "^9.6.0" - } - }, - "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/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", - "dependencies": { - "mimic-response": "^1.0.0" - } - }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" - }, - "node_modules/discord-api-types": { - "version": "0.36.3", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", - "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" - }, - "node_modules/discord.js": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.0.3.tgz", - "integrity": "sha512-wH/VQl4CqN8/+dcXEtYis1iurqxGlDpEe0O4CqH5FGqZGIjVpTdtK0STXXx7bVNX8MT/0GvLZLkmO/5gLDWZVg==", - "dependencies": { - "@discordjs/builders": "^1.0.0", - "@discordjs/collection": "^1.0.0", - "@discordjs/rest": "^1.0.0", - "@sapphire/snowflake": "^3.2.2", - "@types/ws": "^8.5.3", - "discord-api-types": "^0.36.2", - "fast-deep-equal": "^3.1.3", - "lodash.snakecase": "^4.1.1", - "tslib": "^2.4.0", - "undici": "^5.8.0", - "ws": "^8.8.1" - }, - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/file-type": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.3.tgz", - "integrity": "sha512-MFVSozBIhvnx2dkxlf+010Xqn6+ojlMUT9LXQiPNoOijgRtXNMghWdGK0u2o1RoCqzHoVsw65IL8ZBcQ4MhIrw==", - "dependencies": { - "readable-web-to-node-stream": "^3.0.2", - "strtok3": "^7.0.0-alpha.7", - "token-types": "^5.0.0-alpha.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" - } - }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/got/node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "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/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "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/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" - }, - "node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/lodash.snakecase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" - }, - "node_modules/lodash.uniqwith": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", - "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==" - }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/moment": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz", - "integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==", - "engines": { - "node": "*" - } - }, - "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/peek-readable": { - "version": "5.0.0-alpha.5", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0-alpha.5.tgz", - "integrity": "sha512-pJohF/tDwV3ntnT5+EkUo4E700q/j/OCDuPxtM+5/kFGjyOai/sK4/We4Cy1MB2OiTQliWU5DxPvYIKQAdPqAA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "dependencies": { - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/strtok3": { - "version": "7.0.0-alpha.8", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0-alpha.8.tgz", - "integrity": "sha512-u+k19v+rTxBjGYxncRQjGvZYwYvEd0uP3D+uHKe/s4WB1eXS5ZwpZsTlBu5xSS4zEd89mTXECXg6WW3FSeV8cA==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^5.0.0-alpha.5" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/token-types": { - "version": "5.0.0-alpha.2", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.0-alpha.2.tgz", - "integrity": "sha512-EsG9UxAW4M6VATrEEjhPFTKEUi1OiJqTUMIZOGBN49fGxYjZB36k0p7to3HZSmWRoHm1QfZgrg3e02fpqAt5fQ==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/ts-mixer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz", - "integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg==" - }, - "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/undici": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.8.0.tgz", - "integrity": "sha512-1F7Vtcez5w/LwH2G2tGnFIihuWUlc58YidwLiCv+jR2Z50x0tNXpRRw7eOIJ+GvqCqIkg9SB7NWAJ/T9TLfv8Q==", - "engines": { - "node": ">=12.18" - } - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", - "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 - } - } - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "engines": { - "node": ">=8" - } - } - }, - "dependencies": { - "@discordjs/builders": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.0.0.tgz", - "integrity": "sha512-8y91ZfpOHubiGJu5tVyGI9tQCEyHZDTeqUWVcJd0dq7B96xIf84S0L4fwmD1k9zTe1eqEFSk0gc7BpY+FKn7Ww==", - "requires": { - "@sapphire/shapeshift": "^3.5.1", - "discord-api-types": "^0.36.2", - "fast-deep-equal": "^3.1.3", - "ts-mixer": "^6.0.1", - "tslib": "^2.4.0" - } - }, - "@discordjs/collection": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.0.0.tgz", - "integrity": "sha512-nAxDQYE5dNAzEGQ7HU20sujDsG5vLowUKCEqZkKUIlrXERZFTt/60zKUj/g4+AVCGeq+pXC5hivMaNtiC+PY5Q==" - }, - "@discordjs/rest": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.0.0.tgz", - "integrity": "sha512-uDAvnE0P2a8axMdD4C51EGjvCRQ2HZk2Yxf6vHWZgIqG87D8DGKMPwmquIxrrB07MjV+rwci2ObU+mGhGP+bJg==", - "requires": { - "@discordjs/collection": "^1.0.0", - "@sapphire/async-queue": "^1.3.2", - "@sapphire/snowflake": "^3.2.2", - "discord-api-types": "^0.36.2", - "file-type": "^17.1.2", - "tslib": "^2.4.0", - "undici": "^5.7.0" - } - }, - "@sapphire/async-queue": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.3.2.tgz", - "integrity": "sha512-rUpMLATsoAMnlN3gecAcr9Ecnw1vG7zi5Xr+IX22YzRzi1k9PF9vKzoT8RuEJbiIszjcimu3rveqUnvwDopz8g==" - }, - "@sapphire/shapeshift": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.5.1.tgz", - "integrity": "sha512-7JFsW5IglyOIUQI1eE0g6h06D/Far6HqpcowRScgCiLSqTf3hhkPWCWotVTtVycnDCMYIwPeaw6IEPBomKC8pA==", - "requires": { - "fast-deep-equal": "^3.1.3", - "lodash.uniqwith": "^4.5.0" - } - }, - "@sapphire/snowflake": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.2.2.tgz", - "integrity": "sha512-ula2O0kpSZtX9rKXNeQMrHwNd7E4jPDJYUXmEGTFdMRfyfMw+FPyh04oKMjAiDuOi64bYgVkOV3MjK+loImFhQ==" - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" - }, - "@types/node": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", - "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==" - }, - "@types/ws": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", - "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", - "requires": { - "@types/node": "*" - } - }, - "@vitalets/google-translate-api": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@vitalets/google-translate-api/-/google-translate-api-8.0.0.tgz", - "integrity": "sha512-CHOi8DRgDAoLlFQy9pm1KHUauIk5ZXys3+Eh0aSYxzJSuxAE7Z2UL8+5MgNdl1oX7t/O7u+SwGhkhu6+U1bNcg==", - "requires": { - "configstore": "^5.0.1", - "got": "^9.6.0" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" - } - } - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" - }, - "discord-api-types": { - "version": "0.36.3", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", - "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" - }, - "discord.js": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.0.3.tgz", - "integrity": "sha512-wH/VQl4CqN8/+dcXEtYis1iurqxGlDpEe0O4CqH5FGqZGIjVpTdtK0STXXx7bVNX8MT/0GvLZLkmO/5gLDWZVg==", - "requires": { - "@discordjs/builders": "^1.0.0", - "@discordjs/collection": "^1.0.0", - "@discordjs/rest": "^1.0.0", - "@sapphire/snowflake": "^3.2.2", - "@types/ws": "^8.5.3", - "discord-api-types": "^0.36.2", - "fast-deep-equal": "^3.1.3", - "lodash.snakecase": "^4.1.1", - "tslib": "^2.4.0", - "undici": "^5.8.0", - "ws": "^8.8.1" - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "requires": { - "is-obj": "^2.0.0" - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "file-type": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.3.tgz", - "integrity": "sha512-MFVSozBIhvnx2dkxlf+010Xqn6+ojlMUT9LXQiPNoOijgRtXNMghWdGK0u2o1RoCqzHoVsw65IL8ZBcQ4MhIrw==", - "requires": { - "readable-web-to-node-stream": "^3.0.2", - "strtok3": "^7.0.0-alpha.7", - "token-types": "^5.0.0-alpha.2" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "dependencies": { - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" - } - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "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" - } - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "requires": { - "json-buffer": "3.0.0" - } - }, - "lodash.snakecase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" - }, - "lodash.uniqwith": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", - "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==" - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - } - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - }, - "moment": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz", - "integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==" - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" - }, - "peek-readable": { - "version": "5.0.0-alpha.5", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0-alpha.5.tgz", - "integrity": "sha512-pJohF/tDwV3ntnT5+EkUo4E700q/j/OCDuPxtM+5/kFGjyOai/sK4/We4Cy1MB2OiTQliWU5DxPvYIKQAdPqAA==" - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "requires": { - "readable-stream": "^3.6.0" - } - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "strtok3": { - "version": "7.0.0-alpha.8", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0-alpha.8.tgz", - "integrity": "sha512-u+k19v+rTxBjGYxncRQjGvZYwYvEd0uP3D+uHKe/s4WB1eXS5ZwpZsTlBu5xSS4zEd89mTXECXg6WW3FSeV8cA==", - "requires": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^5.0.0-alpha.5" - } - }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" - }, - "token-types": { - "version": "5.0.0-alpha.2", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.0-alpha.2.tgz", - "integrity": "sha512-EsG9UxAW4M6VATrEEjhPFTKEUi1OiJqTUMIZOGBN49fGxYjZB36k0p7to3HZSmWRoHm1QfZgrg3e02fpqAt5fQ==", - "requires": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - } - }, - "ts-mixer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz", - "integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg==" - }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "undici": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.8.0.tgz", - "integrity": "sha512-1F7Vtcez5w/LwH2G2tGnFIihuWUlc58YidwLiCv+jR2Z50x0tNXpRRw7eOIJ+GvqCqIkg9SB7NWAJ/T9TLfv8Q==" - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "requires": { - "prepend-http": "^2.0.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", - "requires": {} - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" - } - } -} diff --git a/package.json b/package.json index dfc048f..96222c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "supportbot", - "version": "7.7b", + "version": "8.1", "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": { @@ -19,8 +19,11 @@ "homepage": "https://github.com/Emerald-Services/SupportBot#readme", "dependencies": { "@vitalets/google-translate-api": "^8.0.0", - "discord.js": "^14.0.3", + "axios": "^1.7.2", + "chatgpt": "^5.2.5", + "discord.js": "^14.13.0", "js-yaml": "^4.1.0", - "moment": "^2.29.3" + "moment": "^2.29.3", + "openai": "^4.50.0" } }