diff --git a/Commands/addUser.js b/Commands/addUser.js new file mode 100644 index 0000000..179c410 --- /dev/null +++ b/Commands/addUser.js @@ -0,0 +1,193 @@ +const fs = require("fs"); +const { + EmbedBuilder, + ApplicationCommandOptionType, + ApplicationCommandType, + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, +} = require("discord.js"); +const yaml = require("js-yaml"); + +const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8")); +const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8")); +const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); + +const Command = require("../Structures/Command.js"); + +module.exports = new Command({ + name: cmdconfig.AddUser.Command, + description: cmdconfig.AddUser.Description, + type: ApplicationCommandType.ChatInput, + options: [ + { + name: "user", + description: "The user to add", + type: ApplicationCommandOptionType.User, + required: true, + }, + ], + permissions: cmdconfig.AddUser.Permission, + + async run(interaction) { + const userToAdd = interaction.options.getUser("user"); + const ticketChannel = interaction.channel; + const ticketDataPath = "./Data/TicketData.json"; + + // Check if the channel is a ticket thread + if (!ticketChannel.isThread()) { + const onlyInTicket = new EmbedBuilder() + .setTitle(msgconfig.AddUser.NotInTicket_Title) + .setDescription(msgconfig.AddUser.NotInTicket_Description) + .setColor(supportbot.Embed.Colours.Error); + + return interaction.reply({ + embeds: [onlyInTicket], + ephemeral: true, + }); + } + + const ticketInviteEmbed = new EmbedBuilder() + .setTitle(msgconfig.AddUser.Invite_Title) + .setDescription(msgconfig.AddUser.Invite_Description.replace("%username%", userToAdd.username)) + .setColor(supportbot.Embed.Colours.General); + + await interaction.reply({ + embeds: [ticketInviteEmbed], + ephemeral: true, + }); + + try { + const dmEmbed = new EmbedBuilder() + .setTitle(msgconfig.AddUser.DM_Title) + .setDescription(msgconfig.AddUser.DM_Description.replace("%channelname%", ticketChannel.name)) + .setColor(supportbot.Embed.Colours.General); + + const acceptButton = new ButtonBuilder() + .setCustomId("accept_invite") + .setLabel(msgconfig.AddUser.Accept_Label) + .setEmoji("✅") + .setStyle(ButtonStyle.Primary); + + const rejectButton = new ButtonBuilder() + .setCustomId("reject_invite") + .setLabel(msgconfig.AddUser.Reject_Label) + .setEmoji("❌") + .setStyle(ButtonStyle.Secondary); + + const row = new ActionRowBuilder().addComponents(acceptButton, rejectButton); + + const dmMessage = await userToAdd.send({ + embeds: [dmEmbed], + components: [row], + }); + + const filter = (i) => i.user.id === userToAdd.id; + const collector = dmMessage.createMessageComponentCollector({ + filter, + time: 60000, + }); + + collector.on("collect", async (i) => { + if (i.customId === "accept_invite") { + try { + await ticketChannel.members.add(userToAdd.id); + + const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8")); + const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id); + if (ticketIndex !== -1) { + ticketData.tickets[ticketIndex].subUsers.push(userToAdd.id); + fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4)); + } + + const acceptedEmbed = new EmbedBuilder() + .setTitle(msgconfig.AddUser.Accepted_Title) + .setDescription(msgconfig.AddUser.Accepted_Message) + .setColor(supportbot.Embed.Colours.Success); + + await i.update({ + embeds: [acceptedEmbed], + components: [], + }); + + const addedToTicketEmbed = new EmbedBuilder() + .setTitle(msgconfig.AddUser.AddedToTicket_Title) + .setDescription(msgconfig.AddUser.AddedToTicket_Description.replace( + "%channel_link%", + `[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})` + )) + .setColor(supportbot.Embed.Colours.General); + + const ticketLinkButton = new ButtonBuilder() + .setLabel(msgconfig.AddUser.ViewTicket_Label) + .setURL(`https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id}`) + .setStyle(ButtonStyle.Link); + + await userToAdd.send({ + embeds: [addedToTicketEmbed], + components: [new ActionRowBuilder().addComponents(ticketLinkButton)], + }); + + } catch (err) { + console.error("Error adding user to the ticket:", err); + + const errorEmbed = new EmbedBuilder() + .setTitle(msgconfig.AddUser.Error_Title) + .setDescription(msgconfig.AddUser.Error_Adding) + .setColor(supportbot.Embed.Colours.Error); + + await i.update({ + embeds: [errorEmbed], + components: [], + }); + } + } else { + const declinedEmbed = new EmbedBuilder() + .setTitle(msgconfig.AddUser.Declined_Title) + .setDescription(msgconfig.AddUser.Declined_Message) + .setColor(supportbot.Embed.Colours.Error); + + await i.update({ + embeds: [declinedEmbed], + components: [], + }); + } + }); + + collector.on("end", (collected) => { + if (collected.size === 0) { + userToAdd.send({ + embeds: [ + new EmbedBuilder() + .setTitle(msgconfig.AddUser.NoResponse_Title) + .setDescription(msgconfig.AddUser.NoResponse_Message) + .setColor(supportbot.Embed.Colours.Warning), + ], + }); + } + }); + } catch (error) { + if (error.code === 50007) { + const errorEmbed = new EmbedBuilder() + .setTitle(msgconfig.AddUser.DM_Error_Title) + .setDescription(msgconfig.AddUser.DM_Error_Description.replace("%username%", userToAdd.username)) + .setColor(supportbot.Embed.Colours.Error); + + await ticketChannel.send({ + embeds: [errorEmbed], + }); + } else { + console.error("Error sending DM:", error); + + const unexpectedErrorEmbed = new EmbedBuilder() + .setTitle(msgconfig.AddUser.Unexpected_Error_Title) + .setDescription(msgconfig.AddUser.Unexpected_Error_Description.replace("%error%", error.message)) + .setColor(supportbot.Embed.Colours.Error); + + await ticketChannel.send({ + embeds: [unexpectedErrorEmbed], + }); + } + } + }, +}); diff --git a/Commands/forceaddUser.js b/Commands/forceaddUser.js new file mode 100644 index 0000000..43908a4 --- /dev/null +++ b/Commands/forceaddUser.js @@ -0,0 +1,119 @@ +// File: Commands/ForceAddUser.js +const fs = require("fs"); +const { + EmbedBuilder, + ApplicationCommandOptionType, + ApplicationCommandType, +} = require("discord.js"); +const yaml = require("js-yaml"); + +const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8")); +const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8")); +const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); + +const Command = require("../Structures/Command.js"); + +module.exports = new Command({ + name: cmdconfig.ForceAddUser.Command, + description: cmdconfig.ForceAddUser.Description, + type: ApplicationCommandType.ChatInput, + options: [ + { + name: "user", + description: "The user to add", + type: ApplicationCommandOptionType.User, + required: true, + }, + ], + permissions: cmdconfig.ForceAddUser.Permission, + + async run(interaction) { + + 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 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] }); + + const userToAdd = interaction.options.getUser("user"); + const ticketChannel = interaction.channel; + const ticketDataPath = "./Data/TicketData.json"; + + if (!ticketChannel.isThread()) { + const onlyInTicket = new EmbedBuilder() + .setTitle(msgconfig.ForceAddUser.NotInTicket_Title) + .setDescription(msgconfig.ForceAddUser.NotInTicket_Description) + .setColor(supportbot.Embed.Colours.Error); + + return interaction.reply({ + embeds: [onlyInTicket], + ephemeral: true, + }); + } + + try { + await ticketChannel.members.add(userToAdd.id); + + const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8")); + const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id); + if (ticketIndex !== -1) { + ticketData.tickets[ticketIndex].subUsers.push(userToAdd.id); + fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4)); + } + + const addedEmbed = new EmbedBuilder() + .setTitle(msgconfig.ForceAddUser.Added_Title) + .setDescription(msgconfig.ForceAddUser.Added_Description.replace( + "%username%", + userToAdd.username + )) + .setColor(supportbot.Embed.Colours.Success); + + await interaction.reply({ + embeds: [addedEmbed], + ephemeral: true, + }); + + const addedToTicketEmbed = new EmbedBuilder() + .setTitle(msgconfig.ForceAddUser.AddedToTicket_Title) + .setDescription(msgconfig.ForceAddUser.AddedToTicket_Description.replace( + "%channel_link%", + `[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})` + )) + .setColor(supportbot.Embed.Colours.General); + + await userToAdd.send({ + embeds: [addedToTicketEmbed], + }); + + } catch (err) { + console.error("Error adding user to the ticket:", err); + + const errorEmbed = new EmbedBuilder() + .setTitle(msgconfig.ForceAddUser.Error_Title) + .setDescription(msgconfig.ForceAddUser.Error_Adding) + .setColor(supportbot.Embed.Colours.Error); + + await interaction.reply({ + embeds: [errorEmbed], + ephemeral: true, + }); + } + }, +}); diff --git a/Commands/genImage.js b/Commands/genImage.js deleted file mode 100644 index de8e94c..0000000 --- a/Commands/genImage.js +++ /dev/null @@ -1,79 +0,0 @@ -const fs = require("fs"); -const Discord = require("discord.js"); -const yaml = require("js-yaml"); -const generateImage = require('../Structures/generateImage.js'); - -const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8")); -const Command = require("../Structures/Command.js"); - -module.exports = new Command({ - name: "image", - description: "Create an image through SupportBot AI", - type: Discord.ApplicationCommandType.ChatInput, - options: [ - { - name: "prompt", - description: "The prompt to generate an image from", - type: Discord.ApplicationCommandOptionType.String, - required: true, - }, - { - name: "negativeprompt", - description: "The negative prompt to exclude from the image", - type: Discord.ApplicationCommandOptionType.String, - required: false, - }, - { - name: "cfgscale", - description: "The cfg scale for the image generation", - type: Discord.ApplicationCommandOptionType.Number, - required: false, - } - ], - permissions: "SendMessages", - - async run(interaction) { - const prompt = interaction.options.getString("prompt"); - const negativePrompt = interaction.options.getString("negativeprompt") || ""; - const cfgScale = interaction.options.getNumber("cfgscale") || 7.5; // Default value - - try { - const imageUrl = await generateImage(prompt, negativePrompt, cfgScale); - - const ImageEmbed = new Discord.EmbedBuilder() - .setTitle("Generated Image") - .setDescription(`Here is the image generated for your prompt: "${prompt}"`) - .setImage(imageUrl) - .setColor(supportbot.Embed.Colours.General) - .setFooter({ - text: supportbot.Embed.Footer, - iconURL: interaction.user.displayAvatarURL(), - }); - - if (!interaction.replied) { - await interaction.reply({ - ephemeral: true, - embeds: [ImageEmbed], - }); - } else { - await interaction.followUp({ - ephemeral: true, - embeds: [ImageEmbed], - }); - } - } catch (error) { - console.error('Error generating image:', error); - if (!interaction.replied) { - await interaction.reply({ - ephemeral: true, - content: `An error occurred while generating the image: ${error.message}. Please try again later.`, - }); - } else { - await interaction.followUp({ - ephemeral: true, - content: `An error occurred while generating the image: ${error.message}. Please try again later.`, - }); - } - } - }, -}); diff --git a/Commands/profile.js b/Commands/profile.js index 582d042..f54ec86 100644 --- a/Commands/profile.js +++ b/Commands/profile.js @@ -25,10 +25,10 @@ function updateClockedInStatus(profileEmbed, clockedIn) { } module.exports = new Command({ - name: 'profile', - description: 'Show user profile', + name: cmdconfig.Profile.Command, + description: cmdconfig.Profile.Description, type: ApplicationCommandType.ChatInput, - permissions: ["SendMessages"], + permissions: cmdconfig.Profile.Permission, options: [ { name: 'user', diff --git a/Commands/removeUser.js b/Commands/removeUser.js new file mode 100644 index 0000000..c2fe64c --- /dev/null +++ b/Commands/removeUser.js @@ -0,0 +1,125 @@ +// File path: Commands/RemoveUser.js + +const fs = require("fs"); +const { + EmbedBuilder, + ApplicationCommandOptionType, + ApplicationCommandType, + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, +} = require("discord.js"); +const yaml = require("js-yaml"); + +const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8")); +const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8")); +const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8")); + +const Command = require("../Structures/Command.js"); + +module.exports = new Command({ + name: cmdconfig.RemoveUser.Command, + description: cmdconfig.RemoveUser.Description, + type: ApplicationCommandType.ChatInput, + options: [ + { + name: "user", + description: "The user to remove", + type: ApplicationCommandOptionType.User, + required: true, + }, + ], + permissions: cmdconfig.RemoveUser.Permission, + + async run(interaction) { + + 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 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] }); + + const userToRemove = interaction.options.getUser("user"); + const ticketChannel = interaction.channel; + const ticketDataPath = "./Data/TicketData.json"; + + // Check if the channel is a ticket thread + if (!ticketChannel.isThread()) { + const onlyInTicket = new EmbedBuilder() + .setTitle(msgconfig.RemoveUser.NotInTicket_Title) + .setDescription(msgconfig.RemoveUser.NotInTicket_Description) + .setColor(supportbot.Embed.Colours.Error); + + return interaction.reply({ + embeds: [onlyInTicket], + ephemeral: true, + }); + } + + try { + await ticketChannel.members.remove(userToRemove.id); + + const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8")); + const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id); + if (ticketIndex !== -1) { + const subUsers = ticketData.tickets[ticketIndex].subUsers; + const userIndex = subUsers.indexOf(userToRemove.id); + if (userIndex !== -1) { + subUsers.splice(userIndex, 1); + fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4)); + } + } + + const removedEmbed = new EmbedBuilder() + .setTitle(msgconfig.RemoveUser.Removed_Title) + .setDescription(msgconfig.RemoveUser.Removed_Message) + .setColor(supportbot.Embed.Colours.Success); + + await interaction.reply({ + embeds: [removedEmbed], + ephemeral: true, + }); + + const removedFromTicketEmbed = new EmbedBuilder() + .setTitle(msgconfig.RemoveUser.RemovedFromTicket_Title) + .setDescription(msgconfig.RemoveUser.RemovedFromTicket_Description.replace( + "%channel_link%", + `[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})` + )) + .setColor(supportbot.Embed.Colours.General); + + await userToRemove.send({ + embeds: [removedFromTicketEmbed], + }); + + } catch (err) { + console.error("Error removing user from the ticket:", err); + + const errorEmbed = new EmbedBuilder() + .setTitle(msgconfig.RemoveUser.Error_Title) + .setDescription(msgconfig.RemoveUser.Error_Removing) + .setColor(supportbot.Embed.Colours.Error); + + await interaction.reply({ + embeds: [errorEmbed], + ephemeral: true, + }); + } + }, +}); diff --git a/Commands/ticket.js b/Commands/ticket.js index 7514a2e..d56b710 100644 --- a/Commands/ticket.js +++ b/Commands/ticket.js @@ -8,7 +8,7 @@ const { ButtonBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, - ButtonStyle + ButtonStyle, } = require("discord.js"); const yaml = require("js-yaml"); @@ -22,7 +22,7 @@ const TicketNumberID = require("../Structures/TicketID.js"); async function getClockedInUsers(guild) { const clockedInUsers = new Set(); - + const profilesDir = './Data/Profiles'; const profileFiles = fs.readdirSync(profilesDir); @@ -201,10 +201,6 @@ async function assignTicketToUser(ticketChannel, Staff, Admin, interaction, atte } } - - - - module.exports = new Command({ name: cmdconfig.OpenTicket.Command, description: cmdconfig.OpenTicket.Description, @@ -220,7 +216,11 @@ module.exports = new Command({ async run(interaction) { try { - let department = interaction.customId?.split("-")[1] || null; + let TicketReason = null; + if (supportbot.Ticket.TicketReason) { + TicketReason = interaction.reason || null; // Retrieve the reason from the interaction object + } + 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); @@ -256,7 +256,7 @@ module.exports = new Command({ } let ticketNumberID = await TicketNumberID.pad(); - const TicketSubject = interaction.options?.getString("reason") || msgconfig.Ticket.InvalidSubject; + const TicketSubject = TicketReason || msgconfig.Ticket.InvalidSubject; const TicketExists = new EmbedBuilder() .setTitle("Ticket Exists!") @@ -304,9 +304,7 @@ module.exports = new Command({ } // Add user to the ticket channel - if (!department) { - await ticketChannel.members.add(interaction.user.id); - } + await ticketChannel.members.add(interaction.user.id); // Save ticket data TicketData.tickets.push({ @@ -335,6 +333,7 @@ module.exports = new Command({ msgconfig.Ticket.TicketCreatedAlert.replace(/%ticketauthor%/g, interaction.user.id) .replace(/%ticketid%/g, ticketChannel.id) .replace(/%ticketusername%/g, interaction.user.username) + .replace(/%ticketreason%/g, TicketSubject) ) .setColor(supportbot.Embed.Colours.General); await interaction.reply({ embeds: [CreatedTicket], ephemeral: true }); @@ -356,24 +355,22 @@ module.exports = new Command({ msgconfig.Ticket.TicketMessage.replace(/%ticketauthor%/g, interaction.user.id) .replace(/%ticketid%/g, ticketChannel.id) .replace(/%ticketusername%/g, interaction.user.username) + .replace(/%ticketreason%/g, TicketSubject) ) .setColor(supportbot.Embed.Colours.General); + // Add reason field if ticket reason is enabled + if (supportbot.Ticket.TicketReason && TicketReason) { + TicketMessage.addFields( + { name: "Reason", value: TicketReason, inline: false } + ); + } + // Create the control panel 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.") @@ -399,11 +396,12 @@ module.exports = new Command({ components: [row2], }); + // Handle department selection if not specified if (!department) { try { - let buttons = supportbot.Departments.map((x) => + const buttons = supportbot.Departments.map((x, index) => new ButtonBuilder() - .setCustomId("Department" + supportbot.Departments.indexOf(x)) + .setCustomId("Department" + index) .setLabel(x.title) .setStyle(x.color) .setEmoji(x.emoji) @@ -411,37 +409,39 @@ module.exports = new Command({ const row = new ActionRowBuilder().addComponents(buttons); - try { - const filter = (i) => i.user.id === interaction.user.id; - await m.awaitMessageComponent({ - filter, - max: 1, - componentType: "BUTTON", - time: supportbot.Ticket.Timeout * 60000, - }); - } catch (e) { - if (e.code === "COLLECTOR_ERROR") { - try { - let ticket = TicketData.tickets.findIndex((t) => t.id === ticketChannel.id); - TicketData.tickets[ticket].open = false; - fs.writeFileSync( - "./Data/TicketData.json", - JSON.stringify(TicketData, null, 4), - (err) => { - if (err) console.error(err); - } - ); - interaction.user.send( - "Your ticket has timed out. Please open a new one, and select a department." - ); - } catch (error) {return assignedUserId; - console.error("An error occurred while handling collector:", error); - } - return await ticketChannel.delete(); + const message = await ticketChannel.send({ + content: "Please select a department:", + components: [row], + }); + + const filter = (i) => i.user.id === interaction.user.id; + await message.awaitMessageComponent({ + filter, + max: 1, + componentType: "BUTTON", + time: supportbot.Ticket.Timeout * 60000, + }); + + } catch (e) { + if (e.code === "COLLECTOR_ERROR") { + try { + const ticket = TicketData.tickets.findIndex((t) => t.id === ticketChannel.id); + TicketData.tickets[ticket].open = false; + fs.writeFileSync( + "./Data/TicketData.json", + JSON.stringify(TicketData, null, 4), + (err) => { + if (err) console.error(err); + } + ); + await interaction.user.send( + "Your ticket has timed out. Please open a new one and select a department." + ); + } catch (error) { + console.error("An error occurred while handling collector:", error); } + await ticketChannel.delete(); } - } catch (error) { - console.error("Error sending message:", error); } } } catch (error) { diff --git a/Commands/userinfo.js b/Commands/userinfo.js deleted file mode 100644 index ef06e7e..0000000 --- a/Commands/userinfo.js +++ /dev/null @@ -1,137 +0,0 @@ -// SupportBot | Emerald Services -// User Info Command - -const fs = require("fs"); -const moment = require("moment"); - -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.UserInfo.Command, - description: cmdconfig.UserInfo.Description, - type: Discord.ApplicationCommandType.ChatInput, - options: [ - { - type: Discord.ApplicationCommandOptionType.User, - name: "user", - description: "The user you want to get info about.", - required: true, - }, // The user input - ], - permissions: cmdconfig.UserInfo.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({ embeds: [NoPerms] }); - - let user = await interaction.options.getUser("user") || interaction.author; // Grab the mentioned user - let member = await interaction.guild.members.cache.get(user.id) // Check for user and his ID - - const UserNotExist = new Discord.EmbedBuilder() - .setTitle("User Not Found!") - .setDescription( - `${msgconfig.Error.UserNotFound}\n\nTry Again:\`/${cmdconfig.UserInfoCommand} <@!User_ID> or @User\`` - ) - .setColor(supportbot.ErrorColour); - - if (!user) return interaction.reply({ embeds: [UserNotExist] }); - - // Flags a user/bot can have - const flags = { - DISCORD_EMPLOYEE: 'Discord Employee', - DISCORD_PARTNER: 'Discord Partner', - BUGHUNTER_LEVEL_1: 'Bug Hunter (Level 1)', - BUGHUNTER_LEVEL_2: 'Bug Hunter (Level 2)', - HYPESQUAD_EVENTS: 'HypeSquad Events', - HOUSE_BRAVERY: 'House of Bravery', - HOUSE_BRILLIANCE: 'House of Brilliance', - HOUSE_BALANCE: 'House of Balance', - EARLY_SUPPORTER: 'Early Supporter', - TEAM_USER: 'Team User', - SYSTEM: 'System', - VERIFIED_BOT: 'Verified Bot', - VERIFIED_DEVELOPER: 'Verified Bot Developer' - }; - - // Status message with icon - let status = { - online: "🟢Online", - idle: "🟡Idle", - dnd: "🔴Do Not Disturb", - offline: "⚫Offline" - }; - - const userFlags = user.flags.toArray(); - - // Embed containing the userinfo - let userembed = new Discord.EmbedBuilder() - .setTitle(`User Info for User: ${user.tag}`) - .setThumbnail(member.displayAvatarURL({ dynamic: true, size: 512 })) - .setColor(member.roles.highest.hexColor) - .addFields( - { name: "Name:", value: `${user.tag}\n<@${member.id}>`, inline: true }, - { name: "ID:", value: `${member.id}`, inline: true }, - { name: "Is Bot:", value: user.bot ? "Yes" : "No", inline: true }, - { name: "House/Badge:", value: `${userFlags.length ? userFlags.map(flag => flags[flag]).join("\n") : "None"}`, inline: true }, - { name: "Current Status:", value: `${status[member.presence ? member.presence.status : "offline"]}`, inline: true }, - { name: "Avatar URL:", value: `[Click Here](${member.displayAvatarURL()})`, inline: true }, - { name: "\u200b", value: "\u200b", inline: false} - ) - .addFields( - { name: "Creation Date:", value: `${moment(user.createdAt).format("MMMM Do YYYY, h:mm:ss a")}\n> ${moment(user.createdAt).startOf("day").fromNow()}`, inline: true }, - { name: "Joined Date:", value: `${moment(member.joinedAt).format("MMMM Do YYYY, h:mm:ss a")}\n> ${moment(member.joinedAt).startOf("day").fromNow()}`, inline: true }, - { name: "Roles Total:", value: `${member.roles.cache.size -1}`, inline: false }, - { name: "Highest Role:", value: `${member.roles.highest.id === interaction.guild.id ? "None" : member.roles.highest.toString()}`, inline: true }, - { name: "Roles:", value: `${member.roles.cache.map(r => r).join(" ").replace("@everyone", " ") || "None"}`, inline: false }, - ) - .setFooter({ text: supportbot.Footer }) - .setTimestamp(); - - // Send embed [userembed] - await interaction.reply({ embeds: [userembed] }).catch((err) => console.error("An error has occured: ", err)); - - }, - }) - -/** - * @INFO - * UserInfo command by Sypher#3415 | 321332200668790786 - * @INFO - * Solely created for SupportBot | https://github.com/Emerald-Services/SupportBot/ - **/ diff --git a/Configs/commands.yml b/Configs/commands.yml index c8aaa6b..3ab19d3 100644 --- a/Configs/commands.yml +++ b/Configs/commands.yml @@ -19,12 +19,6 @@ 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**." @@ -37,9 +31,9 @@ TicketPanel: Permission: ["Administrator"] Enabled: true -TicketStats: - Command: "ticketstats" - Description: "Shows staff members their ticket statistics" +Profile: + Command: "profile" + Description: "Shows the profile for a discord member." Permission: ["SendMessages"] # Command is automatically disabled when the TicketClaims is disabled. @@ -49,9 +43,21 @@ OpenTicket: Permission: ["SendMessages"] Enabled: true -Add: +AddUser: Command: "add" - Description: "Add a user to the ticket." + Description: "Add a user to a support ticket." + Permission: ["SendMessages"] + Enabled: true + +ForceAddUser: + Command: "forceadd" + Description: "Add a user to a support ticket by bypassing the invite system." + Permission: ["SendMessages"] + Enabled: true + +RemoveUser: + Command: "remove" + Description: "Remove a user from a support ticket." Permission: ["SendMessages"] Enabled: true diff --git a/Configs/messages.yml b/Configs/messages.yml index d7fb80d..09fde0a 100644 --- a/Configs/messages.yml +++ b/Configs/messages.yml @@ -70,12 +70,6 @@ Ticket: # <@%user%> - Tags the user who was added to the 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" InvalidSubject: "> No Reason Provided!" @@ -108,6 +102,66 @@ TicketStats: Title: "Your Ticket Stats" +AddUser: + NotInTicket_Title: "Ticket Invitation" + NotInTicket_Description: "> This command can only be used within a ticket thread." + + Invite_Title: "User Invited" + Invite_Description: "> %username% has been invited to join the ticket." + + DM_Title: "Ticket Invitation" + DM_Description: "> You have been invited to join the ticket %channelname%. Do you accept?" + + Accept_Label: "Accept" + Reject_Label: "Reject" + ViewTicket_Label: "Go to Ticket" + + Accepted_Title: "Invitation Accepted" + Accepted_Message: "> You have been added to the ticket." + AddedToTicket_Title: "Added to Ticket" + AddedToTicket_Description: "> You have been added to the ticket %channel_link%." + + Declined_Title: "Invitation Declined" + Declined_Message: "> You have declined the invitation." + + NoResponse_Title: "No Response" + NoResponse_Message: "> You did not respond in time. Please contact staff if you wish to join the ticket." + + Error_Title: "Error" + Error_Adding: "> There was an error adding you to the ticket. Please try again." + + DM_Error_Title: "Error" + DM_Error_Description: "> Unable to send a DM to %username%. Please ensure your DMs are enabled." + + Unexpected_Error_Title: "Error" + Unexpected_Error_Description: "> An unexpected error occurred: %error%" + +RemoveUser: + NotInTicket_Title: "Error" + NotInTicket_Description: "This command can only be used in ticket threads." + + Removed_Title: "User Removed" + Removed_Message: "The user has been successfully removed from the ticket." + + RemovedFromTicket_Title: "Removed from Ticket" + RemovedFromTicket_Description: "You have been removed from the ticket channel %channel_link%." + + Error_Title: "Error" + Error_Removing: "There was an error removing the user from the ticket." + +ForceAddUser: + NotInTicket_Title: "Not a Ticket" + NotInTicket_Description: "This command can only be used within a ticket thread." + + Added_Title: "User Added" + Added_Description: "Successfully added %username% to the ticket." + + AddedToTicket_Title: "You have been added to a Ticket" + AddedToTicket_Description: "You have been added to the ticket channel [%channel_link%]." + + Error_Title: "Error" + Error_Adding: "There was an error adding the user to the ticket." + Error: IncorrectPerms: "> :x: **Err!** You do not have the correct permissions to use this." InvalidChannel: "> :x: **Err!** Channel not found. Please create it!" diff --git a/Configs/supportbot-ai.yml b/Configs/supportbot-ai.yml index 0dd7cc3..02b5494 100644 --- a/Configs/supportbot-ai.yml +++ b/Configs/supportbot-ai.yml @@ -17,11 +17,11 @@ General: # Max tokens you can set is 400 # For more information about tokens, go to https://openai.com/api/pricing/ - OpenAI_Key: "OPEN AI KEY" + OpenAI_Key: "OPENAI_KEY" # To create an OpenAI API key, go to https://platform.openai.com/api-keys - PastebinAPI_Key: "PASTEBIN KEY" + PastebinAPI_Key: "PASTEBIN_KEY" # You can get your Pastebin API Key from https://pastebin.com PastebinAPI_URL: "https://pastebin.com/api/api_post.php" diff --git a/Configs/supportbot.yml b/Configs/supportbot.yml index 092c0f1..f8d52e9 100644 --- a/Configs/supportbot.yml +++ b/Configs/supportbot.yml @@ -11,7 +11,7 @@ # Official Documentation: https://github.com/Emerald-Services/SupportBot/wiki # Third-Party Documentation: COMING SOON -SupportBot_Version: "v8.0.1" +SupportBot_Version: "v8.1" # Do not change the version number # ------------------------- @@ -20,7 +20,7 @@ SupportBot_Version: "v8.0.1" General: Name: "SupportBot" - Token: "BOT TOKEN HERE" + Token: "BOT_TOKEN_HERE" # To get your Discord Bot Token, Go to https://discord.com/developers/applications Addons: diff --git a/Data/Profiles/419821884431925260.json b/Data/Profiles/419821884431925260.json index b096324..bf79b27 100644 --- a/Data/Profiles/419821884431925260.json +++ b/Data/Profiles/419821884431925260.json @@ -1,5 +1,5 @@ { - "clockedIn": true, + "clockedIn": false, "bio": "Hi", "timezone": "GMT" } \ No newline at end of file diff --git a/Data/Profiles/709003903353618506.json b/Data/Profiles/709003903353618506.json new file mode 100644 index 0000000..134d8ba --- /dev/null +++ b/Data/Profiles/709003903353618506.json @@ -0,0 +1,5 @@ +{ + "bio": "", + "timezone": "", + "clockedIn": true +} \ No newline at end of file diff --git a/Data/SuggestionData.json b/Data/SuggestionData.json index b550ff7..c401bda 100644 --- a/Data/SuggestionData.json +++ b/Data/SuggestionData.json @@ -12,5 +12,11 @@ "author": "419821884431925260", "upvotes": [], "downvotes": [] + }, + "1260279162854441042": { + "suggestion": "test", + "author": "419821884431925260", + "upvotes": [], + "downvotes": [] } } \ No newline at end of file diff --git a/Data/TicketData.json b/Data/TicketData.json index 9f923fb..d7b44e2 100644 --- a/Data/TicketData.json +++ b/Data/TicketData.json @@ -179,6 +179,91 @@ "createdAt": "2024-07-02T19:37:19.467Z", "claimedAt": "2024-07-02T19:43:12.873Z", "claimedBy": "419821884431925260" + }, + { + "id": "1259980339816697907", + "name": "ticket-0037", + "user": "419821884431925260", + "number": "0037", + "reason": "> No Reason Provided!", + "open": false, + "subUsers": [], + "createdAt": "2024-07-08T21:12:06.009Z", + "claimedAt": "2024-07-08T21:12:17.454Z", + "claimedBy": "419821884431925260" + }, + { + "id": "1259980831749832807", + "name": "ticket-0038", + "user": "419821884431925260", + "number": "0038", + "reason": "> No Reason Provided!", + "open": false, + "subUsers": [], + "createdAt": "2024-07-08T21:14:01.173Z", + "claimedAt": "2024-07-08T21:14:12.930Z", + "claimedBy": "419821884431925260" + }, + { + "id": "1260004238856163470", + "name": "ticket-0039", + "user": "419821884431925260", + "number": "0039", + "reason": "> No Reason Provided!", + "open": true, + "subUsers": [], + "createdAt": "2024-07-08T22:47:02.254Z", + "claimedAt": "2024-07-08T22:47:11.156Z", + "claimedBy": "419821884431925260" + }, + { + "id": "1260009197207027846", + "name": "ticket-0040", + "user": "419821884431925260", + "number": "0040", + "reason": "test", + "open": true, + "subUsers": [], + "createdAt": "2024-07-08T23:06:44.329Z", + "claimedAt": "2024-07-08T23:06:51.047Z", + "claimedBy": "419821884431925260" + }, + { + "id": "1260257345292865556", + "name": "ticket-0041", + "user": "419821884431925260", + "number": "0041", + "reason": "blob", + "open": true, + "subUsers": [ + "709003903353618506", + "709003903353618506", + "709003903353618506", + "709003903353618506", + "709003903353618506", + "709003903353618506", + "709003903353618506", + "419821884431925260", + "419821884431925260", + "709003903353618506", + "419821884431925260", + "709003903353618506" + ], + "createdAt": "2024-07-09T15:32:47.543Z", + "claimedAt": "2024-07-09T15:33:06.442Z", + "claimedBy": "419821884431925260" + }, + { + "id": "1260263275464233060", + "name": "ticket-0042", + "user": "419821884431925260", + "number": "0042", + "reason": "blob", + "open": true, + "subUsers": [], + "createdAt": "2024-07-09T15:56:21.766Z", + "claimedAt": "2024-07-09T15:58:15.205Z", + "claimedBy": "709003903353618506" } ] } \ No newline at end of file diff --git a/Data/ticket-panel-id.json b/Data/ticket-panel-id.json index 805b116..6b7a3d9 100644 --- a/Data/ticket-panel-id.json +++ b/Data/ticket-panel-id.json @@ -1,4 +1,4 @@ { - "id": 37, + "id": 43, "TicketPanelID": "1250863985335472312" } \ No newline at end of file diff --git a/Events/interactionCreate.js b/Events/interactionCreate.js index c636649..36fe9e6 100644 --- a/Events/interactionCreate.js +++ b/Events/interactionCreate.js @@ -16,20 +16,25 @@ try { } module.exports = new Event("interactionCreate", async (client, interaction) => { - if (interaction.type == Discord.InteractionType.ApplicationCommand) { + console.log("Interaction received:", interaction.type); // Log interaction type + + if (interaction.type === Discord.InteractionType.ApplicationCommand) { const command = client.commands.find( (cmd) => cmd.name.toLowerCase() === interaction.commandName ); + console.log("Command received:", interaction.commandName); // Log command name + if (interaction.user.bot || !interaction.guild) return; const NotValid = new Discord.EmbedBuilder() - .setDescription(`:x: \`Invalid Command\` `) + .setDescription(`:x: \`Invalid Command\``) .setColor(supportbot.Embed.Colours.Error); if (!command) return interaction.reply({ embeds: [NotValid], + ephemeral: true, }); const permission = interaction.member.permissions.has(command.permissions); @@ -43,8 +48,50 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { if (!permission) return interaction.reply({ embeds: [ValidPerms], + ephemeral: true, }); - command.run(interaction); + + try { + if (command.name === cmdconfig.OpenTicket.Command && supportbot.Ticket.TicketReason) { + const modal = new Discord.ModalBuilder() + .setCustomId("ticketReasonModal") + .setTitle("Ticket Reason") + .addComponents( + new Discord.ActionRowBuilder().addComponents( + new Discord.TextInputBuilder() + .setCustomId("reasonInput") + .setLabel("Reason") + .setStyle(Discord.TextInputStyle.Paragraph) + .setRequired(true) + ) + ); + + await interaction.showModal(modal); + } else { + console.log("Running command:", command.name); // Log running command + await command.run(interaction); + } + } catch (error) { + console.error("Error executing command:", error); + await interaction.reply({ + content: "An error occurred while executing the command.", + ephemeral: true, + }); + } + } + + if (interaction.isModalSubmit()) { + if (interaction.customId === "ticketReasonModal") { + const reason = interaction.fields.getTextInputValue("reasonInput"); + interaction.customId = `createticket-${reason}`; + const cmd = client.commands.get(cmdconfig.OpenTicket.Command); + if (cmd) { + interaction.reason = reason; // Attach the reason to the interaction object + await cmd.run(interaction); + } else { + console.error("Command not found."); + } + } } if (interaction.isStringSelectMenu()) { @@ -52,26 +99,11 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { 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); + await closeCommand.run(interaction); } else { console.error("[X] Close Command Not Found"); } @@ -89,32 +121,66 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { } if (interaction.isButton()) { - if (interaction.customId === 'createticket') { - try { - const cmd = client.commands.get(cmdconfig.OpenTicket.Command); - if (!cmd) return; - cmd.run(interaction); - } catch (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 === "createticket") { + if (supportbot.Ticket.TicketReason) { + const modal = new Discord.ModalBuilder() + .setCustomId("ticketReasonModal") + .setTitle("Ticket Reason") + .addComponents( + new Discord.ActionRowBuilder().addComponents( + new Discord.TextInputBuilder() + .setCustomId("reasonInput") + .setLabel("Reason") + .setStyle(Discord.TextInputStyle.Paragraph) + .setRequired(true) + ) + ); + + await interaction.showModal(modal); + } else { + try { + const cmd = client.commands.get(cmdconfig.OpenTicket.Command); + if (!cmd) return; + await cmd.run(interaction); + } catch (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 === "openticket") { - try { - const cmd = client.commands.get(cmdconfig.OpenTicket); - if (!cmd) return; - cmd.run(interaction); - } catch (error) { - console.error(error); + if (supportbot.Ticket.TicketReason) { + const modal = new Discord.ModalBuilder() + .setCustomId("ticketReasonModal") + .setTitle("Ticket Reason") + .addComponents( + new Discord.ActionRowBuilder().addComponents( + new Discord.TextInputBuilder() + .setCustomId("reasonInput") + .setLabel("Reason") + .setStyle(Discord.TextInputStyle.Paragraph) + .setRequired(true) + ) + ); + + await interaction.showModal(modal); + } else { + try { + const cmd = client.commands.get(cmdconfig.OpenTicket.Command); + if (!cmd) return; + await cmd.run(interaction); + } catch (error) { + console.error(error); + } } } - if (interaction.customId.startsWith('claimticket-')) { - const ticketChannelId = interaction.customId.split('-')[1]; + if (interaction.customId.startsWith("claimticket-")) { + const ticketChannelId = interaction.customId.split("-")[1]; const ticketChannel = interaction.guild.channels.cache.get(ticketChannelId); if (!ticketChannel) { return interaction.reply({ @@ -144,7 +210,7 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { const NoPermsClaim = new Discord.EmbedBuilder() .setTitle(msgconfig.Ticket.ClaimTickets.NoPermsToClaimTitle) .setDescription( - msgconfig.Ticket.ClaimTickets.NoPermsToClaim.replace('%channel%', ticketChannel.name) + msgconfig.Ticket.ClaimTickets.NoPermsToClaim.replace("%channel%", ticketChannel.name) ) .setColor(supportbot.Embed.Colours.Error); @@ -160,7 +226,7 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { setTimeout(() => { pingclaimedstaff.delete(); - }, 2000) + }, 2000); const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8")); const ticketIndex = TicketData.tickets.findIndex((t) => t.id === ticketChannelId); @@ -174,13 +240,13 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { 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) + 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)) + .setDescription(msgconfig.Ticket.ClaimTickets.Claimed.replace("%channel%", ticketChannel.id)) .setColor(supportbot.Embed.Colours.Success); await claimMessage.edit({ embeds: [claimedEmbed], components: [] }); @@ -191,36 +257,41 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { } // SUGGESTION INTERACTIONS [START] - - if (interaction.customId === 'upvote' || interaction.customId === 'downvote' || interaction.customId === 'removevote') { + + if ( + interaction.customId === "upvote" || + interaction.customId === "downvote" || + interaction.customId === "removevote" + ) { const suggestion = suggestions[interaction.message.id]; - if (!suggestion) return interaction.reply({ content: 'Suggestion not found.', ephemeral: true }); + if (!suggestion) + return interaction.reply({ content: "Suggestion not found.", ephemeral: true }); const userId = interaction.user.id; const hasUpvoted = suggestion.upvotes.includes(userId); const hasDownvoted = suggestion.downvotes.includes(userId); - if (interaction.customId === 'upvote') { + if (interaction.customId === "upvote") { if (hasUpvoted) { - suggestion.upvotes = suggestion.upvotes.filter(id => id !== userId); + suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId); } else { suggestion.upvotes.push(userId); if (hasDownvoted) { - suggestion.downvotes = suggestion.downvotes.filter(id => id !== userId); + suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId); } } - } else if (interaction.customId === 'downvote') { + } else if (interaction.customId === "downvote") { if (hasDownvoted) { - suggestion.downvotes = suggestion.downvotes.filter(id => id !== userId); + suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId); } else { suggestion.downvotes.push(userId); if (hasUpvoted) { - suggestion.upvotes = suggestion.upvotes.filter(id => id !== userId); + suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId); } } - } else if (interaction.customId === 'removevote') { - suggestion.upvotes = suggestion.upvotes.filter(id => id !== userId); - suggestion.downvotes = suggestion.downvotes.filter(id => id !== userId); + } else if (interaction.customId === "removevote") { + suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId); + suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId); } fs.writeFileSync("./Data/SuggestionData.json", JSON.stringify(suggestions, null, 2)); @@ -228,13 +299,20 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { const upvoteCount = suggestion.upvotes.length; const downvoteCount = suggestion.downvotes.length; - const updatedEmbed = new Discord.EmbedBuilder(interaction.message.embeds[0].data) - .setFields([ - { name: 'Suggestion', value: suggestion.suggestion, inline: true }, - { name: 'From', value: `<@${suggestion.author}>` }, - { name: `${supportbot.Suggestions.UpvoteEmoji} ${supportbot.Suggestions.UpvoteTitle}`, value: `${upvoteCount}`, inline: true }, - { name: `${supportbot.Suggestions.DownvoteEmoji} ${supportbot.Suggestions.DownvoteTitle}`, value: `${downvoteCount}`, inline: true } - ]); + const updatedEmbed = new Discord.EmbedBuilder(interaction.message.embeds[0].data).setFields([ + { name: "Suggestion", value: suggestion.suggestion, inline: true }, + { name: "From", value: `<@${suggestion.author}>` }, + { + name: `${supportbot.Suggestions.UpvoteEmoji} ${supportbot.Suggestions.UpvoteTitle}`, + value: `${upvoteCount}`, + inline: true, + }, + { + name: `${supportbot.Suggestions.DownvoteEmoji} ${supportbot.Suggestions.DownvoteTitle}`, + value: `${downvoteCount}`, + inline: true, + }, + ]); await interaction.update({ embeds: [updatedEmbed] }); } @@ -246,7 +324,9 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { 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."); + return interaction.reply( + "Some roles seem to be missing!\nPlease check for errors when starting the bot." + ); } const NoPerms = new Discord.EmbedBuilder() @@ -256,7 +336,10 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { ) .setColor(supportbot.Embed.Colours.Warn); - if (!interaction.member.roles.cache.has(SupportStaff.id) && !interaction.member.roles.cache.has(Admin.id)) { + if ( + !interaction.member.roles.cache.has(SupportStaff.id) && + !interaction.member.roles.cache.has(Admin.id) + ) { return interaction.reply({ embeds: [NoPerms] }); } } @@ -264,9 +347,7 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { 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); + const embed = new Discord.EmbedBuilder().setDescription(message).setColor(supportbot.Embed.Colours.General); await interaction.reply({ embeds: [embed], @@ -275,7 +356,7 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { } // Modal submission handler for editing profile - if (interaction.type === Discord.InteractionType.ModalSubmit && interaction.customId === 'editProfileModal') { + if (interaction.type === Discord.InteractionType.ModalSubmit && interaction.customId === "editProfileModal") { const userId = interaction.user.id; const profilePath = `./Data/Profiles/${userId}.json`; @@ -286,13 +367,13 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { profileData = { bio: "", timezone: "", - clockedIn: false + clockedIn: false, }; } try { - const newBio = interaction.fields.getTextInputValue('bio'); - const newTimezone = interaction.fields.getTextInputValue('timezone'); + const newBio = interaction.fields.getTextInputValue("bio"); + const newTimezone = interaction.fields.getTextInputValue("timezone"); profileData.bio = newBio; profileData.timezone = newTimezone; @@ -304,22 +385,25 @@ module.exports = new Event("interactionCreate", async (client, interaction) => { .setColor(supportbot.Embed.Colours.General) .setThumbnail(interaction.user.displayAvatarURL()) .addFields( - { name: 'Bio', value: newBio || 'No bio set.', inline: false }, - { name: 'Timezone', value: newTimezone || 'No timezone set.', inline: true } + { name: "Bio", value: newBio || "No bio set.", inline: false }, + { name: "Timezone", value: newTimezone || "No timezone set.", inline: true } ); if (profileData.clockedIn !== undefined) { updatedProfileEmbed.addFields({ - name: 'Clocked In Status', - value: profileData.clockedIn ? '✅ Clocked In' : '❌ Clocked Out', - inline: true + name: "Clocked In Status", + value: profileData.clockedIn ? "✅ Clocked In" : "❌ Clocked Out", + inline: true, }); } await interaction.reply({ embeds: [updatedProfileEmbed], ephemeral: true }); } catch (error) { console.error("Failed to update profile data: ", error); - await interaction.reply({ content: "There was an error while updating your profile. Please try again later.", ephemeral: true }); + await interaction.reply({ + content: "There was an error while updating your profile. Please try again later.", + ephemeral: true, + }); } } }); diff --git a/Events/messageCreate.js b/Events/messageCreate.js index b1999a1..724537b 100644 --- a/Events/messageCreate.js +++ b/Events/messageCreate.js @@ -14,10 +14,10 @@ function loadConfig(path) { } } -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")); +const supportbotai = loadConfig("./Configs/supportbot-ai.yml"); +const supportbot = loadConfig("./Configs/supportbot.yml"); +const cmdconfig = loadConfig("./Configs/commands.yml"); +const msgconfig = loadConfig("./Configs/messages.yml"); // Validate configuration values function validateConfig(config, keys) { @@ -28,6 +28,11 @@ function validateConfig(config, keys) { }); } +validateConfig(supportbotai, ['General', 'Channels', 'Messages']); +validateConfig(supportbot, ['Embed']); +validateConfig(cmdconfig, ['Ping']); +validateConfig(msgconfig, ['ErrorResponse', 'OpenAIError']); + const CHANNELS = [supportbotai.Channels.AIChannel]; // Initialize Discord client @@ -64,11 +69,26 @@ async function createPaste(content) { } } +// Function to fetch latest commands and configuration +function getDynamicData() { + const commands = loadConfig("./Configs/commands.yml"); + const configurations = { + supportbotai: loadConfig("./Configs/supportbot-ai.yml"), + supportbot: loadConfig("./Configs/supportbot.yml"), + cmdconfig: loadConfig("./Configs/commands.yml"), + msgconfig: loadConfig("./Configs/messages.yml"), + }; + + return { commands, configurations }; +} + // 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; + const { commands, configurations } = getDynamicData(); + if (supportbotai.Enabled) { const sendTypingInterval = setInterval(() => { message.channel.sendTyping(); diff --git a/Structures/Client.js b/Structures/Client.js index 4afb632..1b12303 100644 --- a/Structures/Client.js +++ b/Structures/Client.js @@ -85,10 +85,22 @@ class Client extends Discord.Client { tempCommandFiles = tempCommandFiles.filter(item => item !== "Ping.js"); } - if (supportbot.Ticket.ClaimTickets.Enabled === false) { - tempCommandFiles = tempCommandFiles.filter(item => item !== "ticketstats.js"); + if (cmdconfig.AddUser.Enabled === false) { + tempCommandFiles = tempCommandFiles.filter(item => item !== "addUser.js"); } + if (cmdconfig.RemoveUser.Enabled === false) { + tempCommandFiles = tempCommandFiles.filter(item => item !== "removeUser.js"); + } + + if (cmdconfig.ForceAddUser.Enabled === false) { + tempCommandFiles = tempCommandFiles.filter(item => item !== "forceaddUser.js"); + } + + if (cmdconfig.Profile.Enabled === false) { + tempCommandFiles = tempCommandFiles.filter(item => item !== "Profile.js"); + } + const commandFiles = tempCommandFiles; const commands = commandFiles.map((file) => require(`../Commands/${file}`)); diff --git a/Structures/generateImage.js b/Structures/generateImage.js new file mode 100644 index 0000000..d5b201e --- /dev/null +++ b/Structures/generateImage.js @@ -0,0 +1,33 @@ +const fs = require("fs"); +const yaml = require("js-yaml"); +const axios = require("axios"); + +const supportbotai = yaml.load(fs.readFileSync("./Configs/supportbot-ai.yml", "utf8")); + +async function generateImage(prompt, negativePrompt, cfgScale) { + try { + const response = await axios.post('https://api.pepperai.xyz/generate', { + prompt: prompt, + negativePrompt: negativePrompt, + cfgScale: cfgScale + }, { + headers: { + 'Authorization': `Bearer ${supportbotai.General.PepperAI_Key}`, + 'Content-Type': 'application/json' + } + }); + + console.log('PepperAI Response:', response.data); // Log the entire response for debugging + + if (response.data && response.data.imageUrl) { + return response.data.imageUrl; + } else { + throw new Error(`Invalid response structure: ${JSON.stringify(response.data)}`); + } + } catch (error) { + console.error('PepperAI Image Generation Error:', error); + throw error; + } +} + +module.exports = generateImage;