Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3fa8b6d72 | ||
|
|
5c6a9f7306 | ||
|
|
71e33dbf66 | ||
|
|
d468ab1575 | ||
|
|
74482af471 | ||
|
|
0b8b092cb9 | ||
|
|
3cdfaef942 | ||
|
|
fcf441a190 | ||
|
|
5a1c4ad99c | ||
|
|
d9cb72f22e | ||
|
|
58eb37124e | ||
|
|
afeeda3a8d | ||
|
|
fece90d2bd | ||
|
|
357a85fa3d | ||
|
|
f34158caa6 | ||
|
|
1bb343e49a | ||
|
|
dffa5d4161 | ||
|
|
13590b08a8 | ||
|
|
6e14ce209d | ||
|
|
72b8c2247e | ||
|
|
925504a928 | ||
|
|
236d67707f | ||
|
|
753f432c95 | ||
|
|
c824bc51b2 | ||
|
|
39ee540b55 | ||
|
|
903b214051 | ||
|
|
ac0daf5fe7 | ||
|
|
80e38a07e9 | ||
|
|
d2598e09f7 | ||
|
|
28aab47150 | ||
|
|
81bda67ae4 | ||
|
|
25bbd1ff85 | ||
|
|
164d695a5f | ||
|
|
57e4a3e77c | ||
|
|
a6ac532b2b | ||
|
|
4f14722e14 | ||
|
|
9a6eece7a1 | ||
|
|
fd65d0a9a7 | ||
|
|
48500fe8a4 | ||
|
|
8d8d9e4bee | ||
|
|
dcbddf9f23 | ||
|
|
7449c0a61a | ||
|
|
c95b8ccb32 | ||
|
|
2c5bfe8e33 | ||
|
|
a3bbd97333 | ||
|
|
4ea488951d | ||
|
|
481424d5a6 | ||
|
|
fe82e96cc1 | ||
|
|
976258c959 | ||
|
|
83cf0689e2 | ||
|
|
c911cb4423 | ||
|
|
4eadef8b65 | ||
|
|
4e081358ff | ||
|
|
209ec0b435 | ||
|
|
6d363abb54 | ||
|
|
6f8b84aeda | ||
|
|
5b8c5da33a | ||
|
|
b6ef0f95cb | ||
|
|
cce1480a42 | ||
|
|
44fbe9f2d6 | ||
|
|
29db6c7d67 | ||
|
|
26e9b56961 | ||
|
|
979271cfb5 | ||
|
|
69f0b00ed3 | ||
|
|
c1a1839457 | ||
|
|
dd4b53800e | ||
|
|
1fc94528fc | ||
|
|
bb1a817980 | ||
|
|
53305acbc7 | ||
|
|
d0f1bae0bd | ||
|
|
c0cf3b1bb7 | ||
|
|
ce67b668d5 | ||
|
|
3273cfd0e1 | ||
|
|
fd992a6514 | ||
|
|
550d681fe1 | ||
|
|
7d29226953 | ||
|
|
38da72ca91 | ||
|
|
eab11361cb | ||
|
|
b281bba36f | ||
|
|
5e38573aed | ||
|
|
da7b6d487c | ||
|
|
6bf4e5f4bb | ||
|
|
213f532a3c | ||
|
|
45bd88e4d2 | ||
|
|
4eb8658459 | ||
|
|
b37118fee2 | ||
|
|
026caba68a | ||
|
|
2003f8801a | ||
|
|
473bacf13a | ||
|
|
8b3f2bc61a | ||
|
|
3aa373c33c | ||
|
|
9b6263e583 | ||
|
|
3e066d08ce | ||
|
|
aa48e28162 | ||
|
|
dc660ed94a | ||
|
|
e02ecf9553 | ||
|
|
23acc0926f | ||
|
|
3fc1cd18d5 | ||
|
|
ebe29b403e | ||
|
|
dcba3312dd | ||
|
|
7fddeeec37 | ||
|
|
b5341b023f | ||
|
|
bbb7443ef2 | ||
|
|
22df347bb9 | ||
|
|
9aed6b8f35 | ||
|
|
9e7ec9f1bd | ||
|
|
373f43eac5 | ||
|
|
6c91b2791a | ||
|
|
bde62a431f | ||
|
|
615a074540 | ||
|
|
09b335ac46 | ||
|
|
2701880c77 | ||
|
|
24c8f2fb38 | ||
|
|
c3ec158ac3 | ||
|
|
b3690222d0 | ||
|
|
4d7583785b | ||
|
|
17ad1a15db | ||
|
|
4c89de9e76 | ||
|
|
5f25af41f9 | ||
|
|
3a3ee357fc | ||
|
|
08a6d27903 | ||
|
|
33f7675aac | ||
|
|
1178a0a611 | ||
|
|
96ded77bec | ||
|
|
e83ca8cb2b | ||
|
|
e507176d39 | ||
|
|
4e554b8bee | ||
|
|
bc649caa99 | ||
|
|
f7a4c7b616 | ||
|
|
2c7be5882c | ||
|
|
6107d268f7 | ||
|
|
7760699155 | ||
|
|
acf349c72e | ||
|
|
8096e5b882 | ||
|
|
873cfc7dc2 | ||
|
|
038174bc7e | ||
|
|
14881096bb | ||
|
|
ed1905d8f4 | ||
|
|
72c0a2efa3 | ||
|
|
e599d48713 | ||
|
|
7f44634d4f | ||
|
|
44170caac6 | ||
|
|
adedfadd92 | ||
|
|
6b01d0c8fe | ||
|
|
d4d96f59ab | ||
|
|
a1bf7ed6bd | ||
|
|
306e20efc9 | ||
|
|
f593f6e0a8 | ||
|
|
74646a4318 | ||
|
|
8bfcba8832 | ||
|
|
4ba5621a4d | ||
|
|
1f928324c2 | ||
|
|
3771872cd2 | ||
|
|
f359a60343 | ||
|
|
f53afd7bc9 | ||
|
|
e7dcc2ab29 | ||
|
|
0118b9e591 | ||
|
|
ffe42f9777 | ||
|
|
5a467599e9 | ||
|
|
c56e78484a | ||
|
|
1ee0d4a09e | ||
|
|
ffdce5820b | ||
|
|
9fed504f37 | ||
|
|
6c5799be0d | ||
|
|
b6747a0340 | ||
|
|
cd6df02e30 | ||
|
|
edbef6a36f | ||
|
|
b6a0016f5f | ||
|
|
e740c17837 | ||
|
|
7eb949f109 | ||
|
|
02394e310d | ||
|
|
ef83832819 | ||
|
|
a82101ab30 | ||
|
|
007c78930e | ||
|
|
300c83512c | ||
|
|
b674872c56 | ||
|
|
12a7680275 | ||
|
|
c9cf7c942b | ||
|
|
8e0326c8f8 | ||
|
|
13972119a8 | ||
|
|
acf165a119 | ||
|
|
bdff7c6069 | ||
|
|
e2e3376c87 | ||
|
|
3c613088e5 | ||
|
|
7e9ece50a0 | ||
|
|
af81b6536a | ||
|
|
4cd3ecf81f | ||
|
|
31f6b9e08e | ||
|
|
02de920cb3 | ||
|
|
84c0905297 | ||
|
|
250583f859 | ||
|
|
ee7d42196d | ||
|
|
a397de2b9f | ||
|
|
0610df9400 | ||
|
|
ed583deb31 | ||
|
|
e039048fc6 | ||
|
|
f2ea9650c4 | ||
|
|
1e89057006 | ||
|
|
019bb4842f | ||
|
|
4cb45beded | ||
|
|
8a2059f087 | ||
|
|
a6b105a2e1 | ||
|
|
6c14a6a06c | ||
|
|
cddd5d0026 | ||
|
|
78dea91e1d | ||
|
|
3df591ec52 | ||
|
|
1c4032caa6 | ||
|
|
465c422171 | ||
|
|
284e8dc6f5 | ||
|
|
3fc905c82e | ||
|
|
55a42b88ae | ||
|
|
bd26162e4a | ||
|
|
62e7e33406 | ||
|
|
2f0ddcec3f | ||
|
|
7cdfa68e0e | ||
|
|
f8939a964d | ||
|
|
7830e5dda5 | ||
|
|
6aa2f22294 | ||
|
|
50b14e3d44 | ||
|
|
e09c2192c2 | ||
|
|
b725d2cc62 | ||
|
|
abf3f617a4 | ||
|
|
1eda7e66fe | ||
|
|
b5000531c4 | ||
|
|
d4f95e752b | ||
|
|
e31c611f70 | ||
|
|
085481bee6 | ||
|
|
cf610fbe49 | ||
|
|
b681eb3cd2 | ||
|
|
f8ffdf0e81 | ||
|
|
ba38bce1da | ||
|
|
3a39b05fe4 | ||
|
|
27d2982b28 | ||
|
|
33e4d97be5 | ||
|
|
654064d7c5 | ||
|
|
aeb0da9e0d | ||
|
|
cb1a2fe067 | ||
|
|
85667ddfad | ||
|
|
7ad5016966 | ||
|
|
45c3315fd0 | ||
|
|
c5f550dd00 | ||
|
|
37c870c7ab | ||
|
|
155b768f73 | ||
|
|
09f0873f27 | ||
|
|
19a12f6c8f | ||
|
|
79a498d1d6 |
No files matched your search
@@ -1,32 +0,0 @@
|
|||||||
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
|
||||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
|
||||||
|
|
||||||
name: Node.js CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node-version: [10.x, 12.x, 14.x, 15.x]
|
|
||||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
- run: npm ci
|
|
||||||
- run: npm install discord.js --save
|
|
||||||
- run: npm install js-yaml
|
|
||||||
- run: npm run build --if-present
|
|
||||||
- run: node index.js
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
const Discord = require("discord.js");
|
||||||
|
const fs = require("fs");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
const { Command } = require('../Structures/Addon.js'); // Adjust the path as needed
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: "addon",
|
||||||
|
description: "This is a sample addon!",
|
||||||
|
options: [],
|
||||||
|
permissions: ["Administrator"],
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
let disableCommand = true;
|
||||||
|
|
||||||
|
const PingEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(
|
||||||
|
`This is a sample addon.\n\nPong! \`${interaction.client.ws.ping} ms\``
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [PingEmbed],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ApplicationCommandOptionType,
|
||||||
|
ApplicationCommandType,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
ButtonStyle,
|
||||||
|
ChannelType,
|
||||||
|
} = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.AddUser.Command,
|
||||||
|
description: cmdconfig.AddUser.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
description: "The user to add",
|
||||||
|
type: ApplicationCommandOptionType.User,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.AddUser.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const userToAdd = interaction.options.getUser("user");
|
||||||
|
const ticketChannel = interaction.channel;
|
||||||
|
const ticketDataPath = "./Data/TicketData.json";
|
||||||
|
|
||||||
|
if (
|
||||||
|
(supportbot.Ticket.TicketType === "threads" && !ticketChannel.isThread()) ||
|
||||||
|
(supportbot.Ticket.TicketType === "channels" && ticketChannel.type !== ChannelType.GuildText)
|
||||||
|
) {
|
||||||
|
const onlyInTicket = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.NotInTicket_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.NotInTicket_Description)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [onlyInTicket],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const ticketInviteEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Invite_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Invite_Description.replace("%username%", userToAdd.username))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [ticketInviteEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const dmEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.DM_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.DM_Description.replace("%channelname%", ticketChannel.name))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const acceptButton = new ButtonBuilder()
|
||||||
|
.setCustomId("accept_invite")
|
||||||
|
.setLabel(msgconfig.AddUser.Accept_Label)
|
||||||
|
.setEmoji("✅")
|
||||||
|
.setStyle(ButtonStyle.Primary);
|
||||||
|
|
||||||
|
const rejectButton = new ButtonBuilder()
|
||||||
|
.setCustomId("reject_invite")
|
||||||
|
.setLabel(msgconfig.AddUser.Reject_Label)
|
||||||
|
.setEmoji("❌")
|
||||||
|
.setStyle(ButtonStyle.Secondary);
|
||||||
|
|
||||||
|
const row = new ActionRowBuilder().addComponents(acceptButton, rejectButton);
|
||||||
|
|
||||||
|
const dmMessage = await userToAdd.send({
|
||||||
|
embeds: [dmEmbed],
|
||||||
|
components: [row],
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = (i) => i.user.id === userToAdd.id;
|
||||||
|
const collector = dmMessage.createMessageComponentCollector({
|
||||||
|
filter,
|
||||||
|
time: 60000,
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on("collect", async (i) => {
|
||||||
|
if (i.customId === "accept_invite") {
|
||||||
|
try {
|
||||||
|
// Add user to thread or channel based on TicketType
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await ticketChannel.members.add(userToAdd.id); // For threads
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
await ticketChannel.permissionOverwrites.create(userToAdd.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
}); // For channels
|
||||||
|
}
|
||||||
|
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8"));
|
||||||
|
const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
ticketData.tickets[ticketIndex].subUsers.push(userToAdd.id);
|
||||||
|
fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
const acceptedEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Accepted_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Accepted_Message)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await i.update({
|
||||||
|
embeds: [acceptedEmbed],
|
||||||
|
components: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send the added user ticket message in the ticket channel
|
||||||
|
|
||||||
|
const addeduserTicket = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Added_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Added_Description.replace('%username%', userToAdd.username))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await ticketChannel.send({
|
||||||
|
embeds: [addeduserTicket],
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const addedToTicketEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.AddedToTicket_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.AddedToTicket_Description.replace(
|
||||||
|
"%channel_link%",
|
||||||
|
`[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})`
|
||||||
|
))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const ticketLinkButton = new ButtonBuilder()
|
||||||
|
.setLabel(msgconfig.AddUser.ViewTicket_Label)
|
||||||
|
.setURL(`https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id}`)
|
||||||
|
.setStyle(ButtonStyle.Link);
|
||||||
|
|
||||||
|
await userToAdd.send({
|
||||||
|
embeds: [addedToTicketEmbed],
|
||||||
|
components: [new ActionRowBuilder().addComponents(ticketLinkButton)],
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error adding user to the ticket:", err);
|
||||||
|
|
||||||
|
const errorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Error_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Error_Adding)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await i.update({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
components: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const declinedEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Declined_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Declined_Message)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await i.update({
|
||||||
|
embeds: [declinedEmbed],
|
||||||
|
components: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on("end", (collected) => {
|
||||||
|
if (collected.size === 0) {
|
||||||
|
userToAdd.send({
|
||||||
|
embeds: [
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.NoResponse_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.NoResponse_Message)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warning),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === 50007) {
|
||||||
|
const errorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.DM_Error_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.DM_Error_Description.replace("%username%", userToAdd.username))
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await ticketChannel.send({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error("Error sending DM:", error);
|
||||||
|
|
||||||
|
const unexpectedErrorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.AddUser.Unexpected_Error_Title)
|
||||||
|
.setDescription(msgconfig.AddUser.Unexpected_Error_Description.replace("%error%", error.message))
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await ticketChannel.send({
|
||||||
|
embeds: [unexpectedErrorEmbed],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,426 @@
|
|||||||
|
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.CloseTicket.Command,
|
||||||
|
description: cmdconfig.CloseTicket.Description,
|
||||||
|
type: Discord.ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "reason",
|
||||||
|
description: "Ticket Close Reason",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.CloseTicket.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
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! Please 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] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isThread = interaction.channel.type === Discord.ChannelType.PrivateThread;
|
||||||
|
if (
|
||||||
|
(supportbot.Ticket.TicketType === "threads" && !isThread) ||
|
||||||
|
(supportbot.Ticket.TicketType === "channels" && interaction.channel.type !== Discord.ChannelType.GuildText)
|
||||||
|
) {
|
||||||
|
const NotTicketChannel = new Discord.EmbedBuilder()
|
||||||
|
.setTitle("Invalid Channel!")
|
||||||
|
.setDescription(`This command can only be used in a ${supportbot.Ticket.TicketType === "threads" ? "ticket thread" : "ticket channel"}.`)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [NotTicketChannel], ephemeral: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
let tickets;
|
||||||
|
try {
|
||||||
|
tickets = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error reading ticket data file:", err);
|
||||||
|
return interaction.followUp({ content: "There was an error loading ticket data." });
|
||||||
|
}
|
||||||
|
|
||||||
|
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!")
|
||||||
|
.setDescription(msgconfig.Error.NoValidTicket)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
return interaction.followUp({ embeds: [Exists] });
|
||||||
|
}
|
||||||
|
|
||||||
|
let reason = interaction.options?.getString("reason") || "No Reason Provided.";
|
||||||
|
const ticketUserId = ticket.user;
|
||||||
|
|
||||||
|
if (supportbot.Ticket.ReviewSystem.Enabled) {
|
||||||
|
const rating = await collectReviewRating(interaction, ticketUserId);
|
||||||
|
const comment = await collectReviewComment(interaction, ticketUserId);
|
||||||
|
|
||||||
|
const reviewChannel = await getChannel(supportbot.Ticket.ReviewSystem.Channel, interaction.guild);
|
||||||
|
const reviewer = supportbot.Ticket.ClaimTickets ? `<@${ticket.claimedBy}>` : null;
|
||||||
|
|
||||||
|
const reviewEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ReviewSystem.ReviewEmbed.Title)
|
||||||
|
.addFields(
|
||||||
|
{
|
||||||
|
name: msgconfig.ReviewSystem.ReviewEmbed.RatingTitle,
|
||||||
|
value: `${msgconfig.ReviewSystem.ReviewEmbed.ReviewEmoji.repeat(rating)}`,
|
||||||
|
inline: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: msgconfig.ReviewSystem.ReviewEmbed.CommentTitle,
|
||||||
|
value: `\`\`\`${comment}\`\`\``,
|
||||||
|
inline: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.setColor(msgconfig.ReviewSystem.ReviewEmbed.Color);
|
||||||
|
|
||||||
|
if (supportbot.Ticket.ClaimTickets.Enabled) {
|
||||||
|
reviewEmbed.setDescription(
|
||||||
|
`**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedStaffTitle}** ${reviewer}\n**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedByTitle}** <@${ticketUserId}>` || `N/A`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
reviewEmbed.setDescription(
|
||||||
|
`**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedByTitle}** <@${ticketUserId}>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reviewChannel) {
|
||||||
|
await reviewChannel.send({ embeds: [reviewEmbed] });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!interaction.replied && !interaction.deferred) {
|
||||||
|
await interaction.followUp({ embeds: [reviewEmbed] });
|
||||||
|
}
|
||||||
|
|
||||||
|
await handleCloseTicket(interaction, reason, ticket, TicketData);
|
||||||
|
} else {
|
||||||
|
await handleCloseTicket(interaction, reason, ticket, TicketData);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
async function collectReviewRating(interaction, ticketUserId) {
|
||||||
|
const reviewPrompt = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ReviewSystem.Rate.Title)
|
||||||
|
.setDescription(`${msgconfig.ReviewSystem.Rate.Description}`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const stars = new Discord.ActionRowBuilder().addComponents(
|
||||||
|
new Discord.StringSelectMenuBuilder()
|
||||||
|
.setCustomId("starRating")
|
||||||
|
.setPlaceholder("Select a rating")
|
||||||
|
.addOptions([
|
||||||
|
{ label: msgconfig.ReviewSystem.Stars.One, value: "1" },
|
||||||
|
{ label: msgconfig.ReviewSystem.Stars.Two, value: "2" },
|
||||||
|
{ label: msgconfig.ReviewSystem.Stars.Three, value: "3" },
|
||||||
|
{ label: msgconfig.ReviewSystem.Stars.Four, value: "4" },
|
||||||
|
{ label: msgconfig.ReviewSystem.Stars.Five, value: "5" },
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
await interaction.followUp({
|
||||||
|
content: `<@${ticketUserId}>`,
|
||||||
|
embeds: [reviewPrompt],
|
||||||
|
components: [stars],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const starRating = await interaction.channel.awaitMessageComponent({
|
||||||
|
componentType: Discord.ComponentType.StringSelect,
|
||||||
|
filter: (i) => i.customId === "starRating" && i.user.id === ticketUserId,
|
||||||
|
});
|
||||||
|
await starRating.deferUpdate();
|
||||||
|
return starRating.values[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function collectReviewComment(interaction, ticketUserId) {
|
||||||
|
const commentPrompt = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ReviewSystem.Comment.Title)
|
||||||
|
.setDescription(`${msgconfig.ReviewSystem.Comment.Description}`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await interaction.followUp({
|
||||||
|
content: `<@${ticketUserId}>`,
|
||||||
|
embeds: [commentPrompt],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = (response) => response.author.id === ticketUserId;
|
||||||
|
|
||||||
|
const commentCollection = await interaction.channel.awaitMessages({ filter, max: 1 });
|
||||||
|
const comment = commentCollection.first()?.content;
|
||||||
|
return comment && comment.toLowerCase() !== "no" ? comment : "No Comment Provided";
|
||||||
|
}
|
||||||
|
async function handleCloseTicket(interaction, reason, ticket, TicketData) {
|
||||||
|
const { getChannel } = interaction.client;
|
||||||
|
|
||||||
|
let tickets;
|
||||||
|
try {
|
||||||
|
tickets = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error reading ticket data:", err);
|
||||||
|
return interaction.followUp("Failed to load ticket data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let tUser = interaction.client.users.cache.get(ticket.user);
|
||||||
|
let transcriptChannel = await getChannel(supportbot.Ticket.Log.TicketDataLog, interaction.guild);
|
||||||
|
|
||||||
|
if (!transcriptChannel) {
|
||||||
|
console.log("Transcript channel missing or inaccessible");
|
||||||
|
return interaction.followUp("Error: Transcript log channel is missing or bot lacks permission.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Fetch all messages from the channel
|
||||||
|
let allMessages = [];
|
||||||
|
let lastId = null;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const options = { limit: 100 };
|
||||||
|
if (lastId) {
|
||||||
|
options.before = lastId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const messages = await interaction.channel.messages.fetch(options);
|
||||||
|
if (messages.size === 0) break;
|
||||||
|
|
||||||
|
allMessages = [...allMessages, ...messages.values()];
|
||||||
|
lastId = messages.last().id;
|
||||||
|
|
||||||
|
if (messages.size < 100) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort messages by timestamp
|
||||||
|
allMessages.sort((a, b) => a.createdTimestamp - b.createdTimestamp);
|
||||||
|
|
||||||
|
// Create transcript data
|
||||||
|
const transcriptData = allMessages.map(msg => ({
|
||||||
|
content: msg.content || "No content",
|
||||||
|
username: msg.author.username,
|
||||||
|
userId: msg.author.id,
|
||||||
|
avatar: msg.author.displayAvatarURL(),
|
||||||
|
timestamp: msg.createdAt.toISOString(),
|
||||||
|
attachments: Array.from(msg.attachments.values()).map(att => ({
|
||||||
|
url: att.url,
|
||||||
|
name: att.name
|
||||||
|
})),
|
||||||
|
embeds: msg.embeds.map(embed => ({
|
||||||
|
title: embed.title,
|
||||||
|
description: embed.description,
|
||||||
|
fields: embed.fields
|
||||||
|
}))
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Update ticket status
|
||||||
|
tickets.tickets[TicketData].open = false;
|
||||||
|
tickets.tickets[TicketData].messages = transcriptData;
|
||||||
|
fs.writeFileSync("./Data/TicketData.json", JSON.stringify(tickets, null, 4));
|
||||||
|
|
||||||
|
const transcriptEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.TicketLog.Title)
|
||||||
|
.setColor(msgconfig.TicketLog.Colour)
|
||||||
|
.setFooter({ text: supportbot.Embed.Footer, iconURL: interaction.user.displayAvatarURL() })
|
||||||
|
.setDescription(
|
||||||
|
`> **Ticket:** ${interaction.channel.name} (\`${interaction.channel.id}\`)\n` +
|
||||||
|
`> **User:** ${tUser?.tag || "Unknown User"} (\`${tUser?.id || ticket.user}\`)\n` +
|
||||||
|
`> **Closed by:** <@${interaction.user.id}>\n` +
|
||||||
|
`> **Message Count:** ${transcriptData.length}`
|
||||||
|
)
|
||||||
|
.addFields({ name: "Reason", value: `\`\`\`${reason}\`\`\``, inline: true });
|
||||||
|
|
||||||
|
const html = createTranscriptHTML(
|
||||||
|
{
|
||||||
|
id: interaction.channel.id,
|
||||||
|
messages: transcriptData,
|
||||||
|
name: interaction.channel.name
|
||||||
|
},
|
||||||
|
reason
|
||||||
|
);
|
||||||
|
|
||||||
|
const fileName = `${interaction.channel.id}-transcript.html`;
|
||||||
|
fs.writeFileSync(`./Data/Transcripts/${fileName}`, html);
|
||||||
|
|
||||||
|
await transcriptChannel.send({
|
||||||
|
embeds: [transcriptEmbed],
|
||||||
|
files: [{
|
||||||
|
attachment: `./Data/Transcripts/${fileName}`,
|
||||||
|
name: `SPOILER_${fileName}`,
|
||||||
|
spoiler: true
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
if (interaction.channel.type === Discord.ChannelType.GuildText ||
|
||||||
|
interaction.channel.type === Discord.ChannelType.PrivateThread) {
|
||||||
|
await interaction.channel.delete();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error handling ticket close:", err);
|
||||||
|
interaction.followUp("An error occurred while closing the ticket.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseMarkdown(content) {
|
||||||
|
// Convert **bold** text to <strong> tags
|
||||||
|
content = content.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
|
||||||
|
|
||||||
|
// Convert _italic_ text to <em> tags
|
||||||
|
content = content.replace(/_(.*?)_/g, '<em>$1</em>');
|
||||||
|
|
||||||
|
// Convert inline `code` to <code> tags
|
||||||
|
content = content.replace(/`(.*?)`/g, '<code>$1</code>');
|
||||||
|
|
||||||
|
// Convert [text](link) to <a> tags
|
||||||
|
content = content.replace(/\[(.*?)\]\((.*?)\)/g, '<a href="$2" target="_blank">$1</a>');
|
||||||
|
|
||||||
|
// Convert multiline code blocks ```code``` to <pre><code> tags
|
||||||
|
content = content.replace(/```(.*?)```/gs, '<pre><code>$1</code></pre>');
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTranscriptHTML(ticket, reason) {
|
||||||
|
return `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<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: 20px;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.message-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
.username {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #4CAF50;
|
||||||
|
}
|
||||||
|
.timestamp {
|
||||||
|
margin-left: auto;
|
||||||
|
color: #888;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
.embed {
|
||||||
|
border-left: 4px solid #4CAF50;
|
||||||
|
padding-left: 10px;
|
||||||
|
margin: 10px 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
.attachment {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: rgba(76, 175, 80, 0.1);
|
||||||
|
border: 1px solid #4CAF50;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
margin: 5px 0;
|
||||||
|
color: #4CAF50;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="mb-6">
|
||||||
|
<h1 class="text-3xl font-bold mb-4">Ticket Transcript</h1>
|
||||||
|
<p><strong>Channel:</strong> ${ticket.name}</p>
|
||||||
|
<p><strong>Ticket ID:</strong> ${ticket.id}</p>
|
||||||
|
<p><strong>Message Count:</strong> ${ticket.messages.length}</p>
|
||||||
|
<p><strong>Close Reason:</strong> ${reason}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="messages">
|
||||||
|
${ticket.messages.map(msg => `
|
||||||
|
<div class="message">
|
||||||
|
<div class="message-header">
|
||||||
|
<img src="${msg.avatar}" alt="Avatar" class="avatar">
|
||||||
|
<span class="username">${msg.username}</span>
|
||||||
|
<span class="timestamp">${new Date(msg.timestamp).toLocaleString()}</span>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
${parseMarkdown(msg.content)}
|
||||||
|
|
||||||
|
${msg.embeds.map(embed => `
|
||||||
|
<div class="embed">
|
||||||
|
${embed.title ? `<div class="font-bold">${embed.title}</div>` : ''}
|
||||||
|
${embed.description ? `<div>${embed.description}</div>` : ''}
|
||||||
|
${embed.fields.map(field => `
|
||||||
|
<div class="mt-2">
|
||||||
|
<strong>${field.name}:</strong>
|
||||||
|
<div>${field.value}</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
|
||||||
|
${msg.attachments.map(att => `
|
||||||
|
<a href="${att.url}" class="attachment" target="_blank">
|
||||||
|
📎 ${att.name}
|
||||||
|
</a>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
}
|
||||||
@@ -0,0 +1,479 @@
|
|||||||
|
const {
|
||||||
|
ApplicationCommandType,
|
||||||
|
ApplicationCommandOptionType,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
EmbedBuilder,
|
||||||
|
StringSelectMenuBuilder,
|
||||||
|
ModalBuilder,
|
||||||
|
TextInputBuilder,
|
||||||
|
TextInputStyle,
|
||||||
|
ButtonStyle,
|
||||||
|
ComponentType
|
||||||
|
} = require('discord.js');
|
||||||
|
const Command = require('../Structures/Command.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'));
|
||||||
|
|
||||||
|
// Helper function to validate and convert hex color
|
||||||
|
function parseColor(color) {
|
||||||
|
if (!color) return 0x5865F2;
|
||||||
|
if (typeof color === 'number') return color;
|
||||||
|
if (typeof color !== 'string') return 0x5865F2;
|
||||||
|
color = color.replace('#', '');
|
||||||
|
if (/^[0-9A-F]{6}$/i.test(color)) {
|
||||||
|
return parseInt(color, 16);
|
||||||
|
}
|
||||||
|
return 0x5865F2;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Embed.Command,
|
||||||
|
description: cmdconfig.Embed.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'channel',
|
||||||
|
description: 'Select channel to send the message',
|
||||||
|
type: ApplicationCommandOptionType.Channel,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.Embed.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
// Permission check
|
||||||
|
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 (!interaction.member.roles.cache.has(SupportStaff.id) &&
|
||||||
|
!interaction.member.roles.cache.has(Admin.id)) {
|
||||||
|
const NoPerms = new EmbedBuilder()
|
||||||
|
.setTitle('Invalid Permissions!')
|
||||||
|
.setDescription(`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``)
|
||||||
|
.setColor(0xFF0000);
|
||||||
|
return interaction.reply({ embeds: [NoPerms], ephemeral: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const channel = interaction.options.getChannel('channel');
|
||||||
|
|
||||||
|
// Initial message state
|
||||||
|
const messageData = {
|
||||||
|
type: 'embed',
|
||||||
|
title: 'New Embed',
|
||||||
|
description: 'Click the buttons below to edit this embed',
|
||||||
|
color: 0x5865F2,
|
||||||
|
fields: [],
|
||||||
|
footer: null,
|
||||||
|
thumbnail: null,
|
||||||
|
image: null,
|
||||||
|
timestamp: false
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create initial embed
|
||||||
|
function createEmbed() {
|
||||||
|
const embed = new EmbedBuilder()
|
||||||
|
.setTitle(messageData.title)
|
||||||
|
.setDescription(messageData.description)
|
||||||
|
.setColor(messageData.color);
|
||||||
|
|
||||||
|
if (messageData.fields.length > 0) {
|
||||||
|
embed.addFields(messageData.fields);
|
||||||
|
}
|
||||||
|
if (messageData.footer) {
|
||||||
|
embed.setFooter({ text: messageData.footer });
|
||||||
|
}
|
||||||
|
if (messageData.thumbnail) {
|
||||||
|
embed.setThumbnail(messageData.thumbnail);
|
||||||
|
}
|
||||||
|
if (messageData.image) {
|
||||||
|
embed.setImage(messageData.image);
|
||||||
|
}
|
||||||
|
if (messageData.timestamp) {
|
||||||
|
embed.setTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
return embed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create type selector
|
||||||
|
const typeRow = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new StringSelectMenuBuilder()
|
||||||
|
.setCustomId('message_type')
|
||||||
|
.setPlaceholder('Select message type')
|
||||||
|
.addOptions([
|
||||||
|
{
|
||||||
|
label: 'Embed Message',
|
||||||
|
description: 'Send as an embedded message',
|
||||||
|
value: 'embed'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Text Message',
|
||||||
|
description: 'Send as a plain text message',
|
||||||
|
value: 'text'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create button rows function
|
||||||
|
function createButtons(messageType) {
|
||||||
|
const buttons = [];
|
||||||
|
|
||||||
|
if (messageType === 'embed') {
|
||||||
|
// Only show these buttons for embed mode
|
||||||
|
const row1 = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('edit_title')
|
||||||
|
.setLabel('Edit Title')
|
||||||
|
.setStyle(ButtonStyle.Secondary),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('edit_description')
|
||||||
|
.setLabel('Edit Description')
|
||||||
|
.setStyle(ButtonStyle.Secondary),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('edit_color')
|
||||||
|
.setLabel('Edit Color')
|
||||||
|
.setStyle(ButtonStyle.Secondary),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('add_field')
|
||||||
|
.setLabel('Add Field')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
const row2 = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('edit_footer')
|
||||||
|
.setLabel('Edit Footer')
|
||||||
|
.setStyle(ButtonStyle.Secondary),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('edit_image')
|
||||||
|
.setLabel('Add Image')
|
||||||
|
.setStyle(ButtonStyle.Secondary),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('edit_thumbnail')
|
||||||
|
.setLabel('Add Thumbnail')
|
||||||
|
.setStyle(ButtonStyle.Secondary),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('toggle_timestamp')
|
||||||
|
.setLabel('Toggle Timestamp')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
buttons.push(row1, row2);
|
||||||
|
} else {
|
||||||
|
// Text mode only shows edit text button
|
||||||
|
const textRow = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('edit_description')
|
||||||
|
.setLabel('Edit Text')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
buttons.push(textRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send button always shows
|
||||||
|
const sendRow = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('send_message')
|
||||||
|
.setLabel('Send')
|
||||||
|
.setStyle(ButtonStyle.Success)
|
||||||
|
);
|
||||||
|
|
||||||
|
buttons.push(sendRow);
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to update the message preview
|
||||||
|
async function updatePreview(i) {
|
||||||
|
if (messageData.type === 'embed') {
|
||||||
|
await i.update({
|
||||||
|
content: 'Customize your message:',
|
||||||
|
embeds: [createEmbed()],
|
||||||
|
components: [typeRow, ...createButtons('embed')]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// For text mode, just show the text directly
|
||||||
|
await i.update({
|
||||||
|
content: messageData.description,
|
||||||
|
embeds: [],
|
||||||
|
components: [typeRow, ...createButtons('text')]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send initial message
|
||||||
|
const message = await interaction.reply({
|
||||||
|
content: messageData.type === 'text' ? messageData.description : 'Customize your message:',
|
||||||
|
components: [typeRow, ...createButtons(messageData.type)],
|
||||||
|
embeds: messageData.type === 'embed' ? [createEmbed()] : [],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create collector for interactions
|
||||||
|
const collector = message.createMessageComponentCollector({
|
||||||
|
time: 900000
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('collect', async (i) => {
|
||||||
|
if (i.user.id !== interaction.user.id) {
|
||||||
|
return i.reply({
|
||||||
|
content: 'You cannot edit this message.',
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (i.customId) {
|
||||||
|
case 'message_type':
|
||||||
|
messageData.type = i.values[0];
|
||||||
|
await updatePreview(i);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'edit_description':
|
||||||
|
const descModal = new ModalBuilder()
|
||||||
|
.setCustomId('desc_modal')
|
||||||
|
.setTitle(messageData.type === 'embed' ? 'Edit Description' : 'Edit Text');
|
||||||
|
|
||||||
|
descModal.addComponents(
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('desc_input')
|
||||||
|
.setLabel(messageData.type === 'embed' ? 'Description' : 'Message Text')
|
||||||
|
.setStyle(TextInputStyle.Paragraph)
|
||||||
|
.setValue(messageData.description)
|
||||||
|
.setMaxLength(4000)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.showModal(descModal);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'edit_title':
|
||||||
|
const titleModal = new ModalBuilder()
|
||||||
|
.setCustomId('title_modal')
|
||||||
|
.setTitle('Edit Title');
|
||||||
|
|
||||||
|
titleModal.addComponents(
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('title_input')
|
||||||
|
.setLabel('Title')
|
||||||
|
.setStyle(TextInputStyle.Short)
|
||||||
|
.setValue(messageData.title)
|
||||||
|
.setMaxLength(256)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.showModal(titleModal);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'edit_color':
|
||||||
|
const colorModal = new ModalBuilder()
|
||||||
|
.setCustomId('color_modal')
|
||||||
|
.setTitle('Edit Color');
|
||||||
|
|
||||||
|
colorModal.addComponents(
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('color_input')
|
||||||
|
.setLabel('Color (HEX)')
|
||||||
|
.setStyle(TextInputStyle.Short)
|
||||||
|
.setPlaceholder('#FF0000')
|
||||||
|
.setMinLength(6)
|
||||||
|
.setMaxLength(7)
|
||||||
|
.setValue(messageData.color.toString(16).padStart(6, '0'))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.showModal(colorModal);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'add_field':
|
||||||
|
const fieldModal = new ModalBuilder()
|
||||||
|
.setCustomId('field_modal')
|
||||||
|
.setTitle('Add Field');
|
||||||
|
|
||||||
|
fieldModal.addComponents(
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('field_name')
|
||||||
|
.setLabel('Field Name')
|
||||||
|
.setStyle(TextInputStyle.Short)
|
||||||
|
.setMaxLength(256)
|
||||||
|
),
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('field_value')
|
||||||
|
.setLabel('Field Value')
|
||||||
|
.setStyle(TextInputStyle.Paragraph)
|
||||||
|
.setMaxLength(1024)
|
||||||
|
),
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('field_inline')
|
||||||
|
.setLabel('Inline? (true/false)')
|
||||||
|
.setStyle(TextInputStyle.Short)
|
||||||
|
.setValue('false')
|
||||||
|
.setPlaceholder('true or false')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.showModal(fieldModal);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'edit_footer':
|
||||||
|
const footerModal = new ModalBuilder()
|
||||||
|
.setCustomId('footer_modal')
|
||||||
|
.setTitle('Edit Footer');
|
||||||
|
|
||||||
|
footerModal.addComponents(
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('footer_input')
|
||||||
|
.setLabel('Footer Text')
|
||||||
|
.setStyle(TextInputStyle.Short)
|
||||||
|
.setValue(messageData.footer || '')
|
||||||
|
.setMaxLength(2048)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.showModal(footerModal);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'edit_image':
|
||||||
|
const imageModal = new ModalBuilder()
|
||||||
|
.setCustomId('image_modal')
|
||||||
|
.setTitle('Add Image');
|
||||||
|
|
||||||
|
imageModal.addComponents(
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('image_input')
|
||||||
|
.setLabel('Image URL')
|
||||||
|
.setStyle(TextInputStyle.Short)
|
||||||
|
.setValue(messageData.image || '')
|
||||||
|
.setPlaceholder('https://example.com/image.png')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.showModal(imageModal);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'edit_thumbnail':
|
||||||
|
const thumbnailModal = new ModalBuilder()
|
||||||
|
.setCustomId('thumbnail_modal')
|
||||||
|
.setTitle('Add Thumbnail');
|
||||||
|
|
||||||
|
thumbnailModal.addComponents(
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('thumbnail_input')
|
||||||
|
.setLabel('Thumbnail URL')
|
||||||
|
.setStyle(TextInputStyle.Short)
|
||||||
|
.setValue(messageData.thumbnail || '')
|
||||||
|
.setPlaceholder('https://example.com/thumbnail.png')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.showModal(thumbnailModal);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'toggle_timestamp':
|
||||||
|
messageData.timestamp = !messageData.timestamp;
|
||||||
|
await updatePreview(i);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'send_message':
|
||||||
|
try {
|
||||||
|
if (messageData.type === 'embed') {
|
||||||
|
await channel.send({ embeds: [createEmbed()] });
|
||||||
|
} else {
|
||||||
|
await channel.send(messageData.description);
|
||||||
|
}
|
||||||
|
await i.update({
|
||||||
|
content: 'Message sent successfully!',
|
||||||
|
components: [],
|
||||||
|
embeds: []
|
||||||
|
});
|
||||||
|
collector.stop();
|
||||||
|
} catch (error) {
|
||||||
|
await i.reply({
|
||||||
|
content: 'Failed to send message. Please check channel permissions.',
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle modal submissions
|
||||||
|
interaction.client.on('interactionCreate', async (modal) => {
|
||||||
|
if (!modal.isModalSubmit()) return;
|
||||||
|
if (modal.user.id !== interaction.user.id) return;
|
||||||
|
|
||||||
|
switch (modal.customId) {
|
||||||
|
case 'title_modal':
|
||||||
|
messageData.title = modal.fields.getTextInputValue('title_input');
|
||||||
|
break;
|
||||||
|
case 'desc_modal':
|
||||||
|
messageData.description = modal.fields.getTextInputValue('desc_input');
|
||||||
|
break;
|
||||||
|
case 'color_modal':
|
||||||
|
messageData.color = parseColor(modal.fields.getTextInputValue('color_input'));
|
||||||
|
break;
|
||||||
|
case 'field_modal':
|
||||||
|
const inlineValue = modal.fields.getTextInputValue('field_inline').toLowerCase();
|
||||||
|
messageData.fields.push({
|
||||||
|
name: modal.fields.getTextInputValue('field_name'),
|
||||||
|
value: modal.fields.getTextInputValue('field_value'),
|
||||||
|
inline: inlineValue === 'true'
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'footer_modal':
|
||||||
|
messageData.footer = modal.fields.getTextInputValue('footer_input');
|
||||||
|
break;
|
||||||
|
case 'image_modal':
|
||||||
|
messageData.image = modal.fields.getTextInputValue('image_input');
|
||||||
|
break;
|
||||||
|
case 'thumbnail_modal':
|
||||||
|
messageData.thumbnail = modal.fields.getTextInputValue('thumbnail_input');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await updatePreview(modal);
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('end', () => {
|
||||||
|
interaction.editReply({
|
||||||
|
content: 'Message editor timed out.',
|
||||||
|
components: [],
|
||||||
|
embeds: []
|
||||||
|
}).catch(() => {});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ApplicationCommandOptionType,
|
||||||
|
ApplicationCommandType,
|
||||||
|
ChannelType,
|
||||||
|
} = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.ForceAddUser.Command,
|
||||||
|
description: cmdconfig.ForceAddUser.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
description: "The user to forcefully add",
|
||||||
|
type: ApplicationCommandOptionType.User,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.ForceAddUser.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const userToAdd = interaction.options.getUser("user");
|
||||||
|
const ticketChannel = interaction.channel;
|
||||||
|
const ticketDataPath = "./Data/TicketData.json";
|
||||||
|
|
||||||
|
if (
|
||||||
|
(supportbot.Ticket.TicketType === "threads" && !ticketChannel.isThread()) ||
|
||||||
|
(supportbot.Ticket.TicketType === "channels" && ticketChannel.type !== ChannelType.GuildText)
|
||||||
|
) {
|
||||||
|
const onlyInTicket = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ForceAddUser.NotInTicket_Title)
|
||||||
|
.setDescription(msgconfig.ForceAddUser.NotInTicket_Description)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [onlyInTicket],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
try {
|
||||||
|
// Explicitly ensure the bot is in the thread
|
||||||
|
const botMember = await ticketChannel.members.fetch(interaction.client.user.id).catch(() => null);
|
||||||
|
if (!botMember) {
|
||||||
|
await ticketChannel.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay to ensure API has processed the bot's membership
|
||||||
|
await new Promise(res => setTimeout(res, 1000));
|
||||||
|
|
||||||
|
// Attempt to add the user to the thread
|
||||||
|
await ticketChannel.members.add(userToAdd.id);
|
||||||
|
|
||||||
|
console.log("User successfully added to the thread.");
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error adding user to the thread:", err.message);
|
||||||
|
const errorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ForceAddUser.Error_Title)
|
||||||
|
.setDescription(`An error occurred: ${err.message}`)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
await ticketChannel.permissionOverwrites.create(userToAdd.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8"));
|
||||||
|
const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
ticketData.tickets[ticketIndex].subUsers.push(userToAdd.id);
|
||||||
|
fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
const addedEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ForceAddUser.Added_Title)
|
||||||
|
.setDescription(
|
||||||
|
msgconfig.ForceAddUser.Added_Description.replace("%username%", userToAdd.username)
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [addedEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addedToTicketEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ForceAddUser.AddedToTicket_Title)
|
||||||
|
.setDescription(
|
||||||
|
msgconfig.ForceAddUser.AddedToTicket_Description.replace(
|
||||||
|
"%channel_link%",
|
||||||
|
`[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await userToAdd.send({
|
||||||
|
embeds: [addedToTicketEmbed],
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error adding user to the ticket:", err);
|
||||||
|
|
||||||
|
const errorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.ForceAddUser.Error_Title)
|
||||||
|
.setDescription(msgconfig.ForceAddUser.Error_Adding)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
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 Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Help.Command,
|
||||||
|
description: cmdconfig.Help.Description,
|
||||||
|
type: Discord.ApplicationCommandType.ChatInput,
|
||||||
|
options: [],
|
||||||
|
permissions: cmdconfig.Help.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const { getRole } = interaction.client;
|
||||||
|
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
if (!SupportStaff || !Admin) {
|
||||||
|
return interaction.reply(
|
||||||
|
"Some roles seem to be missing!\nPlease check for errors when starting the bot."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate regular commands and addon commands
|
||||||
|
let botCommands = "";
|
||||||
|
let addonCommands = "";
|
||||||
|
|
||||||
|
interaction.client.commands.forEach((command) => {
|
||||||
|
if (command.permissions) {
|
||||||
|
if (command.addon) {
|
||||||
|
addonCommands += `\`${command.name}\` `;
|
||||||
|
} else {
|
||||||
|
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 || "No commands available.",
|
||||||
|
inline: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
HelpEmbed1.setFooter({
|
||||||
|
text: supportbot.Embed.Footer,
|
||||||
|
iconURL: interaction.user.displayAvatarURL(),
|
||||||
|
});
|
||||||
|
|
||||||
|
interaction.reply({
|
||||||
|
ephemeral: true,
|
||||||
|
embeds: [HelpEmbed1],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Info 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.Info.Command,
|
||||||
|
description: cmdconfig.Info.Description,
|
||||||
|
options: [],
|
||||||
|
permissions: cmdconfig.Info.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
let disableCommand = true;
|
||||||
|
|
||||||
|
const InfoButton = new Discord.ButtonBuilder()
|
||||||
|
.setLabel(msgconfig.Info.Button)
|
||||||
|
.setURL(msgconfig.Info.URL)
|
||||||
|
.setStyle("Link");
|
||||||
|
|
||||||
|
const inforow = new Discord.ActionRowBuilder().addComponents(InfoButton);
|
||||||
|
|
||||||
|
const InfoEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setURL(msgconfig.Info.URL)
|
||||||
|
.setTitle(msgconfig.Info.Title)
|
||||||
|
.setDescription(msgconfig.Info.Description)
|
||||||
|
.setColor(msgconfig.Info.Colour)
|
||||||
|
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [InfoEmbed],
|
||||||
|
components: [inforow],
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
});
|
||||||
+261
@@ -0,0 +1,261 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const { ApplicationCommandOptionType, ApplicationCommandType, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType } = 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");
|
||||||
|
|
||||||
|
// Function to chunk array into smaller arrays
|
||||||
|
function chunkArray(arr, size) {
|
||||||
|
const chunks = [];
|
||||||
|
for (let i = 0; i < arr.length; i += size) {
|
||||||
|
chunks.push(arr.slice(i, i + size));
|
||||||
|
}
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Mod.Command,
|
||||||
|
description: cmdconfig.Mod.Command,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: cmdconfig.Mod.TicketBlacklist.Command,
|
||||||
|
description: cmdconfig.Mod.TicketBlacklist.Description,
|
||||||
|
type: ApplicationCommandOptionType.SubcommandGroup,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: cmdconfig.Mod.TicketBlacklist.Add.Command,
|
||||||
|
description: msgconfig.Mod.TicketBlacklist.Add.Description || "Add a user to the ticket blacklist",
|
||||||
|
type: ApplicationCommandOptionType.Subcommand,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'user',
|
||||||
|
description: msgconfig.Mod.TicketBlacklist.Add.UserDescription || "User to blacklist",
|
||||||
|
type: ApplicationCommandOptionType.User,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'reason',
|
||||||
|
description: msgconfig.Mod.TicketBlacklist.Add.ReasonDescription || "Reason for blacklisting",
|
||||||
|
type: ApplicationCommandOptionType.String,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: cmdconfig.Mod.TicketBlacklist.Remove.Command,
|
||||||
|
description: msgconfig.Mod.TicketBlacklist.Remove.Description || "Remove a user from the ticket blacklist",
|
||||||
|
type: ApplicationCommandOptionType.Subcommand,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'user',
|
||||||
|
description: msgconfig.Mod.TicketBlacklist.Remove.UserDescription || "User to remove from blacklist",
|
||||||
|
type: ApplicationCommandOptionType.User,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'reason',
|
||||||
|
description: msgconfig.Mod.TicketBlacklist.Remove.ReasonDescription || "Reason for removing from blacklist",
|
||||||
|
type: ApplicationCommandOptionType.String,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "view",
|
||||||
|
description: msgconfig.Mod.TicketBlacklist.View.Description || "View all blacklisted users",
|
||||||
|
type: ApplicationCommandOptionType.Subcommand,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.Mod.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const { getRole } = interaction.client;
|
||||||
|
|
||||||
|
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
let Moderator = await getRole(supportbot.Roles.StaffMember.Moderator, interaction.guild);
|
||||||
|
|
||||||
|
if (!SupportStaff || !Admin || !Moderator) {
|
||||||
|
const missingRolesEmbed = new EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Error.InvalidChannel || "Required roles are missing!")
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
return interaction.reply({ embeds: [missingRolesEmbed] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoPerms = new EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Error.IncorrectPerms || "You do not have the correct permissions!")
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
if (!interaction.member.roles.cache.has(Admin.id) && !interaction.member.roles.cache.has(Moderator.id) && (!supportbot.Mod.AllowSupportStaff || !interaction.member.roles.cache.has(SupportStaff.id))) {
|
||||||
|
return interaction.reply({ embeds: [NoPerms] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const subcommand = interaction.options.getSubcommand(false);
|
||||||
|
const user = interaction.options.getUser('user');
|
||||||
|
const reason = interaction.options.getString('reason') || "No reason provided";
|
||||||
|
|
||||||
|
try {
|
||||||
|
let blacklistedUsers;
|
||||||
|
try {
|
||||||
|
blacklistedUsers = JSON.parse(fs.readFileSync("./Data/BlacklistedUsers.json", "utf8")).blacklistedUsers;
|
||||||
|
if (!Array.isArray(blacklistedUsers)) {
|
||||||
|
blacklistedUsers = [];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
blacklistedUsers = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subcommand === cmdconfig.Mod.TicketBlacklist.Add.Command) {
|
||||||
|
if (blacklistedUsers.includes(user.id)) {
|
||||||
|
const alreadyBlacklistedEmbed = new EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Mod.TicketBlacklist.Add.AlreadyBlacklisted.replace("{userTag}", user.tag) || ":x: User is already blacklisted.")
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
return interaction.reply({ embeds: [alreadyBlacklistedEmbed], ephemeral: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
blacklistedUsers.push(user.id);
|
||||||
|
fs.writeFileSync("./Data/BlacklistedUsers.json", JSON.stringify({ "blacklistedUsers": blacklistedUsers }, null, 4));
|
||||||
|
|
||||||
|
const successEmbed = new EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Mod.TicketBlacklist.Add.Success.replace("{userTag}", user.tag) || ":white_check_mark: User has been blacklisted.")
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
const blacklistChannel = interaction.guild.channels.cache.get(supportbot.Ticket.Log.TicketBlacklistLog);
|
||||||
|
if (blacklistChannel) {
|
||||||
|
const blacklistLogEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.TicketBlacklistLog.Title || "Ticket Blacklist Log")
|
||||||
|
.setColor(msgconfig.TicketBlacklistLog.Colour || supportbot.Embed.Colours.Success)
|
||||||
|
.setFooter({ text: supportbot.Embed.Footer, iconURL: interaction.user.displayAvatarURL() })
|
||||||
|
.setDescription(`> **User:** ${user.tag} (\`${user.id}\`)\n> **Actioned by:** <@${interaction.user.id}>`)
|
||||||
|
.addFields({ name: "Action", value: "\`\`\`Removed from blacklist\`\`\`", inline: false })
|
||||||
|
.addFields({ name: "Reason", value: `\`\`\`${reason}\`\`\``, inline: false });
|
||||||
|
|
||||||
|
blacklistChannel.send({ embeds: [blacklistLogEmbed] });
|
||||||
|
}
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [successEmbed],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (subcommand === cmdconfig.Mod.TicketBlacklist.Remove.Command) {
|
||||||
|
if (!blacklistedUsers.includes(user.id)) {
|
||||||
|
const notBlacklistedEmbed = new EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Mod.TicketBlacklist.Remove.NotBlacklisted.replace("{userTag}", user.tag) || ":x: User is not blacklisted.")
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
return interaction.reply({ embeds: [notBlacklistedEmbed], ephemeral: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
blacklistedUsers = blacklistedUsers.filter(id => id !== user.id);
|
||||||
|
fs.writeFileSync("./Data/BlacklistedUsers.json", JSON.stringify({ "blacklistedUsers": blacklistedUsers }, null, 4));
|
||||||
|
|
||||||
|
const removedEmbed = new EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Mod.TicketBlacklist.Remove.Success.replace("{userTag}", user.tag) || ":white_check_mark: User has been removed from the blacklist.")
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
const blacklistChannel = interaction.guild.channels.cache.get(supportbot.Ticket.Log.TicketBlacklistLog);
|
||||||
|
if (blacklistChannel) {
|
||||||
|
const blacklistLogEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.TicketBlacklistLog.Title || "Ticket Blacklist Log")
|
||||||
|
.setColor(msgconfig.TicketBlacklistLog.Colour || supportbot.Embed.Colours.Success)
|
||||||
|
.setFooter({ text: supportbot.Embed.Footer, iconURL: interaction.user.displayAvatarURL() })
|
||||||
|
.setDescription(`> **User:** ${user.tag} (\`${user.id}\`)\n> **Actioned by:** <@${interaction.user.id}>`)
|
||||||
|
.addFields({ name: "Action", value: "\`\`\`Removed from blacklist\`\`\`", inline: false })
|
||||||
|
.addFields({ name: "Reason", value: `\`\`\`${reason}\`\`\``, inline: false });
|
||||||
|
|
||||||
|
blacklistChannel.send({ embeds: [blacklistLogEmbed] });
|
||||||
|
}
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [removedEmbed], ephemeral: true });
|
||||||
|
|
||||||
|
} else if (subcommand === "view") {
|
||||||
|
if (blacklistedUsers.length === 0) {
|
||||||
|
const noBlacklistedUsersEmbed = new EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Mod.TicketBlacklist.View.NoBlacklistedUsers || "No users are blacklisted.")
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
return interaction.reply({ embeds: [noBlacklistedUsersEmbed], ephemeral: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const chunkedUsers = chunkArray(blacklistedUsers, 5);
|
||||||
|
let currentPage = 0;
|
||||||
|
|
||||||
|
const createEmbed = (page) => {
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.Mod.TicketBlacklist.View.EmbedTitle || "Blacklisted Users")
|
||||||
|
.setDescription(chunkedUsers[page].map(id => `<@${id}>`).join("\n"))
|
||||||
|
.setColor(supportbot.Embed.Colours.Success)
|
||||||
|
.setFooter({ text: `Page ${page + 1} of ${chunkedUsers.length}` });
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttons = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('previous')
|
||||||
|
.setLabel('Previous')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
.setDisabled(currentPage === 0),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('next')
|
||||||
|
.setLabel('Next')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
.setDisabled(currentPage === chunkedUsers.length - 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
const response = await interaction.reply({
|
||||||
|
embeds: [createEmbed(currentPage)],
|
||||||
|
components: chunkedUsers.length > 1 ? [buttons] : [],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (chunkedUsers.length <= 1) return;
|
||||||
|
|
||||||
|
const collector = response.createMessageComponentCollector({
|
||||||
|
componentType: ComponentType.Button,
|
||||||
|
time: 60000
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('collect', async (i) => {
|
||||||
|
if (i.user.id !== interaction.user.id) {
|
||||||
|
return i.reply({
|
||||||
|
content: 'You cannot use these buttons.',
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === 'previous' && currentPage > 0) {
|
||||||
|
currentPage--;
|
||||||
|
} else if (i.customId === 'next' && currentPage < chunkedUsers.length - 1) {
|
||||||
|
currentPage++;
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons.components[0].setDisabled(currentPage === 0);
|
||||||
|
buttons.components[1].setDisabled(currentPage === chunkedUsers.length - 1);
|
||||||
|
|
||||||
|
await i.update({
|
||||||
|
embeds: [createEmbed(currentPage)],
|
||||||
|
components: [buttons]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('end', () => {
|
||||||
|
buttons.components.forEach(button => button.setDisabled(true));
|
||||||
|
interaction.editReply({
|
||||||
|
components: [buttons]
|
||||||
|
}).catch(() => {});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in mod command:", error);
|
||||||
|
const errorEmbed = new EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Error.ActionFailed || "An error occurred while processing your request.")
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
interaction.reply({ embeds: [errorEmbed], ephemeral: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Ping 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 Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Ping.Command,
|
||||||
|
description: cmdconfig.Ping.Description,
|
||||||
|
options: [],
|
||||||
|
permissions: cmdconfig.Ping.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
let disableCommand = true;
|
||||||
|
|
||||||
|
const PingEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(
|
||||||
|
`:ping_pong: **Ping:** \`${interaction.client.ws.ping} ms\``
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [PingEmbed],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,320 @@
|
|||||||
|
const { EmbedBuilder, ModalBuilder, TextInputBuilder, TextInputStyle, ApplicationCommandType, ActionRowBuilder, ButtonBuilder, ButtonStyle, ApplicationCommandOptionType } = 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");
|
||||||
|
|
||||||
|
const clockedInUsers = new Set();
|
||||||
|
|
||||||
|
function updateClockedInStatus(profileEmbed, clockedIn) {
|
||||||
|
profileEmbed.data.fields = profileEmbed.data.fields.map(field => {
|
||||||
|
if (field.name === 'Clocked In Status') {
|
||||||
|
field.value = clockedIn ? '✅ Clocked In' : '❌ Clocked Out';
|
||||||
|
}
|
||||||
|
return field;
|
||||||
|
});
|
||||||
|
return profileEmbed;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Profile.Command,
|
||||||
|
description: cmdconfig.Profile.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
permissions: cmdconfig.Profile.Permission,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'user',
|
||||||
|
description: 'The user to view the profile of',
|
||||||
|
type: ApplicationCommandOptionType.User,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
|
||||||
|
const userOption = interaction.options.getUser('user');
|
||||||
|
const viewingUser = userOption || interaction.user;
|
||||||
|
const viewingUserId = viewingUser.id;
|
||||||
|
const interactionUserId = interaction.user.id;
|
||||||
|
|
||||||
|
const user = interaction.guild.members.cache.get(viewingUserId);
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (!Staff || !Admin) {
|
||||||
|
return interaction.editReply({
|
||||||
|
content: "Some roles seem to be missing!\nPlease check for errors when starting the bot.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const isStaff = user.roles.cache.has(Staff.id) || user.roles.cache.has(Admin.id);
|
||||||
|
const isOwnProfile = interactionUserId === viewingUserId;
|
||||||
|
|
||||||
|
const profilePath = `./Data/Profiles/${viewingUserId}.json`;
|
||||||
|
let profileData;
|
||||||
|
|
||||||
|
if (fs.existsSync(profilePath)) {
|
||||||
|
profileData = JSON.parse(fs.readFileSync(profilePath, "utf8"));
|
||||||
|
} else {
|
||||||
|
profileData = {
|
||||||
|
bio: "",
|
||||||
|
timezone: "",
|
||||||
|
clockedIn: false
|
||||||
|
};
|
||||||
|
fs.writeFileSync(profilePath, JSON.stringify(profileData, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { bio, timezone, clockedIn } = profileData;
|
||||||
|
|
||||||
|
let profileEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(`${viewingUser.username}'s Profile`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General)
|
||||||
|
.setThumbnail(viewingUser.displayAvatarURL())
|
||||||
|
.addFields(
|
||||||
|
{ name: 'Bio', value: bio || 'No bio set.', inline: false },
|
||||||
|
{ name: 'Timezone', value: timezone || 'No timezone set.', inline: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isStaff) {
|
||||||
|
profileEmbed.addFields({ name: 'Clocked In Status', value: clockedIn ? '✅ Clocked In' : '❌ Clocked Out', inline: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttonRow = new ActionRowBuilder();
|
||||||
|
if (isOwnProfile) {
|
||||||
|
buttonRow.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('editProfile')
|
||||||
|
.setLabel('Edit Profile')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isStaff) {
|
||||||
|
buttonRow.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('clockInOut')
|
||||||
|
.setLabel(clockedIn ? 'Clock Out' : 'Clock In')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStaff && supportbot.Ticket.ClaimTickets.Enabled) {
|
||||||
|
buttonRow.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('viewTicketStats')
|
||||||
|
.setLabel('View Ticket Stats')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.editReply({ embeds: [profileEmbed], components: buttonRow.components.length > 0 ? [buttonRow] : [] });
|
||||||
|
|
||||||
|
const filter = i => (
|
||||||
|
['editProfile', 'clockInOut', 'viewTicketStats', 'showOpenTickets', 'backToStats', 'backToProfile'].includes(i.customId)
|
||||||
|
&& i.user.id === interactionUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
const collector = interaction.channel.createMessageComponentCollector({ filter, time: 60000 });
|
||||||
|
|
||||||
|
collector.on('collect', async i => {
|
||||||
|
if (i.customId === 'editProfile') {
|
||||||
|
const modal = new ModalBuilder()
|
||||||
|
.setCustomId('editProfileModal')
|
||||||
|
.setTitle('Edit Profile')
|
||||||
|
.addComponents(
|
||||||
|
new ActionRowBuilder().addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('bio')
|
||||||
|
.setLabel('Bio')
|
||||||
|
.setStyle(TextInputStyle.Paragraph)
|
||||||
|
.setPlaceholder('Enter your bio')
|
||||||
|
.setValue(String(bio))
|
||||||
|
.setRequired(false)
|
||||||
|
),
|
||||||
|
new ActionRowBuilder().addComponents(
|
||||||
|
new TextInputBuilder()
|
||||||
|
.setCustomId('timezone')
|
||||||
|
.setLabel('Timezone')
|
||||||
|
.setStyle(TextInputStyle.Short)
|
||||||
|
.setPlaceholder('Enter your timezone')
|
||||||
|
.setValue(String(timezone))
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.showModal(modal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === 'clockInOut') {
|
||||||
|
profileData.clockedIn = !profileData.clockedIn;
|
||||||
|
fs.writeFileSync(profilePath, JSON.stringify(profileData, null, 2));
|
||||||
|
profileEmbed = updateClockedInStatus(profileEmbed, profileData.clockedIn);
|
||||||
|
|
||||||
|
if (profileData.clockedIn) {
|
||||||
|
clockedInUsers.add(viewingUserId);
|
||||||
|
} else {
|
||||||
|
clockedInUsers.delete(viewingUserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedButtonRow = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('editProfile')
|
||||||
|
.setLabel('Edit Profile')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isStaff) {
|
||||||
|
updatedButtonRow.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('clockInOut')
|
||||||
|
.setLabel(profileData.clockedIn ? 'Clock Out' : 'Clock In')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (supportbot.Ticket.ClaimTickets.Enabled) {
|
||||||
|
updatedButtonRow.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('viewTicketStats')
|
||||||
|
.setLabel('View Ticket Stats')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await i.update({ embeds: [profileEmbed], components: [updatedButtonRow] });
|
||||||
|
|
||||||
|
let clockedinout = new EmbedBuilder()
|
||||||
|
.setTitle(profileData.clockedIn ? 'Clocked In!' : 'Clocked Out!')
|
||||||
|
.setDescription(profileData.clockedIn ? 'You have successfully clocked in.' : 'You have successfully clocked out.')
|
||||||
|
.setColor(supportbot.Embed.Colours.General)
|
||||||
|
|
||||||
|
await interaction.followUp({ embeds: [clockedinout], ephemeral: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === 'viewTicketStats') {
|
||||||
|
const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketsClaimed = TicketData.tickets.filter(t => t.claimedBy === viewingUserId);
|
||||||
|
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);
|
||||||
|
|
||||||
|
const statsEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.TicketStats.Title)
|
||||||
|
.setDescription(`> Ticket stats for <@${viewingUserId}>`)
|
||||||
|
.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 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const statsButtonRow = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('showOpenTickets')
|
||||||
|
.setLabel('Show Open Tickets')
|
||||||
|
.setStyle(ButtonStyle.Secondary),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('backToProfile')
|
||||||
|
.setLabel('Back to Profile')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.update({ embeds: [statsEmbed], components: [statsButtonRow] });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === 'showOpenTickets') {
|
||||||
|
const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketsOpen = TicketData.tickets.filter(t => t.claimedBy === viewingUserId && t.open);
|
||||||
|
|
||||||
|
const openTicketsEmbed = new EmbedBuilder()
|
||||||
|
.setTitle('Active Tickets')
|
||||||
|
.setDescription(ticketsOpen.map(t => `<#${t.id}>`).join('\n') || 'No active tickets.')
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const openTicketsButtonRow = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('backToStats')
|
||||||
|
.setLabel('Back to Stats')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.update({ embeds: [openTicketsEmbed], components: [openTicketsButtonRow] });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === 'backToStats') {
|
||||||
|
const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketsClaimed = TicketData.tickets.filter(t => t.claimedBy === viewingUserId);
|
||||||
|
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);
|
||||||
|
|
||||||
|
const statsEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.TicketStats.Title)
|
||||||
|
.setDescription(`> Ticket stats for <@${viewingUserId}>`)
|
||||||
|
.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 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const statsButtonRow = new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('showOpenTickets')
|
||||||
|
.setLabel('Show Open Tickets')
|
||||||
|
.setStyle(ButtonStyle.Secondary),
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('backToProfile')
|
||||||
|
.setLabel('Back to Profile')
|
||||||
|
.setStyle(ButtonStyle.Secondary)
|
||||||
|
);
|
||||||
|
|
||||||
|
await i.update({ embeds: [statsEmbed], components: [statsButtonRow] });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.customId === 'backToProfile') {
|
||||||
|
await i.update({ embeds: [profileEmbed], components: buttonRow.components.length > 0 ? [buttonRow] : [] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports.clockedInUsers = clockedInUsers;
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ApplicationCommandOptionType,
|
||||||
|
ApplicationCommandType,
|
||||||
|
ChannelType,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
ButtonStyle,
|
||||||
|
} = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.RemoveUser.Command,
|
||||||
|
description: cmdconfig.RemoveUser.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
description: "The user to remove",
|
||||||
|
type: ApplicationCommandOptionType.User,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.RemoveUser.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
|
||||||
|
const { getRole } = interaction.client;
|
||||||
|
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
if (!SupportStaff || !Admin) {
|
||||||
|
return interaction.reply(
|
||||||
|
"Some roles seem to be missing!\nPlease check for errors when starting the bot."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoPerms = new EmbedBuilder()
|
||||||
|
.setTitle("Invalid Permissions!")
|
||||||
|
.setDescription(
|
||||||
|
`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!interaction.member.roles.cache.has(SupportStaff.id) &&
|
||||||
|
!interaction.member.roles.cache.has(Admin.id)
|
||||||
|
) {
|
||||||
|
return interaction.reply({ embeds: [NoPerms] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const userToRemove = interaction.options.getUser("user");
|
||||||
|
const ticketChannel = interaction.channel;
|
||||||
|
const ticketDataPath = "./Data/TicketData.json";
|
||||||
|
|
||||||
|
// Check if the channel is a ticket thread or text channel based on TicketType
|
||||||
|
if (
|
||||||
|
(supportbot.Ticket.TicketType === "threads" && !ticketChannel.isThread()) ||
|
||||||
|
(supportbot.Ticket.TicketType === "channels" && ticketChannel.type !== ChannelType.GuildText)
|
||||||
|
) {
|
||||||
|
const onlyInTicket = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.RemoveUser.NotInTicket_Title)
|
||||||
|
.setDescription(msgconfig.RemoveUser.NotInTicket_Description)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [onlyInTicket],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Remove user from thread or channel based on TicketType
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await ticketChannel.members.remove(userToRemove.id); // For threads
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
await ticketChannel.permissionOverwrites.delete(userToRemove.id); // For channels
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the ticket data
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8"));
|
||||||
|
const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
const subUsers = ticketData.tickets[ticketIndex].subUsers;
|
||||||
|
const userIndex = subUsers.indexOf(userToRemove.id);
|
||||||
|
if (userIndex !== -1) {
|
||||||
|
subUsers.splice(userIndex, 1);
|
||||||
|
fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const removedEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.RemoveUser.Removed_Title)
|
||||||
|
.setDescription(msgconfig.RemoveUser.Removed_Message)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [removedEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const removedFromTicketEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.RemoveUser.RemovedFromTicket_Title)
|
||||||
|
.setDescription(msgconfig.RemoveUser.RemovedFromTicket_Description.replace(
|
||||||
|
"%channel_link%",
|
||||||
|
`[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})`
|
||||||
|
))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await userToRemove.send({
|
||||||
|
embeds: [removedFromTicketEmbed],
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error removing user from the ticket:", err);
|
||||||
|
|
||||||
|
const errorEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.RemoveUser.Error_Title)
|
||||||
|
.setDescription(msgconfig.RemoveUser.Error_Removing)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
const { Command } = require('../Structures/Addon.js');
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const fs = require("fs");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
const settingsFilePath = path.resolve(__dirname, '../Data/settings.json');
|
||||||
|
|
||||||
|
function loadSettings() {
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(settingsFilePath)) {
|
||||||
|
const data = fs.readFileSync(settingsFilePath, 'utf8');
|
||||||
|
return JSON.parse(data);
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error reading settings file:", error);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveSettings(settings) {
|
||||||
|
try {
|
||||||
|
fs.writeFileSync(settingsFilePath, JSON.stringify(settings, null, 2), 'utf8');
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error writing settings file:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Settings.Command,
|
||||||
|
description: cmdconfig.Settings.Description,
|
||||||
|
permissions: cmdconfig.Settings.Permission,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'setstatus',
|
||||||
|
type: Discord.ApplicationCommandOptionType.Subcommand,
|
||||||
|
description: 'Set the bot status',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'status',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'Choose the bot status',
|
||||||
|
required: true,
|
||||||
|
choices: [
|
||||||
|
{ name: 'Online 🟢', value: 'online' },
|
||||||
|
{ name: 'Idle 🌙', value: 'idle' },
|
||||||
|
{ name: 'Do Not Disturb ⛔', value: 'dnd' },
|
||||||
|
{ name: 'Invisible 👻', value: 'invisible' }
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'setactivity',
|
||||||
|
type: Discord.ApplicationCommandOptionType.Subcommand,
|
||||||
|
description: 'Set the bot activity',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'Choose the activity type',
|
||||||
|
required: true,
|
||||||
|
choices: [
|
||||||
|
{ name: 'Playing 🎮', value: 'PLAYING' },
|
||||||
|
{ name: 'Watching 👀', value: 'WATCHING' },
|
||||||
|
{ name: 'Listening 🎧', value: 'LISTENING' },
|
||||||
|
{ name: 'Competing 🏆', value: 'COMPETING' }
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'message',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'The activity message',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'streammode',
|
||||||
|
type: Discord.ApplicationCommandOptionType.Subcommand,
|
||||||
|
description: 'Set the bot streaming status',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'toggle',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'Turn streaming mode on or off',
|
||||||
|
required: true,
|
||||||
|
choices: [
|
||||||
|
{ name: 'On', value: 'on' },
|
||||||
|
{ name: 'Off', value: 'off' }
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'twitchurl',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'Twitch stream URL (Required if turning on)',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'setnickname',
|
||||||
|
type: Discord.ApplicationCommandOptionType.Subcommand,
|
||||||
|
description: 'Set the bot nickname',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'nickname',
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
description: 'The new nickname for the bot',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const subcommand = interaction.options.getSubcommand();
|
||||||
|
const settings = loadSettings();
|
||||||
|
|
||||||
|
if (subcommand === 'setstatus') {
|
||||||
|
const status = interaction.options.getString('status');
|
||||||
|
|
||||||
|
try {
|
||||||
|
interaction.client.user.setPresence({
|
||||||
|
status: status,
|
||||||
|
activities: interaction.client.user.presence.activities || [],
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.status = status;
|
||||||
|
saveSettings(settings);
|
||||||
|
|
||||||
|
const embed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`Status set to **${status.charAt(0).toUpperCase() + status.slice(1)}**`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
return interaction.reply({ content: `Failed to set status: ${error.message}`, ephemeral: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subcommand === 'setactivity') {
|
||||||
|
const activityType = interaction.options.getString('type');
|
||||||
|
const activityMessage = interaction.options.getString('message');
|
||||||
|
|
||||||
|
try {
|
||||||
|
interaction.client.user.setPresence({
|
||||||
|
activities: [{ name: activityMessage, type: Discord.ActivityType[activityType] }],
|
||||||
|
status: interaction.client.user.presence.status || 'online',
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.activity = { type: activityType, message: activityMessage };
|
||||||
|
saveSettings(settings);
|
||||||
|
|
||||||
|
const embed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`Activity set to **${activityType.toLowerCase()} ${activityMessage}**`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
return interaction.reply({ content: `Failed to set activity: ${error.message}`, ephemeral: true });
|
||||||
|
}
|
||||||
|
} else if (subcommand === 'streammode') {
|
||||||
|
const toggle = interaction.options.getString('toggle');
|
||||||
|
const twitchUrl = interaction.options.getString('twitchurl');
|
||||||
|
|
||||||
|
if (toggle === 'on') {
|
||||||
|
if (!twitchUrl) {
|
||||||
|
return interaction.reply({ content: 'Please provide a Twitch URL to stream.', ephemeral: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
interaction.client.user.setPresence({
|
||||||
|
activities: [{ name: 'Streaming', type: Discord.ActivityType.Streaming, url: twitchUrl }],
|
||||||
|
status: 'online',
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.streaming = { active: true, url: twitchUrl };
|
||||||
|
saveSettings(settings);
|
||||||
|
|
||||||
|
const embed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`**Streaming mode enabled!**\nStreaming: [Twitch](${twitchUrl})`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
return interaction.reply({ content: `Failed to enable streaming mode: ${error.message}`, ephemeral: true });
|
||||||
|
}
|
||||||
|
} else if (toggle === 'off') {
|
||||||
|
try {
|
||||||
|
interaction.client.user.setPresence({
|
||||||
|
activities: interaction.client.user.presence.activities.filter(a => a.type !== Discord.ActivityType.Streaming),
|
||||||
|
status: settings.status || 'online',
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.streaming = { active: false };
|
||||||
|
saveSettings(settings);
|
||||||
|
|
||||||
|
const embed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`**Streaming mode disabled!**`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
return interaction.reply({ content: `Failed to disable streaming mode: ${error.message}`, ephemeral: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (subcommand === 'setnickname') {
|
||||||
|
const nickname = interaction.options.getString('nickname');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const guild = interaction.guild;
|
||||||
|
const botMember = guild.members.cache.get(interaction.client.user.id);
|
||||||
|
await botMember.setNickname(nickname);
|
||||||
|
|
||||||
|
settings.nickname = nickname;
|
||||||
|
saveSettings(settings);
|
||||||
|
|
||||||
|
const embed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`Bot nickname set to **${nickname}**`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
return interaction.reply({ content: `Failed to set nickname: ${error.message}`, ephemeral: true });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return interaction.reply({ content: 'Invalid command usage.', ephemeral: true });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
description: cmdconfig.Suggestion.Description,
|
||||||
|
type: Discord.ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "suggestion",
|
||||||
|
description: "Create a Suggestion",
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.Suggestion.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
const { getChannel } = interaction.client;
|
||||||
|
|
||||||
|
const suggestChannel = await getChannel(
|
||||||
|
supportbot.Suggestions.Channel,
|
||||||
|
interaction.guild
|
||||||
|
);
|
||||||
|
|
||||||
|
const NoChannel = new Discord.EmbedBuilder()
|
||||||
|
.setTitle("Missing Channel!")
|
||||||
|
.setDescription(msgconfig.Error.InvalidChannel)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
if (!suggestChannel) return interaction.reply({ embeds: [NoChannel] });
|
||||||
|
|
||||||
|
let suggestion = interaction.options.getString("suggestion");
|
||||||
|
|
||||||
|
const SuggestEmbed = new Discord.EmbedBuilder()
|
||||||
|
.addFields(
|
||||||
|
{ 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,
|
||||||
|
iconURL: interaction.user.displayAvatarURL(),
|
||||||
|
})
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const UpvoteButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("upvote")
|
||||||
|
.setEmoji(supportbot.Suggestions.UpvoteEmoji)
|
||||||
|
.setStyle(supportbot.Suggestions.Buttons.Upvote);
|
||||||
|
|
||||||
|
const DownvoteButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("downvote")
|
||||||
|
.setEmoji(supportbot.Suggestions.DownvoteEmoji)
|
||||||
|
.setStyle(supportbot.Suggestions.Buttons.Downvote);
|
||||||
|
|
||||||
|
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(`${msgconfig.Suggestions.Sent_Title}`)
|
||||||
|
.setDescription(`${msgconfig.Suggestions.Sent}`)
|
||||||
|
.addFields(
|
||||||
|
{ name: "Sent to:", value: `<#${suggestChannel.id}>` },
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
ephemeral: true,
|
||||||
|
embeds: [Submitted]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,550 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ApplicationCommandOptionType,
|
||||||
|
ApplicationCommandType,
|
||||||
|
ChannelType,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
StringSelectMenuBuilder,
|
||||||
|
StringSelectMenuOptionBuilder,
|
||||||
|
ButtonStyle,
|
||||||
|
MessageCollector,
|
||||||
|
} = 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 msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
|
||||||
|
const Command = require("../Structures/Command.js");
|
||||||
|
const TicketNumberID = require("../Structures/TicketID.js");
|
||||||
|
|
||||||
|
async function isBlacklisted(userId) {
|
||||||
|
let blacklistData;
|
||||||
|
try {
|
||||||
|
blacklistData = JSON.parse(fs.readFileSync("./Data/BlacklistedUsers.json", "utf8"));
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error reading BlacklistedUsers.json:", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blacklistData || !Array.isArray(blacklistData.blacklistedUsers)) {
|
||||||
|
console.error("blacklistedUsers is not defined or is not an array");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return blacklistData.blacklistedUsers.includes(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getClockedInUsers(guild) {
|
||||||
|
const clockedInUsers = new Set();
|
||||||
|
|
||||||
|
const profilesDir = './Data/Profiles';
|
||||||
|
const profileFiles = fs.readdirSync(profilesDir);
|
||||||
|
|
||||||
|
for (const file of profileFiles) {
|
||||||
|
const profileData = JSON.parse(fs.readFileSync(`${profilesDir}/${file}`, "utf8"));
|
||||||
|
if (profileData.clockedIn) {
|
||||||
|
const userId = file.replace('.json', '');
|
||||||
|
const member = await guild.members.fetch(userId);
|
||||||
|
if (member) clockedInUsers.add(member.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clockedInUsers;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function askTicketQuestions(ticketChannel, interaction, questions) {
|
||||||
|
const answers = [];
|
||||||
|
let questionIndex = 0;
|
||||||
|
|
||||||
|
const sendNextQuestion = async () => {
|
||||||
|
if (questionIndex < questions.length) {
|
||||||
|
|
||||||
|
const questionsEmbed = new EmbedBuilder()
|
||||||
|
.setDescription(`**${questionIndex + 1}.** ${questions[questionIndex]}`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General)
|
||||||
|
|
||||||
|
const questionMessage = await ticketChannel.send({
|
||||||
|
embeds: [questionsEmbed],
|
||||||
|
});
|
||||||
|
|
||||||
|
const collector = new MessageCollector(ticketChannel, {
|
||||||
|
filter: (m) => m.author.id === interaction.user.id,
|
||||||
|
max: 1,
|
||||||
|
time: 60000,
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on("collect", async (message) => {
|
||||||
|
answers.push({ question: questions[questionIndex], answer: message.content });
|
||||||
|
questionIndex++;
|
||||||
|
await message.delete();
|
||||||
|
await questionMessage.delete();
|
||||||
|
sendNextQuestion();
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const summaryEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.Ticket.TicketQuestions.Details.Title)
|
||||||
|
.setDescription(msgconfig.Ticket.TicketQuestions.Details.Description.replace('%user%', interaction.user.id))
|
||||||
|
.setColor(supportbot.Embed.Colours.General)
|
||||||
|
.addFields(
|
||||||
|
answers.map((a) => ({
|
||||||
|
name: `Q: ${a.question}`,
|
||||||
|
value: `A: ${a.answer}`,
|
||||||
|
inline: false,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
await ticketChannel.send({
|
||||||
|
embeds: [summaryEmbed]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start asking the first question
|
||||||
|
sendNextQuestion();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function assignTicketToUser(ticketChannel, Staff, Admin, interaction, attempts = 0) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const clockedInUsers = await getClockedInUsers(interaction.guild);
|
||||||
|
|
||||||
|
if (clockedInUsers.size === 0 || attempts >= 2) {
|
||||||
|
const claimChannel = await interaction.guild.channels.cache.get(supportbot.Ticket.ClaimTickets.Channel);
|
||||||
|
if (claimChannel) {
|
||||||
|
const claimEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimTitle)
|
||||||
|
.setDescription(msgconfig.Ticket.ClaimTickets.ClaimMessage)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const claimButton = new ButtonBuilder()
|
||||||
|
.setCustomId(`claimticket-${ticketChannel.id}`)
|
||||||
|
.setLabel(supportbot.Ticket.ClaimTickets.ButtonTitle || 'Claim Ticket')
|
||||||
|
.setStyle(ButtonStyle.Primary);
|
||||||
|
|
||||||
|
const row = new ActionRowBuilder().addComponents(claimButton);
|
||||||
|
|
||||||
|
const claimMessage = await claimChannel.send({
|
||||||
|
content: `<@&${Staff.id}> <@&${Admin.id}>`,
|
||||||
|
embeds: [claimEmbed],
|
||||||
|
components: [row],
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = i => i.customId === `claimticket-${ticketChannel.id}` && i.member.roles.cache.has(Staff.id);
|
||||||
|
const collector = claimMessage.createMessageComponentCollector({ filter, time: 120000 });
|
||||||
|
|
||||||
|
collector.on('collect', async i => {
|
||||||
|
await ticketChannel.send({ content: `<@${i.user.id}> has claimed the ticket.` });
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('end', async collected => {
|
||||||
|
if (collected.size === 0) {
|
||||||
|
await claimMessage.delete();
|
||||||
|
|
||||||
|
await claimChannel.send({
|
||||||
|
content: `Ticket is still unclaimed. \nCC: [<@&${Staff.id}> <@&${Admin.id}]`,
|
||||||
|
embeds: [new EmbedBuilder().setDescription(`Ticket is still unclaimed: <#${ticketChannel.id}>`).setColor(supportbot.Embed.Colours.Warn)],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
console.error("Claim channel not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const clockedInArray = Array.from(clockedInUsers);
|
||||||
|
const assignedUserId = clockedInArray[Math.floor(Math.random() * clockedInArray.length)];
|
||||||
|
const assignedUser = await interaction.guild.members.fetch(assignedUserId);
|
||||||
|
|
||||||
|
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 || 'Claim Ticket')
|
||||||
|
.setStyle(ButtonStyle.Primary);
|
||||||
|
|
||||||
|
const row = new ActionRowBuilder().addComponents(claimButton);
|
||||||
|
|
||||||
|
const claimChannel = await interaction.guild.channels.cache.get(supportbot.Ticket.ClaimTickets.Channel);
|
||||||
|
if (!claimChannel) {
|
||||||
|
console.error("Claim channel not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const claimMessage = await claimChannel.send({
|
||||||
|
content: `${assignedUser}`,
|
||||||
|
embeds: [claimEmbed],
|
||||||
|
components: [row],
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = i => i.customId === `claimticket-${ticketChannel.id}` && i.user.id === assignedUserId;
|
||||||
|
const collector = claimMessage.createMessageComponentCollector({ filter, time: 120000 });
|
||||||
|
|
||||||
|
collector.on('collect', async i => {
|
||||||
|
await ticketChannel.send({ content: `<@${assignedUserId}>` }).then(msg => setTimeout(() => msg.delete(), 5000));
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('end', async collected => {
|
||||||
|
if (collected.size === 0) {
|
||||||
|
await claimMessage.delete();
|
||||||
|
|
||||||
|
if (attempts >= 1) {
|
||||||
|
await claimChannel.send({
|
||||||
|
content: `No one claimed the ticket. Tagging roles: <@&${Staff.id}> <@&${Admin.id}>`,
|
||||||
|
embeds: [new EmbedBuilder().setDescription(`Ticket is still unclaimed: <#${ticketChannel.id}>`).setColor(supportbot.Embed.Colours.Warn)],
|
||||||
|
});
|
||||||
|
|
||||||
|
const claimEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimTitle)
|
||||||
|
.setDescription(msgconfig.Ticket.ClaimTickets.ClaimMessage)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
const claimButton = new ButtonBuilder()
|
||||||
|
.setCustomId(`claimticket-${ticketChannel.id}`)
|
||||||
|
.setLabel(supportbot.Ticket.ClaimTickets.ButtonTitle)
|
||||||
|
.setEmoji(supportbot.Ticket.ClaimTickets.ButtonEmoji)
|
||||||
|
.setStyle(ButtonStyle.Primary);
|
||||||
|
|
||||||
|
const row = new ActionRowBuilder().addComponents(claimButton);
|
||||||
|
|
||||||
|
const claimMessage = await claimChannel.send({
|
||||||
|
embeds: [claimEmbed],
|
||||||
|
components: [row],
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = i => i.customId === `claimticket-${ticketChannel.id}` && i.member.roles.cache.has(Staff.id);
|
||||||
|
const collector = claimMessage.createMessageComponentCollector({ filter, time: 120000 });
|
||||||
|
|
||||||
|
collector.on('collect', async i => {
|
||||||
|
console.log(`Ticket ${ticketChannel.id} claimed by user ${i.user.id}`);
|
||||||
|
await ticketChannel.member.add(i.user.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('end', async collected => {
|
||||||
|
if (collected.size === 0) {
|
||||||
|
console.log(`No one claimed the ticket (${ticketChannel.id}), notifying all staff`);
|
||||||
|
await claimMessage.delete();
|
||||||
|
|
||||||
|
await claimChannel.send({
|
||||||
|
content: `No one claimed the ticket. Tagging roles: <@&${Staff.id}> <@&${Admin.id}>`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const ReassigningEmbed = new EmbedBuilder()
|
||||||
|
.setTitle(msgconfig.Ticket.ClaimTickets.ReassigningTitle)
|
||||||
|
.setDescription(msgconfig.Ticket.ClaimTickets.ReassigningMessage.replace('%user%', assignedUserId))
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
await claimChannel.send({ embeds: [ReassigningEmbed], components: [] });
|
||||||
|
await assignTicketToUser(ticketChannel, Staff, Admin, interaction, attempts + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return assignedUserId;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in assignTicketToUser function:", error);
|
||||||
|
if (error instanceof CombinedError) {
|
||||||
|
console.error("CombinedError details:", error.errors);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.OpenTicket.Command,
|
||||||
|
description: cmdconfig.OpenTicket.Description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "reason",
|
||||||
|
description: "Ticket Reason",
|
||||||
|
type: ApplicationCommandOptionType.String,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.OpenTicket.Permission,
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (await isBlacklisted(interaction.user.id)) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: msgconfig.Ticket.Blacklisted,
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let TicketReason = null;
|
||||||
|
if (supportbot.Ticket.TicketReason) {
|
||||||
|
TicketReason = interaction.reason || null; // Retrieve the reason from the interaction object
|
||||||
|
}
|
||||||
|
|
||||||
|
let TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
let User = interaction.guild.members.cache.get(interaction.user.id);
|
||||||
|
|
||||||
|
if (
|
||||||
|
supportbot.Ticket.TicketsPerUser &&
|
||||||
|
TicketData.tickets.filter((t) => t.user === interaction.user.id && t.open).length >= supportbot.Ticket.TicketsPerUser
|
||||||
|
) {
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
{
|
||||||
|
title: "Too Many Tickets!",
|
||||||
|
description: `You can't have more than ${supportbot.Ticket.TicketsPerUser} open tickets!`,
|
||||||
|
color: supportbot.Embed.Colours.Warn,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let ticketNumberID = await TicketNumberID.pad();
|
||||||
|
const TicketSubject = TicketReason || msgconfig.Ticket.InvalidSubject;
|
||||||
|
|
||||||
|
const TicketExists = new EmbedBuilder()
|
||||||
|
.setTitle("Ticket Exists!")
|
||||||
|
.setDescription(msgconfig.Ticket.TicketExists);
|
||||||
|
|
||||||
|
if (
|
||||||
|
await interaction.guild.channels.cache.find(
|
||||||
|
(ticketChannel) => ticketChannel.name === `${supportbot.Ticket.Channel}${ticketNumberID}`
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return await interaction.reply({
|
||||||
|
embeds: [TicketExists],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Staff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
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.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
let ticketChannel;
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
const TicketHome = interaction.guild.channels.cache.find(
|
||||||
|
(c) => c.name === supportbot.Ticket.TicketHome || c.id === supportbot.Ticket.TicketHome
|
||||||
|
);
|
||||||
|
|
||||||
|
const channel = await getChannel(supportbot.Ticket.TicketHome, interaction.guild);
|
||||||
|
ticketChannel = await channel.threads.create({
|
||||||
|
name: `${supportbot.Ticket.Channel}${ticketNumberID}`,
|
||||||
|
type: ChannelType.PrivateThread,
|
||||||
|
parent: TicketHome,
|
||||||
|
autoArchiveDuration: 60,
|
||||||
|
reason: 'support ticket',
|
||||||
|
});
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
const category = interaction.guild.channels.cache.find(
|
||||||
|
(c) => c.name === supportbot.Ticket.TicketChannelsCategory || c.id === supportbot.Ticket.TicketChannelsCategory
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!category) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: "The ticket category does not exist!",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ticketChannel = await interaction.guild.channels.create({
|
||||||
|
name: `${supportbot.Ticket.Channel}${ticketNumberID}`,
|
||||||
|
type: ChannelType.GuildText,
|
||||||
|
parent: category.id,
|
||||||
|
reason: 'support ticket',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move to secondary category if the primary one is full
|
||||||
|
if (category.children.size >= 50) {
|
||||||
|
const secondaryCategory = interaction.guild.channels.cache.find(
|
||||||
|
(c) => c.name === supportbot.Ticket.TicketChannelsCategory2 || c.id === supportbot.Ticket.TicketChannelsCategory2
|
||||||
|
);
|
||||||
|
|
||||||
|
if (secondaryCategory) {
|
||||||
|
await ticketChannel.setParent(secondaryCategory.id);
|
||||||
|
} else {
|
||||||
|
return interaction.reply({
|
||||||
|
content: "The secondary ticket category does not exist!",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign ticket to a user if claiming tickets is enabled
|
||||||
|
if (supportbot.Ticket.ClaimTickets.Enabled) {
|
||||||
|
const assignedUserId = await assignTicketToUser(ticketChannel, Staff, Admin, interaction);
|
||||||
|
if (!assignedUserId) {
|
||||||
|
const claimChannel = await interaction.guild.channels.cache.get(supportbot.Ticket.ClaimTickets.Channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await ticketChannel.members.add(interaction.user.id);
|
||||||
|
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
|
||||||
|
await ticketChannel.permissionOverwrites.create(interaction.user.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await ticketChannel.permissionOverwrites.create(Admin, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await ticketChannel.permissionOverwrites.create(interaction.guild.roles.everyone, {
|
||||||
|
ViewChannel: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ask questions to the user after the ticket is opened
|
||||||
|
if (supportbot.Ticket.Questions.Enabled) {
|
||||||
|
const questions = supportbot.Ticket.Questions.List || [];
|
||||||
|
if (questions.length > 0) {
|
||||||
|
await askTicketQuestions(ticketChannel, interaction, questions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save ticket data
|
||||||
|
TicketData.tickets.push({
|
||||||
|
id: ticketChannel.id,
|
||||||
|
name: ticketChannel.name,
|
||||||
|
user: interaction.user.id,
|
||||||
|
number: ticketNumberID,
|
||||||
|
reason: TicketSubject,
|
||||||
|
open: true,
|
||||||
|
subUsers: [],
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
claimedAt: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
"./Data/TicketData.json",
|
||||||
|
JSON.stringify(TicketData, null, 4),
|
||||||
|
(err) => {
|
||||||
|
if (err) console.error(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Notify the user that the ticket was created
|
||||||
|
const CreatedTicket = new EmbedBuilder()
|
||||||
|
.setDescription(
|
||||||
|
msgconfig.Ticket.TicketCreatedAlert.replace(/%ticketauthor%/g, interaction.user.id)
|
||||||
|
.replace(/%ticketid%/g, ticketChannel.id)
|
||||||
|
.replace(/%ticketusername%/g, interaction.user.username)
|
||||||
|
.replace(/%ticketreason%/g, TicketSubject)
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
await interaction.reply({ embeds: [CreatedTicket], ephemeral: true });
|
||||||
|
|
||||||
|
// Create the ticket message
|
||||||
|
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)
|
||||||
|
.replace(/%ticketusername%/g, interaction.user.username)
|
||||||
|
)
|
||||||
|
.setDescription(
|
||||||
|
msgconfig.Ticket.TicketMessage.replace(/%ticketauthor%/g, interaction.user.id)
|
||||||
|
.replace(/%ticketid%/g, ticketChannel.id)
|
||||||
|
.replace(/%ticketusername%/g, interaction.user.username)
|
||||||
|
.replace(/%ticketreason%/g, TicketSubject)
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.General);
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketReason && TicketReason) {
|
||||||
|
TicketMessage.addFields(
|
||||||
|
{ name: "Reason", value: TicketReason, inline: false }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the control panel
|
||||||
|
const SelectMenus = new StringSelectMenuBuilder()
|
||||||
|
.setCustomId("ticketcontrolpanel")
|
||||||
|
.setPlaceholder("Ticket Control Panel")
|
||||||
|
.addOptions(
|
||||||
|
new StringSelectMenuOptionBuilder()
|
||||||
|
.setLabel("Close")
|
||||||
|
.setDescription("Close the ticket.")
|
||||||
|
.setEmoji(supportbot.SelectMenus.Tickets.CloseEmoji)
|
||||||
|
.setValue("ticketclose"),
|
||||||
|
new StringSelectMenuOptionBuilder()
|
||||||
|
.setLabel("Voice Channel")
|
||||||
|
.setDescription("Create a support voice channel.")
|
||||||
|
.setEmoji(supportbot.SelectMenus.Tickets.VCEmoji)
|
||||||
|
.setValue("supportvc"),
|
||||||
|
new StringSelectMenuOptionBuilder()
|
||||||
|
.setLabel("Archive")
|
||||||
|
.setDescription("Archive the ticket.")
|
||||||
|
.setEmoji(supportbot.SelectMenus.Tickets.ArchiveEmoji)
|
||||||
|
.setValue("archiveticket"),
|
||||||
|
...(supportbot.Ticket.TicketType === "threads" ? [
|
||||||
|
new StringSelectMenuOptionBuilder()
|
||||||
|
.setLabel("Lock Ticket")
|
||||||
|
.setDescription("Lock the ticket.")
|
||||||
|
.setEmoji(supportbot.SelectMenus.Tickets.LockEmoji)
|
||||||
|
.setValue("lockticket")
|
||||||
|
] : []),
|
||||||
|
new StringSelectMenuOptionBuilder()
|
||||||
|
.setLabel("Rename Ticket")
|
||||||
|
.setDescription("Rename the ticket.")
|
||||||
|
.setEmoji(supportbot.SelectMenus.Tickets.RenameEmoji)
|
||||||
|
.setValue("renameticket")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
SelectMenus.addOptions(
|
||||||
|
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"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const row2 = new ActionRowBuilder().addComponents(SelectMenus);
|
||||||
|
|
||||||
|
await ticketChannel.send({
|
||||||
|
embeds: [TicketMessage],
|
||||||
|
components: [row2],
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in run method:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
// 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 { getChannel } = interaction.client;
|
||||||
|
|
||||||
|
const channel = await getChannel(
|
||||||
|
supportbot.Ticket.TicketHome,
|
||||||
|
interaction.guild
|
||||||
|
);
|
||||||
|
|
||||||
|
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,117 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Translate 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");
|
||||||
|
const translate = require("@vitalets/google-translate-api");
|
||||||
|
|
||||||
|
module.exports = new Command({
|
||||||
|
name: cmdconfig.Translate.Command,
|
||||||
|
description: cmdconfig.Translate.Description,
|
||||||
|
type: Discord.ApplicationCommandType.ChatInput,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
name: "language",
|
||||||
|
description: "A 2 letter language code",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: Discord.ApplicationCommandOptionType.String,
|
||||||
|
name: "text",
|
||||||
|
description: "The text to translate",
|
||||||
|
required: true,
|
||||||
|
}, // The input text for the translation
|
||||||
|
],
|
||||||
|
permissions: cmdconfig.Translate.Permission, // The permission the user/role at least requires
|
||||||
|
|
||||||
|
async run(interaction) {
|
||||||
|
let disableCommand = true;
|
||||||
|
|
||||||
|
const { getRole } = interaction.client;
|
||||||
|
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||||
|
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||||
|
if (!SupportStaff || !Admin)
|
||||||
|
|
||||||
|
return interaction.reply(
|
||||||
|
"Some roles seem to be missing!\nPlease check for errors when starting the bot."
|
||||||
|
);
|
||||||
|
|
||||||
|
const NoPerms = new Discord.EmbedBuilder()
|
||||||
|
.setTitle("Invalid Permissions!")
|
||||||
|
.setDescription(
|
||||||
|
`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!interaction.member.roles.cache.has(SupportStaff.id) &&
|
||||||
|
!interaction.member.roles.cache.has(Admin.id)
|
||||||
|
)
|
||||||
|
return interaction.reply({ embeds: [NoPerms] });
|
||||||
|
|
||||||
|
const { getChannel } = interaction.client;
|
||||||
|
let lang = interaction.options.getString("language"); // Grab choice of language code by user
|
||||||
|
let url = "https://www.science.co.il/language/Codes.php"; // URL to all available language codes
|
||||||
|
let text = await interaction.options.getString("text"); // Grab the text to translate by the user
|
||||||
|
let translatelog = await getChannel(
|
||||||
|
supportbot.Translate.TranslateLog,
|
||||||
|
interaction.guild
|
||||||
|
); // Grab the set logging channel for translations
|
||||||
|
|
||||||
|
|
||||||
|
// Return message if user has provided an invalid language code
|
||||||
|
const result = await translate(text, { to: lang }).catch(async (err) => {
|
||||||
|
if (err && err.code == 400) {
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new Discord.EmbedBuilder()
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn)
|
||||||
|
.setTitle("Valid Language Codes")
|
||||||
|
.setURL(url)
|
||||||
|
.setDescription(
|
||||||
|
"Click the title to see which 2 letter language codes are valid."
|
||||||
|
),
|
||||||
|
],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!result) return;
|
||||||
|
|
||||||
|
// Embed containing language code, original text and translated text
|
||||||
|
let transembed = new Discord.EmbedBuilder()
|
||||||
|
.setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL({ dynamic: true }) })
|
||||||
|
.setColor(supportbot.Embed.Colours.Success)
|
||||||
|
.setDescription(`**Translation to ${lang}**`)
|
||||||
|
.addFields(
|
||||||
|
{ name: "Original text", value: text },
|
||||||
|
{ name: "Translated text", value: result.text },
|
||||||
|
)
|
||||||
|
.setFooter({ text: `Author: ${interaction.user.id}` })
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
// Send embed [transembed] with translated message to channel
|
||||||
|
await interaction.reply({ embeds: [transembed] });
|
||||||
|
|
||||||
|
// Send embed [transembed] to logging channel
|
||||||
|
await translatelog.send({ embeds: [transembed] });
|
||||||
|
},
|
||||||
|
|
||||||
|
})
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
# ___ _ ___ _
|
||||||
|
# / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
|
||||||
|
# \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
|
||||||
|
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
|
||||||
|
# |_| |_|
|
||||||
|
#
|
||||||
|
# SupportBot created by Emerald Services
|
||||||
|
# Installed with MIT License
|
||||||
|
#
|
||||||
|
# Discord Support: https://discord.gg/emeraldsrv
|
||||||
|
# Official Documentation: https://docs.emeraldsrv.com
|
||||||
|
# Addons Marketplace: https://community.emeraldsrv.com
|
||||||
|
#
|
||||||
|
# Commands Configuration (commands.yml)
|
||||||
|
|
||||||
|
Help:
|
||||||
|
Command: "help"
|
||||||
|
Description: "Get a list of all the commands."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Info:
|
||||||
|
Command: "info"
|
||||||
|
Description: "Get information about the **ServerName**."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
TicketPanel:
|
||||||
|
Command: "ticketpanel"
|
||||||
|
Description: "Create the ticket creation panel"
|
||||||
|
Permission: ["Administrator"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Profile:
|
||||||
|
Command: "profile"
|
||||||
|
Description: "Shows the profile for a discord member."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
# Command is automatically disabled when the TicketClaims is disabled.
|
||||||
|
|
||||||
|
OpenTicket:
|
||||||
|
Command: "ticket"
|
||||||
|
Description: "Create a support ticket."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
AddUser:
|
||||||
|
Command: "add"
|
||||||
|
Description: "Add a user to a support ticket."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
ForceAddUser:
|
||||||
|
Command: "forceadd"
|
||||||
|
Description: "Add a user to a support ticket by bypassing the invite system."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
RemoveUser:
|
||||||
|
Command: "remove"
|
||||||
|
Description: "Remove a user from a support ticket."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
CloseTicket:
|
||||||
|
Command: "close"
|
||||||
|
Description: "Close a support ticket"
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Suggestion:
|
||||||
|
Command: "suggest"
|
||||||
|
Description: "Create a suggestion."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Embed:
|
||||||
|
Command: "embed"
|
||||||
|
Description: "Build a discord embed."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Translate:
|
||||||
|
Command: "translate"
|
||||||
|
Description: "Translate something to english"
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
UserInfo:
|
||||||
|
Command: "userinfo"
|
||||||
|
Description: "Get info about a user."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Ping:
|
||||||
|
Command: "ping"
|
||||||
|
Description: "Pong."
|
||||||
|
Permission: ["SendMessages"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
# ---------------------------------------
|
||||||
|
# Bot Moderator Commands
|
||||||
|
# ---------------------------------------
|
||||||
|
|
||||||
|
Mod:
|
||||||
|
Command: "mod"
|
||||||
|
Description: "Execute a moderation action."
|
||||||
|
Permission: ["BanMembers", "KickMembers"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
TicketBlacklist:
|
||||||
|
Command: "ticket-blacklist"
|
||||||
|
Description: "Blacklist a user from creating Tickets."
|
||||||
|
|
||||||
|
Add:
|
||||||
|
Command: "add"
|
||||||
|
Description: "Add a user to the blacklist."
|
||||||
|
|
||||||
|
Remove:
|
||||||
|
Command: "remove"
|
||||||
|
Description: "Remove a user from the blacklist."
|
||||||
|
|
||||||
|
View:
|
||||||
|
Command: "view"
|
||||||
|
Description: "View all blacklisted users."
|
||||||
|
|
||||||
|
# ---------------------------------------
|
||||||
|
# Bot Administrator Commands
|
||||||
|
# ---------------------------------------
|
||||||
|
|
||||||
|
Settings:
|
||||||
|
Command: "settings"
|
||||||
|
Description: "Update bot settings."
|
||||||
|
Permission: ["Administrator"]
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
# ---------------------------------------
|
||||||
|
# Command Description Configuration
|
||||||
|
# ---------------------------------------
|
||||||
|
|
||||||
|
BlacklistDesc: "Blacklist a user from creating Tickets."
|
||||||
|
TicketAddDesc: "Add a user to a support ticket."
|
||||||
|
TicketRemoveDesc: "Remove a user from a support ticket."
|
||||||
|
TranslateCommandDesc: "Translates the language provided, along with the abbreviation (2 char) long language code"
|
||||||
|
OpenTicketDesc: "Open a new support ticket."
|
||||||
|
CloseTicketDesc: "Close your support ticket."
|
||||||
|
InfoCommandDesc: "Get information about the brand."
|
||||||
|
PingCommandDesc: "Pong!"
|
||||||
|
HelpCommandDesc: "Get a list of all the commands."
|
||||||
|
EmbedCommandDesc: "Send a message as an embed."
|
||||||
|
SuggestCommandDesc: "Suggest a feature for the server."
|
||||||
|
UserInfoCommandDesc: "Get info about a user."
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
# ___ _ ___ _
|
||||||
|
# / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
|
||||||
|
# \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
|
||||||
|
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
|
||||||
|
# |_| |_|
|
||||||
|
#
|
||||||
|
# SupportBot created by Emerald Services
|
||||||
|
# Installed with MIT License
|
||||||
|
#
|
||||||
|
# Discord Support: https://discord.gg/emeraldsrv
|
||||||
|
# Official Documentation: https://docs.emeraldsrv.com
|
||||||
|
# Addons Marketplace: https://community.emeraldsrv.com
|
||||||
|
#
|
||||||
|
# Messages Configuration (messages.yml)
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Info Command
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
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://docs.emeraldsrv.com"
|
||||||
|
Colour: "#f74343"
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Welcome/Leave Messages
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
Welcome:
|
||||||
|
Embed:
|
||||||
|
Colour: "#f74343"
|
||||||
|
Title: "Welcome to ServerName"
|
||||||
|
Message: ":smile: %joined_user% has just landed!"
|
||||||
|
Thumbnail: "BOT"
|
||||||
|
|
||||||
|
ImageEnabled: false
|
||||||
|
ImageURL: "https://animagelink.png/"
|
||||||
|
|
||||||
|
Leave:
|
||||||
|
Embed:
|
||||||
|
Colour: "#f74343"
|
||||||
|
Title: "Goodbye!"
|
||||||
|
Message: ":slight_frown: %joined_user% has recently dropped out!"
|
||||||
|
Thumbnail: "BOT"
|
||||||
|
|
||||||
|
ImageEnabled: false
|
||||||
|
ImageURL: "https://animagelink.png/"
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Suggestion Messages
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
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 Messages
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
Ticket:
|
||||||
|
|
||||||
|
# Available Placeholders:
|
||||||
|
|
||||||
|
# %ticketusername% - User who created the ticket.
|
||||||
|
# <@%ticketauthor%> - Tags the user who created the ticket.
|
||||||
|
# <#%ticketid%> - Mentions the ticket channel.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
TicketArchived: ":white_check_mark: Ticket archived."
|
||||||
|
TicketUnarchived: ":white_check_mark: Ticket unarchived."
|
||||||
|
TicketLocked: ":lock: Ticket is locked."
|
||||||
|
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.
|
||||||
|
|
||||||
|
Blacklisted: ":x: You are not allowed to open a ticket"
|
||||||
|
Muted: ":x: You are `Muted` and therefore not allowed to open any tickets"
|
||||||
|
InvalidSubject: "No Reason Provided!"
|
||||||
|
|
||||||
|
ConfirmClose: "Please confirm closing the ticket by clicking the button below."
|
||||||
|
CloseTimeout: "Ticket close confirmation timed out."
|
||||||
|
|
||||||
|
RenamedSuccess: "🏷️ Ticket renamed successfully!"
|
||||||
|
|
||||||
|
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."
|
||||||
|
|
||||||
|
ReassigningTitle: "Reassigning!..."
|
||||||
|
ReassigningMessage: "<@%user%> did not claim the ticket. **Reassigning...**"
|
||||||
|
|
||||||
|
TicketQuestions:
|
||||||
|
Details:
|
||||||
|
Title: "Ticket Details"
|
||||||
|
Description: "Questions by <@%user%>" # Use <@%user%> to display the username.
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Review Messages
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
ReviewSystem:
|
||||||
|
Rate:
|
||||||
|
Title: "Review us!"
|
||||||
|
Description: "Please rate our support for this ticket (1-5 stars)."
|
||||||
|
|
||||||
|
Stars:
|
||||||
|
One: "⭐ 1 Star"
|
||||||
|
Two: "⭐⭐ 2 Stars"
|
||||||
|
Three: "⭐⭐⭐ 3 Stars"
|
||||||
|
Four: "⭐⭐⭐⭐ 4 Stars"
|
||||||
|
Five: "⭐⭐⭐⭐⭐ 5 Stars"
|
||||||
|
|
||||||
|
Comment:
|
||||||
|
Title: "Write a comment."
|
||||||
|
Description: "Write a comment about your experience."
|
||||||
|
|
||||||
|
ReviewEmbed:
|
||||||
|
Title: "Ticket Review"
|
||||||
|
CommentTitle: "Comment"
|
||||||
|
RatingTitle: "Rating"
|
||||||
|
ReviewedStaffTitle: "Reviewed Staff:"
|
||||||
|
ReviewedByTitle: "Reviewed By:"
|
||||||
|
ReviewEmoji: "⭐"
|
||||||
|
Color: "#f7a943"
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Profile Messages
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
TicketStats:
|
||||||
|
OpenTickets: "✅ Open Tickets"
|
||||||
|
TotalTickets: "🎫 Total Tickets"
|
||||||
|
ResponseTime: "⏱️ Average Response Time"
|
||||||
|
|
||||||
|
Title: "Your Ticket Stats"
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Mod Command Messages
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
Mod:
|
||||||
|
|
||||||
|
TicketBlacklist:
|
||||||
|
Add:
|
||||||
|
Description: "Add a user to the ticket blacklist"
|
||||||
|
UserDescription: "User to blacklist"
|
||||||
|
AlreadyBlacklisted: ":x: {userTag} is already blacklisted."
|
||||||
|
Success: ":white_check_mark: {userTag} has been added to the blacklist. They can no longer use the ticket system."
|
||||||
|
|
||||||
|
Remove:
|
||||||
|
Description: "Remove a user from the ticket blacklist"
|
||||||
|
UserDescription: "User to remove from blacklist"
|
||||||
|
NotBlacklisted: ":x: {userTag} is not blacklisted."
|
||||||
|
Success: ":white_check_mark: {userTag} has been removed from the blacklist. They can now use the ticket system again."
|
||||||
|
|
||||||
|
View:
|
||||||
|
Description: "View the list of all blacklisted users"
|
||||||
|
NoBlacklistedUsers: ":information_source: There are currently no users on the blacklist."
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Logging Messages
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
TicketLog:
|
||||||
|
Title: "Ticket Log"
|
||||||
|
Colour: "#0cc559"
|
||||||
|
|
||||||
|
TicketBlacklistLog:
|
||||||
|
Title: "Ticket Blacklist Log"
|
||||||
|
Colour: "#0cc559"
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Misc Messages
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
AddUser:
|
||||||
|
NotInTicket_Title: "Ticket Invitation"
|
||||||
|
NotInTicket_Description: "This command can only be used within a ticket thread."
|
||||||
|
|
||||||
|
Invite_Title: "User Invited"
|
||||||
|
Invite_Description: "%username% has been invited to join the ticket."
|
||||||
|
|
||||||
|
DM_Title: "Ticket Invitation"
|
||||||
|
DM_Description: "You have been invited to join the ticket %channelname%. Do you accept?"
|
||||||
|
|
||||||
|
Accept_Label: "Accept"
|
||||||
|
Reject_Label: "Reject"
|
||||||
|
ViewTicket_Label: "Go to Ticket"
|
||||||
|
|
||||||
|
Accepted_Title: "Invitation Accepted"
|
||||||
|
Accepted_Message: "You have been added to the ticket."
|
||||||
|
AddedToTicket_Title: "Added to Ticket"
|
||||||
|
AddedToTicket_Description: "You have been added to the ticket %channel_link%."
|
||||||
|
|
||||||
|
# Added Message for inside the ticket, this informs everyone inside the ticket that the user has been added.
|
||||||
|
Added_Title: "User Added"
|
||||||
|
Added_Description: "Successfully added **%username%** to the ticket."
|
||||||
|
|
||||||
|
Declined_Title: "Invitation Declined"
|
||||||
|
Declined_Message: "You have declined the invitation."
|
||||||
|
|
||||||
|
NoResponse_Title: "No Response"
|
||||||
|
NoResponse_Message: "You did not respond in time. Please contact staff if you wish to join the ticket."
|
||||||
|
|
||||||
|
Error_Title: "Error"
|
||||||
|
Error_Adding: "There was an error adding you to the ticket. Please try again."
|
||||||
|
|
||||||
|
DM_Error_Title: "Error"
|
||||||
|
DM_Error_Description: "Unable to send a DM to %username%. Please ensure your DMs are enabled."
|
||||||
|
|
||||||
|
Unexpected_Error_Title: "Error"
|
||||||
|
Unexpected_Error_Description: "An unexpected error occurred: %error%"
|
||||||
|
|
||||||
|
RemoveUser:
|
||||||
|
NotInTicket_Title: "Error"
|
||||||
|
NotInTicket_Description: "This command can only be used in ticket threads."
|
||||||
|
|
||||||
|
Removed_Title: "User Removed"
|
||||||
|
Removed_Message: "The user has been successfully removed from the ticket."
|
||||||
|
|
||||||
|
RemovedFromTicket_Title: "Removed from Ticket"
|
||||||
|
RemovedFromTicket_Description: "You have been removed from the ticket channel %channel_link%."
|
||||||
|
|
||||||
|
Error_Title: "Error"
|
||||||
|
Error_Removing: "There was an error removing the user from the ticket."
|
||||||
|
|
||||||
|
ForceAddUser:
|
||||||
|
NotInTicket_Title: "Not a Ticket"
|
||||||
|
NotInTicket_Description: "This command can only be used within a ticket thread."
|
||||||
|
|
||||||
|
Added_Title: "User Added"
|
||||||
|
Added_Description: "Successfully added %username% to the ticket."
|
||||||
|
|
||||||
|
AddedToTicket_Title: "You have been added to a Ticket"
|
||||||
|
AddedToTicket_Description: "You have been added to the ticket channel [%channel_link%]."
|
||||||
|
|
||||||
|
Error_Title: "Error"
|
||||||
|
Error_Adding: "There was an error adding the user to the ticket."
|
||||||
|
|
||||||
|
Error:
|
||||||
|
IncorrectPermissions: ":x: **Error!** You do not have the correct permissions to use this command."
|
||||||
|
MissingChannel: ":x: **Error!** Required channel not found. Please ensure it is set up correctly!"
|
||||||
|
UserNotFound: ":x: **Error!** Specified user not found. Please check if they are in this server."
|
||||||
|
CommandNotAllowedHere: ":warning: This command cannot be used in this channel."
|
||||||
|
EntryAlreadyExists: ":warning: Cannot complete the action, as the entry already exists."
|
||||||
|
EntryDoesNotExist: ":warning: Cannot complete the action, as the entry does not exist."
|
||||||
|
ActionFailed: ":x: **Error!** An error occurred while processing your request. Please try again later."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# -------------------------
|
||||||
|
# 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-mini"
|
||||||
|
# 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_API_KEY"
|
||||||
|
# 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: "AI_BOT_CHANNEL"
|
||||||
|
# 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`"
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
# ___ _ ___ _
|
||||||
|
# / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
|
||||||
|
# \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
|
||||||
|
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
|
||||||
|
# |_| |_|
|
||||||
|
#
|
||||||
|
# SupportBot created by Emerald Services
|
||||||
|
# Installed with MIT License
|
||||||
|
#
|
||||||
|
# Discord Support: https://discord.gg/emeraldsrv
|
||||||
|
# Official Documentation: https://docs.emeraldsrv.com
|
||||||
|
# Addons Marketplace: https://community.emeraldsrv.com
|
||||||
|
#
|
||||||
|
# SupportBot Configuration (supportbot.yml)
|
||||||
|
|
||||||
|
SupportBot_Version: "v8.3"
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# General
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
General:
|
||||||
|
Name: "SupportBot"
|
||||||
|
Token: "BOT_TOKEN"
|
||||||
|
|
||||||
|
Addons:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Activity
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
Activity:
|
||||||
|
Status: "SupportBot v8"
|
||||||
|
Type: "Competing"
|
||||||
|
StreamingURL: "https://www.twitch.tv/YOUR_TWITCH_NAME"
|
||||||
|
|
||||||
|
# Available Types:
|
||||||
|
# Playing
|
||||||
|
# Watching
|
||||||
|
# Listening
|
||||||
|
# Competing
|
||||||
|
# Streaming (URL required)
|
||||||
|
|
||||||
|
# You can also update the activity via Discord using: /settings
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Embeds
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
Embed:
|
||||||
|
Colours:
|
||||||
|
General: 0x0cc559
|
||||||
|
Success: 0x04b545
|
||||||
|
Error: 0xd13030
|
||||||
|
Warn: 0xfca117
|
||||||
|
|
||||||
|
Footer: "SupportBot | Developed by Emerald Development"
|
||||||
|
|
||||||
|
# Use 0x<hexcode> to change the colour of the embeds.
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Roles
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
Roles:
|
||||||
|
AutoRole:
|
||||||
|
Enabled: true
|
||||||
|
Role: "ROLE_ID"
|
||||||
|
|
||||||
|
StaffMember:
|
||||||
|
Staff: "ROLE_ID"
|
||||||
|
Admin: "ROLE_ID"
|
||||||
|
Moderator: "ROLE_ID"
|
||||||
|
|
||||||
|
Mod:
|
||||||
|
AllowSupportStaff: false
|
||||||
|
|
||||||
|
# Allow Support Staff to use the /mod command. (More in detail customisation in commands.yml)
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# System Messages
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
Welcome:
|
||||||
|
Enabled: true
|
||||||
|
Channel: "JOIN_CHANNEL_ID"
|
||||||
|
|
||||||
|
Leave:
|
||||||
|
Enabled: true
|
||||||
|
Channel: "JOIN_CHANNEL_ID"
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Suggestions
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
Suggestions:
|
||||||
|
Channel: "SUGGESTIONS_CHANNEL_ID"
|
||||||
|
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
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
VoiceTickets:
|
||||||
|
Name: "%username%'s VC"
|
||||||
|
Category: "VOICEE_CATEGORY_ID"
|
||||||
|
|
||||||
|
Ticket:
|
||||||
|
TicketType: "channels"
|
||||||
|
|
||||||
|
# Available TicketTypes:
|
||||||
|
# channels - Tickets will be created as channels in the TicketChannelsCategory
|
||||||
|
# threads - Tickets will be created as threads through the "TicketHome" channel.
|
||||||
|
|
||||||
|
TicketHome: "TICKETHOME_CHANNEL_ID"
|
||||||
|
|
||||||
|
# What is TicketHome?
|
||||||
|
# - Channel where the Ticket creation panel is sent.
|
||||||
|
# - Channel where ticket threads are made. (only if ticket threads is enabled above.)
|
||||||
|
|
||||||
|
# For TicketType: channels
|
||||||
|
TicketChannelsCategory: "TICKETCHANNEL_CATEGORY_ID"
|
||||||
|
TicketChannelsCategory2: "TICKETCHANNEL_BACKUP_CATEGORY_ID" # This will be used if the first category has reached the max channel limit.
|
||||||
|
TicketArchiveCategory: "ARCHIVE_CATEGORY_ID"
|
||||||
|
# ---
|
||||||
|
|
||||||
|
Channel: "ticket-" # The prefix for ticket channel names
|
||||||
|
TicketsPerUser: 100
|
||||||
|
DMTranscripts: true
|
||||||
|
TicketReason: true
|
||||||
|
# If ticket reason is set to false, It will not prompt to create a reason
|
||||||
|
|
||||||
|
TicketSubject: "description"
|
||||||
|
|
||||||
|
# Available TicketSubjects:
|
||||||
|
# "description" will display the ticket reason within the channel description
|
||||||
|
# "embed" will display the ticket reason within the ticket embed
|
||||||
|
|
||||||
|
Timeout: 5
|
||||||
|
# Set to true to allow all staff to access the ticket
|
||||||
|
|
||||||
|
Close:
|
||||||
|
StaffOnly: true
|
||||||
|
# Set to false is anyone is able to close a ticket.
|
||||||
|
|
||||||
|
Confirmation_Button: "Confirm Close"
|
||||||
|
Confirmation_Emoji: "🗑️"
|
||||||
|
Confirmation_Style: "2"
|
||||||
|
|
||||||
|
Title: "Are you sure you want to close this ticket?"
|
||||||
|
|
||||||
|
# Available Button Styles:
|
||||||
|
# 1 - Blurple
|
||||||
|
# 2 - Grey
|
||||||
|
# 3 - Green
|
||||||
|
# 4 - Red
|
||||||
|
|
||||||
|
Invites:
|
||||||
|
StaffOnly: true
|
||||||
|
|
||||||
|
ClaimTickets:
|
||||||
|
Enabled: true
|
||||||
|
Channel: "CLAIM_TICKETS_CHANNEL_ID"
|
||||||
|
# Channel where the ticket assignments are sent for staff to claim.
|
||||||
|
|
||||||
|
ClaimAcceptTime: 120000
|
||||||
|
# How long the assigned user has to accept the ticket before it gets re-assigned to someone else.
|
||||||
|
# 120000 = 2 Minutes
|
||||||
|
# 180000 = 3 Minutes
|
||||||
|
# 240000 = 4 Minutes
|
||||||
|
# 300000 = 5 Minutes
|
||||||
|
# Time in Mliseconds
|
||||||
|
|
||||||
|
ButtonTitle: "Claim Ticket"
|
||||||
|
ButtonEmoji: "🎫"
|
||||||
|
Button: "1"
|
||||||
|
|
||||||
|
# Available Button Styles
|
||||||
|
# 1 - Blurple
|
||||||
|
# 2 - Grey
|
||||||
|
# 3 - Green
|
||||||
|
# 4 - Red
|
||||||
|
|
||||||
|
ReviewSystem:
|
||||||
|
Enabled: true
|
||||||
|
Channel: "REVIEW_CHANNEL_ID"
|
||||||
|
UseModal: true
|
||||||
|
|
||||||
|
Questions:
|
||||||
|
Enabled: true # Set to false to disable ticket questions
|
||||||
|
List:
|
||||||
|
- "Please provide your account email?"
|
||||||
|
- "What is the nature of your issue?"
|
||||||
|
- "Have you tried resolving the issue yourself?"
|
||||||
|
|
||||||
|
Log:
|
||||||
|
TicketDataLog: "TICKET_DATA_LOG_ID"
|
||||||
|
TickeDataTitle: "Ticket Data"
|
||||||
|
TicketBlacklistLog: "TICKET_BLACKLIST_LOG_ID"
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Buttons
|
||||||
|
# -------------------------
|
||||||
|
Buttons:
|
||||||
|
General:
|
||||||
|
Delete: "🗑️"
|
||||||
|
DeleteStyle: "4"
|
||||||
|
|
||||||
|
Voice:
|
||||||
|
TicketDeleteText: "Delete Voice Channel"
|
||||||
|
|
||||||
|
Tickets:
|
||||||
|
ClaimEmoji: "🧑💻"
|
||||||
|
ClaimStyle: "1"
|
||||||
|
|
||||||
|
Unarchive: "Unarchive Ticket"
|
||||||
|
Unarchive_Emoji: "♻️"
|
||||||
|
Unarchive_Style: "2"
|
||||||
|
|
||||||
|
Unlock: "Unlock Ticket"
|
||||||
|
Unlock_Emoji: "🔓"
|
||||||
|
Unlock_Style: "2"
|
||||||
|
|
||||||
|
# Available Button Styles
|
||||||
|
# 1 - Blurple
|
||||||
|
# 2 - Grey
|
||||||
|
# 3 - Green
|
||||||
|
# 4 - Red
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Select Menus
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
SelectMenus:
|
||||||
|
Tickets:
|
||||||
|
PanelEmoji: "⚙️"
|
||||||
|
|
||||||
|
CloseEmoji: "🗑️"
|
||||||
|
ArchiveEmoji: "♻️"
|
||||||
|
LockEmoji: "🔐"
|
||||||
|
RenameEmoji: "🏷️"
|
||||||
|
VCEmoji: "🔊"
|
||||||
|
|
||||||
|
EnableInvitesEmoji: "📤"
|
||||||
|
DisableInvitesEmoji: "📥"
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Logging
|
||||||
|
# -------------------------
|
||||||
|
|
||||||
|
MessageDelete:
|
||||||
|
Channel: "MESSAGE_DELETE_CHANNEL_ID""
|
||||||
|
Colour: "#d92525"
|
||||||
|
|
||||||
|
MessageUpdate:
|
||||||
|
Channel: "MESSAGE_UPDATE_CHANNEL_ID"
|
||||||
|
Colour: "#f2a024"
|
||||||
|
|
||||||
|
Translate:
|
||||||
|
TranslateLog: "TRANSLATE_LOG_ID"
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# ___ _ ___ _
|
||||||
|
# / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
|
||||||
|
# \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
|
||||||
|
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
|
||||||
|
# |_| |_|
|
||||||
|
#
|
||||||
|
# SupportBot created by Emerald Services
|
||||||
|
# Installed with MIT License
|
||||||
|
#
|
||||||
|
# Discord Support: https://discord.gg/emeraldsrv
|
||||||
|
# Official Documentation: https://docs.emeraldsrv.com
|
||||||
|
# Addons Marketplace: https://community.emeraldsrv.com
|
||||||
|
#
|
||||||
|
# Ticket Creation Panel Configuration (ticket-panel.yml)
|
||||||
|
|
||||||
|
# -------------------------------
|
||||||
|
# Ticket Panel Configuration
|
||||||
|
# -------------------------------
|
||||||
|
|
||||||
|
Panel: true
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Ticket Panel Message Configuration #2b2d31
|
||||||
|
# ----------------------------------------
|
||||||
|
|
||||||
|
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: false
|
||||||
|
TicketPanel_Image: true
|
||||||
|
|
||||||
|
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/dejQvkg.png"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"blacklistedUsers": []
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"tickets": [
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"bio": "",
|
||||||
|
"timezone": "",
|
||||||
|
"clockedIn": false
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"TicketPanelID": "000000000000000"
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const Event = require("../Structures/Event.js");
|
||||||
|
module.exports = new Event("guildCreate", async (client) => {
|
||||||
|
console.log(
|
||||||
|
`\u001b[31m`,
|
||||||
|
`${client.user.username} is not in the correct server set in your config. Please leave all other servers and restart the bot.`
|
||||||
|
);
|
||||||
|
console.log(`\u001b[31m`, `${client.user.username} will now exit.`);
|
||||||
|
return process.exit(1);
|
||||||
|
});
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
const Event = require("../Structures/Event.js");
|
||||||
|
|
||||||
|
module.exports = new Event("guildDelete", async (client) => {
|
||||||
|
console.log(
|
||||||
|
`\u001b[31m`,
|
||||||
|
`${client.user.username} is not in the correct server set in your config. Please join the server and restart the bot.`
|
||||||
|
);
|
||||||
|
console.log(`\u001b[31m`, `${client.user.username} will now exit.`);
|
||||||
|
return process.exit(1);
|
||||||
|
});
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
const Discord = require('discord.js');
|
||||||
|
const fs = require("fs");
|
||||||
|
const Event = require("../Structures/Event.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")
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = new Event("guildMemberAdd", async (client, member, interaction, guild) => {
|
||||||
|
|
||||||
|
if (supportbot.Welcome.Enabled) {
|
||||||
|
const WelcomeChannel = member.guild.channels.cache.get(supportbot.Welcome.Channel) ||
|
||||||
|
member.guild.channels.cache.find(channel => channel.name === supportbot.Welcome.Channel);
|
||||||
|
|
||||||
|
const WelcomeEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setColor(msgconfig.Welcome.Embed.Colour)
|
||||||
|
.setTitle(msgconfig.Welcome.Embed.Title)
|
||||||
|
.setDescription(msgconfig.Welcome.Embed.Message.replace(/%joined_user%/g, member.user))
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
if (msgconfig.Welcome.Embed.Thumbnail === "BOT") {
|
||||||
|
WelcomeEmbed.setThumbnail(client.user.displayAvatarURL())
|
||||||
|
} else if (msgconfig.Welcome.Embed.Thumbnail === "USER") {
|
||||||
|
WelcomeEmbed.setThumbnail(member.user.displayAvatarURL())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msgconfig.Welcome.Embed.ImageEnabled) {
|
||||||
|
WelcomeEmbed.setImage(msgconfig.Welcome.Embed.ImageURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WelcomeChannel) {
|
||||||
|
WelcomeChannel.send({ embeds: [WelcomeEmbed] });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Roles.AutoRole.Enabled) {
|
||||||
|
const role = member.guild.roles.cache.get(supportbot.Roles.AutoRole.Role) ||
|
||||||
|
member.guild.roles.cache.find(role => role.name === supportbot.Roles.AutoRole.Role);
|
||||||
|
if (role) {
|
||||||
|
member.roles.add(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\u001b[32m`, `[+]`, `\u001b[33m`, `${member.user.username} joined the server!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
const Discord = require('discord.js');
|
||||||
|
const fs = require("fs");
|
||||||
|
const Event = require("../Structures/Event.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")
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = new Event("guildMemberRemove", async (client, member, interaction, guild) => {
|
||||||
|
|
||||||
|
if (supportbot.Leave.Enabled) {
|
||||||
|
const LeaveChannel = member.guild.channels.cache.get(supportbot.Leave.Channel) ||
|
||||||
|
member.guild.channels.cache.find(channel => channel.name === supportbot.Leave.Channel);
|
||||||
|
|
||||||
|
const LeaveEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setColor(msgconfig.Leave.Embed.Colour)
|
||||||
|
.setTitle(msgconfig.Leave.Embed.Title)
|
||||||
|
.setDescription(msgconfig.Leave.Embed.Message.replace(/%left_user%/g, member.user))
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
if (msgconfig.Leave.Embed.Thumbnail === "BOT") {
|
||||||
|
LeaveEmbed.setThumbnail(client.user.displayAvatarURL());
|
||||||
|
} else if (msgconfig.Leave.Embed.Thumbnail === "USER") {
|
||||||
|
LeaveEmbed.setThumbnail(member.user.displayAvatarURL());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msgconfig.Leave.Embed.ImageEnabled) {
|
||||||
|
LeaveEmbed.setImage(msgconfig.Leave.Embed.ImageURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LeaveChannel) {
|
||||||
|
LeaveChannel.send({
|
||||||
|
embeds: [LeaveEmbed]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\u001b[31m`, `[-]`, `\u001b[33m`, `${member.user.username} left the server!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,831 @@
|
|||||||
|
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 Event = require("../Structures/Event.js");
|
||||||
|
|
||||||
|
let suggestions;
|
||||||
|
try {
|
||||||
|
suggestions = require("../Data/SuggestionData.json");
|
||||||
|
} catch (error) {
|
||||||
|
suggestions = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||||
|
|
||||||
|
if (interaction.type === Discord.InteractionType.ApplicationCommand) {
|
||||||
|
const command = client.commands.find(
|
||||||
|
(cmd) => cmd.name.toLowerCase() === interaction.commandName
|
||||||
|
);
|
||||||
|
|
||||||
|
if (interaction.user.bot || !interaction.guild) return;
|
||||||
|
|
||||||
|
const NotValid = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`:x: \`Invalid Command\``)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
if (!command)
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [NotValid],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const permission = interaction.member.permissions.has(command.permissions);
|
||||||
|
|
||||||
|
const ValidPerms = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(
|
||||||
|
"> :x: `Invalid Permissions` Do you have the correct permissions to execute this command?"
|
||||||
|
)
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
if (!permission)
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [ValidPerms],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (command.name === cmdconfig.OpenTicket.Command && supportbot.Ticket.TicketReason) {
|
||||||
|
const modal = new Discord.ModalBuilder()
|
||||||
|
.setCustomId("ticketReasonModal")
|
||||||
|
.setTitle("Ticket Reason")
|
||||||
|
.addComponents(
|
||||||
|
new Discord.ActionRowBuilder().addComponents(
|
||||||
|
new Discord.TextInputBuilder()
|
||||||
|
.setCustomId("reasonInput")
|
||||||
|
.setLabel("Reason")
|
||||||
|
.setStyle(Discord.TextInputStyle.Paragraph)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await interaction.showModal(modal);
|
||||||
|
} else {
|
||||||
|
console.log("\u001b[32m", "[Executed]", "\u001b[37;1m", `${interaction.user.username} has executed ${command.name}`);
|
||||||
|
await command.run(interaction);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error executing command:", error);
|
||||||
|
await interaction.reply({
|
||||||
|
content: "An error occurred while executing the command.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.isModalSubmit()) {
|
||||||
|
if (interaction.customId === "ticketReasonModal") {
|
||||||
|
const reason = interaction.fields.getTextInputValue("reasonInput");
|
||||||
|
interaction.customId = `createticket-${reason}`;
|
||||||
|
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
|
||||||
|
if (cmd) {
|
||||||
|
interaction.reason = reason; // Attach the reason to the interaction object
|
||||||
|
await cmd.run(interaction);
|
||||||
|
} else {
|
||||||
|
console.error("Command not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.customId === "renameTicketModal") {
|
||||||
|
const newTicketName = interaction.fields.getTextInputValue("renameTicket");
|
||||||
|
|
||||||
|
// Fixing the ticketChannelId extraction and lookup
|
||||||
|
const ticketChannelId = interaction.channel.id;
|
||||||
|
|
||||||
|
let ticketChannel;
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
ticketChannel = interaction.guild.channels.cache.get(ticketChannelId);
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
ticketChannel = interaction.guild.channels.cache.get(ticketChannelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ticketChannel) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: "Ticket channel not found.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ticketChannel.setName(newTicketName);
|
||||||
|
|
||||||
|
const renamedsuccess = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Ticket.RenamedSuccess)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [renamedsuccess],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error renaming the ticket:", error);
|
||||||
|
return interaction.reply({
|
||||||
|
content: "There was an error renaming the ticket.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (interaction.isStringSelectMenu()) {
|
||||||
|
if (interaction.customId === "ticketcontrolpanel") {
|
||||||
|
const selectedOption = interaction.values[0];
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
switch (selectedOption) {
|
||||||
|
|
||||||
|
case "ticketclose":
|
||||||
|
const closeCommand = client.commands.get(cmdconfig.CloseTicket.Command);
|
||||||
|
if (closeCommand) {
|
||||||
|
await closeCommand.run(interaction);
|
||||||
|
} else {
|
||||||
|
console.error("[X] Close Command Not Found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "supportvc":
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketInfo = ticketData.tickets.find(t => t.id === interaction.channel.id);
|
||||||
|
|
||||||
|
if (ticketInfo) {
|
||||||
|
const user = interaction.guild.members.cache.get(ticketInfo.user) || ticketInfo.user;
|
||||||
|
const claimedBy = interaction.guild.members.cache.get(ticketInfo.claimedBy) || ticketInfo.claimedBy;
|
||||||
|
const Admin = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Admin);
|
||||||
|
const Staff = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Staff);
|
||||||
|
|
||||||
|
const VCcategory = interaction.guild.channels.cache.find(
|
||||||
|
(c) => c.name === supportbot.VoiceTickets.Category || c.id === supportbot.VoiceTickets.Category
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!VCcategory) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: "The Support VC category does not exist!",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let username = user ? user.user.username : "Unknown User";
|
||||||
|
|
||||||
|
let SupportVoice = await interaction.guild.channels.create({
|
||||||
|
name: supportbot.VoiceTickets.Name.replace(/%username%/g, username),
|
||||||
|
type: Discord.ChannelType.GuildVoice,
|
||||||
|
parent: VCcategory,
|
||||||
|
permissionOverwrites: [
|
||||||
|
{
|
||||||
|
id: user,
|
||||||
|
allow: [
|
||||||
|
Discord.PermissionsBitField.Flags.Connect,
|
||||||
|
Discord.PermissionsBitField.Flags.Speak,
|
||||||
|
Discord.PermissionsBitField.Flags.ViewChannel,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: Staff,
|
||||||
|
allow: [
|
||||||
|
Discord.PermissionsBitField.Flags.Connect,
|
||||||
|
Discord.PermissionsBitField.Flags.Speak,
|
||||||
|
Discord.PermissionsBitField.Flags.ViewChannel,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: Admin,
|
||||||
|
allow: [
|
||||||
|
Discord.PermissionsBitField.Flags.Connect,
|
||||||
|
Discord.PermissionsBitField.Flags.Speak,
|
||||||
|
Discord.PermissionsBitField.Flags.ViewChannel,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: interaction.guild.id,
|
||||||
|
deny: [Discord.PermissionsBitField.Flags.ViewChannel],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
ticketInfo.voiceChannelId = SupportVoice.id;
|
||||||
|
|
||||||
|
fs.writeFileSync("./Data/TicketData.json", JSON.stringify(ticketData, null, 2));
|
||||||
|
|
||||||
|
const VCDeleteButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("deleteSupportVC")
|
||||||
|
.setLabel(supportbot.Buttons.Voice.TicketDeleteText)
|
||||||
|
.setEmoji(supportbot.Buttons.General.Delete)
|
||||||
|
.setStyle(supportbot.Buttons.General.DeleteStyle);
|
||||||
|
|
||||||
|
const VCDeleteRow = new Discord.ActionRowBuilder().addComponents(VCDeleteButton);
|
||||||
|
|
||||||
|
const vcmadeembed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(`> **Support VC Created:** <#${SupportVoice.id}>`)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [vcmadeembed],
|
||||||
|
components: [VCDeleteRow],
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "archiveticket":
|
||||||
|
const arcembed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Ticket.TicketArchived)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
const CloseButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("confirmCloseTicket")
|
||||||
|
.setLabel(supportbot.Ticket.Close.Confirmation_Button)
|
||||||
|
.setEmoji(supportbot.Ticket.Close.Confirmation_Emoji)
|
||||||
|
.setStyle(supportbot.Ticket.Close.Confirmation_Style);
|
||||||
|
|
||||||
|
const unarchiveButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("unarchiveTicket")
|
||||||
|
.setLabel(supportbot.Buttons.Tickets.Unarchive)
|
||||||
|
.setEmoji(supportbot.Buttons.Tickets.Unarchive_Emoji)
|
||||||
|
.setStyle(supportbot.Buttons.Tickets.Unarchive_Style);
|
||||||
|
|
||||||
|
const ArchivedOptions = new Discord.ActionRowBuilder()
|
||||||
|
.addComponents(CloseButton, unarchiveButton);
|
||||||
|
|
||||||
|
await interaction.channel.send({
|
||||||
|
embeds: [arcembed],
|
||||||
|
components: [ArchivedOptions],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await interaction.channel.setArchived(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
await interaction.channel.setParent(supportbot.Ticket.TicketArchiveCategory);
|
||||||
|
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketInfo = ticketData.tickets.find(t => t.id === interaction.channel.id);
|
||||||
|
|
||||||
|
if (ticketInfo) {
|
||||||
|
const user = interaction.guild.members.cache.get(ticketInfo.user) || ticketInfo.user;
|
||||||
|
const claimedBy = interaction.guild.members.cache.get(ticketInfo.claimedBy) || ticketInfo.claimedBy;
|
||||||
|
const Admin = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Admin);
|
||||||
|
const Staff = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Staff);
|
||||||
|
|
||||||
|
if (user && user.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(user.id, {
|
||||||
|
ViewChannel: false,
|
||||||
|
SendMessages: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.ClaimTickets === true) {
|
||||||
|
if (claimedBy && claimedBy.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(claimedBy.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.ClaimTickets === false) {
|
||||||
|
if (Staff && Staff.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(claimedBy.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Admin && Admin.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(Admin.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.channel.permissionOverwrites.edit(interaction.guild.roles.everyone.id, {
|
||||||
|
ViewChannel: false,
|
||||||
|
SendMessages: false,
|
||||||
|
ReadMessageHistory: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "lockticket":
|
||||||
|
const lockembed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Ticket.TicketLocked)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
const unlockButton = new Discord.ButtonBuilder()
|
||||||
|
.setCustomId("unlockTicket")
|
||||||
|
.setLabel(supportbot.Buttons.Tickets.Unlock)
|
||||||
|
.setEmoji(supportbot.Buttons.Tickets.Unlock_Emoji)
|
||||||
|
.setStyle(supportbot.Buttons.Tickets.Unlock_Style);
|
||||||
|
|
||||||
|
const LockedOptions = new Discord.ActionRowBuilder()
|
||||||
|
.addComponents(unlockButton);
|
||||||
|
|
||||||
|
await interaction.channel.send({
|
||||||
|
embeds: [lockembed],
|
||||||
|
components: [LockedOptions],
|
||||||
|
ephemeral: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await interaction.channel.setLocked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "unlockTicket":
|
||||||
|
const unlockEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Ticket.TicketUnlocked)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.channel.send({
|
||||||
|
embeds: [unlockEmbed],
|
||||||
|
ephemeral: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await interaction.channel.setLocked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "enableinvites":
|
||||||
|
await handleInvites(interaction, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "disableinvites":
|
||||||
|
await handleInvites(interaction, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "renameticket":
|
||||||
|
const modal = new Discord.ModalBuilder()
|
||||||
|
.setCustomId("renameTicketModal")
|
||||||
|
.setTitle("Rename Channel")
|
||||||
|
.addComponents(
|
||||||
|
new Discord.ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new Discord.TextInputBuilder()
|
||||||
|
.setCustomId("renameTicket")
|
||||||
|
.setLabel("New Channel Name")
|
||||||
|
.setStyle(Discord.TextInputStyle.Short)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
await interaction.showModal(modal);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.customId === 'deleteSupportVC') {
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketInfo = ticketData.tickets.find(t => t.id === interaction.channel.id);
|
||||||
|
|
||||||
|
if (ticketInfo && ticketInfo.voiceChannelId) {
|
||||||
|
try {
|
||||||
|
const voiceChannel = await interaction.guild.channels.fetch(ticketInfo.voiceChannelId).catch(() => null);
|
||||||
|
|
||||||
|
if (voiceChannel) {
|
||||||
|
await voiceChannel.delete();
|
||||||
|
|
||||||
|
const successEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription('✅ Support voice channel has been successfully deleted!')
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [successEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
ticketInfo.voiceChannelId = null;
|
||||||
|
fs.writeFileSync("./Data/TicketData.json", JSON.stringify(ticketData, null, 2));
|
||||||
|
} else {
|
||||||
|
const errorEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription('❌ The associated voice channel could not be found.')
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting the Voice Channel:', error);
|
||||||
|
|
||||||
|
const errorEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription('❌ **There was an error trying to delete this voice channel. Please try again later.**')
|
||||||
|
.setColor(supportbot.Embed.Colours.Error);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const errorEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription('⚠️ This button is not linked to a valid voice channel.')
|
||||||
|
.setColor(supportbot.Embed.Colours.Warn);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [errorEmbed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (interaction.isButton()) {
|
||||||
|
if (interaction.customId === "unarchiveTicket") {
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await interaction.channel.setArchived(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
await interaction.channel.setParent(supportbot.Ticket.TicketChannelsCategory);
|
||||||
|
|
||||||
|
const ticketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||||
|
const ticketInfo = ticketData.tickets.find(t => t.id === interaction.channel.id);
|
||||||
|
|
||||||
|
if (ticketInfo) {
|
||||||
|
const user = interaction.guild.members.cache.get(ticketInfo.user) || ticketInfo.user;
|
||||||
|
const claimedBy = interaction.guild.members.cache.get(ticketInfo.claimedBy) || ticketInfo.claimedBy;
|
||||||
|
const Admin = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Admin);
|
||||||
|
const Staff = await interaction.guild.roles.fetch(supportbot.Roles.StaffMember.Staff);
|
||||||
|
|
||||||
|
if (user && user.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(user.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.ClaimTickets === true) {
|
||||||
|
if (claimedBy && claimedBy.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(claimedBy.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.ClaimTickets === false) {
|
||||||
|
if (Staff && Staff.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(claimedBy.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Admin && Admin.id) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(Admin.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.channel.permissionOverwrites.edit(interaction.guild.roles.everyone.id, {
|
||||||
|
ViewChannel: false,
|
||||||
|
SendMessages: false,
|
||||||
|
ReadMessageHistory: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const unrcembed = new Discord.EmbedBuilder()
|
||||||
|
.setDescription(msgconfig.Ticket.TicketUnarchived)
|
||||||
|
.setColor(supportbot.Embed.Colours.Success);
|
||||||
|
|
||||||
|
await interaction.update({
|
||||||
|
embeds: [unrcembed],
|
||||||
|
components: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.customId === "createticket") {
|
||||||
|
if (supportbot.Ticket.TicketReason) {
|
||||||
|
const modal = new Discord.ModalBuilder()
|
||||||
|
.setCustomId("ticketReasonModal")
|
||||||
|
.setTitle("Ticket Reason")
|
||||||
|
.addComponents(
|
||||||
|
new Discord.ActionRowBuilder().addComponents(
|
||||||
|
new Discord.TextInputBuilder()
|
||||||
|
.setCustomId("reasonInput")
|
||||||
|
.setLabel("Reason")
|
||||||
|
.setStyle(Discord.TextInputStyle.Paragraph)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await interaction.showModal(modal);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
|
||||||
|
if (!cmd) return;
|
||||||
|
await cmd.run(interaction);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error executing the ticket command:", error);
|
||||||
|
await interaction.reply({
|
||||||
|
content: "An error occurred while creating the ticket.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.customId === "openticket") {
|
||||||
|
if (supportbot.Ticket.TicketReason) {
|
||||||
|
const modal = new Discord.ModalBuilder()
|
||||||
|
.setCustomId("ticketReasonModal")
|
||||||
|
.setTitle("Ticket Reason")
|
||||||
|
.addComponents(
|
||||||
|
new Discord.ActionRowBuilder().addComponents(
|
||||||
|
new Discord.TextInputBuilder()
|
||||||
|
.setCustomId("reasonInput")
|
||||||
|
.setLabel("Reason")
|
||||||
|
.setStyle(Discord.TextInputStyle.Paragraph)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await interaction.showModal(modal);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
|
||||||
|
if (!cmd) return;
|
||||||
|
await cmd.run(interaction);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.customId.startsWith("claimticket-")) {
|
||||||
|
const ticketChannelId = interaction.customId.split("-")[1];
|
||||||
|
const ticketChannel = interaction.guild.channels.cache.get(ticketChannelId);
|
||||||
|
if (!ticketChannel) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: "Ticket channel not found.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportbot.Ticket.TicketType === "threads") {
|
||||||
|
await ticketChannel.members.add(interaction.user.id);
|
||||||
|
|
||||||
|
} else if (supportbot.Ticket.TicketType === "channels") {
|
||||||
|
await ticketChannel.permissionOverwrites.create(interaction.user.id, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await ticketChannel.permissionOverwrites.create(Admin, {
|
||||||
|
ViewChannel: true,
|
||||||
|
SendMessages: true,
|
||||||
|
ReadMessageHistory: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await ticketChannel.permissionOverwrites.create(interaction.guild.roles.everyone, {
|
||||||
|
ViewChannel: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// SUGGESTION INTERACTIONS [START]
|
||||||
|
|
||||||
|
if (
|
||||||
|
interaction.customId === "upvote" ||
|
||||||
|
interaction.customId === "downvote" ||
|
||||||
|
interaction.customId === "removevote"
|
||||||
|
) {
|
||||||
|
const suggestion = suggestions[interaction.message.id];
|
||||||
|
if (!suggestion)
|
||||||
|
return interaction.reply({ content: "Suggestion not found.", ephemeral: true });
|
||||||
|
|
||||||
|
const userId = interaction.user.id;
|
||||||
|
const hasUpvoted = suggestion.upvotes.includes(userId);
|
||||||
|
const hasDownvoted = suggestion.downvotes.includes(userId);
|
||||||
|
|
||||||
|
if (interaction.customId === "upvote") {
|
||||||
|
if (hasUpvoted) {
|
||||||
|
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
|
||||||
|
} else {
|
||||||
|
suggestion.upvotes.push(userId);
|
||||||
|
if (hasDownvoted) {
|
||||||
|
suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (interaction.customId === "downvote") {
|
||||||
|
if (hasDownvoted) {
|
||||||
|
suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId);
|
||||||
|
} else {
|
||||||
|
suggestion.downvotes.push(userId);
|
||||||
|
if (hasUpvoted) {
|
||||||
|
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (interaction.customId === "removevote") {
|
||||||
|
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
|
||||||
|
suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync("./Data/SuggestionData.json", JSON.stringify(suggestions, null, 2));
|
||||||
|
|
||||||
|
const upvoteCount = suggestion.upvotes.length;
|
||||||
|
const downvoteCount = suggestion.downvotes.length;
|
||||||
|
|
||||||
|
const updatedEmbed = new Discord.EmbedBuilder(interaction.message.embeds[0].data).setFields([
|
||||||
|
{ name: "Suggestion", value: suggestion.suggestion, inline: true },
|
||||||
|
{ name: "From", value: `<@${suggestion.author}>` },
|
||||||
|
{
|
||||||
|
name: `${supportbot.Suggestions.UpvoteEmoji} ${supportbot.Suggestions.UpvoteTitle}`,
|
||||||
|
value: `${upvoteCount}`,
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `${supportbot.Suggestions.DownvoteEmoji} ${supportbot.Suggestions.DownvoteTitle}`,
|
||||||
|
value: `${downvoteCount}`,
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
await interaction.update({ embeds: [updatedEmbed] });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleInvites(interaction, enable) {
|
||||||
|
if (supportbot.Ticket.Invites.StaffOnly) {
|
||||||
|
const { getRole, getChannel } = interaction.client;
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modal submission handler for editing profile
|
||||||
|
if (interaction.type === Discord.InteractionType.ModalSubmit && interaction.customId === "editProfileModal") {
|
||||||
|
const userId = interaction.user.id;
|
||||||
|
const profilePath = `./Data/Profiles/${userId}.json`;
|
||||||
|
|
||||||
|
let profileData;
|
||||||
|
if (fs.existsSync(profilePath)) {
|
||||||
|
profileData = JSON.parse(fs.readFileSync(profilePath, "utf8"));
|
||||||
|
} else {
|
||||||
|
profileData = {
|
||||||
|
bio: "",
|
||||||
|
timezone: "",
|
||||||
|
clockedIn: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const newBio = interaction.fields.getTextInputValue("bio");
|
||||||
|
const newTimezone = interaction.fields.getTextInputValue("timezone");
|
||||||
|
|
||||||
|
profileData.bio = newBio;
|
||||||
|
profileData.timezone = newTimezone;
|
||||||
|
|
||||||
|
fs.writeFileSync(profilePath, JSON.stringify(profileData, null, 2));
|
||||||
|
|
||||||
|
const updatedProfileEmbed = new Discord.EmbedBuilder()
|
||||||
|
.setTitle(`${interaction.user.username}'s Profile`)
|
||||||
|
.setColor(supportbot.Embed.Colours.General)
|
||||||
|
.setThumbnail(interaction.user.displayAvatarURL())
|
||||||
|
.addFields(
|
||||||
|
{ name: "Bio", value: newBio || "No bio set.", inline: false },
|
||||||
|
{ name: "Timezone", value: newTimezone || "No timezone set.", inline: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (profileData.clockedIn !== undefined) {
|
||||||
|
updatedProfileEmbed.addFields({
|
||||||
|
name: "Clocked In Status",
|
||||||
|
value: profileData.clockedIn ? "✅ Clocked In" : "❌ Clocked Out",
|
||||||
|
inline: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.reply({ embeds: [updatedProfileEmbed], ephemeral: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to update profile data: ", error);
|
||||||
|
await interaction.reply({
|
||||||
|
content: "There was an error while updating your profile. Please try again later.",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
const { EmbedBuilder } = require('discord.js');
|
||||||
|
const fs = require("fs");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
const Event = require("../Structures/Event.js");
|
||||||
|
|
||||||
|
// Load the configuration files
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
|
||||||
|
module.exports = new Event("messageDelete", async (client, message) => {
|
||||||
|
|
||||||
|
// Check if the message is from a guild and not from a bot
|
||||||
|
if (!message.guild || message.author.bot) return;
|
||||||
|
|
||||||
|
// Get the delete log channel either by ID or by name
|
||||||
|
const deleteLogChannel = message.guild.channels.cache.get(supportbot.MessageDelete.Channel) ||
|
||||||
|
message.guild.channels.cache.find(channel => channel.name === supportbot.MessageDelete.Channel);
|
||||||
|
|
||||||
|
// Create the embed for the deleted message
|
||||||
|
const deletedMessageEmbed = new EmbedBuilder()
|
||||||
|
.setColor(supportbot.MessageDelete.Colour)
|
||||||
|
.setTitle("Message Deleted")
|
||||||
|
.setDescription(`> **Channel:** <#${message.channel.id}>\n> **Message ID** [${message.id}](https://discord.com/channels/${message.guild.id}/${message.channel.id}/${message.id})\n> **Message author:** ${message.author.tag} (${message.author.id})\n> **Message Crated:** <t:${Math.floor(message.createdTimestamp / 1000)}:F>`)
|
||||||
|
.addFields(
|
||||||
|
{ name: 'Message', value: message.content || '*No content*', inline: false }
|
||||||
|
)
|
||||||
|
.setThumbnail(message.author.displayAvatarURL())
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
// If the message contains an attachment, add it to the embed
|
||||||
|
if (message.attachments.size > 0) {
|
||||||
|
const attachment = message.attachments.first();
|
||||||
|
deletedMessageEmbed.addFields({ name: 'Attachment', value: `[${attachment.name}](${attachment.proxyURL})` });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the embed to the delete log channel if the channel is found
|
||||||
|
if (deleteLogChannel) {
|
||||||
|
deleteLogChannel.send({
|
||||||
|
embeds: [deletedMessageEmbed]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
const { EmbedBuilder } = require('discord.js');
|
||||||
|
const fs = require("fs");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
const Event = require("../Structures/Event.js");
|
||||||
|
|
||||||
|
// Load the configuration files
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||||
|
|
||||||
|
module.exports = new Event("messageUpdate", async (client, oldMessage, newMessage) => {
|
||||||
|
|
||||||
|
// Check if the message is from a guild and not from a bot
|
||||||
|
if (!newMessage.guild || newMessage.author.bot) return;
|
||||||
|
|
||||||
|
// Fetch old message if it's not cached (important for message content)
|
||||||
|
if (!oldMessage.content && oldMessage.partial) {
|
||||||
|
try {
|
||||||
|
oldMessage = await oldMessage.fetch();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error fetching old message:', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback if content is missing
|
||||||
|
const oldMessageContent = oldMessage.content || (oldMessage.attachments.size > 0 ? 'Contains attachment(s)' : '*No content*');
|
||||||
|
const newMessageContent = newMessage.content || (newMessage.attachments.size > 0 ? 'Contains attachment(s)' : '*No content*');
|
||||||
|
|
||||||
|
// Get the update log channel either by ID or by name
|
||||||
|
const updateLogChannel = newMessage.guild.channels.cache.get(supportbot.MessageUpdate.Channel) ||
|
||||||
|
newMessage.guild.channels.cache.find(channel => channel.name === supportbot.MessageUpdate.Channel);
|
||||||
|
|
||||||
|
// Create the embed for the updated message
|
||||||
|
const updatedMessageEmbed = new EmbedBuilder()
|
||||||
|
.setColor(supportbot.MessageUpdate.Colour)
|
||||||
|
.setTitle("Message Updated")
|
||||||
|
.setDescription(`> **Channel:** <#${newMessage.channel.id}>\n> **Message ID:** [${newMessage.id}](https://discord.com/channels/${newMessage.guild.id}/${newMessage.channel.id}/${newMessage.id})\n> **Message author:** ${newMessage.author.tag} (${newMessage.author.id})\n> **Message Created:** <t:${Math.floor(oldMessage.createdTimestamp / 1000)}:F>`)
|
||||||
|
.addFields(
|
||||||
|
{ name: 'Old Message', value: oldMessageContent, inline: false },
|
||||||
|
{ name: 'New Message', value: newMessageContent, inline: false }
|
||||||
|
)
|
||||||
|
.setThumbnail(newMessage.author.displayAvatarURL())
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
// If the new message contains an attachment, add it to the embed
|
||||||
|
if (newMessage.attachments.size > 0) {
|
||||||
|
const attachment = newMessage.attachments.first();
|
||||||
|
updatedMessageEmbed.addFields({ name: 'Attachment', value: `[${attachment.name}](${attachment.proxyURL})` });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the embed to the update log channel if the channel is found
|
||||||
|
if (updateLogChannel) {
|
||||||
|
updateLogChannel.send({
|
||||||
|
embeds: [updatedMessageEmbed]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
+143
@@ -0,0 +1,143 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Ready Event
|
||||||
|
|
||||||
|
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(
|
||||||
|
fs.readFileSync("./Configs/supportbot.yml", "utf8")
|
||||||
|
);
|
||||||
|
const panelconfig = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/ticket-panel.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");
|
||||||
|
|
||||||
|
let chan1 = client.channels.cache.get(supportbot.Ticket.TicketHome);
|
||||||
|
|
||||||
|
module.exports = new Event("ready", async (client, interaction) => {
|
||||||
|
const { getRole, getChannel, getCategory } = client;
|
||||||
|
|
||||||
|
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[33m`, `――――――――――――――――――――――――――――――――――――――――――――`);
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[31m`, `┏━━━┓╋╋╋╋╋╋╋╋╋╋╋╋╋┏┓┏━━┓╋╋╋┏┓`);
|
||||||
|
console.log(`\u001b[31m`, `┃┏━┓┃╋╋╋╋╋╋╋╋╋╋╋╋┏┛┗┫┏┓┃╋╋┏┛┗┓`);
|
||||||
|
console.log(`\u001b[31m`, `┃┗━━┳┓┏┳━━┳━━┳━━┳┻┓┏┫┗┛┗┳━┻┓┏┛`);
|
||||||
|
console.log(`\u001b[31m`, `┗━━┓┃┃┃┃┏┓┃┏┓┃┏┓┃┏┫┃┃┏━┓┃┏┓┃┃`);
|
||||||
|
console.log(`\u001b[31m`, `┃┗━┛┃┗┛┃┗┛┃┗┛┃┗┛┃┃┃┗┫┗━┛┃┗┛┃┗┓`);
|
||||||
|
console.log(`\u001b[31m`, `┗━━━┻━━┫┏━┫┏━┻━━┻┛┗━┻━━━┻━━┻━┛`);
|
||||||
|
console.log(`\u001b[31m`, `┗╋╋╋╋╋╋╋┃┃╋┃┃`);
|
||||||
|
console.log(`\u001b[31m`, `╋╋╋╋╋╋╋┗┛╋┗┛`);
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[33m`, `――――――――――――――――――――――――――――――――――――――――――――`);
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[33m`, `${supportbot.General.Name} | [${supportbot.SupportBot_Version}]`, `\u001b[32m`, `Connected to Discord`,);
|
||||||
|
console.log("\u001b[32m", "SupportBot created by Emerald Development ");
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[33m`, `――――――――――――――――― [Links] ――――――――――――――――――`);
|
||||||
|
console.log("\u001b[32m", "Discord: https://dsc.gg/emerald-dev");
|
||||||
|
console.log("\u001b[32m", "Website: https://emeraldsrv.com");
|
||||||
|
console.log("\u001b[32m", "Community: https://community.emeraldsrv.com");
|
||||||
|
console.log("\u001b[32m", "Documentation: https://docs.emeraldsrv.com");
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[33m`, `――――――――――――――――― [Invite] ――――――――――――――――――`);
|
||||||
|
console.log("\u001b[32m", `Invite URL: https://discord.com/api/oauth2/authorize?client_id=${client.user.id}&permissions=8&scope=bot%20applications.commands`);
|
||||||
|
console.log(` `);
|
||||||
|
console.log(`\u001b[33m`, `――――――――――――――――― [Config Check] ――――――――――――――――――`);
|
||||||
|
console.log("\u001b[32m", "Config initialization...");
|
||||||
|
|
||||||
|
const roles = [
|
||||||
|
supportbot.Roles.StaffMember.Admin,
|
||||||
|
supportbot.Roles.StaffMember.Staff
|
||||||
|
];
|
||||||
|
|
||||||
|
if (supportbot.Roles.AutoRole.Role) roles.push(supportbot.Roles.AutoRole.Role);
|
||||||
|
|
||||||
|
const channels = [
|
||||||
|
supportbot.Suggestions.Channel,
|
||||||
|
supportbot.Ticket.Log.TicketLog,
|
||||||
|
supportbot.Ticket.Log.TranscriptLog,
|
||||||
|
supportbot.Ticket.TicketHome,
|
||||||
|
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 r of roles) {
|
||||||
|
const find = await getRole(r, client.guilds.cache.first());
|
||||||
|
if (!find) missingR.push(r);
|
||||||
|
}
|
||||||
|
// for (let cat of categories) {
|
||||||
|
// const find = await getCategory(cat, client.guilds.cache.first());
|
||||||
|
// if (!find) missingCat.push(cat);
|
||||||
|
// }
|
||||||
|
|
||||||
|
const missingRoles = await Promise.all(roles.map(role => getRole(role, client.guilds.cache.first())));
|
||||||
|
const missingChannels = await Promise.all(channels.map(channel => getChannel(channel, client.guilds.cache.first())));
|
||||||
|
|
||||||
|
if (missingRoles.some(role => !role)) {
|
||||||
|
console.log("\u001b[31m", `Missing roles in your server configuration: ${missingRoles.filter(role => !role).join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingChannels.some(channel => !channel)) {
|
||||||
|
console.log("\u001b[31m", `Missing channels in your server configuration: ${missingChannels.filter(channel => !channel).join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\u001b[32m", "Configs initialized, No problems were detected.");
|
||||||
|
console.log(` `);
|
||||||
|
|
||||||
|
});
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2021 Emerald Services
|
Copyright (c) 2024 Emerald Services
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
@@ -1,13 +1,96 @@
|
|||||||

|
<h1 align="center">
|
||||||
|
<br>
|
||||||
|
<a href="https://github.com/Emerald-Services/SupportBot"><img src="https://i.imgur.com/cuadAYv.png"></a>
|
||||||
|
<br>
|
||||||
|
SupportBot
|
||||||
|
<br>
|
||||||
|
</h1>
|
||||||
|
|
||||||
## What is SupportBot?
|
<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%20-%20v14-blue?style=for-the-badge" alt="shield.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://github.com/nodejs/node">
|
||||||
|
<img src="https://img.shields.io/badge/NODE.JS%20-%20v20.x-green?style=for-the-badge" 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>
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
| SupportBot | Node.JS | Discord.JS | Supported |
|
||||||
|
|------------|---------|------------|------------|
|
||||||
|
| 8.x | 20.x | 14.x. | ✅ Yes
|
||||||
|
| 7.7.3 | 16.x | 13.x. | ✅ Yes
|
||||||
|
| 7.x | 16.x | 13.x. | ❌ No
|
||||||
|
| 6.x | 14.x | 13.x. | ❌ No
|
||||||
|
| 5.x | 12.x | 13.x. | ❌ No
|
||||||
|
| 4.x | 11.x | 13.x. | ❌ No
|
||||||
|
| Older | 10.x | 13.x. | ❌ No
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://emeraldsrv.com/">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="https://github.com/Emerald-Services/SupportBot/wiki/Third-Party-Developer">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.com/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
|
||||||
|
|
||||||
|
- [Official addons repository](https://github.com/Emerald-Services/Addons/)
|
||||||
|
- [Syphers Addons](https://github.com/SypherRed/SB_Addons_Unofficial)
|
||||||
|
- [BuiltByBit](https://builtbybit.com/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>
|
||||||
|
|
||||||
|
## Hosting
|
||||||
|
|
||||||
|
You can use our [Pterodactyl egg](https://github.com/Emerald-Services/Pterodactyl-Egg) to host it on your own panel. We currently don't offer hosting for you, altough we might add this in the future.
|
||||||
|
If you don't know how to install pterodactyl, you could always host it on replit:
|
||||||
|
|
||||||
|
[]([https://repl.it/github/ItsNyoty/iki](https://repl.it/github/Emerald-Services/SupportBot
|
||||||
|
)
|
||||||
|
|
||||||
SupportBot is an open-sourced support system for discord. It's completely free to use with high amounts of customisation to match your own brand.
|
|
||||||
|
|
||||||
## Quick Links
|
|
||||||
|
|
||||||
**|** [Discord](https://emeraldsrv.dev/discord) **|**
|
|
||||||
[Hosting](https://emeraldsrv.dev/hosting) **|**
|
|
||||||
[Documentation](https://docs.emeraldsrv.dev) **|**
|
|
||||||
[Download via Polymart](https://polymart.org/resource/supportbot-1-discord-ticket-bot.518) **|**
|
|
||||||
[Download via MC-Market](https://www.mc-market.org/resources/8940/) **|**
|
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Use this section to tell people about which versions of your project are
|
||||||
|
currently being supported with security updates.
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 7.7.2 | :white_check_mark: |
|
||||||
|
| 7.7.1 | :white_check_mark: |
|
||||||
|
| < 4.0 | :x: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Use this section to tell people how to report a vulnerability.
|
||||||
|
|
||||||
|
Tell them where to go, how often they can expect to get an update on a
|
||||||
|
reported vulnerability, what to expect if the vulnerability is accepted or
|
||||||
|
declined, etc.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Addon Structure
|
||||||
|
class Command {
|
||||||
|
constructor(options) {
|
||||||
|
this.name = options.name;
|
||||||
|
this.description = options.description;
|
||||||
|
this.permissions = options.permissions;
|
||||||
|
this.options = options.options || [];
|
||||||
|
this.run = options.run;
|
||||||
|
this.defaultPermission = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to dynamically update options
|
||||||
|
setOptions(options) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Event {
|
||||||
|
constructor(event, run) {
|
||||||
|
this.event = event;
|
||||||
|
this.run = run;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { Command, Event };
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const { GatewayIntentBits, Partials } = require('discord.js');
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
const { Command, Event } = require('./Addon.js'); // Adjust the path as needed
|
||||||
|
|
||||||
|
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||||
|
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||||
|
|
||||||
|
class Client extends Discord.Client {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
intents: [
|
||||||
|
GatewayIntentBits.Guilds,
|
||||||
|
GatewayIntentBits.GuildMembers,
|
||||||
|
GatewayIntentBits.GuildMessages,
|
||||||
|
GatewayIntentBits.MessageContent
|
||||||
|
],
|
||||||
|
partials: [Partials.Message, Partials.Channel]
|
||||||
|
});
|
||||||
|
|
||||||
|
this.commands = new Discord.Collection();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getChannel(channel, guild) {
|
||||||
|
if (!channel) return null; // Add check for undefined channel
|
||||||
|
return guild.channels.cache.find(
|
||||||
|
(c) =>
|
||||||
|
(c.type === Discord.ChannelType.GuildText || c.type === Discord.ChannelType.GuildNews) &&
|
||||||
|
(c.id === channel || (c.name && c.name.toLowerCase() === channel.toLowerCase()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRole(role, guild) {
|
||||||
|
if (!role) return null; // Add check for undefined role
|
||||||
|
return guild.roles.cache.find(
|
||||||
|
(r) => r.id === role || (r.name && r.name.toLowerCase() === role.toLowerCase())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCategory(category, guild) {
|
||||||
|
if (!category) return null; // Add check for undefined category
|
||||||
|
return guild.channels.cache.find(
|
||||||
|
(c) =>
|
||||||
|
c.type === Discord.ChannelType.GuildCategory &&
|
||||||
|
(c.id === category || (c.name && c.name.toLowerCase() === category.toLowerCase()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async start(token) {
|
||||||
|
let tempCommandFiles = fs.readdirSync("./Commands").filter((file) => file.endsWith(".js"));
|
||||||
|
|
||||||
|
if (cmdconfig.Suggestion.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "suggest.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Help.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "help.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Info.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "info.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.OpenTicket.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "ticket.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.CloseTicket.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "close.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Embed.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "embed.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Translate.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "translate.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.UserInfo.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "userinfo.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Ping.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "Ping.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.AddUser.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "addUser.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.RemoveUser.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "removeUser.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.ForceAddUser.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "forceaddUser.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Profile.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "profile.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Settings.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "settings.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdconfig.Mod.Enabled === false) {
|
||||||
|
tempCommandFiles = tempCommandFiles.filter(item => item !== "mod.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandFiles = tempCommandFiles;
|
||||||
|
const commands = commandFiles.map((file) => require(`../Commands/${file}`));
|
||||||
|
|
||||||
|
// Load main commands
|
||||||
|
console.log(`\u001b[33m`, "――――――――――――――――――――――――――――――――――――――――――――");
|
||||||
|
|
||||||
|
commands.forEach((cmd) => {
|
||||||
|
console.log(`\u001b[32m`, `[CMD]`, `\u001b[37;1m`, `${cmd.name}`, `\u001b[32;1m`, "Loaded");
|
||||||
|
this.commands.set(cmd.name, cmd);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load addon commands and events
|
||||||
|
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Commands ▬▬▬▬▬▬▬");
|
||||||
|
|
||||||
|
if (supportbot.General.Addons.Enabled) {
|
||||||
|
const addonFiles = fs.readdirSync("./Addons").filter((file) => file.endsWith(".js"));
|
||||||
|
|
||||||
|
const addons = addonFiles.map((file) => {
|
||||||
|
const addon = require(`../Addons/${file}`);
|
||||||
|
addon.name = file.split(".")[0];
|
||||||
|
return addon;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Addons
|
||||||
|
console.log(" ");
|
||||||
|
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Addons ▬▬▬▬▬▬▬");
|
||||||
|
|
||||||
|
addons.forEach((addon) => {
|
||||||
|
console.log(
|
||||||
|
`\u001b[32m`,
|
||||||
|
`[ADDON]`,
|
||||||
|
`\u001b[37;1m`,
|
||||||
|
`${addon.name}`,
|
||||||
|
`\u001b[32;1m`,
|
||||||
|
"Loaded"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (addon instanceof Command) {
|
||||||
|
this.commands.set(addon.name, addon);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addon.events && Array.isArray(addon.events)) {
|
||||||
|
addon.events.forEach((event) => {
|
||||||
|
if (event instanceof Event) {
|
||||||
|
this.on(event.event, (...args) => event.run(this, ...args));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Addons ▬▬▬▬▬▬▬");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register Slash Commands
|
||||||
|
|
||||||
|
this.once("ready", async () => {
|
||||||
|
await this.guilds.cache.first()?.commands.set(this.commands);
|
||||||
|
console.log(
|
||||||
|
"\u001b[32m",
|
||||||
|
`[SUCCESS]`,
|
||||||
|
`\u001b[37;1m`,
|
||||||
|
`Slash Commands Registered for ${this.guilds.cache.first().name}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(" ");
|
||||||
|
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Events ▬▬▬▬▬▬▬");
|
||||||
|
|
||||||
|
fs.readdirSync("./Events").filter((file) => file.endsWith(".js")).forEach((file) => {
|
||||||
|
const event = require(`../Events/${file}`);
|
||||||
|
console.log(`\u001b[32m`, `[EVENT]`, `\u001b[37;1m`, `${event.event}`, `\u001b[32;1m`, "Loaded");
|
||||||
|
this.on(event.event, (...args) => event.run(this, ...args));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Events ▬▬▬▬▬▬▬");
|
||||||
|
if (process.argv[2] !== "test") {
|
||||||
|
await this.login(token);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`\u001b[31;1m`,
|
||||||
|
"RUNNING IN TEST MODE, IF NOT INTENDED, PLEASE USE npm start"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Client;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Command Structure
|
||||||
|
|
||||||
|
class Command {
|
||||||
|
constructor(options) {
|
||||||
|
this.name = options.name;
|
||||||
|
this.description = options.description;
|
||||||
|
this.permissions = options.permissions || [];
|
||||||
|
this.options = options.options || [];
|
||||||
|
this.run = options.run;
|
||||||
|
this.defaultPermission = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = Command;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Event Structure
|
||||||
|
class Event {
|
||||||
|
constructor(event, run) {
|
||||||
|
this.event = event;
|
||||||
|
this.run = run;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Event;
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// SupportBot | Emerald Services
|
||||||
|
// Ticket ID Structure
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
class TicketNumberID {
|
||||||
|
static async pad() {
|
||||||
|
let num = await this.get();
|
||||||
|
let n = num + "";
|
||||||
|
await this.set(num + 1);
|
||||||
|
return n.length >= 4 ? n : new Array(4 - n.length + 1).join("0") + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async get() {
|
||||||
|
let ticketnumberID = await JSON.parse(
|
||||||
|
fs.readFileSync("./Data/ticket-panel-id.json", "utf8")
|
||||||
|
);
|
||||||
|
if (!ticketnumberID.id) {
|
||||||
|
return this.set(0);
|
||||||
|
} else {
|
||||||
|
return ticketnumberID.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async set(value) {
|
||||||
|
let ticketnumberID = await JSON.parse(
|
||||||
|
fs.readFileSync("./Data/ticket-panel-id.json", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
ticketnumberID.id = value;
|
||||||
|
fs.writeFileSync(
|
||||||
|
"./Data/ticket-panel-id.json",
|
||||||
|
JSON.stringify(ticketnumberID, null, 4),
|
||||||
|
(err) => {
|
||||||
|
if (err) console.error(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async reset() {
|
||||||
|
return await this.set(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TicketNumberID;
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Help Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
|
|
||||||
// location for the addons configuration, to keep it simple we generate a settings folder within the addons directory.
|
|
||||||
const example = yaml.load(fs.readFileSync('./addons/settings/exampleaddon.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: example.ExampleAddonCommand,
|
|
||||||
description: example.ExampleAddonDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
if (supportbot.DeleteMessages == "true") message.delete();
|
|
||||||
message.channel.send(example.ExampleAddonMessage)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Vendored
BIN
Binary file not shown.
@@ -1,9 +0,0 @@
|
|||||||
#
|
|
||||||
# SupportBot, Created by Emerald Services
|
|
||||||
# Example Addon
|
|
||||||
#
|
|
||||||
|
|
||||||
ExampleAddonCommand: "exampleaddon"
|
|
||||||
ExampleAddonDesc: "This is the default/example addon for SupportBot."
|
|
||||||
|
|
||||||
ExampleAddonMessage: "> :white_check_mark: This is the **default** addon for SupportBot. You can download addons from our website, https://emeraldservices.xyz/"
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Add User
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.AddUser,
|
|
||||||
description: supportbot.AddUserDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let SupportStaff = message.guild.roles.cache.find(SupportTeam => SupportTeam.name === supportbot.Staff) || message.guild.roles.cache.find(SupportTeam => SupportTeam.id === supportbot.Staff)
|
|
||||||
let Admins = message.guild.roles.cache.find(AdminUser => AdminUser.name === supportbot.Admin) || message.guild.roles.cache.find(AdminUser => AdminUser.id === supportbot.Admin)
|
|
||||||
|
|
||||||
const NoPerms = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Permissions!")
|
|
||||||
.setDescription(`${supportbot.IncorrectPerms}\n\nRole Required: \`${supportbot.Staff}\` or \`${supportbot.Admin}\``)
|
|
||||||
.setColor(supportbot.WarningColour)
|
|
||||||
|
|
||||||
if (message.member.roles.cache.has(SupportStaff.id) || message.member.roles.cache.has(Admins.id)) {
|
|
||||||
if (!message.channel.name.startsWith( `${supportbot.TicketChannel}-` )) {
|
|
||||||
const Exists = new Discord.MessageEmbed()
|
|
||||||
.setTitle("No Ticket Found!")
|
|
||||||
.setDescription(`${supportbot.NoValidTicket}`)
|
|
||||||
.setColor(supportbot.WarningColour);
|
|
||||||
message.channel.send({ embed: Exists });
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let rUser = message.guild.member(message.mentions.users.first() || message.guild.members.cache.get(args[0]));
|
|
||||||
const UserNotExist = new Discord.MessageEmbed()
|
|
||||||
.setTitle("User Not Found!")
|
|
||||||
.setDescription(`${supportbot.UserNotFound}\n\nTry Again:\`${supportbot.Prefix}${supportbot.AddUser} <user#0000>\``)
|
|
||||||
.setColor(supportbot.ErrorColour)
|
|
||||||
|
|
||||||
if (!rUser) return message.channel.send({ embed: UserNotExist });
|
|
||||||
|
|
||||||
message.channel.updateOverwrite(rUser, {
|
|
||||||
VIEW_CHANNEL: true,
|
|
||||||
CREATE_INVITE: false,
|
|
||||||
SEND_MESSAGES: true,
|
|
||||||
READ_MESSAGES: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const Complete = new Discord.MessageEmbed()
|
|
||||||
.setTitle("User Added!")
|
|
||||||
.setDescription(supportbot.AddedUser.replace(/%user%/g, rUser.id))
|
|
||||||
.setTimestamp()
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
message.channel.send({ embed: Complete });
|
|
||||||
} else {
|
|
||||||
|
|
||||||
return message.channel.send({ embed: NoPerms });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Announce
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const { execute } = require("./help");
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.AnnounceCommand,
|
|
||||||
description: supportbot.AnnounceDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let locateChannel = message.guild.channels.cache.find(AnnouncementChannel => AnnouncementChannel.name === supportbot.AnnouncementChannel) || message.guild.channels.cache.find(AnnouncementChannel => AnnouncementChannel.id === supportbot.AnnouncementChannel)
|
|
||||||
|
|
||||||
const errornochannel = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Channel")
|
|
||||||
.setDescription(`${supportbot.InvalidChannel}\n\nChannel Required: \`${supportbot.AnnouncementChannel}`)
|
|
||||||
.setColor(supportbot.ErrorColour);
|
|
||||||
|
|
||||||
if(!locateChannel) return message.channel.send({ embed: errornochannel });
|
|
||||||
|
|
||||||
let Admins = message.guild.roles.cache.find(adminRole => adminRole.name === supportbot.Admin) || message.guild.roles.cache.find(adminRole => adminRole.id === supportbot.Admin)
|
|
||||||
|
|
||||||
const NoPerms = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Permissions!")
|
|
||||||
.setDescription(`${supportbot.IncorrectPerms}\n\nRole Required: \`${Admins.name}\``)
|
|
||||||
.setColor(supportbot.WarningColour)
|
|
||||||
|
|
||||||
if (!message.member.roles.cache.has(Admins.id))
|
|
||||||
return message.channel.send({ embed: NoPerms });
|
|
||||||
|
|
||||||
|
|
||||||
const embed = new Discord.MessageEmbed()
|
|
||||||
.setDescription(`> **${supportbot.AnnouncementStarter}**`)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
message.channel.send({ embed: embed });
|
|
||||||
|
|
||||||
let announcement = []
|
|
||||||
message.channel.awaitMessages(response => response.content.length > 2, {
|
|
||||||
max: 1,
|
|
||||||
time: 500000,
|
|
||||||
errors: ['time'],
|
|
||||||
}).then((collected) => {
|
|
||||||
announcement.push(collected.map(r => r.content));
|
|
||||||
|
|
||||||
locateChannel.send('@everyone')
|
|
||||||
const AnnouncementEmbed = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.AnnouncementTitle)
|
|
||||||
.setThumbnail(supportbot.AnnouncementIcon)
|
|
||||||
.setDescription(announcement)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
.setFooter(supportbot.EmbedFooter, message.author.displayAvatarURL());
|
|
||||||
|
|
||||||
locateChannel.send({ embed: AnnouncementEmbed }).then(async function(msg) {
|
|
||||||
const AnnouncementComplete = new Discord.MessageEmbed()
|
|
||||||
.setColor(supportbot.SuccessColour)
|
|
||||||
.setDescription(`:white_check_mark: You have successfully created an announcement. <#${locateChannel.id}>`)
|
|
||||||
message.channel.send({ embed: AnnouncementComplete })
|
|
||||||
})
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
-108
@@ -1,108 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Say Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const { execute } = require("./help");
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.BanUser,
|
|
||||||
description: supportbot.BanDesc,
|
|
||||||
|
|
||||||
execute(message, args, member) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let SupportStaff = message.guild.roles.cache.find(adminRole => adminRole.name === supportbot.Admin) || message.guild.roles.cache.find(adminRole => adminRole.id === supportbot.Admin)
|
|
||||||
|
|
||||||
const NoPerms = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Permissions!")
|
|
||||||
.setDescription(`${supportbot.IncorrectPerms}\n\nRole Required: \`${SupportStaff.name}\``)
|
|
||||||
.setColor(supportbot.WarningColour)
|
|
||||||
|
|
||||||
if (!message.member.roles.cache.has(SupportStaff.id))
|
|
||||||
return message.channel.send({ embed: NoPerms });
|
|
||||||
|
|
||||||
let locateChannel = message.guild.channels.cache.find(ModLogChannel => ModLogChannel.name === supportbot.ModLogChannel) || message.guild.channels.cache.find(ModLogChannel => ModLogChannel.id === supportbot.ModLogChannel)
|
|
||||||
|
|
||||||
const errornochannel = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Channel")
|
|
||||||
.setDescription(`${supportbot.InvalidChannel}\n\nChannel Required: \`${supportbot.ModLogChannel}\``)
|
|
||||||
.setColor(supportbot.ErrorColour);
|
|
||||||
|
|
||||||
if(!locateChannel) return message.channel.send({ embed: errornochannel });
|
|
||||||
|
|
||||||
const user = message.mentions.members.first() || message.guild.members.cache.get(args[0]);
|
|
||||||
|
|
||||||
const embed1 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :x: Please provide a reason to ban.\n\n`Try Again!`")
|
|
||||||
.setColor(supportbot.ErrorColour)
|
|
||||||
|
|
||||||
if (!args[0]) return message.channel.send({
|
|
||||||
embed: embed1
|
|
||||||
});
|
|
||||||
|
|
||||||
const embed2 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :detective: **Hmm!** Can\'t seem tp find this user.\n\n`Are they in the server?`")
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
if (!user) return message.channel.send({
|
|
||||||
embed: embed2
|
|
||||||
})
|
|
||||||
|
|
||||||
const embed3 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :x: **Err No!** Cannot punish this user!\n\n`Reason: Their permissions and or roles are greater than mine.`")
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
if(!user.bannable) return message.channel.send({
|
|
||||||
embed: embed3
|
|
||||||
});
|
|
||||||
|
|
||||||
const embed4 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :joy: **OML!** Did you really just try to ban yourself!")
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
if(user.id === message.author.id) return message.channel.send({
|
|
||||||
embed: embed4
|
|
||||||
});
|
|
||||||
|
|
||||||
let reason = args.slice(1).join(" ");
|
|
||||||
|
|
||||||
if(!reason) reason = 'No Reason Provided.';
|
|
||||||
|
|
||||||
const embed5 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :thinking: **Hmm** Something seems to have gone wrong.\n\n`Check your system for errors!`")
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
user.ban({ days: supportbot.DaysBannedFor, reason: `${reason}` }).catch(err => {
|
|
||||||
message.channel.send({ embed: embed5 })
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const successEmbed = new Discord.MessageEmbed()
|
|
||||||
.setDescription(`> :white_check_mark: **OOF!** ${user} has been banned!`)
|
|
||||||
.setColor(supportbot.SuccessColour)
|
|
||||||
message.channel.send({
|
|
||||||
embed: successEmbed
|
|
||||||
})
|
|
||||||
|
|
||||||
const logEmbed = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.BanTitle)
|
|
||||||
.setThumbnail(supportbot.ModThumbnail)
|
|
||||||
.addField('Banned User:', user)
|
|
||||||
.addField('Staff Member', message.author)
|
|
||||||
.addField('Reason:', reason)
|
|
||||||
.setFooter(supportbot.EmbedFooter)
|
|
||||||
.setColor(supportbot.BanLogColour)
|
|
||||||
.setTimestamp()
|
|
||||||
|
|
||||||
locateChannel.send({ embed: logEmbed })
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Blacklist Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const { execute } = require("./help");
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.BlacklistUser,
|
|
||||||
description: supportbot.BlacklistDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let SupportStaff = message.guild.roles.cache.find(adminRole => adminRole.name === supportbot.Admin) || message.guild.roles.cache.find(adminRole => adminRole.id === supportbot.Admin)
|
|
||||||
|
|
||||||
const NoPerms = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Permissions!")
|
|
||||||
.setDescription(`${supportbot.IncorrectPerms}\n\nRole Required: \`${SupportStaff.name}\``)
|
|
||||||
.setColor(supportbot.WarningColour)
|
|
||||||
|
|
||||||
if (!message.member.roles.cache.has(SupportStaff.id)) {
|
|
||||||
return message.channel.send({ embed: NoPerms });
|
|
||||||
}
|
|
||||||
|
|
||||||
let locateChannel = message.guild.channels.cache.find(ModLogChannel => ModLogChannel.name === supportbot.ModLogChannel) || message.guild.channels.cache.find(ModLogChannel => ModLogChannel.id === supportbot.ModLogChannel)
|
|
||||||
|
|
||||||
const user = message.mentions.members.first() || message.guild.members.cache.get(args[0]);
|
|
||||||
|
|
||||||
const errornochannel = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Channel")
|
|
||||||
.setDescription(`${supportbot.InvalidChannel}\n\nChannel Required: \`${supportbot.ModLogChannel}\``)
|
|
||||||
.setColor(supportbot.ErrorColour);
|
|
||||||
|
|
||||||
if(!locateChannel) return message.channel.send({ embed: errornochannel });
|
|
||||||
|
|
||||||
const embed1 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :x: Please mention or write an ID\n\n`Try Again!`")
|
|
||||||
.setColor(supportbot.ErrorColour)
|
|
||||||
|
|
||||||
if (!args[0]) return message.channel.send({
|
|
||||||
embed: embed1
|
|
||||||
});
|
|
||||||
|
|
||||||
const embed2 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :detective: **Hmm!** Can\'t seem tp find this user.\n\n`Are they in the server?`")
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
if (!user) return message.channel.send({
|
|
||||||
embed: embed2
|
|
||||||
});
|
|
||||||
|
|
||||||
let role = message.guild.roles.cache.find(role => role.name === supportbot.TicketBlackListRole) || message.guild.roles.cache.find(role => role.id === supportbot.TicketBlackListRole)
|
|
||||||
|
|
||||||
const embed3 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :detective: **Hmm!** Can\'t seem to find the blacklist role.\n\n`Did you created it?")
|
|
||||||
.setColor(supportbot.ErrorColour)
|
|
||||||
|
|
||||||
|
|
||||||
if (!role) return message.channel.send({
|
|
||||||
embed: embed3
|
|
||||||
});
|
|
||||||
|
|
||||||
const embed4 = new Discord.MessageEmbed()
|
|
||||||
.setDescription(`${user} is already blacklisted`)
|
|
||||||
.setColor(supportbot.ErrorColour)
|
|
||||||
|
|
||||||
if(user.roles.cache.find(role => role.name === supportbot.TicketBlackListRole) || user.roles.cache.find(role => role.id === supportbot.TicketBlackListRole)) {
|
|
||||||
return message.channel.send({
|
|
||||||
embed: embed4
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
user.roles.add(role);
|
|
||||||
|
|
||||||
const embed5 = new Discord.MessageEmbed()
|
|
||||||
.setDescription(`Blacklisted ${user} successfully from creating a ticket`)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
message.channel.send({
|
|
||||||
embed: embed5
|
|
||||||
});
|
|
||||||
|
|
||||||
const logEmbed = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.BlacklistTitle)
|
|
||||||
.setThumbnail(supportbot.ModThumbnail)
|
|
||||||
.addField('Banned User:', user)
|
|
||||||
.addField('Staff Member', message.author)
|
|
||||||
.setFooter(supportbot.EmbedFooter)
|
|
||||||
.setColor(supportbot.BlacklistColour)
|
|
||||||
.setTimestamp()
|
|
||||||
|
|
||||||
locateChannel.send({ embed: logEmbed });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Say Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const { execute } = require("./help");
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.BotSay,
|
|
||||||
description: supportbot.BotSayDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let SupportStaff = message.guild.roles.cache.find(adminRole => adminRole.name === supportbot.Staff) || message.guild.roles.cache.find(adminRole => adminRole.id === supportbot.Staff)
|
|
||||||
|
|
||||||
const NoPerms = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Permissions!")
|
|
||||||
.setDescription(`${supportbot.IncorrectPerms}\n\nRole Required: \`${SupportStaff.name}\``)
|
|
||||||
.setColor(supportbot.WarningColour)
|
|
||||||
|
|
||||||
if (!message.member.roles.cache.has(SupportStaff.id))
|
|
||||||
return message.channel.send({ embed: NoPerms });
|
|
||||||
|
|
||||||
|
|
||||||
const embed = new Discord.MessageEmbed()
|
|
||||||
.setDescription(`> **What would you like me to say!**`)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
message.channel.send({ embed: embed });
|
|
||||||
|
|
||||||
let announcement = []
|
|
||||||
message.channel.awaitMessages(response => response.content.length > 2, {
|
|
||||||
max: 1,
|
|
||||||
time: 500000,
|
|
||||||
errors: ['time'],
|
|
||||||
}).then((collected) => {
|
|
||||||
announcement.push(collected.map(r => r.content));
|
|
||||||
|
|
||||||
const AnnouncementEmbed = new Discord.MessageEmbed()
|
|
||||||
.setDescription(announcement)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
message.channel.send({ embed: AnnouncementEmbed })
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Close Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const { execute } = require("./help");
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.CloseTicket,
|
|
||||||
description: supportbot.CloseTicketDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
if (!message.channel.name.startsWith( `${supportbot.TicketChannel}-` )) {
|
|
||||||
const Exists = new Discord.MessageEmbed()
|
|
||||||
.setTitle("No Ticket Found!")
|
|
||||||
.setDescription(`${supportbot.NoValidTicket}`)
|
|
||||||
.setColor(supportbot.WarningColour);
|
|
||||||
message.channel.send({ embed: Exists });
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.CloseConfirmation) {
|
|
||||||
const CloseTicketRequest = new Discord.MessageEmbed()
|
|
||||||
.setTitle(`**${supportbot.ClosingTicket}**`)
|
|
||||||
.setDescription(`Please confirm by repeating the following word.. \`${supportbot.ClosingConfirmation_Word}\` `)
|
|
||||||
.setColor(supportbot.EmbedColour);
|
|
||||||
|
|
||||||
message.channel.send(CloseTicketRequest).then(m => {
|
|
||||||
message.channel.awaitMessages( response => response.content.toLowerCase() === supportbot.ClosingConfirmation_Word, {
|
|
||||||
max: 1,
|
|
||||||
time: 20000,
|
|
||||||
errors: [ 'time' ],
|
|
||||||
|
|
||||||
|
|
||||||
}).then( collected => {
|
|
||||||
let logChannel = message.guild.channels.cache.find(channel => channel.name === supportbot.TranscriptLog) || message.guild.channels.cache.find(channel => channel.id === supportbot.TranscriptLog)
|
|
||||||
let user = message.author;
|
|
||||||
let reason = args.join(" ") || "No Reason Provided.";
|
|
||||||
|
|
||||||
let name = message.channel.name;
|
|
||||||
let ticketChannel = message.channel;
|
|
||||||
|
|
||||||
message.channel.send(`**${supportbot.ClosingTicket}**`)
|
|
||||||
|
|
||||||
.then(() => {
|
|
||||||
const logEmbed = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.TranscriptTitle)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
.setFooter(supportbot.EmbedFooter)
|
|
||||||
.addField("Closed By", message.author.tag)
|
|
||||||
.addField("Reason", reason);
|
|
||||||
|
|
||||||
message.channel.messages.fetch({ limit: 100 }).then( msgs => {
|
|
||||||
let html = '';
|
|
||||||
|
|
||||||
msgs = msgs.sort( ( a, b ) => a.createdTimestamp - b.createdTimestamp );
|
|
||||||
html += `<strong>Server Name:</strong> ${message.guild.name}<br>`;
|
|
||||||
html += `<strong>Ticket:</strong> ${ticketChannel.name}<br>`;
|
|
||||||
html += `<strong>Message:</strong> ${msgs.size} Messages<br><br><br>`;
|
|
||||||
|
|
||||||
msgs.forEach( msg => {
|
|
||||||
if ( msg.content ) {
|
|
||||||
html += `<strong>User:</strong> ${msg.author.tag}<br>`;
|
|
||||||
html += `<strong>Message:</strong> ${msg.content}<br>`;
|
|
||||||
html += `-----<br><br>`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
logChannel.send(logEmbed).catch(err => {
|
|
||||||
message.reply(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
logChannel.send( new Discord.MessageAttachment( Buffer.from( html ), `${name}.html` ) );
|
|
||||||
|
|
||||||
message.channel.delete();
|
|
||||||
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
}).catch( () => {
|
|
||||||
m.edit('The request to close the ticket has timed out.').then( m2 => m2.delete( 3000 ) );
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!supportbot.CloseConfirmation) {
|
|
||||||
|
|
||||||
let logChannel = message.guild.channels.cache.find(channel => channel.name === supportbot.TranscriptLog) || message.guild.channels.cache.find(channel => channel.id === supportbot.TranscriptLog)
|
|
||||||
let user = message.author;
|
|
||||||
let reason = args.join(" ") || "No Reason Provided.";
|
|
||||||
|
|
||||||
let name = message.channel.name;
|
|
||||||
let ticketChannel = message.channel;
|
|
||||||
|
|
||||||
message.channel.send(`**${supportbot.ClosingTicket}**`)
|
|
||||||
|
|
||||||
.then(() => {
|
|
||||||
const logEmbed = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.TranscriptTitle)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
.setFooter(supportbot.EmbedFooter)
|
|
||||||
.addField("Closed By", message.author.tag)
|
|
||||||
.addField("Reason", reason);
|
|
||||||
|
|
||||||
message.channel.messages.fetch({ limit: 100 }).then( msgs => {
|
|
||||||
let html = '';
|
|
||||||
|
|
||||||
msgs = msgs.sort( ( a, b ) => a.createdTimestamp - b.createdTimestamp );
|
|
||||||
html += `<strong>Server Name:</strong> ${message.guild.name}<br>`;
|
|
||||||
html += `<strong>Ticket:</strong> ${ticketChannel.name}<br>`;
|
|
||||||
html += `<strong>Message:</strong> ${msgs.size} Messages<br><br><br>`;
|
|
||||||
|
|
||||||
msgs.forEach( msg => {
|
|
||||||
if ( msg.content ) {
|
|
||||||
html += `<strong>User:</strong> ${msg.author.tag}<br>`;
|
|
||||||
html += `<strong>Message:</strong> ${msg.content}<br>`;
|
|
||||||
html += `-----<br><br>`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
logChannel.send(logEmbed).catch(err => {
|
|
||||||
message.reply(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
logChannel.send( new Discord.MessageAttachment( Buffer.from( html ), `${name}.html` ) );
|
|
||||||
|
|
||||||
message.channel.delete();
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
}).catch( () => {
|
|
||||||
m.edit('The request to close the ticket has timed out.').then( m2 => m2.delete( 3000 ) );
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Help Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.HelpCommand,
|
|
||||||
description: supportbot.HelpDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let SupportStaff = message.guild.roles.cache.find(adminRole => adminRole.name === supportbot.Staff) || message.guild.roles.cache.find(staffRole => staffRole.id === supportbot.Staff);
|
|
||||||
let AdminStaff = message.guild.roles.cache.find(adminRole => adminRole.name === supportbot.Admin) || message.guild.roles.cache.find(adminRole => adminRole.id === supportbot.Admin);
|
|
||||||
|
|
||||||
if (supportbot.HelpMenu) {
|
|
||||||
let generalCommands = "";
|
|
||||||
generalCommands += `**${supportbot.Prefix}${supportbot.HelpCommand}** ${supportbot.HelpDesc}\n`;
|
|
||||||
generalCommands += `**${supportbot.Prefix}${supportbot.LinksCommand}** ${supportbot.LinksDesc}\n`;
|
|
||||||
generalCommands += `**${supportbot.Prefix}${supportbot.SuggestCommand}** ${supportbot.SuggestionDesc}\n`;
|
|
||||||
generalCommands += `**${supportbot.Prefix}${supportbot.PingCommand}** ${supportbot.PingDesc}\n`;
|
|
||||||
|
|
||||||
let supportCommands = "";
|
|
||||||
supportCommands += `**${supportbot.Prefix}${supportbot.NewTicket} [reason]** ${supportbot.NewTicketDesc}\n`
|
|
||||||
supportCommands += `**${supportbot.Prefix}${supportbot.CloseTicket} [reason]** ${supportbot.CloseTicketDesc}\n`
|
|
||||||
|
|
||||||
let staffCommands = "";
|
|
||||||
staffCommands += `**${supportbot.Prefix}${supportbot.AddUser} <user#0000>** ${supportbot.AddUserDesc}\n`
|
|
||||||
staffCommands += `**${supportbot.Prefix}${supportbot.RemoveUser} <user#0000>** ${supportbot.RemoveUserDesc}\n`
|
|
||||||
staffCommands += `**${supportbot.Prefix}${supportbot.BotSay}** ${supportbot.BotSayDesc}\n`
|
|
||||||
staffCommands += `**${supportbot.Prefix}${supportbot.PurgeMessage}** ${supportbot.PurgeDesc}\n`
|
|
||||||
staffCommands += `**${supportbot.Prefix}${supportbot.ChatLog}** ${supportbot.ChatLogDesc}\n`
|
|
||||||
|
|
||||||
let adminCommands = "";
|
|
||||||
adminCommands += `**${supportbot.Prefix}${supportbot.AnnounceCommand}** ${supportbot.AnnounceDesc} \`Admin Only\`\n`
|
|
||||||
adminCommands += `**${supportbot.Prefix}${supportbot.BanUser}** ${supportbot.BanDesc} \`Admin Only\` \n`
|
|
||||||
adminCommands += `**${supportbot.Prefix}${supportbot.KickUser}** ${supportbot.KickDesc} \`Admin Only\` \n`
|
|
||||||
adminCommands += `**${supportbot.Prefix}${supportbot.BlacklistUser}** ${supportbot.BlacklistDesc} \`Admin Only\` \n`
|
|
||||||
|
|
||||||
const HelpEmbed1 = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.Bot_Name)
|
|
||||||
.setThumbnail(message.author.displayAvatarURL())
|
|
||||||
|
|
||||||
.addFields(
|
|
||||||
{ name: '🖥️ General Commands\n', value: `${generalCommands}\n`, inline: false },
|
|
||||||
{ name: '🎫 Support Commands\n', value: `${supportCommands}\n`, inline: false },
|
|
||||||
)
|
|
||||||
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
.setFooter(supportbot.EmbedFooter, message.author.displayAvatarURL());
|
|
||||||
|
|
||||||
if (message.member.roles.cache.has(SupportStaff.id)) {
|
|
||||||
HelpEmbed1.addFields(
|
|
||||||
{ name: '🔐 Staff Commands\n', value: `${staffCommands}\n`, inline: false },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.member.roles.cache.has(AdminStaff.id)) {
|
|
||||||
HelpEmbed1.addFields(
|
|
||||||
{ name: '🔐 Admin Commands\n', value: `${adminCommands}\n`, inline: false },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.SendHelpPage === "dm") {
|
|
||||||
message.author.send({
|
|
||||||
embed: HelpEmbed1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.SendHelpPage === "channel") {
|
|
||||||
message.channel.send({
|
|
||||||
embed: HelpEmbed1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Say Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const { execute } = require("./help");
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.KickUser,
|
|
||||||
description: supportbot.KickDesc,
|
|
||||||
|
|
||||||
execute(message, args, member) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let SupportStaff = message.guild.roles.cache.find(adminRole => adminRole.name === supportbot.Admin) || message.guild.roles.cache.find(adminRole => adminRole.id === supportbot.Admin)
|
|
||||||
|
|
||||||
const NoPerms = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Permissions!")
|
|
||||||
.setDescription(`${supportbot.IncorrectPerms}\n\nRole Required: \`${SupportStaff.name}\``)
|
|
||||||
.setColor(supportbot.WarningColour)
|
|
||||||
|
|
||||||
if (!message.member.roles.cache.has(SupportStaff.id))
|
|
||||||
return message.channel.send({ embed: NoPerms });
|
|
||||||
|
|
||||||
let locateChannel = message.guild.channels.cache.find(ModLogChannel => ModLogChannel.name === supportbot.ModLogChannel) || message.guild.channels.cache.find(ModLogChannel => ModLogChannel.id === supportbot.ModLogChannel)
|
|
||||||
|
|
||||||
const errornochannel = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Channel")
|
|
||||||
.setDescription(`${supportbot.InvalidChannel}\n\nChannel Required: \`${supportbot.ModLogChannel}\``)
|
|
||||||
.setColor(supportbot.ErrorColour);
|
|
||||||
|
|
||||||
if(!locateChannel) return message.channel.send({ embed: errornochannel });
|
|
||||||
|
|
||||||
const user = message.mentions.members.first() || message.guild.members.cache.get(args[0]);
|
|
||||||
|
|
||||||
const embed1 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :x: Please provide a reason to kick.\n\n`Try Again!`")
|
|
||||||
.setColor(supportbot.ErrorColour)
|
|
||||||
|
|
||||||
if (!args[0]) return message.channel.send({
|
|
||||||
embed: embed1
|
|
||||||
});
|
|
||||||
|
|
||||||
const embed2 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :detective: **Hmm!** Can\'t seem tp find this user.\n\n`Are they in the server?`")
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
if (!user) return message.channel.send({
|
|
||||||
embed: embed2
|
|
||||||
})
|
|
||||||
|
|
||||||
const embed3 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :x: **Err No!** Cannot punish this user!\n\n`Reason: Their permissions and or roles are greater than mine.`")
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
if(!user.kickable) return message.channel.send({
|
|
||||||
embed: embed3
|
|
||||||
});
|
|
||||||
|
|
||||||
const embed4 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :joy: **OML!** Did you really just try to kick yourself!")
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
if(user.id === message.author.id) return message.channel.send({
|
|
||||||
embed: embed4
|
|
||||||
});
|
|
||||||
|
|
||||||
let reason = args.slice(1).join(" ");
|
|
||||||
|
|
||||||
if(!reason) reason = 'No Reason Provided.';
|
|
||||||
|
|
||||||
const embed5 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :thinking: **Hmm** Something seems to have gone wrong.\n\n`Check your system for errors!`")
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
user.kick({ reason: `${reason}` }).catch(err => {
|
|
||||||
message.channel.send({ embed: embed5 })
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const successEmbed = new Discord.MessageEmbed()
|
|
||||||
.setDescription(`> :white_check_mark: **OOF!** ${user} has been kicked!`)
|
|
||||||
.setColor(supportbot.SuccessColour)
|
|
||||||
|
|
||||||
message.channel.send({
|
|
||||||
embed: successEmbed
|
|
||||||
})
|
|
||||||
|
|
||||||
const logEmbed = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.KickTitle)
|
|
||||||
.setThumbnail(supportbot.ModThumbnail)
|
|
||||||
.addField('Kicked User:', user)
|
|
||||||
.addField('Staff Member', message.author)
|
|
||||||
.addField('Reason:', reason)
|
|
||||||
.setFooter(supportbot.EmbedFooter)
|
|
||||||
.setColor(supportbot.KickLogColour)
|
|
||||||
.setTimestamp()
|
|
||||||
|
|
||||||
locateChannel.send({ embed: logEmbed })
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Links Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const { execute } = require("./help");
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.LinksCommand,
|
|
||||||
description: supportbot.LinksDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
const LinksEmbed = new Discord.MessageEmbed()
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
let botLinks = supportbot.LINKS;
|
|
||||||
|
|
||||||
let links = '';
|
|
||||||
|
|
||||||
for ( let name in botLinks ) {
|
|
||||||
links += `[${name}](${botLinks[ name ]})\n`;
|
|
||||||
};
|
|
||||||
|
|
||||||
LinksEmbed.addField(supportbot.LinksTitle, links)
|
|
||||||
|
|
||||||
message.channel.send({ embed: LinksEmbed });
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Ping Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.PingCommand,
|
|
||||||
description: supportbot.PingDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let ping = Date.now() - message.createdTimestamp + " ms";
|
|
||||||
|
|
||||||
const PingCommandEmbed = new Discord.MessageEmbed()
|
|
||||||
.setDescription(`🏓 **Pong!** \`${Date.now() - message.createdTimestamp}ms\``)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
message.channel.send({ embed: PingCommandEmbed });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Say Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const { execute } = require("./help");
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.PurgeMessage,
|
|
||||||
description: supportbot.PurgeDesc,
|
|
||||||
|
|
||||||
execute(message, args, member) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let SupportStaff = message.guild.roles.cache.find(adminRole => adminRole.name === supportbot.Staff) || message.guild.roles.cache.find(adminRole => adminRole.id === supportbot.Staff)
|
|
||||||
|
|
||||||
const NoPerms = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Permissions!")
|
|
||||||
.setDescription(`${supportbot.IncorrectPerms}\n\nRole Required: \`${SupportStaff.name}\``)
|
|
||||||
.setColor(supportbot.WarningColour)
|
|
||||||
|
|
||||||
if (!message.member.roles.cache.has(SupportStaff.id))
|
|
||||||
return message.channel.send({ embed: NoPerms });
|
|
||||||
|
|
||||||
let locateChannel = message.guild.channels.cache.find(ModLogChannel => ModLogChannel.name === supportbot.ModLogChannel) || message.guild.channels.cache.find(ModLogChannel => ModLogChannel.id === supportbot.ModLogChannel)
|
|
||||||
|
|
||||||
const errornochannel = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Channel")
|
|
||||||
.setDescription(`${supportbot.InvalidChannel}\n\nChannel Required: \`${supportbot.ModLogChannel}\``)
|
|
||||||
.setColor(supportbot.ErrorColour);
|
|
||||||
|
|
||||||
if(!locateChannel) return message.channel.send({ embed: errornochannel });
|
|
||||||
|
|
||||||
const embed1 = new Discord.MessageEmbed()
|
|
||||||
.setDescription(`> :thinking: **Hmm!** Please enter a valid number of message to purge!\n\n\`${supportbot.Prefix}${supportbot.PurgeMessage} <message count>\` `)
|
|
||||||
.setColor(supportbot.WarningColour)
|
|
||||||
|
|
||||||
if (!args[0]) return message.channel.send({
|
|
||||||
embed: embed1
|
|
||||||
});
|
|
||||||
|
|
||||||
const messagePrune = parseInt(args[0])
|
|
||||||
|
|
||||||
const embed2 = new Discord.MessageEmbed()
|
|
||||||
.setDescription("> :person_facepalming: **Grr!** Can you count? That ain't a number :joy:")
|
|
||||||
.setColor(supportbot.ErrorColour)
|
|
||||||
|
|
||||||
if (isNaN(messagePrune)) return message.reply({
|
|
||||||
embed: embed2
|
|
||||||
})
|
|
||||||
|
|
||||||
message.channel.bulkDelete(messagePrune).then(() => {
|
|
||||||
|
|
||||||
const embed3 = new Discord.MessageEmbed()
|
|
||||||
.setDescription(`> :recycle: \`${args[0]} messages\` **have been purged!** `)
|
|
||||||
.setColor(supportbot.ErrorColour)
|
|
||||||
message.channel.send({
|
|
||||||
embed: embed3
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const logEmbed = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.PruneLogTitle)
|
|
||||||
.setThumbnail(supportbot.PruneThumbnail)
|
|
||||||
.addField('Messages Purged', `\`${args[0]} messages\``)
|
|
||||||
.addField('Staff Member', message.author)
|
|
||||||
.setFooter(supportbot.EmbedFooter)
|
|
||||||
.setColor(supportbot.PruneColour)
|
|
||||||
.setTimestamp()
|
|
||||||
|
|
||||||
locateChannel.send({ embed: logEmbed })
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Remove User
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.RemoveUser,
|
|
||||||
description: supportbot.RemoveUserDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let SupportStaff = message.guild.roles.cache.find(SupportTeam => SupportTeam.name === supportbot.Staff) || message.guild.roles.cache.find(SupportTeam => SupportTeam.id === supportbot.Staff)
|
|
||||||
let Admins = message.guild.roles.cache.find(AdminUser => AdminUser.name === supportbot.Admin) || message.guild.roles.cache.find(AdminUser => AdminUser.id === supportbot.Admin)
|
|
||||||
|
|
||||||
const NoPerms = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Permissions!")
|
|
||||||
.setDescription(`${supportbot.IncorrectPerms}\n\nRole Required: \`${supportbot.Staff}\` or \`${supportbot.Admin}\``)
|
|
||||||
.setColor(supportbot.WarningColour)
|
|
||||||
|
|
||||||
if (message.member.roles.cache.has(SupportStaff.id) || message.member.roles.cache.has(Admins.id)) {
|
|
||||||
if (!message.channel.name.startsWith( `${supportbot.TicketChannel}-` )) {
|
|
||||||
const Exists = new Discord.MessageEmbed()
|
|
||||||
.setTitle("No Ticket Found!")
|
|
||||||
.setDescription(`${supportbot.NoValidTicket}`)
|
|
||||||
.setColor(supportbot.WarningColour);
|
|
||||||
message.channel.send({ embed: Exists });
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let rUser = message.guild.member(message.mentions.users.first() || message.guild.members.cache.get(args[0]));
|
|
||||||
const UserNotExist = new Discord.MessageEmbed()
|
|
||||||
.setTitle("User Not Found!")
|
|
||||||
.setDescription(`${supportbot.UserNotFound}\n\nTry Again:\`${supportbot.Prefix}${supportbot.RemoveUser} <user#0000>\``)
|
|
||||||
.setColor(supportbot.ErrorColour)
|
|
||||||
|
|
||||||
if (!rUser) return message.channel.send({ embed: UserNotExist });
|
|
||||||
|
|
||||||
message.channel.updateOverwrite(rUser, {
|
|
||||||
VIEW_CHANNEL: false,
|
|
||||||
CREATE_INVITE: false,
|
|
||||||
SEND_MESSAGES: false,
|
|
||||||
READ_MESSAGES: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const Complete = new Discord.MessageEmbed()
|
|
||||||
.setTitle("User Removed!")
|
|
||||||
.setDescription(supportbot.RemovedUser.replace(/%user%/g, rUser.id))
|
|
||||||
.setTimestamp()
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
message.channel.send({ embed: Complete });
|
|
||||||
} else {
|
|
||||||
return message.channel.send({ embed: NoPerms });
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Suggest Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.SuggestCommand,
|
|
||||||
description: supportbot.SuggestionDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let locateChannel = message.guild.channels.cache.find(SuggestionChannel => SuggestionChannel.name === supportbot.SuggestionChannel) || message.guild.channels.cache.find(SuggestionChannel => SuggestionChannel.id === supportbot.SuggestionChannel)
|
|
||||||
|
|
||||||
const errornochannel = new Discord.MessageEmbed()
|
|
||||||
.setTitle("Invalid Channel")
|
|
||||||
.setDescription(`${supportbot.InvalidChannel}\n\nChannel Required: \`${supportbot.SuggestionChannel}\``)
|
|
||||||
.setColor(supportbot.ErrorColour);
|
|
||||||
|
|
||||||
if(!locateChannel) return message.channel.send({ embed: errornochannel });
|
|
||||||
|
|
||||||
const embed = new Discord.MessageEmbed()
|
|
||||||
.setDescription(`> **${supportbot.SuggestionStarter}**`)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
message.channel.send({ embed: embed });
|
|
||||||
|
|
||||||
let suggestion = []
|
|
||||||
message.channel.awaitMessages(response => response.content.length > 2, {
|
|
||||||
max: 1,
|
|
||||||
time: 500000,
|
|
||||||
errors: ['time'],
|
|
||||||
}).then((collected) => {
|
|
||||||
suggestion.push(collected.map(r => r.content));
|
|
||||||
|
|
||||||
const SuggestionMessage = new Discord.MessageEmbed()
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
.setFooter(supportbot.EmbedFooter)
|
|
||||||
|
|
||||||
.addField(supportbot.SuggestionTitle, suggestion, true)
|
|
||||||
.addField("From", `<@${message.author.id}>`, true)
|
|
||||||
|
|
||||||
if (supportbot.SuggestionMessage_Icon === "BOT") {
|
|
||||||
SuggestionMessage.setThumbnail(bot.user.displayAvatarURL())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.SuggestionMessage_Icon === "USER") {
|
|
||||||
SuggestionMessage.setThumbnail(message.author.displayAvatarURL())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.SuggestionMessage_Icon === "CUSTOM") {
|
|
||||||
SuggestionMessage.setThumbnail(supportbot.SuggestionIcon_URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
locateChannel.send({ embed: SuggestionMessage }).then(async function(msg) {
|
|
||||||
msg.react(supportbot.SuggestReact_1).then(() => msg.react(supportbot.SuggestReact_2));
|
|
||||||
});
|
|
||||||
|
|
||||||
const SuggestionComplete = new Discord.MessageEmbed()
|
|
||||||
.setColor(supportbot.SuccessColour)
|
|
||||||
.setDescription(`:white_check_mark: Your suggestion has been successfully created. <#${locateChannel.id}>`)
|
|
||||||
message.channel.send({ embed: SuggestionComplete })
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,230 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Ticket Command
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const bot = new Discord.Client()
|
|
||||||
|
|
||||||
const fs = require("fs")
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
const TicketNumberID = require('../utils/TicketNumber.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.NewTicket,
|
|
||||||
description: supportbot.NewTicketDesc,
|
|
||||||
|
|
||||||
async execute(message, args) {
|
|
||||||
if (!message.channel.name === supportbot.ReactionChannel || !message.channel.id === supportbot.ReactionChannel) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
let reactionUser = message.guild.members.cache.get(message.author.id)
|
|
||||||
|
|
||||||
if (reactionUser.roles.cache.find(role => role.name === supportbot.TicketBlackListRole) || reactionUser.roles.cache.find(role => role.id === supportbot.TicketBlackListRole)) {
|
|
||||||
return message.channel.send(`<@${message.author.id}> ${supportbot.TicketBlackListMessage}`).then(msg => {
|
|
||||||
msg.delete({timeout: 3500})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ticket ID
|
|
||||||
let ticketNumberID = TicketNumberID.pad(message.guild.id);
|
|
||||||
|
|
||||||
// Ticket Subject
|
|
||||||
const TicketSubject = args || supportbot.NoTicketSubject;
|
|
||||||
|
|
||||||
const channel = await message.guild.channels.create(`${supportbot.TicketChannel}-${ticketNumberID}`);
|
|
||||||
|
|
||||||
if (message.channel.name === supportbot.ReactionChannel || message.channel.id === supportbot.ReactionChannel) {
|
|
||||||
const CreatedTicket = new Discord.MessageEmbed()
|
|
||||||
.setDescription(supportbot.TicketCreatedAlert.replace(/%ticketauthor%/g, message.author.id).replace(/%ticketid%/g, channel.id).replace(/%ticketusername%/g, message.author.username))
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
message.channel.send({embed: CreatedTicket}).then((r) => {
|
|
||||||
r.delete({ timeout:5000 })
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
const CreatedTicket = new Discord.MessageEmbed()
|
|
||||||
.setDescription(supportbot.TicketCreatedAlert.replace(/%ticketauthor%/g, message.author.id).replace(/%ticketid%/g, channel.id).replace(/%ticketusername%/g, message.author.username))
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
message.channel.send({embed: CreatedTicket});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ticket Category
|
|
||||||
let TicketCategory = message.guild.channels.cache.find(category => category.name === supportbot.TicketCategory) || message.guild.channels.cache.find(category => category.id === supportbot.TicketCategory)
|
|
||||||
|
|
||||||
// Locate Roles
|
|
||||||
let StaffMember = message.guild.roles.cache.find(SupportTeam => SupportTeam.name === supportbot.Staff) || message.guild.roles.cache.find(SupportTeam => SupportTeam.id === supportbot.Staff)
|
|
||||||
let ServerAdmins = message.guild.roles.cache.find(AdminUser => AdminUser.name === supportbot.Admin) || message.guild.roles.cache.find(AdminUser => AdminUser.id === supportbot.Admin)
|
|
||||||
|
|
||||||
if (TicketCategory) {
|
|
||||||
channel.setParent(TicketCategory.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
channel.updateOverwrite(message.guild.id, {
|
|
||||||
SEND_MESSAGES: false,
|
|
||||||
VIEW_CHANNEL: false
|
|
||||||
})
|
|
||||||
|
|
||||||
channel.updateOverwrite(message.author, {
|
|
||||||
SEND_MESSAGES: true,
|
|
||||||
VIEW_CHANNEL: true
|
|
||||||
})
|
|
||||||
|
|
||||||
channel.updateOverwrite(StaffMember, {
|
|
||||||
SEND_MESSAGES: true,
|
|
||||||
VIEW_CHANNEL: true
|
|
||||||
})
|
|
||||||
|
|
||||||
channel.updateOverwrite(ServerAdmins, {
|
|
||||||
SEND_MESSAGES: true,
|
|
||||||
VIEW_CHANNEL: true
|
|
||||||
})
|
|
||||||
|
|
||||||
// Ticket Created, Message Sent
|
|
||||||
|
|
||||||
if (supportbot.AllowTicketMentions) {
|
|
||||||
channel.send(`<@${message.author.id}>`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const TicketMessage = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.Ticket_Title.replace(/%ticketauthor%/g, message.author.id).replace(/%ticketid%/g, channel.id).replace(/%ticketusername%/g, message.author.username))
|
|
||||||
.setDescription(supportbot.TicketMessage.replace(/%ticketauthor%/g, message.author.id).replace(/%ticketid%/g, channel.id).replace(/%ticketusername%/g, message.author.username))
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
if (supportbot.TicketSubject === "embed") {
|
|
||||||
|
|
||||||
if (TicketSubject != 'No Reason Provided.') {
|
|
||||||
TicketMessage.addFields({ name: 'Reason', value: TicketSubject })
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.TicketSubject === "description") {
|
|
||||||
|
|
||||||
if (TicketSubject != 'No Reason Provided.') {
|
|
||||||
channel.setTopic(`Reason: ${TicketSubject} - User ID: ${message.author.id} - Ticket: ${channel.name}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const reactionMessage = await channel.send({
|
|
||||||
embed: TicketMessage
|
|
||||||
}).then( async function(ticketmsg) {
|
|
||||||
await ticketmsg.react(supportbot.TicketLockReaction)
|
|
||||||
await ticketmsg.react(supportbot.TicketDeleteReaction)
|
|
||||||
|
|
||||||
const collector = ticketmsg.createReactionCollector(
|
|
||||||
(reaction, user) => message.guild.roles.cache.find((staff) => staff.name === supportbot.Staff),
|
|
||||||
{ dispose: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
collector.on('collect', (reaction, user) => {
|
|
||||||
switch (reaction.emoji.name) {
|
|
||||||
case supportbot.TicketLockReaction:
|
|
||||||
|
|
||||||
channel.updateOverwrite(message.author, {
|
|
||||||
SEND_MESSAGES: false,
|
|
||||||
VIEW_CHANNEL: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const LockTicketEmbed = new Discord.MessageEmbed()
|
|
||||||
.setDescription(supportbot.TicketLockMessage)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
channel.send({embed: LockTicketEmbed})
|
|
||||||
break;
|
|
||||||
|
|
||||||
case supportbot.TicketDeleteReaction:
|
|
||||||
const DeleteTicketEmbed = new Discord.MessageEmbed()
|
|
||||||
.setDescription(supportbot.TicketDeleteMessage)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
channel.send({embed: DeleteTicketEmbed})
|
|
||||||
|
|
||||||
let logChannel = message.guild.channels.cache.find(channel => channel.name === supportbot.TranscriptLog) || message.guild.channels.cache.find(channel => channel.id === supportbot.TranscriptLog)
|
|
||||||
let user = message.author;
|
|
||||||
let reason = args.join(" ") || "No Reason Provided.";
|
|
||||||
|
|
||||||
let name = message.channel.name;
|
|
||||||
let ticketChannel = message.channel;
|
|
||||||
|
|
||||||
message.channel.send(`**${supportbot.ClosingTicket}**`)
|
|
||||||
|
|
||||||
.then(() => {
|
|
||||||
const logEmbed = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.TranscriptTitle)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
.setFooter(supportbot.EmbedFooter)
|
|
||||||
.addField("Closed By", message.author.tag)
|
|
||||||
.addField("Reason", reason);
|
|
||||||
|
|
||||||
message.channel.messages.fetch({ limit: 100 }).then( msgs => {
|
|
||||||
let html = '';
|
|
||||||
|
|
||||||
msgs = msgs.sort( ( a, b ) => a.createdTimestamp - b.createdTimestamp );
|
|
||||||
html += `<strong>Server Name:</strong> ${message.guild.name}<br>`;
|
|
||||||
html += `<strong>Ticket:</strong> ${ticketChannel.name}<br>`;
|
|
||||||
html += `<strong>Message:</strong> ${msgs.size} Messages<br><br><br>`;
|
|
||||||
|
|
||||||
msgs.forEach( msg => {
|
|
||||||
if ( msg.content ) {
|
|
||||||
html += `<strong>User:</strong> ${msg.author.tag}<br>`;
|
|
||||||
html += `<strong>Message:</strong> ${msg.content}<br>`;
|
|
||||||
html += `-----<br><br>`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
logChannel.send(logEmbed).catch(err => {
|
|
||||||
message.reply(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
const TranscriptSavedEmbed = new Discord.MessageEmbed()
|
|
||||||
.setDescription(supportbot.TranscriptSavedMessage)
|
|
||||||
.setColor(supportbot.SuccessColour)
|
|
||||||
channel.send({embed: TranscriptSavedEmbed})
|
|
||||||
|
|
||||||
logChannel.send( new Discord.MessageAttachment( Buffer.from( html ), `${name}.html` ) );
|
|
||||||
setTimeout(() => channel.delete(), supportbot.TicketDeleteTime);
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
}).catch( () => {
|
|
||||||
m.edit('The request to close the ticket has timed out.').then( m2 => m2.delete( 3000 ) );
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
fs.writeFileSync("./storage/SupportTickets.json", '{\n "ticket": "' + channel.name + '", \n "id":' + message.author.id + "\n}", (err) => {
|
|
||||||
if (!err) return;
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
// Ticket Logs
|
|
||||||
|
|
||||||
const errornochannel = new Discord.MessageEmbed()
|
|
||||||
.setTitle("SupportBot Error!")
|
|
||||||
.setDescription(`:x: **Error!** Channel not Found, This command cannot be executed proberbly as their is no channel within this server.\nThis is configurable via **supportbot-config.yml**\n\nChannel Required: \`${supportbot.TicketLog}\`\n\nError Code: \`SB-03\``)
|
|
||||||
.setColor(supportbot.ErrorColour);
|
|
||||||
|
|
||||||
const TicketLogs = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.TicketLog_Title)
|
|
||||||
.setThumbnail(supportbot.Ticket_Thumbnail)
|
|
||||||
.addFields(
|
|
||||||
{ name: 'Ticket', value: `<#${channel.id}>` },
|
|
||||||
{ name: 'User', value: `<@${message.author.id}>` },
|
|
||||||
)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
.setFooter(supportbot.EmbedFooter)
|
|
||||||
|
|
||||||
let locateChannel = message.guild.channels.cache.find(LocateChannel => LocateChannel.name === supportbot.TicketLog) || message.guild.channels.cache.find(LocateChannel => LocateChannel.id === supportbot.TicketLog)
|
|
||||||
|
|
||||||
if(!locateChannel) return message.channel.send({ embed: errornochannel });
|
|
||||||
|
|
||||||
locateChannel.send({ embed: TicketLogs });
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
// SupportBot, Created by Emerald Services
|
|
||||||
// Announce
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const { execute } = require("./help");
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: supportbot.ChatLog,
|
|
||||||
description: supportbot.ChatLogDesc,
|
|
||||||
|
|
||||||
execute(message, args) {
|
|
||||||
if (supportbot.DeleteMessages) message.delete();
|
|
||||||
|
|
||||||
let name = message.channel.name;
|
|
||||||
|
|
||||||
message.channel.messages.fetch({ limit: 100 }).then( msgs => {
|
|
||||||
let html = '';
|
|
||||||
|
|
||||||
msgs = msgs.sort( ( a, b ) => a.createdTimestamp - b.createdTimestamp );
|
|
||||||
html += `<strong>--- Channel Transcript ---</strong><br>`;
|
|
||||||
html += `<strong>Server Name:</strong> ${message.guild.name}<br>`;
|
|
||||||
html += `<strong>Channel:</strong> ${name}<br>`;
|
|
||||||
html += `<strong>Message:</strong> ${msgs.size} Messages<br><br><br>`;
|
|
||||||
|
|
||||||
msgs.forEach( msg => {
|
|
||||||
if ( msg.content ) {
|
|
||||||
html += `<strong>User:</strong> ${msg.author.tag}<br>`;
|
|
||||||
html += `<strong>Message:</strong> ${msg.content}<br>`;
|
|
||||||
html += `-----<br><br>`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const TranscriptSavedEmbed = new Discord.MessageEmbed()
|
|
||||||
.setDescription(supportbot.ChatLogSavedMessage)
|
|
||||||
.setColor(supportbot.SuccessColour)
|
|
||||||
message.channel.send({embed: TranscriptSavedEmbed})
|
|
||||||
|
|
||||||
const errornochannel = new Discord.MessageEmbed()
|
|
||||||
.setTitle("SupportBot Error!")
|
|
||||||
.setDescription(`:x: **Error!** Channel not Found, This command cannot be executed proberbly as their is no channel within this server.\nThis is configurable via **supportbot-config.yml**\n\nChannel Required: \`${supportbot.TicketLog}\`\n\nError Code: \`SB-03\``)
|
|
||||||
.setColor(supportbot.ErrorColour);
|
|
||||||
|
|
||||||
const ChatLogs = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.ChatLog_Title)
|
|
||||||
.setThumbnail(supportbot.ChatLog_Thumbnail)
|
|
||||||
.addFields(
|
|
||||||
{ name: 'Channel', value: `<#${message.channel.id}>` },
|
|
||||||
{ name: 'User', value: `<@${message.author.id}>` },
|
|
||||||
)
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
.setFooter(supportbot.EmbedFooter)
|
|
||||||
|
|
||||||
let locateChannel = message.guild.channels.cache.find(LocateChannel => LocateChannel.name === supportbot.ChatLogChannel) || message.guild.channels.cache.find(LocateChannel => LocateChannel.id === supportbot.ChatLogChannel)
|
|
||||||
|
|
||||||
if(!locateChannel) return message.channel.send({ embed: errornochannel });
|
|
||||||
|
|
||||||
locateChannel.send( new Discord.MessageAttachment( Buffer.from( html ), `${name}.html` ) );
|
|
||||||
locateChannel.send({ embed: ChatLogs });
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
// SupportBot 6.0, Created by Emerald Services
|
|
||||||
// Ready Event
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = async (bot, member) => {
|
|
||||||
|
|
||||||
if (supportbot.SystemMessages) {
|
|
||||||
const SystemChannel = member.guild.channels.cache.find(channel => channel.name === supportbot.SystemMessage_Channel) || member.guild.channels.cache.get(supportbot.SystemMessage_Channel)
|
|
||||||
|
|
||||||
if (!SystemChannel) return;
|
|
||||||
|
|
||||||
console.log(`[${supportbot.Bot_Name}]: ${member.user.username} has joined ${member.guild.name}!`)
|
|
||||||
console.log(supportbot.AutoRole_Role)
|
|
||||||
|
|
||||||
const role = member.guild.roles.cache.find(role => role.name === supportbot.AutoRole_Role) || member.guild.roles.cache.find(role => role.id === supportbot.AutoRole_Role)
|
|
||||||
|
|
||||||
member.roles.add(role).catch(console.error);
|
|
||||||
|
|
||||||
if (supportbot.SystemMessage_Type === "embed") {
|
|
||||||
|
|
||||||
const GuildAddMember = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.Welcome_Title)
|
|
||||||
.setDescription(supportbot.WelcomeMessage.replace(/%member%/g, `<@!${member.user.id}>`).replace(/%guildname%/g, member.guild.name))
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
if (supportbot.SystemMessage_Icon === "BOT") {
|
|
||||||
GuildAddMember.setThumbnail(bot.user.displayAvatarURL())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.SystemMessage_Icon === "USER") {
|
|
||||||
GuildAddMember.setThumbnail(member.user.displayAvatarURL())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.SystemMessage_Icon === "CUSTOM") {
|
|
||||||
SuggestionMessage.setThumbnail(supportbot.SystemMessageIcon_URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (supportbot.SystemMessage_EmbedFooter) {
|
|
||||||
GuildAddMember.setFooter(supportbot.EmbedFooter)
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemChannel.send({ embed: GuildAddMember });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.SystemMessage_Type === "normal") {
|
|
||||||
SystemChannel.send(supportbot.WelcomeMessage.replace(/%member%/g, member.user.username).replace(/%guildname%/g, member.guild.name))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
// SupportBot 6.0, Created by Emerald Services
|
|
||||||
// Ready Event
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = async (bot, member) => {
|
|
||||||
|
|
||||||
if (supportbot.SystemMessages) {
|
|
||||||
const SystemChannel = member.guild.channels.cache.find(channel => channel.name === supportbot.SystemMessage_Channel) || member.guild.channels.cache.get(supportbot.SystemMessage_Channel)
|
|
||||||
|
|
||||||
if (!SystemChannel) return;
|
|
||||||
|
|
||||||
console.log(`[${supportbot.Bot_Name}]: ${member.user.username} has left ${member.guild.name}!`)
|
|
||||||
|
|
||||||
if (supportbot.SystemMessage_Type === "embed") {
|
|
||||||
const GuildRemoveMember = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.Leave_Title)
|
|
||||||
.setDescription(supportbot.LeaveMessage.replace(/%member%/g, member.user.username).replace(/%guildname%/g, member.guild.name))
|
|
||||||
.setColor(supportbot.EmbedColour)
|
|
||||||
|
|
||||||
if (supportbot.SystemMessage_Icon === "BOT") {
|
|
||||||
GuildRemoveMember.setThumbnail(bot.user.displayAvatarURL())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.SystemMessage_Icon === "USER") {
|
|
||||||
GuildRemoveMember.setThumbnail(member.user.displayAvatarURL())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (supportbot.SystemMessage_EmbedFooter === "true") {
|
|
||||||
GuildRemoveMember.setFooter(supportbot.EmbedFooter)
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemChannel.send({ embed: GuildRemoveMember });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.SystemMessage_Type === "normal") {
|
|
||||||
SystemChannel.send(supportbot.LeaveMessage.replace(/%member%/g, member.user.username).replace(/%guildname%/g, member.guild.name))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
// SupportBot 6.0, Created by Emerald Services
|
|
||||||
// Message Event
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = async (bot, message) => {
|
|
||||||
if(message.author.bot) return;
|
|
||||||
if(message.channel.type === "dm") return;
|
|
||||||
if (message.content.indexOf(supportbot.Prefix) !== 0) return;
|
|
||||||
|
|
||||||
let messageArray = message.content.split(" ");
|
|
||||||
const args = message.content.slice(supportbot.Prefix.length).trim().split(/ +/g);
|
|
||||||
const command = args.shift().toLowerCase();
|
|
||||||
|
|
||||||
console.log(`\u001b[32m`, `[${supportbot.Bot_Name}]`, `\u001b[36m`, `${message.author.tag}`, `\u001b[33m`, `has executed the command`, `\u001b[36m`,`${supportbot.Prefix}${command}`)
|
|
||||||
|
|
||||||
const cmd = bot.commands.get(command);
|
|
||||||
if(!cmd) return;
|
|
||||||
cmd.execute(message, args);
|
|
||||||
};
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
// SupportBot 6.0, Created by Emerald Services
|
|
||||||
// Message Reaction Event
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
const tickets = yaml.load(fs.readFileSync('./storage/ticketreaction.yml', 'utf8'));
|
|
||||||
|
|
||||||
module.exports = async (client, reaction, user) => {
|
|
||||||
|
|
||||||
let message = {
|
|
||||||
guild: reaction.message.channel.guild,
|
|
||||||
author: user,
|
|
||||||
content: "N/A",
|
|
||||||
channel: reaction.message.channel
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.ReactionTickets) {
|
|
||||||
if (reaction.message.id === tickets.ReactionMessage_ID) {
|
|
||||||
if (reaction.emoji.name == supportbot.ReactionEmoji || reaction.emoji.id == supportbot.ReactionEmoji) {
|
|
||||||
await reaction.users.remove(user.id)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const cmd = client.commands.get(supportbot.NewTicket);
|
|
||||||
if(!cmd) return;
|
|
||||||
|
|
||||||
cmd.execute(message, message.content);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = async (bot, message, packet) => {
|
|
||||||
if (!['MESSAGE_REACTION_ADD', 'MESSAGE_REACTION_REMOVE'].includes(packet.t)) return;
|
|
||||||
|
|
||||||
const channel = bot.channels.cache.get(packet.d.channel_id);
|
|
||||||
if (channel.messages.has(packet.d.message_id)) return;
|
|
||||||
|
|
||||||
channel.messages.fetch(packet.d.message_id).then(message => {
|
|
||||||
const emoji = packet.d.emoji.id ? `${packet.d.emoji.name}:${packet.d.emoji.id}` : packet.d.emoji.name;
|
|
||||||
const reaction = message.reactions.get(emoji);
|
|
||||||
if (reaction) reaction.users.set(packet.d.user_id, bot.users.get(packet.d.user_id));
|
|
||||||
if (packet.t === 'MESSAGE_REACTION_ADD') {
|
|
||||||
bot.emit('messageReactionAdd', reaction, bot.users.get(packet.d.user_id));
|
|
||||||
}
|
|
||||||
if (packet.t === 'MESSAGE_REACTION_REMOVE') {
|
|
||||||
bot.emit('messageReactionRemove', reaction, bot.users.get(packet.d.user_id));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
// SupportBot 6.0, Created by Emerald Services
|
|
||||||
// Ready Event
|
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
const tickets = yaml.load(fs.readFileSync('./storage/ticketreaction.yml', 'utf8'));
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = async (bot) => {
|
|
||||||
bot.user.setActivity(supportbot.BotActivity, {
|
|
||||||
type: supportbot.ActivityType,
|
|
||||||
url: supportbot.StreamingURL
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`\u001b[32m`, `┏━━━┓╋╋╋╋╋╋╋╋╋╋╋╋╋┏┓┏━━┓╋╋╋┏┓`)
|
|
||||||
console.log(`\u001b[32m`, `┃┏━┓┃╋╋╋╋╋╋╋╋╋╋╋╋┏┛┗┫┏┓┃╋╋┏┛┗┓`)
|
|
||||||
console.log(`\u001b[32m`, `┃┗━━┳┓┏┳━━┳━━┳━━┳┻┓┏┫┗┛┗┳━┻┓┏┛`)
|
|
||||||
console.log(`\u001b[32m`, `┗━━┓┃┃┃┃┏┓┃┏┓┃┏┓┃┏┫┃┃┏━┓┃┏┓┃┃`)
|
|
||||||
console.log(`\u001b[32m`, `┃┗━┛┃┗┛┃┗┛┃┗┛┃┗┛┃┃┃┗┫┗━┛┃┗┛┃┗┓`)
|
|
||||||
console.log(`\u001b[32m`, `┗━━━┻━━┫┏━┫┏━┻━━┻┛┗━┻━━━┻━━┻━┛`)
|
|
||||||
console.log(`\u001b[32m`, `┗╋╋╋╋╋╋╋┃┃╋┃┃`)
|
|
||||||
console.log(`\u001b[32m`, `╋╋╋╋╋╋╋┗┛╋┗┛`)
|
|
||||||
console.log(` `)
|
|
||||||
console.log(`\u001b[31m`, `――――――――――――――――――――――――――――――――――――――――――――`)
|
|
||||||
console.log(` `)
|
|
||||||
console.log(`\u001b[33m`, `${supportbot.Bot_Name} v${supportbot.SupportBot_Version}`, `\u001b[36m`, `Connected to Discord`)
|
|
||||||
console.log(`\u001b[33m`, `Documentation:`, `\u001b[36m`, `https://docs.emeraldsrv.dev`)
|
|
||||||
console.log(`\u001b[33m`, `Discord:`, `\u001b[36m`, `https://emeraldsrv.dev/discord`)
|
|
||||||
console.log(`\u001b[33m`, `Hosting:`, `\u001b[36m`, `https://emeraldsrv.dev/hosting`)
|
|
||||||
console.log(` `)
|
|
||||||
console.log(`\u001b[37m`, `SupportBot proudly created by Emerald Services`)
|
|
||||||
console.log(` `)
|
|
||||||
console.log(`\u001b[31m`, `――――――――――――――――――――――――――――――――――――――――――――`)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (supportbot.ReactionTickets === true) {
|
|
||||||
let chan1 = bot.channels.cache.find(channel => channel.name === supportbot.ReactionChannel)
|
|
||||||
|
|
||||||
if (!chan1) {
|
|
||||||
console.log('\u001b[33m', "[WARN] Ticket reaction panel is not setup, You can do so via the configuration file!")
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
chan1.messages.fetch(tickets.ReactionMessage_ID).catch(r => {
|
|
||||||
let embed = new Discord.MessageEmbed()
|
|
||||||
.setTitle(supportbot.ReactionMessage.replace(/%reaction_emoji%/g, supportbot.ReactionEmoji))
|
|
||||||
.setColor(supportbot.SuccessColour)
|
|
||||||
.setFooter(supportbot.EmbedFooter);
|
|
||||||
|
|
||||||
if (supportbot.ReactionPanel_Description === true) {
|
|
||||||
embed.setDescription(supportbot.ReactionDescription)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.ReactionPanel_Thumbnail === true) {
|
|
||||||
embed.setThumbnail(supportbot.ReactionThumbnail)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportbot.ReactionPanel_Image === true) {
|
|
||||||
embed.setImage(supportbot.ReactionImage)
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.channels.cache.find(channel => channel.name === supportbot.ReactionChannel).send({
|
|
||||||
embed: embed
|
|
||||||
}).then(r => {
|
|
||||||
let data = {
|
|
||||||
"ReactionMessage_ID": `${r.id}`
|
|
||||||
}
|
|
||||||
let yamlStr = yaml.dump(data);
|
|
||||||
fs.writeFileSync('./storage/ticketreaction.yml', yamlStr, 'utf8');
|
|
||||||
|
|
||||||
r.react(supportbot.ReactionEmoji);
|
|
||||||
}).catch(e => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -8,98 +8,37 @@
|
|||||||
// Installed with MIT License
|
// Installed with MIT License
|
||||||
//
|
//
|
||||||
// Discord Support: https://emeraldsrv.dev/discord
|
// Discord Support: https://emeraldsrv.dev/discord
|
||||||
|
// Community Resources: https://emeraldsrv.dev/resources
|
||||||
|
|
||||||
const Discord = require("discord.js");
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const bot = new Discord.Client();
|
|
||||||
|
|
||||||
bot.commands = new Discord.Collection();
|
const yaml = require("js-yaml");
|
||||||
|
const supportbot = yaml.load(
|
||||||
|
fs.readFileSync("./Configs/supportbot.yml", "utf8")
|
||||||
|
);
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
const Client = require("./Structures/Client.js");
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
const client = new Client({
|
||||||
|
intents: ['Guilds', 'GuildMembers', 'GuildMessages', 'MessageContent']
|
||||||
const { promisify } = require("util");
|
|
||||||
const readdir = promisify(require("fs").readdir);
|
|
||||||
|
|
||||||
String.prototype.toProperCase = function () {
|
|
||||||
return this.replace(
|
|
||||||
/([^\W_]+[^\s-]*) */g,
|
|
||||||
(txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const init = async () => {
|
|
||||||
const evtFiles = await readdir("./events/");
|
|
||||||
|
|
||||||
console.info(`\u001b[36m`, `➢ SupportBot Events`);
|
|
||||||
console.info(` `);
|
|
||||||
|
|
||||||
evtFiles.forEach((file, i) => {
|
|
||||||
const eventName = file.split(".")[0];
|
|
||||||
const event = require(`./events/${file}`);
|
|
||||||
console.info(`\u001b[32m`, `[${supportbot.Bot_Name}]:`, `\u001b[36m`, `#${i + 1} Event Loaded: ${eventName.toProperCase()} `);
|
|
||||||
|
|
||||||
bot.on(eventName, event.bind(null, bot));
|
|
||||||
delete require.cache[require.resolve(`./events/${file}`)];
|
|
||||||
});
|
|
||||||
|
|
||||||
console.info(`\u001b[32m`, `[${supportbot.Bot_Name}]:`, `\u001b[36m`, `Successfully loaded ${evtFiles.length} events.`);
|
|
||||||
console.log(`\u001b[31m`, `――――――――――――――――――――――――――――――――――――――――――――`)
|
|
||||||
console.log(` `)
|
|
||||||
};
|
|
||||||
|
|
||||||
init();
|
|
||||||
|
|
||||||
fs.readdir("./commands/", (err, files) => {
|
|
||||||
|
|
||||||
console.info(`\u001b[36m`, `➢ SupportBot Commands`);
|
|
||||||
console.info(` `);
|
|
||||||
|
|
||||||
if (err) console.info(err, "error");
|
|
||||||
|
|
||||||
let jsfiles = files.filter((f) => f.split(".").pop() === "js");
|
|
||||||
|
|
||||||
if (jsfiles.length <= 0) {
|
|
||||||
console.log(`[${supportbot.Bot_Name}]: No commands found. Try to Re-download the resource`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsfiles.forEach((f, i) => {
|
|
||||||
let props = require(`./commands/${f}`);
|
|
||||||
|
|
||||||
console.info(`\u001b[32m`, `[${supportbot.Bot_Name}]:`, `\u001b[36m`, `#${i + 1} Command Loaded: ${props.name.toProperCase()}`);
|
|
||||||
bot.commands.set(props.name, props);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.info(`\u001b[32m`, `[${supportbot.Bot_Name}]:`, `\u001b[36m`, `Loaded ${jsfiles.length} commands!`);
|
|
||||||
console.log(`\u001b[31m`, `――――――――――――――――――――――――――――――――――――――――――――`)
|
|
||||||
console.log(` `)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.readdir("./addons/", (err, files) => {
|
client.start(supportbot.General.Token);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
console.info(`\u001b[36m`, `➢ SupportBot Addons`);
|
|
||||||
console.info(` `);
|
|
||||||
|
|
||||||
if (err) console.info(err, "error");
|
|
||||||
|
|
||||||
let jsfiles = files.filter((f) => f.split(".").pop() === "js");
|
|
||||||
|
|
||||||
if (jsfiles.length <= 0) {
|
|
||||||
console.log(`[${supportbot.Bot_Name}]: No addons found. You can download addons from https://emeraldsrv.dev`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsfiles.forEach((f, i) => {
|
|
||||||
let props = require(`./addons/${f}`);
|
|
||||||
|
|
||||||
console.info(`\u001b[32m`, `[${supportbot.Bot_Name}]:`, `\u001b[36m`, `#${i + 1} Addon Loaded: ${props.name.toProperCase()}`);
|
|
||||||
bot.commands.set(props.name, props);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.info(`\u001b[32m`, `[${supportbot.Bot_Name}]:`, `\u001b[36m`, `Loaded ${jsfiles.length} addons!`);
|
|
||||||
console.log(`\u001b[31m`, `――――――――――――――――――――――――――――――――――――――――――――`)
|
|
||||||
console.log(` `)
|
|
||||||
});
|
|
||||||
|
|
||||||
bot.login(supportbot.Token);
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
SupportBot Language Compatibility
|
|
||||||
|
|
||||||
In order to switch languages simple remove the current existig configuration file and replace it with one of the files here renamnig the file to "supportbot-config.yml" from (for example) "supportbot-config_es.yml" to home directory of SupportBot.
|
|
||||||
|
|
||||||
-> Delete the existing supportbot-config.yml file
|
|
||||||
-> Download the new file for whatever language
|
|
||||||
-> Upload the file to SupportBot and rename it to supportbot-config.yml
|
|
||||||
-> Job Done, restart the bot :wink:
|
|
||||||
@@ -1,310 +0,0 @@
|
|||||||
# ___ _ ___ _
|
|
||||||
# / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
|
|
||||||
# \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
|
|
||||||
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
|
|
||||||
# |_| |_|
|
|
||||||
#
|
|
||||||
# SupportBot created by Emerald Services
|
|
||||||
# Installed with MIT License
|
|
||||||
#
|
|
||||||
# Discord Support: https://emeraldsrv.dev/discord
|
|
||||||
|
|
||||||
SupportBot_Version: "7.1 pre-1"
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# General Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
Token: "BOT_TOKEN_HERE"
|
|
||||||
Prefix: "!!"
|
|
||||||
Bot_Name: "SupportBot"
|
|
||||||
|
|
||||||
DeleteMessages: true
|
|
||||||
# Should the bot delete command messages after executed?
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Activity Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
BotActivity: "-help | SupportBot"
|
|
||||||
|
|
||||||
StreamingURL: "https://www.twitch.tv/YOUR_TWITCH_NAME"
|
|
||||||
# Set The ActivityType to "STREAMING" for a streaming status!
|
|
||||||
|
|
||||||
ActivityType: "PLAYING"
|
|
||||||
# Activity status can either be PLAYING, WATCHING, LISTENING or STREAMING.
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Embed Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
EmbedColour: "#f74343"
|
|
||||||
EmbedFooter: "SupportBot | The #1 Supportive Discord Bot"
|
|
||||||
|
|
||||||
ErrorColour: "#d12519"
|
|
||||||
SuccessColour: "#04b545"
|
|
||||||
WarningColour: "#fca117"
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Help Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
HelpMenu: true # Do not change!
|
|
||||||
SendHelpPage: "channel" # Set to channel or dm
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Role Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
AutoRole: true
|
|
||||||
AutoRole_Role: "Member"
|
|
||||||
LockdownRole: "@everyone"
|
|
||||||
|
|
||||||
Staff: "Staff"
|
|
||||||
Admin: "Admin"
|
|
||||||
TicketBlackListRole: "Blacklisted"
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Tickets Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
# --- General Config ---
|
|
||||||
# --- Start ---
|
|
||||||
|
|
||||||
TicketCategory: "▬▬ TICKETS ▬▬"
|
|
||||||
TicketChannel: "ticket"
|
|
||||||
|
|
||||||
TicketLog: "ticket-logs"
|
|
||||||
TranscriptLog: "transcripts"
|
|
||||||
|
|
||||||
TranscriptTitle: "Ticket Transcript"
|
|
||||||
TicketBlackListMessage: "You are not allowed to open a ticket"
|
|
||||||
|
|
||||||
TicketSubject: "description"
|
|
||||||
# "description" will displays the ticket reason within the channel description
|
|
||||||
# "embed" will displays the ticket reason within the ticket embed
|
|
||||||
|
|
||||||
AllowTicketMentions: true
|
|
||||||
# Set to true to allow the ticket to mention the author and the support team.
|
|
||||||
# Set to false to dis-allow mentions within tickets.
|
|
||||||
|
|
||||||
# --- Panel Config ---
|
|
||||||
# --- Start ---
|
|
||||||
|
|
||||||
ReactionChannel: "create-ticket"
|
|
||||||
ReactionEmoji: "📩"
|
|
||||||
# For cusomt emojis: <:emoji_name:EMOJI_ID>
|
|
||||||
|
|
||||||
ReactionTickets: true
|
|
||||||
ReactionMessage: "React with %reaction_emoji% to create a Support Ticket!"
|
|
||||||
|
|
||||||
ReactionPanel_Description: true
|
|
||||||
ReactionDescription: "Create a support ticket to contact a member of staff."
|
|
||||||
|
|
||||||
ReactionPanel_Thumbnail: true
|
|
||||||
ReactionThumbnail: "https://hotemoji.com/images/dl/5/ticket-emoji-by-twitter.png"
|
|
||||||
|
|
||||||
ReactionPanel_Image: true
|
|
||||||
ReactionImage: "https://wallpapercave.com/wp/wp4462546.jpg"
|
|
||||||
|
|
||||||
# --- Creation Config ---
|
|
||||||
# --- Start ---
|
|
||||||
|
|
||||||
# Available Placeholders:
|
|
||||||
|
|
||||||
# %ticketusername% - User who created the ticket.
|
|
||||||
# <@%ticketauthor%> - Tags the user who created the ticket.
|
|
||||||
# <#%ticketid%> - Mentions the ticket channel.
|
|
||||||
|
|
||||||
|
|
||||||
Ticket_Title: "Server Support | %ticketusername%"
|
|
||||||
TicketMessage: "Hello <@%ticketauthor%>, Thank you for creating a support ticket\nPlease wait patiently whilst a member of our team reaches out to you."
|
|
||||||
|
|
||||||
Ticket_Thumbnail: "https://images.emojiterra.com/google/android-pie/512px/1f39f.png"
|
|
||||||
NoTicketSubject: "No Reason Provided!"
|
|
||||||
|
|
||||||
TicketCreatedAlert: ":ticket: Your support ticket has been created: <#%ticketid%>"
|
|
||||||
|
|
||||||
AddedUser: "👍 <@%user%> has been added to this ticket"
|
|
||||||
RemovedUser: "👍 <@%user%> has been removed from this ticket"
|
|
||||||
|
|
||||||
|
|
||||||
TicketLockReaction: "🔒"
|
|
||||||
TicketDeleteReaction: "⛔"
|
|
||||||
|
|
||||||
TranscriptSavedMessage: "📝 **Transcript Saved!**"
|
|
||||||
TicketLockMessage: "❌ **Ticket Locked!**"
|
|
||||||
TicketDeleteMessage: "⚠ **Ticket Deleting!**" # Tickets deleting after 5 seconds by default.
|
|
||||||
TicketDeleteTime: 5000 # Time must be set in miliseconds.
|
|
||||||
|
|
||||||
# --- Closing Config ---
|
|
||||||
# --- Start ---
|
|
||||||
|
|
||||||
ClosingTicket: ":warning: You have requested to close your support ticket."
|
|
||||||
ClosingConfirmation_Word: "confirm"
|
|
||||||
CloseConfirmation: true
|
|
||||||
|
|
||||||
# --- Departments Config ---
|
|
||||||
# --- Start ---
|
|
||||||
|
|
||||||
TicketDepartments: true
|
|
||||||
|
|
||||||
AllowStaff: true
|
|
||||||
# If set to true users with the "Staff" role will not be able to view tickets
|
|
||||||
# without a valid department role set below.
|
|
||||||
|
|
||||||
# Set to false to allow "Staff" to see tickets whether its a department for them or not.
|
|
||||||
|
|
||||||
DepartmentEmoji_1: "🙋"
|
|
||||||
DepartmentEmoji_2: "💸"
|
|
||||||
DepartmentEmoji_3: "📗"
|
|
||||||
# Ticket emojis, the emojis are what users will need to react with inorder to proceed furthur if departments are enabled.
|
|
||||||
|
|
||||||
DepartmentTitle_1: "Support"
|
|
||||||
DepartmentTitle_2: "Billing"
|
|
||||||
DepartmentTitle_3: "Other"
|
|
||||||
# Ticket department title, This is the title for a ticket department to help users know what is available.
|
|
||||||
|
|
||||||
DepartmentRole_1: "Support"
|
|
||||||
DepartmentRole_2: "Admin"
|
|
||||||
DepartmentRole_3: "Support"
|
|
||||||
# Ticket roles are the roles that will be able to gain access to tickets depending on what department has been choosen.
|
|
||||||
|
|
||||||
# --------------------------------
|
|
||||||
# System Messages Configuration
|
|
||||||
# --------------------------------
|
|
||||||
|
|
||||||
# Available Placeholders:
|
|
||||||
# %guildname% - This displays the name of the discord server.
|
|
||||||
|
|
||||||
SystemMessages: true
|
|
||||||
SystemMessage_EmbedFooter: false
|
|
||||||
|
|
||||||
SystemMessage_Channel: "system-messages"
|
|
||||||
SystemMessage_Type: "embed"
|
|
||||||
# There are 2 types of how you can send system messages, 'normal' or 'embed'
|
|
||||||
|
|
||||||
SystemMessage_Icon: "USER"
|
|
||||||
# USER - This will display the user's icon of who joins.
|
|
||||||
# BOT - This will display the bot's icon when a someone joins.
|
|
||||||
|
|
||||||
Welcome_Title: "User Joined!"
|
|
||||||
WelcomeMessage: "Hello %member%, Welcome to %guildname%!"
|
|
||||||
# %member% define the user who joined and %guildnamne% defines the server name.
|
|
||||||
|
|
||||||
Leave_Title: "User Left!"
|
|
||||||
LeaveMessage: "Goodbye %member%, Thank you for visting %guildname%!"
|
|
||||||
# %member% define the user who left and %guildnamne% defines the server name.
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Links Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
LinksTitle: "Server Links"
|
|
||||||
|
|
||||||
LINKS:
|
|
||||||
"Website": "https://www.example.com"
|
|
||||||
"Store": "https://store.example.com"
|
|
||||||
"Discord": "https://discord.gg/example"
|
|
||||||
# "Twitter": "https://twitter.com/example"
|
|
||||||
# "Add More": "Just follow this format!"
|
|
||||||
|
|
||||||
# --------------------------
|
|
||||||
# Suggestion Configuration
|
|
||||||
# --------------------------
|
|
||||||
|
|
||||||
SuggestionChannel: "suggestions"
|
|
||||||
SuggestionTitle: "Suggestion"
|
|
||||||
|
|
||||||
SuggestionStarter: "What would you like to suggest?"
|
|
||||||
SuggestReact_1: 👍
|
|
||||||
SuggestReact_2: 👎
|
|
||||||
|
|
||||||
# ----------------------------
|
|
||||||
# Announcement Configuration
|
|
||||||
# ----------------------------
|
|
||||||
|
|
||||||
AnnouncementChannel: "announcements"
|
|
||||||
AnnouncementTitle: "Servername Announcement"
|
|
||||||
AnnouncementIcon: "https://i.imgur.com/HbkZyB7.png"
|
|
||||||
|
|
||||||
AnnouncementStarter: "What would you like to announce?"
|
|
||||||
|
|
||||||
# --------------------------
|
|
||||||
# Moderation Configuration
|
|
||||||
# --------------------------
|
|
||||||
|
|
||||||
BanTitle: "User Banned!"
|
|
||||||
DaysBannedFor: 7
|
|
||||||
BanLogColour: "#D911B4"
|
|
||||||
|
|
||||||
KickTitle: "User Kicked!"
|
|
||||||
KickLogColour: "#D9B111"
|
|
||||||
|
|
||||||
ModThumbnail: "https://i.imgur.com/l6P3DF6.png"
|
|
||||||
ModLogChannel: "mod-logs"
|
|
||||||
|
|
||||||
PruneLogTitle: "Bulk Delete"
|
|
||||||
PruneThumbnail: "https://i.imgur.com/OAgW2vR.png"
|
|
||||||
PruneColour: "#1BA30C"
|
|
||||||
|
|
||||||
BlacklistTitle: "Blacklisted User"
|
|
||||||
BlacklistColour: "#000000"
|
|
||||||
|
|
||||||
# --------------------------
|
|
||||||
# Command Configuration
|
|
||||||
# --------------------------
|
|
||||||
|
|
||||||
# --- User Commands ---
|
|
||||||
|
|
||||||
HelpCommand: "help"
|
|
||||||
LinksCommand: "links"
|
|
||||||
PingCommand: "ping"
|
|
||||||
SuggestCommand: "suggest"
|
|
||||||
|
|
||||||
# --- Ticket Commands ---
|
|
||||||
|
|
||||||
NewTicket: "ticket"
|
|
||||||
CloseTicket: "close"
|
|
||||||
AddUser: "add"
|
|
||||||
RemoveUser: "remove"
|
|
||||||
RenameTicket: "rename"
|
|
||||||
|
|
||||||
# --- Staff/Admin Commands ---
|
|
||||||
|
|
||||||
BotSay: "say"
|
|
||||||
PurgeMessage: "purge"
|
|
||||||
|
|
||||||
AnnounceCommand: "announce"
|
|
||||||
BanUser: "ban"
|
|
||||||
KickUser: "kick"
|
|
||||||
BlacklistUser: "blacklist"
|
|
||||||
|
|
||||||
# --------------------------
|
|
||||||
# Messages Configuration
|
|
||||||
# --------------------------
|
|
||||||
|
|
||||||
# --- Command Messages ---
|
|
||||||
|
|
||||||
NewTicketDesc: "Create a new support ticket"
|
|
||||||
AnnounceDesc: "Create a server announcement"
|
|
||||||
CloseTicketDesc: "Close your support ticket"
|
|
||||||
LinksDesc: "View some important links"
|
|
||||||
PingDesc: "Get the bot's latency"
|
|
||||||
HelpDesc: "Get a list of all the commands"
|
|
||||||
RemoveUserDesc: "Remove a user from a support ticket"
|
|
||||||
AddUserDesc: "Add a user to a support ticket"
|
|
||||||
SuggestionDesc: "Create a server suggestion"
|
|
||||||
BotSayDesc: "Say something with the bot"
|
|
||||||
BanDesc: "Ban a member from this server."
|
|
||||||
KickDesc: "Kick a member from this server."
|
|
||||||
PurgeDesc: "Purge messages from the chat."
|
|
||||||
BlacklistDesc: "Decline a member to open a ticket"
|
|
||||||
|
|
||||||
# Error / Warning Messages
|
|
||||||
|
|
||||||
IncorrectPerms: ":x: **Err!** You do not have the correct permissions to use this command."
|
|
||||||
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. This command is used when closing a ticket."
|
|
||||||
TicketExists: ":warning: This ticket cannot be opened, It already exists!"
|
|
||||||
Generated
-519
@@ -1,519 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "supportbot",
|
|
||||||
"version": "7.0.0",
|
|
||||||
"lockfileVersion": 1,
|
|
||||||
"requires": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@discordjs/collection": {
|
|
||||||
"version": "0.1.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz",
|
|
||||||
"integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ=="
|
|
||||||
},
|
|
||||||
"@discordjs/form-data": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==",
|
|
||||||
"requires": {
|
|
||||||
"asynckit": "^0.4.0",
|
|
||||||
"combined-stream": "^1.0.8",
|
|
||||||
"mime-types": "^2.1.12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@tootallnate/once": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw=="
|
|
||||||
},
|
|
||||||
"abab": {
|
|
||||||
"version": "2.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
|
|
||||||
"integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q=="
|
|
||||||
},
|
|
||||||
"abort-controller": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
|
||||||
"requires": {
|
|
||||||
"event-target-shim": "^5.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"acorn": {
|
|
||||||
"version": "8.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz",
|
|
||||||
"integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA=="
|
|
||||||
},
|
|
||||||
"acorn-globals": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz",
|
|
||||||
"integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==",
|
|
||||||
"requires": {
|
|
||||||
"acorn": "^7.1.1",
|
|
||||||
"acorn-walk": "^7.1.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"acorn": {
|
|
||||||
"version": "7.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
|
||||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"acorn-walk": {
|
|
||||||
"version": "7.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
|
|
||||||
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA=="
|
|
||||||
},
|
|
||||||
"agent-base": {
|
|
||||||
"version": "6.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
|
||||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
|
||||||
"requires": {
|
|
||||||
"debug": "4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"argparse": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
|
||||||
},
|
|
||||||
"asynckit": {
|
|
||||||
"version": "0.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
|
||||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
|
||||||
},
|
|
||||||
"browser-process-hrtime": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
|
|
||||||
},
|
|
||||||
"combined-stream": {
|
|
||||||
"version": "1.0.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
|
||||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
|
||||||
"requires": {
|
|
||||||
"delayed-stream": "~1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cssom": {
|
|
||||||
"version": "0.4.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
|
|
||||||
"integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw=="
|
|
||||||
},
|
|
||||||
"cssstyle": {
|
|
||||||
"version": "2.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
|
|
||||||
"integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
|
|
||||||
"requires": {
|
|
||||||
"cssom": "~0.3.6"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"cssom": {
|
|
||||||
"version": "0.3.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
|
|
||||||
"integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data-urls": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==",
|
|
||||||
"requires": {
|
|
||||||
"abab": "^2.0.3",
|
|
||||||
"whatwg-mimetype": "^2.3.0",
|
|
||||||
"whatwg-url": "^8.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"debug": {
|
|
||||||
"version": "4.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
|
||||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
|
||||||
"requires": {
|
|
||||||
"ms": "2.1.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"decimal.js": {
|
|
||||||
"version": "10.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz",
|
|
||||||
"integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
|
|
||||||
},
|
|
||||||
"deep-is": {
|
|
||||||
"version": "0.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
|
|
||||||
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
|
|
||||||
},
|
|
||||||
"delayed-stream": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
|
||||||
},
|
|
||||||
"discord.js": {
|
|
||||||
"version": "12.5.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz",
|
|
||||||
"integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==",
|
|
||||||
"requires": {
|
|
||||||
"@discordjs/collection": "^0.1.6",
|
|
||||||
"@discordjs/form-data": "^3.0.1",
|
|
||||||
"abort-controller": "^3.0.0",
|
|
||||||
"node-fetch": "^2.6.1",
|
|
||||||
"prism-media": "^1.2.9",
|
|
||||||
"setimmediate": "^1.0.5",
|
|
||||||
"tweetnacl": "^1.0.3",
|
|
||||||
"ws": "^7.4.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domexception": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==",
|
|
||||||
"requires": {
|
|
||||||
"webidl-conversions": "^5.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"webidl-conversions": {
|
|
||||||
"version": "5.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
|
|
||||||
"integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"escodegen": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==",
|
|
||||||
"requires": {
|
|
||||||
"esprima": "^4.0.1",
|
|
||||||
"estraverse": "^5.2.0",
|
|
||||||
"esutils": "^2.0.2",
|
|
||||||
"optionator": "^0.8.1",
|
|
||||||
"source-map": "~0.6.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"esprima": {
|
|
||||||
"version": "4.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
|
||||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
|
||||||
},
|
|
||||||
"estraverse": {
|
|
||||||
"version": "5.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
|
|
||||||
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ=="
|
|
||||||
},
|
|
||||||
"esutils": {
|
|
||||||
"version": "2.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
|
||||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
|
|
||||||
},
|
|
||||||
"event-target-shim": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
|
|
||||||
},
|
|
||||||
"fast-levenshtein": {
|
|
||||||
"version": "2.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
|
||||||
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
|
|
||||||
},
|
|
||||||
"form-data": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
|
||||||
"requires": {
|
|
||||||
"asynckit": "^0.4.0",
|
|
||||||
"combined-stream": "^1.0.8",
|
|
||||||
"mime-types": "^2.1.12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"html-encoding-sniffer": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==",
|
|
||||||
"requires": {
|
|
||||||
"whatwg-encoding": "^1.0.5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"http-proxy-agent": {
|
|
||||||
"version": "4.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
|
|
||||||
"integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
|
|
||||||
"requires": {
|
|
||||||
"@tootallnate/once": "1",
|
|
||||||
"agent-base": "6",
|
|
||||||
"debug": "4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"https-proxy-agent": {
|
|
||||||
"version": "5.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
|
|
||||||
"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
|
|
||||||
"requires": {
|
|
||||||
"agent-base": "6",
|
|
||||||
"debug": "4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"iconv-lite": {
|
|
||||||
"version": "0.4.24",
|
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
|
||||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
|
||||||
"requires": {
|
|
||||||
"safer-buffer": ">= 2.1.2 < 3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"is-potential-custom-element-name": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
|
|
||||||
},
|
|
||||||
"js-yaml": {
|
|
||||||
"version": "4.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
|
||||||
"requires": {
|
|
||||||
"argparse": "^2.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jsdom": {
|
|
||||||
"version": "16.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz",
|
|
||||||
"integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==",
|
|
||||||
"requires": {
|
|
||||||
"abab": "^2.0.5",
|
|
||||||
"acorn": "^8.2.4",
|
|
||||||
"acorn-globals": "^6.0.0",
|
|
||||||
"cssom": "^0.4.4",
|
|
||||||
"cssstyle": "^2.3.0",
|
|
||||||
"data-urls": "^2.0.0",
|
|
||||||
"decimal.js": "^10.2.1",
|
|
||||||
"domexception": "^2.0.1",
|
|
||||||
"escodegen": "^2.0.0",
|
|
||||||
"form-data": "^3.0.0",
|
|
||||||
"html-encoding-sniffer": "^2.0.1",
|
|
||||||
"http-proxy-agent": "^4.0.1",
|
|
||||||
"https-proxy-agent": "^5.0.0",
|
|
||||||
"is-potential-custom-element-name": "^1.0.1",
|
|
||||||
"nwsapi": "^2.2.0",
|
|
||||||
"parse5": "6.0.1",
|
|
||||||
"saxes": "^5.0.1",
|
|
||||||
"symbol-tree": "^3.2.4",
|
|
||||||
"tough-cookie": "^4.0.0",
|
|
||||||
"w3c-hr-time": "^1.0.2",
|
|
||||||
"w3c-xmlserializer": "^2.0.0",
|
|
||||||
"webidl-conversions": "^6.1.0",
|
|
||||||
"whatwg-encoding": "^1.0.5",
|
|
||||||
"whatwg-mimetype": "^2.3.0",
|
|
||||||
"whatwg-url": "^8.5.0",
|
|
||||||
"ws": "^7.4.6",
|
|
||||||
"xml-name-validator": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"levn": {
|
|
||||||
"version": "0.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
|
|
||||||
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
|
|
||||||
"requires": {
|
|
||||||
"prelude-ls": "~1.1.2",
|
|
||||||
"type-check": "~0.3.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lodash": {
|
|
||||||
"version": "4.17.21",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
|
||||||
},
|
|
||||||
"mime-db": {
|
|
||||||
"version": "1.48.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
|
||||||
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
|
|
||||||
},
|
|
||||||
"mime-types": {
|
|
||||||
"version": "2.1.31",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
|
|
||||||
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
|
|
||||||
"requires": {
|
|
||||||
"mime-db": "1.48.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ms": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
|
||||||
},
|
|
||||||
"node-fetch": {
|
|
||||||
"version": "2.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
|
||||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
|
||||||
},
|
|
||||||
"nwsapi": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
|
|
||||||
"integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ=="
|
|
||||||
},
|
|
||||||
"optionator": {
|
|
||||||
"version": "0.8.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
|
|
||||||
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
|
|
||||||
"requires": {
|
|
||||||
"deep-is": "~0.1.3",
|
|
||||||
"fast-levenshtein": "~2.0.6",
|
|
||||||
"levn": "~0.3.0",
|
|
||||||
"prelude-ls": "~1.1.2",
|
|
||||||
"type-check": "~0.3.2",
|
|
||||||
"word-wrap": "~1.2.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parse5": {
|
|
||||||
"version": "6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
|
|
||||||
},
|
|
||||||
"prelude-ls": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
|
||||||
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
|
|
||||||
},
|
|
||||||
"prism-media": {
|
|
||||||
"version": "1.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.1.tgz",
|
|
||||||
"integrity": "sha512-nyYAa3KB4qteJIqdguKmwxTJgy55xxUtkJ3uRnOvO5jO+frci+9zpRXw6QZVcfDeva3S654fU9+26P2OSTzjHw=="
|
|
||||||
},
|
|
||||||
"psl": {
|
|
||||||
"version": "1.8.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
|
|
||||||
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
|
|
||||||
},
|
|
||||||
"punycode": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
|
||||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
|
||||||
},
|
|
||||||
"safer-buffer": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
|
||||||
},
|
|
||||||
"saxes": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
|
|
||||||
"requires": {
|
|
||||||
"xmlchars": "^2.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"setimmediate": {
|
|
||||||
"version": "1.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
|
||||||
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
|
|
||||||
},
|
|
||||||
"source-map": {
|
|
||||||
"version": "0.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"symbol-tree": {
|
|
||||||
"version": "3.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
|
|
||||||
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
|
|
||||||
},
|
|
||||||
"tough-cookie": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
|
|
||||||
"requires": {
|
|
||||||
"psl": "^1.1.33",
|
|
||||||
"punycode": "^2.1.1",
|
|
||||||
"universalify": "^0.1.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tr46": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==",
|
|
||||||
"requires": {
|
|
||||||
"punycode": "^2.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tweetnacl": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
|
|
||||||
},
|
|
||||||
"type-check": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
|
|
||||||
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
|
|
||||||
"requires": {
|
|
||||||
"prelude-ls": "~1.1.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"universalify": {
|
|
||||||
"version": "0.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
|
||||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
|
|
||||||
},
|
|
||||||
"w3c-hr-time": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==",
|
|
||||||
"requires": {
|
|
||||||
"browser-process-hrtime": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"w3c-xmlserializer": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
|
|
||||||
"requires": {
|
|
||||||
"xml-name-validator": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"webidl-conversions": {
|
|
||||||
"version": "6.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
|
|
||||||
"integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w=="
|
|
||||||
},
|
|
||||||
"whatwg-encoding": {
|
|
||||||
"version": "1.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
|
|
||||||
"integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
|
|
||||||
"requires": {
|
|
||||||
"iconv-lite": "0.4.24"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"whatwg-mimetype": {
|
|
||||||
"version": "2.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
|
|
||||||
"integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
|
|
||||||
},
|
|
||||||
"whatwg-url": {
|
|
||||||
"version": "8.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz",
|
|
||||||
"integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==",
|
|
||||||
"requires": {
|
|
||||||
"lodash": "^4.7.0",
|
|
||||||
"tr46": "^2.1.0",
|
|
||||||
"webidl-conversions": "^6.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"word-wrap": {
|
|
||||||
"version": "1.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
|
||||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
|
|
||||||
},
|
|
||||||
"ws": {
|
|
||||||
"version": "7.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.1.tgz",
|
|
||||||
"integrity": "sha512-2c6faOUH/nhoQN6abwMloF7Iyl0ZS2E9HGtsiLrWn0zOOMWlhtDmdf/uihDt6jnuCxgtwGBNy6Onsoy2s2O2Ow=="
|
|
||||||
},
|
|
||||||
"xml-name-validator": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
|
|
||||||
},
|
|
||||||
"xmlchars": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
|
||||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+20
-8
@@ -1,19 +1,31 @@
|
|||||||
{
|
{
|
||||||
"name": "supportbot",
|
"name": "supportbot",
|
||||||
"version": "7.1",
|
"version": "8.3",
|
||||||
"description": "SupportBot, a free open-source discord ticket application with ease of use.",
|
"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",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"supportbot": "node index.js"
|
"setup": "npm i && node index.js",
|
||||||
|
"start": "node index.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/Emerald-Services/SupportBot.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
|
||||||
"supportbot"
|
|
||||||
],
|
|
||||||
"author": "Emerald Services",
|
"author": "Emerald Services",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/Emerald-Services/SupportBot/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://community.emeraldsrv.dev",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"discord.js": "^12.5.3",
|
"@paypal/checkout-server-sdk": "^1.0.3",
|
||||||
|
"@vitalets/google-translate-api": "^8.0.0",
|
||||||
|
"axios": "^1.7.2",
|
||||||
|
"discord.js": "^14.13.0",
|
||||||
|
"js": "^0.1.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"jsdom": "^16.7.0"
|
"moment": "^2.29.3",
|
||||||
|
"ms": "^2.1.3",
|
||||||
|
"openai": "^4.50.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
{}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ReactionMessage_ID: ''
|
|
||||||
@@ -1,300 +0,0 @@
|
|||||||
# ___ _ ___ _
|
|
||||||
# / __> _ _ ___ ___ ___ _ _ _| |_ | . > ___ _| |_
|
|
||||||
# \__ \| | || . \| . \/ . \| '_> | | | . \/ . \ | |
|
|
||||||
# <___/`___|| _/| _/\___/|_| |_| |___/\___/ |_|
|
|
||||||
# |_| |_|
|
|
||||||
#
|
|
||||||
# SupportBot created by Emerald Services
|
|
||||||
# Installed with MIT License
|
|
||||||
#
|
|
||||||
# Discord Support: https://emeraldsrv.dev/discord
|
|
||||||
|
|
||||||
SupportBot_Version: "7.1"
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# General Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
Token: "BOT_TOKEN_HERE"
|
|
||||||
Prefix: "!"
|
|
||||||
Bot_Name: "SupportBot"
|
|
||||||
|
|
||||||
DeleteMessages: true
|
|
||||||
# Should the bot delete command messages after executed?
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Activity Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
BotActivity: "-help | SupportBot"
|
|
||||||
|
|
||||||
StreamingURL: "https://www.twitch.tv/YOUR_TWITCH_NAME"
|
|
||||||
# Set The ActivityType to "STREAMING" for a streaming status!
|
|
||||||
|
|
||||||
ActivityType: "PLAYING"
|
|
||||||
# Activity status can either be PLAYING, WATCHING, LISTENING or STREAMING.
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Embed Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
EmbedColour: "#f74343"
|
|
||||||
EmbedFooter: "SupportBot | The #1 Supportive Discord Bot"
|
|
||||||
|
|
||||||
ErrorColour: "#d12519"
|
|
||||||
SuccessColour: "#04b545"
|
|
||||||
WarningColour: "#fca117"
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Help Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
HelpMenu: true # Do not change!
|
|
||||||
SendHelpPage: "channel" # Set to channel or dm
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Role Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
AutoRole: true
|
|
||||||
AutoRole_Role: "Member"
|
|
||||||
LockdownRole: "@everyone"
|
|
||||||
|
|
||||||
Staff: "Staff"
|
|
||||||
Admin: "Admin"
|
|
||||||
TicketBlackListRole: "Blacklisted"
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Tickets Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
# --- General Config ---
|
|
||||||
# --- Start ---
|
|
||||||
|
|
||||||
TicketCategory: "▬▬ TICKETS ▬▬"
|
|
||||||
TicketChannel: "ticket"
|
|
||||||
|
|
||||||
TicketLog: "ticket-logs"
|
|
||||||
TranscriptLog: "transcripts"
|
|
||||||
|
|
||||||
TranscriptTitle: "Ticket Transcript"
|
|
||||||
TicketLog_Title: "Ticket Log"
|
|
||||||
TicketBlackListMessage: "You are not allowed to open a ticket"
|
|
||||||
|
|
||||||
TicketSubject: "description"
|
|
||||||
# "description" will displays the ticket reason within the channel description
|
|
||||||
# "embed" will displays the ticket reason within the ticket embed
|
|
||||||
|
|
||||||
AllowTicketMentions: true
|
|
||||||
# Set to true to allow the ticket to mention the author and the support team.
|
|
||||||
# Set to false to dis-allow mentions within tickets.
|
|
||||||
|
|
||||||
# --- Panel Config ---
|
|
||||||
# --- Start ---
|
|
||||||
|
|
||||||
ReactionChannel: "create-ticket"
|
|
||||||
ReactionEmoji: "📩"
|
|
||||||
# For cusomt emojis: <:emoji_name:EMOJI_ID>
|
|
||||||
|
|
||||||
ReactionTickets: true
|
|
||||||
ReactionMessage: "React with %reaction_emoji% to create a Support Ticket!"
|
|
||||||
|
|
||||||
ReactionPanel_Description: true
|
|
||||||
ReactionDescription: "Create a support ticket to contact a member of staff."
|
|
||||||
|
|
||||||
ReactionPanel_Thumbnail: true
|
|
||||||
ReactionThumbnail: "https://hotemoji.com/images/dl/5/ticket-emoji-by-twitter.png"
|
|
||||||
|
|
||||||
ReactionPanel_Image: true
|
|
||||||
ReactionImage: "https://wallpapercave.com/wp/wp4462546.jpg"
|
|
||||||
|
|
||||||
# --- Creation Config ---
|
|
||||||
# --- Start ---
|
|
||||||
|
|
||||||
# Available Placeholders:
|
|
||||||
|
|
||||||
# %ticketusername% - User who created the ticket.
|
|
||||||
# <@%ticketauthor%> - Tags the user who created the ticket.
|
|
||||||
# <#%ticketid%> - Mentions the ticket channel.
|
|
||||||
|
|
||||||
Ticket_Title: "Server Support | %ticketusername%"
|
|
||||||
TicketMessage: "Hello <@%ticketauthor%>, Thank you for creating a support ticket\nPlease wait patiently whilst a member of our team reaches out to you."
|
|
||||||
|
|
||||||
Ticket_Thumbnail: "https://images.emojiterra.com/google/android-pie/512px/1f39f.png"
|
|
||||||
NoTicketSubject: "No Reason Provided!"
|
|
||||||
|
|
||||||
TicketCreatedAlert: ":ticket: Your support ticket has been created: <#%ticketid%>"
|
|
||||||
|
|
||||||
AddedUser: "👍 <@%user%> has been added to this ticket"
|
|
||||||
RemovedUser: "👍 <@%user%> has been removed from this ticket"
|
|
||||||
|
|
||||||
|
|
||||||
TicketLockReaction: "🔒"
|
|
||||||
TicketDeleteReaction: "⛔"
|
|
||||||
|
|
||||||
TranscriptSavedMessage: "📝 **Transcript Saved!**"
|
|
||||||
TicketLockMessage: "❌ **Ticket Locked!**"
|
|
||||||
TicketDeleteMessage: "⚠ **Ticket Deleting!**" # Tickets deleting after 5 seconds by default.
|
|
||||||
TicketDeleteTime: 5000 # Time must be set in miliseconds.
|
|
||||||
|
|
||||||
# --- Closing Config ---
|
|
||||||
# --- Start ---
|
|
||||||
|
|
||||||
ClosingTicket: ":warning: You have requested to close your support ticket."
|
|
||||||
ClosingConfirmation_Word: "confirm"
|
|
||||||
CloseConfirmation: true
|
|
||||||
|
|
||||||
# --------------------------------
|
|
||||||
# System Messages Configuration
|
|
||||||
# --------------------------------
|
|
||||||
|
|
||||||
# Available Placeholders:
|
|
||||||
# %guildname% - This displays the name of the discord server.
|
|
||||||
|
|
||||||
SystemMessages: true
|
|
||||||
SystemMessage_EmbedFooter: false
|
|
||||||
|
|
||||||
SystemMessage_Channel: "system-messages"
|
|
||||||
SystemMessage_Type: "embed"
|
|
||||||
# There are 2 types of how you can send system messages, 'normal' or 'embed'
|
|
||||||
|
|
||||||
SystemMessage_Icon: "USER"
|
|
||||||
# USER - This will display the user's icon of who joins.
|
|
||||||
# BOT - This will display the bot's icon when a someone joins.
|
|
||||||
# CUSTOM - This will allow you to use a custom image, set this below!
|
|
||||||
SystemMessageIcon_URL: "https://imgur.com/example.png"
|
|
||||||
|
|
||||||
Welcome_Title: "User Joined!"
|
|
||||||
WelcomeMessage: "Hello %member%, Welcome to %guildname%!"
|
|
||||||
# %member% define the user who joined and %guildnamne% defines the server name.
|
|
||||||
|
|
||||||
Leave_Title: "User Left!"
|
|
||||||
LeaveMessage: "Goodbye %member%, Thank you for visting %guildname%!"
|
|
||||||
# %member% define the user who left and %guildnamne% defines the server name.
|
|
||||||
|
|
||||||
# -------------------------
|
|
||||||
# Links Configuration
|
|
||||||
# -------------------------
|
|
||||||
|
|
||||||
LinksTitle: "Server Links"
|
|
||||||
|
|
||||||
LINKS:
|
|
||||||
"Website": "https://www.example.com"
|
|
||||||
"Store": "https://store.example.com"
|
|
||||||
"Discord": "https://discord.gg/example"
|
|
||||||
# "Twitter": "https://twitter.com/example"
|
|
||||||
# "Add More": "Just follow this format!"
|
|
||||||
|
|
||||||
# --------------------------
|
|
||||||
# Suggestion Configuration
|
|
||||||
# --------------------------
|
|
||||||
|
|
||||||
SuggestionChannel: "suggestions"
|
|
||||||
SuggestionTitle: "Suggestion"
|
|
||||||
|
|
||||||
SuggestionStarter: "What would you like to suggest?"
|
|
||||||
SuggestReact_1: 👍
|
|
||||||
SuggestReact_2: 👎
|
|
||||||
|
|
||||||
SuggestionMessage_Icon: "USER"
|
|
||||||
# USER - This will display the user's icon of who joins.
|
|
||||||
# BOT - This will display the bot's icon when a someone joins.
|
|
||||||
# CUSTOM - This will allow you to use a custom image, set this below!
|
|
||||||
SuggestionIcon_URL: "https://imgur.com/example.png"
|
|
||||||
|
|
||||||
# ----------------------------
|
|
||||||
# Announcement Configuration
|
|
||||||
# ----------------------------
|
|
||||||
|
|
||||||
AnnouncementChannel: "announcements"
|
|
||||||
AnnouncementTitle: "Servername Announcement"
|
|
||||||
AnnouncementIcon: "https://i.imgur.com/HbkZyB7.png"
|
|
||||||
|
|
||||||
AnnouncementStarter: "What would you like to announce?"
|
|
||||||
|
|
||||||
# --------------------------
|
|
||||||
# Moderation Configuration
|
|
||||||
# --------------------------
|
|
||||||
|
|
||||||
ChatLog_Title: "Chat Log"
|
|
||||||
ChatLogChannel: "chat-logs"
|
|
||||||
ChatLogColour: "#1BA30C"
|
|
||||||
ChatLog_Thumbnail: "https://cdn.iconscout.com/icon/free/png-256/chat-2639493-2187526.png"
|
|
||||||
ChatLogSavedMessage: "📝 **Channel Transcript Saved!**"
|
|
||||||
|
|
||||||
BanTitle: "User Banned!"
|
|
||||||
DaysBannedFor: 7
|
|
||||||
BanLogColour: "#D911B4"
|
|
||||||
|
|
||||||
KickTitle: "User Kicked!"
|
|
||||||
KickLogColour: "#D9B111"
|
|
||||||
|
|
||||||
ModThumbnail: "https://i.imgur.com/l6P3DF6.png"
|
|
||||||
ModLogChannel: "mod-logs"
|
|
||||||
|
|
||||||
PruneLogTitle: "Bulk Delete"
|
|
||||||
PruneThumbnail: "https://i.imgur.com/OAgW2vR.png"
|
|
||||||
PruneColour: "#1BA30C"
|
|
||||||
|
|
||||||
BlacklistTitle: "Blacklisted User"
|
|
||||||
BlacklistColour: "#000000"
|
|
||||||
|
|
||||||
# --------------------------
|
|
||||||
# Command Configuration
|
|
||||||
# --------------------------
|
|
||||||
|
|
||||||
# --- User Commands ---
|
|
||||||
|
|
||||||
HelpCommand: "help"
|
|
||||||
LinksCommand: "links"
|
|
||||||
PingCommand: "ping"
|
|
||||||
SuggestCommand: "suggest"
|
|
||||||
|
|
||||||
# --- Ticket Commands ---
|
|
||||||
|
|
||||||
NewTicket: "ticket"
|
|
||||||
CloseTicket: "close"
|
|
||||||
AddUser: "add"
|
|
||||||
RemoveUser: "remove"
|
|
||||||
RenameTicket: "rename"
|
|
||||||
|
|
||||||
# --- Staff/Admin Commands ---
|
|
||||||
|
|
||||||
ChatLog: "transcript"
|
|
||||||
BotSay: "say"
|
|
||||||
PurgeMessage: "purge"
|
|
||||||
|
|
||||||
AnnounceCommand: "announce"
|
|
||||||
BanUser: "ban"
|
|
||||||
KickUser: "kick"
|
|
||||||
BlacklistUser: "blacklist"
|
|
||||||
|
|
||||||
# --------------------------
|
|
||||||
# Messages Configuration
|
|
||||||
# --------------------------
|
|
||||||
|
|
||||||
# --- Command Messages ---
|
|
||||||
|
|
||||||
BotSayDesc: "Say something with the bot"
|
|
||||||
ChatLogDesc: "Get a transcript of a channel"
|
|
||||||
NewTicketDesc: "Create a new support ticket"
|
|
||||||
AnnounceDesc: "Create a server announcement"
|
|
||||||
CloseTicketDesc: "Close your support ticket"
|
|
||||||
LinksDesc: "View some important links"
|
|
||||||
PingDesc: "Get the bot's latency"
|
|
||||||
HelpDesc: "Get a list of all the commands"
|
|
||||||
RemoveUserDesc: "Remove a user from a support ticket"
|
|
||||||
AddUserDesc: "Add a user to a support ticket"
|
|
||||||
SuggestionDesc: "Create a server suggestion"
|
|
||||||
BanDesc: "Ban a member from this server."
|
|
||||||
KickDesc: "Kick a member from this server."
|
|
||||||
PurgeDesc: "Purge messages from the chat."
|
|
||||||
BlacklistDesc: "Decline a member to open a ticket"
|
|
||||||
|
|
||||||
# Error / Warning Messages
|
|
||||||
|
|
||||||
IncorrectPerms: ":x: **Err!** You do not have the correct permissions to use this command."
|
|
||||||
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. This command is used when closing a ticket."
|
|
||||||
TicketExists: ":warning: This ticket cannot be opened, It already exists!"
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
// SupportBot Utils
|
|
||||||
// Ticket Numbers
|
|
||||||
|
|
||||||
const discord = require("discord.js")
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const supportbot = yaml.load(fs.readFileSync('./supportbot-config.yml', 'utf8'));
|
|
||||||
|
|
||||||
class TicketNumberID {
|
|
||||||
|
|
||||||
static pad(guildId) {
|
|
||||||
let n = this.get(guildId) + '';
|
|
||||||
let z = '0';
|
|
||||||
let width = 4;
|
|
||||||
setTimeout(() => {
|
|
||||||
this.set(guildId, this.get(guildId) + 1);
|
|
||||||
}, 50);
|
|
||||||
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get(guildId) {
|
|
||||||
|
|
||||||
let ticketnumberID = JSON.parse(fs.readFileSync("./storage/TicketID.json", "utf8"));
|
|
||||||
|
|
||||||
if (!ticketnumberID[guildId]) {
|
|
||||||
ticketnumberID[guildId] = {
|
|
||||||
id: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync("./storage/TicketID.json", JSON.stringify(ticketnumberID, null, 4), err => {
|
|
||||||
if (err) console.log(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return ticketnumberID[guildId].id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static set(guildId, value) {
|
|
||||||
let ticketnumberID = JSON.parse(fs.readFileSync("./storage/TicketID.json", "utf8"));
|
|
||||||
|
|
||||||
ticketnumberID[guildId] = {
|
|
||||||
id: value
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync("./storage/TicketID.json", JSON.stringify(ticketnumberID, null, 4), err => {
|
|
||||||
if (err) console.log(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static reset(guildId) {
|
|
||||||
let ticketnumberID = JSON.parse(fs.readFileSync("./storage/TicketID.json", "utf8"));
|
|
||||||
|
|
||||||
ticketnumberID[guildId] = {
|
|
||||||
id: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync("./storage/TicketID.json", JSON.stringify(ticketnumberID, null, 4), err => {
|
|
||||||
if (err) console.log(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = TicketNumberID;
|
|
||||||
Reference in new issue
Block a user