SupportBot 8.0

This commit is contained in:
1tzEmerald committed 2024-06-12 12:54:31 +01:00
1 parent 2c5bfe8e33
commit c95b8ccb32
30 files changed
+1426 -2293

No files matched your search

BIN
View File
Binary file not shown.
-2
View File
@@ -1,2 +0,0 @@
## SupportBot Addons
This is a developer version of SupportBot, Addons are not yet supported.
-104
View File
@@ -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} <user#0000>\``
)
.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);
}
);
},
});
+262 -139
View File
@@ -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 = `
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
<style>
body {
background-color: #1a1a1a;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: white;
margin: 0;
padding: 0;
height: 100%;
display: flex;
flex-direction: column;
}
.container {
backdrop-filter: blur(10px);
background-color: rgba(0, 128, 0, 0.3);
border-radius: 15px;
padding: 20px;
margin: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
flex-grow: 1;
display: flex;
flex-direction: column;
max-width: 1000px;
width: 100%;
margin: auto;
}
.message {
display: flex;
align-items: center;
margin-bottom: 10px;
padding: 10px;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
}
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 10px;
}
.content {
flex: 1;
}
.username {
font-weight: bold;
}
.timestamp {
font-size: 0.8em;
color: #bbb;
}
.download-button {
background-color: #4CAF50;
color: white;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin-top: 20px;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1 class="text-2xl font-bold mb-4">Ticket Transcript</h1>
<p><strong>Server Name:</strong> ${interaction.guild.name}</p>
<p><strong>Ticket:</strong> ${interaction.channel.name}</p>
<p><strong>Messages:</strong> ${msgs.size} Messages</p>
<div class="mt-4">
`;
msgs = msgs.sort((a, b) => a.createdTimestamp - b.createdTimestamp);
msgs.forEach((msg) => {
if (msg.content) {
html += `
<div class="message">
<img class="avatar" src="${msg.author.displayAvatarURL()}" alt="Avatar">
<div class="content">
<p class="username">${msg.author.tag}</p>
<p class="timestamp">${msg.createdAt.toLocaleString()}</p>
<p>${convertMarkdownToHTML(msg.content)}</p>
</div>
</div>
`;
}
});
const fileName = `${interaction.channel.name}.html`;
html += `
</div>
<a href="${fileName}" download class="download-button">Download Transcript</a>
</div>
</body>
</html>
`;
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 += `<style>* {background-color: #2c2f33;color: #fff;font-family: Arial, Helvetica, sans-serif;}</style>`;
html += `<strong>Server Name:</strong> ${interaction.guild.name}<br>`;
html += `<strong>Ticket:</strong> ${interaction.channel.name}<br>`;
html += `<strong>Message:</strong> ${msgs.size} Messages<br><br><br>`;
let file = new Discord.AttachmentBuilder(
Buffer.from(html),
{ name: fileName }
);
await msgs.forEach((msg) => {
if (msg.content) {
html += `<strong>User:</strong> ${msg.author.tag}<br>`;
html += `<strong>Message:</strong> ${msg.content}<br>`;
html += `-----<br><br>`;
}
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 <strong>bold</strong>
text = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
// Convert *italic* to <em>italic</em>
text = text.replace(/\*(.*?)\*/g, '<em>$1</em>');
// Convert __underline__ to <u>underline</u>
text = text.replace(/__(.*?)__/g, '<u>$1</u>');
// Convert ~~strikethrough~~ to <s>strikethrough</s>
text = text.replace(/~~(.*?)~~/g, '<s>$1</s>');
// Convert inline code `code` to <code>code</code>
text = text.replace(/`(.*?)`/g, '<code>$1</code>');
// Convert blockquotes > quote to <blockquote>quote</blockquote>
text = text.replace(/^> (.*?$)/gm, '<blockquote>$1</blockquote>');
// Convert multiline code blocks ```code``` to <pre><code>code</code></pre>
text = text.replace(/```(.*?)```/gs, '<pre><code>$1</code></pre>');
// Convert line breaks to <br>
text = text.replace(/\n/g, '<br>');
return text;
}
+87 -40
View File
@@ -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],
+30 -42
View File
@@ -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],
});
},
});
-107
View File
@@ -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} <user#0000>\``
)
.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);
}
);
},
});
+54 -40
View File
@@ -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]
})
});
},
});
+141 -187
View File
@@ -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);
}
}
},
});
+115
View File
@@ -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,
});
}
}
},
});
+56
View File
@@ -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 });
}
}
});
+21 -9
View File
@@ -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"
+41 -7
View File
@@ -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."
+40
View File
@@ -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<hexcode>
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`"
+97 -67
View File
@@ -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<hexcode>
Success: 0x04b545 # 0x<hexcode>
Error: 0xd13030 # 0x<hexcode>
Warn: 0xfca117 # 0x<hexcode>
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"
+20 -8
View File
@@ -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"
PanelImage: "https://i.imgur.com/dejQvkg.png"
BIN
View File
Binary file not shown.
+16
View File
@@ -0,0 +1,16 @@
{
"1249719789069402180": {
"suggestion": "test",
"author": "419821884431925260",
"upvotes": [
"419821884431925260"
],
"downvotes": []
},
"1249762468360884290": {
"suggestion": "test",
"author": "419821884431925260",
"upvotes": [],
"downvotes": []
}
}
+3
View File
@@ -0,0 +1,3 @@
{
}
+5 -1
View File
@@ -1 +1,5 @@
{"tickets": [{}]}
{
"tickets": [
{}
]
}
+2 -2
View File
@@ -1,4 +1,4 @@
{
"id": 4,
"TicketPanelID": ""
"id": 0,
"TicketPanelID": "0000000000000000000"
}
+165 -80
View File
@@ -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,
});
}
});
+166
View File
@@ -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;
}
});
+60 -104
View File
@@ -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);
});
});
}
});
-21
View File
@@ -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.
-75
View File
@@ -1,75 +0,0 @@
<h1 align="center">
<br>
<a href="https://github.com/Emerald-Services/SupportBot"><img src="https://i.imgur.com/tzi3d7Q.png"></a>
<br>
SupportBot
<br>
</h1>
<div align="center">
<a href="https://opensource.org/licenses/MIT">
<img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge" alt="shield.png">
</a>
<a href="https://github.com/discordjs">
<img src="https://img.shields.io/badge/discord.js-v13.6.x-blue.svg?style=for-the-badge&logo=javascript.svg" alt="shield.png">
</a>
<a href="https://github.com/nodejs/node">
<img src="https://img.shields.io/badge/node.js-v16.14.x-green.svg?style=for-the-badge&logo=node" alt="shield.png">
</a>
<a href="https://github.com/Emerald-Services/SupportBot/releases">
<img src="https://img.shields.io/github/downloads/Emerald-Services/SupportBot/total?style=for-the-badge" alt="shield.png">
</a>
</div>
<p align="center">
<a href="https://emeraldsrv.dev/">Website</a>
•
<a href="https://github.com/Emerald-Services/SupportBot/wiki">Wiki</a>
<br>
<a href="#about">About</a>
•
<a href="#support">Support</a>
•
<a href="#license">License</a>
•
<a href="#third-party">Third-Party</a>
•
<a href="#contributors">Contributors</a>
</p>
## 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
<a href="https://emeraldsrv.dev/discord">
<img alt="Discord" src="https://img.shields.io/discord/597779408295821323?logo=discord&logoColor=white&style=for-the-badge">
</a>
## 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
<a href="https://github.com/Emerald-Services/SupportBot/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Emerald-Services/SupportBot">
</a>
+17 -9
View File
@@ -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}`));
+22 -1
View File
@@ -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);
-1245
View File
File diff suppressed because it is too large. Load diff
+6 -3
View File
@@ -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"
}
}