SupportBot 8.0
This commit is contained in:
1 parent
2c5bfe8e33
commit
c95b8ccb32
30 files changed
+1426
-2293
No files matched your search
Vendored
BIN
Binary file not shown.
@@ -1,2 +0,0 @@
|
||||
## SupportBot Addons
|
||||
This is a developer version of SupportBot, Addons are not yet supported.
|
||||
-104
@@ -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
@@ -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
@@ -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
@@ -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],
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -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
@@ -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
@@ -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."
|
||||
|
||||
@@ -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
@@ -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"
|
||||
@@ -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"
|
||||
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"1249719789069402180": {
|
||||
"suggestion": "test",
|
||||
"author": "419821884431925260",
|
||||
"upvotes": [
|
||||
"419821884431925260"
|
||||
],
|
||||
"downvotes": []
|
||||
},
|
||||
"1249762468360884290": {
|
||||
"suggestion": "test",
|
||||
"author": "419821884431925260",
|
||||
"upvotes": [],
|
||||
"downvotes": []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1 +1,5 @@
|
||||
{"tickets": [{}]}
|
||||
{
|
||||
"tickets": [
|
||||
{}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"id": 4,
|
||||
"TicketPanelID": ""
|
||||
"id": 0,
|
||||
"TicketPanelID": "0000000000000000000"
|
||||
}
|
||||
+165
-80
@@ -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,
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
@@ -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
@@ -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}`));
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Generated
-1245
File diff suppressed because it is too large.
Load diff
+6
-3
@@ -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"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user