Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81bda67ae4 | ||
|
|
25bbd1ff85 | ||
|
|
164d695a5f | ||
|
|
57e4a3e77c | ||
|
|
a6ac532b2b | ||
|
|
4f14722e14 | ||
|
|
9a6eece7a1 | ||
|
|
fd65d0a9a7 | ||
|
|
48500fe8a4 |
No files matched your search
@@ -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,193 @@
|
||||
const fs = require("fs");
|
||||
const {
|
||||
EmbedBuilder,
|
||||
ApplicationCommandOptionType,
|
||||
ApplicationCommandType,
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
} = require("discord.js");
|
||||
const yaml = require("js-yaml");
|
||||
|
||||
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||
|
||||
const Command = require("../Structures/Command.js");
|
||||
|
||||
module.exports = new Command({
|
||||
name: cmdconfig.AddUser.Command,
|
||||
description: cmdconfig.AddUser.Description,
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
options: [
|
||||
{
|
||||
name: "user",
|
||||
description: "The user to add",
|
||||
type: ApplicationCommandOptionType.User,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
permissions: cmdconfig.AddUser.Permission,
|
||||
|
||||
async run(interaction) {
|
||||
const userToAdd = interaction.options.getUser("user");
|
||||
const ticketChannel = interaction.channel;
|
||||
const ticketDataPath = "./Data/TicketData.json";
|
||||
|
||||
// Check if the channel is a ticket thread
|
||||
if (!ticketChannel.isThread()) {
|
||||
const onlyInTicket = new EmbedBuilder()
|
||||
.setTitle(msgconfig.AddUser.NotInTicket_Title)
|
||||
.setDescription(msgconfig.AddUser.NotInTicket_Description)
|
||||
.setColor(supportbot.Embed.Colours.Error);
|
||||
|
||||
return interaction.reply({
|
||||
embeds: [onlyInTicket],
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
const ticketInviteEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.AddUser.Invite_Title)
|
||||
.setDescription(msgconfig.AddUser.Invite_Description.replace("%username%", userToAdd.username))
|
||||
.setColor(supportbot.Embed.Colours.General);
|
||||
|
||||
await interaction.reply({
|
||||
embeds: [ticketInviteEmbed],
|
||||
ephemeral: true,
|
||||
});
|
||||
|
||||
try {
|
||||
const dmEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.AddUser.DM_Title)
|
||||
.setDescription(msgconfig.AddUser.DM_Description.replace("%channelname%", ticketChannel.name))
|
||||
.setColor(supportbot.Embed.Colours.General);
|
||||
|
||||
const acceptButton = new ButtonBuilder()
|
||||
.setCustomId("accept_invite")
|
||||
.setLabel(msgconfig.AddUser.Accept_Label)
|
||||
.setEmoji("✅")
|
||||
.setStyle(ButtonStyle.Primary);
|
||||
|
||||
const rejectButton = new ButtonBuilder()
|
||||
.setCustomId("reject_invite")
|
||||
.setLabel(msgconfig.AddUser.Reject_Label)
|
||||
.setEmoji("❌")
|
||||
.setStyle(ButtonStyle.Secondary);
|
||||
|
||||
const row = new ActionRowBuilder().addComponents(acceptButton, rejectButton);
|
||||
|
||||
const dmMessage = await userToAdd.send({
|
||||
embeds: [dmEmbed],
|
||||
components: [row],
|
||||
});
|
||||
|
||||
const filter = (i) => i.user.id === userToAdd.id;
|
||||
const collector = dmMessage.createMessageComponentCollector({
|
||||
filter,
|
||||
time: 60000,
|
||||
});
|
||||
|
||||
collector.on("collect", async (i) => {
|
||||
if (i.customId === "accept_invite") {
|
||||
try {
|
||||
await ticketChannel.members.add(userToAdd.id);
|
||||
|
||||
const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8"));
|
||||
const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id);
|
||||
if (ticketIndex !== -1) {
|
||||
ticketData.tickets[ticketIndex].subUsers.push(userToAdd.id);
|
||||
fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4));
|
||||
}
|
||||
|
||||
const acceptedEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.AddUser.Accepted_Title)
|
||||
.setDescription(msgconfig.AddUser.Accepted_Message)
|
||||
.setColor(supportbot.Embed.Colours.Success);
|
||||
|
||||
await i.update({
|
||||
embeds: [acceptedEmbed],
|
||||
components: [],
|
||||
});
|
||||
|
||||
const addedToTicketEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.AddUser.AddedToTicket_Title)
|
||||
.setDescription(msgconfig.AddUser.AddedToTicket_Description.replace(
|
||||
"%channel_link%",
|
||||
`[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})`
|
||||
))
|
||||
.setColor(supportbot.Embed.Colours.General);
|
||||
|
||||
const ticketLinkButton = new ButtonBuilder()
|
||||
.setLabel(msgconfig.AddUser.ViewTicket_Label)
|
||||
.setURL(`https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id}`)
|
||||
.setStyle(ButtonStyle.Link);
|
||||
|
||||
await userToAdd.send({
|
||||
embeds: [addedToTicketEmbed],
|
||||
components: [new ActionRowBuilder().addComponents(ticketLinkButton)],
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error("Error adding user to the ticket:", err);
|
||||
|
||||
const errorEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.AddUser.Error_Title)
|
||||
.setDescription(msgconfig.AddUser.Error_Adding)
|
||||
.setColor(supportbot.Embed.Colours.Error);
|
||||
|
||||
await i.update({
|
||||
embeds: [errorEmbed],
|
||||
components: [],
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const declinedEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.AddUser.Declined_Title)
|
||||
.setDescription(msgconfig.AddUser.Declined_Message)
|
||||
.setColor(supportbot.Embed.Colours.Error);
|
||||
|
||||
await i.update({
|
||||
embeds: [declinedEmbed],
|
||||
components: [],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
collector.on("end", (collected) => {
|
||||
if (collected.size === 0) {
|
||||
userToAdd.send({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setTitle(msgconfig.AddUser.NoResponse_Title)
|
||||
.setDescription(msgconfig.AddUser.NoResponse_Message)
|
||||
.setColor(supportbot.Embed.Colours.Warning),
|
||||
],
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.code === 50007) {
|
||||
const errorEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.AddUser.DM_Error_Title)
|
||||
.setDescription(msgconfig.AddUser.DM_Error_Description.replace("%username%", userToAdd.username))
|
||||
.setColor(supportbot.Embed.Colours.Error);
|
||||
|
||||
await ticketChannel.send({
|
||||
embeds: [errorEmbed],
|
||||
});
|
||||
} else {
|
||||
console.error("Error sending DM:", error);
|
||||
|
||||
const unexpectedErrorEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.AddUser.Unexpected_Error_Title)
|
||||
.setDescription(msgconfig.AddUser.Unexpected_Error_Description.replace("%error%", error.message))
|
||||
.setColor(supportbot.Embed.Colours.Error);
|
||||
|
||||
await ticketChannel.send({
|
||||
embeds: [unexpectedErrorEmbed],
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
+2
-1
@@ -81,7 +81,8 @@ module.exports = new Command({
|
||||
const CloseButton = new Discord.ButtonBuilder()
|
||||
.setCustomId("confirmCloseTicket")
|
||||
.setLabel(supportbot.Ticket.Close.Confirmation_Button)
|
||||
.setStyle(Discord.ButtonStyle.Danger);
|
||||
.setEmoji(supportbot.Ticket.Close.Confirmation_Emoji)
|
||||
.setStyle(supportbot.Ticket.Close.Confirmation_Style);
|
||||
|
||||
const row = new Discord.ActionRowBuilder().addComponents(CloseButton);
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
// File: Commands/ForceAddUser.js
|
||||
const fs = require("fs");
|
||||
const {
|
||||
EmbedBuilder,
|
||||
ApplicationCommandOptionType,
|
||||
ApplicationCommandType,
|
||||
} = require("discord.js");
|
||||
const yaml = require("js-yaml");
|
||||
|
||||
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||
|
||||
const Command = require("../Structures/Command.js");
|
||||
|
||||
module.exports = new Command({
|
||||
name: cmdconfig.ForceAddUser.Command,
|
||||
description: cmdconfig.ForceAddUser.Description,
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
options: [
|
||||
{
|
||||
name: "user",
|
||||
description: "The user to add",
|
||||
type: ApplicationCommandOptionType.User,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
permissions: cmdconfig.ForceAddUser.Permission,
|
||||
|
||||
async run(interaction) {
|
||||
|
||||
const { getRole } = interaction.client;
|
||||
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||
if (!SupportStaff || !Admin)
|
||||
|
||||
return interaction.reply(
|
||||
"Some roles seem to be missing!\nPlease check for errors when starting the bot."
|
||||
);
|
||||
|
||||
const NoPerms = new EmbedBuilder()
|
||||
.setTitle("Invalid Permissions!")
|
||||
.setDescription(
|
||||
`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``
|
||||
)
|
||||
.setColor(supportbot.Embed.Colours.Warn);
|
||||
|
||||
if (
|
||||
!interaction.member.roles.cache.has(SupportStaff.id) &&
|
||||
!interaction.member.roles.cache.has(Admin.id)
|
||||
)
|
||||
return interaction.reply({ embeds: [NoPerms] });
|
||||
|
||||
const userToAdd = interaction.options.getUser("user");
|
||||
const ticketChannel = interaction.channel;
|
||||
const ticketDataPath = "./Data/TicketData.json";
|
||||
|
||||
if (!ticketChannel.isThread()) {
|
||||
const onlyInTicket = new EmbedBuilder()
|
||||
.setTitle(msgconfig.ForceAddUser.NotInTicket_Title)
|
||||
.setDescription(msgconfig.ForceAddUser.NotInTicket_Description)
|
||||
.setColor(supportbot.Embed.Colours.Error);
|
||||
|
||||
return interaction.reply({
|
||||
embeds: [onlyInTicket],
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await ticketChannel.members.add(userToAdd.id);
|
||||
|
||||
const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8"));
|
||||
const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id);
|
||||
if (ticketIndex !== -1) {
|
||||
ticketData.tickets[ticketIndex].subUsers.push(userToAdd.id);
|
||||
fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4));
|
||||
}
|
||||
|
||||
const addedEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.ForceAddUser.Added_Title)
|
||||
.setDescription(msgconfig.ForceAddUser.Added_Description.replace(
|
||||
"%username%",
|
||||
userToAdd.username
|
||||
))
|
||||
.setColor(supportbot.Embed.Colours.Success);
|
||||
|
||||
await interaction.reply({
|
||||
embeds: [addedEmbed],
|
||||
ephemeral: true,
|
||||
});
|
||||
|
||||
const addedToTicketEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.ForceAddUser.AddedToTicket_Title)
|
||||
.setDescription(msgconfig.ForceAddUser.AddedToTicket_Description.replace(
|
||||
"%channel_link%",
|
||||
`[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})`
|
||||
))
|
||||
.setColor(supportbot.Embed.Colours.General);
|
||||
|
||||
await userToAdd.send({
|
||||
embeds: [addedToTicketEmbed],
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error("Error adding user to the ticket:", err);
|
||||
|
||||
const errorEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.ForceAddUser.Error_Title)
|
||||
.setDescription(msgconfig.ForceAddUser.Error_Adding)
|
||||
.setColor(supportbot.Embed.Colours.Error);
|
||||
|
||||
await interaction.reply({
|
||||
embeds: [errorEmbed],
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
+10
-21
@@ -1,17 +1,9 @@
|
||||
// SupportBot | Emerald Services
|
||||
// Help 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 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");
|
||||
|
||||
@@ -32,11 +24,17 @@ module.exports = new Command({
|
||||
);
|
||||
}
|
||||
|
||||
// Fetch all commands from the client's commands collection
|
||||
// Separate regular commands and addon commands
|
||||
let botCommands = "";
|
||||
let addonCommands = "";
|
||||
|
||||
interaction.client.commands.forEach((command) => {
|
||||
if (command.permissions) {
|
||||
botCommands += `\`${command.name}\` `;
|
||||
if (command.addon) {
|
||||
addonCommands += `\`${command.name}\` `;
|
||||
} else {
|
||||
botCommands += `\`${command.name}\` `;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -51,15 +49,6 @@ module.exports = new Command({
|
||||
inline: false,
|
||||
});
|
||||
|
||||
// Conditionally add Addons section
|
||||
if (supportbot.General.Addons.Enabled) {
|
||||
HelpEmbed1.addFields({
|
||||
name: "🛠️ Addons\n",
|
||||
value: "No addons available.",
|
||||
inline: false,
|
||||
});
|
||||
}
|
||||
|
||||
HelpEmbed1.setFooter({
|
||||
text: supportbot.Embed.Footer,
|
||||
iconURL: interaction.user.displayAvatarURL(),
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
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();
|
||||
|
||||
async function getRole(roleName, guild) {
|
||||
return guild.roles.cache.find(role => role.name === roleName);
|
||||
}
|
||||
|
||||
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 }); // Acknowledge the interaction immediately
|
||||
|
||||
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 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,125 @@
|
||||
// File path: Commands/RemoveUser.js
|
||||
|
||||
const fs = require("fs");
|
||||
const {
|
||||
EmbedBuilder,
|
||||
ApplicationCommandOptionType,
|
||||
ApplicationCommandType,
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
} = require("discord.js");
|
||||
const yaml = require("js-yaml");
|
||||
|
||||
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||
|
||||
const Command = require("../Structures/Command.js");
|
||||
|
||||
module.exports = new Command({
|
||||
name: cmdconfig.RemoveUser.Command,
|
||||
description: cmdconfig.RemoveUser.Description,
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
options: [
|
||||
{
|
||||
name: "user",
|
||||
description: "The user to remove",
|
||||
type: ApplicationCommandOptionType.User,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
permissions: cmdconfig.RemoveUser.Permission,
|
||||
|
||||
async run(interaction) {
|
||||
|
||||
const { getRole } = interaction.client;
|
||||
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||
if (!SupportStaff || !Admin)
|
||||
|
||||
return interaction.reply(
|
||||
"Some roles seem to be missing!\nPlease check for errors when starting the bot."
|
||||
);
|
||||
|
||||
const NoPerms = new EmbedBuilder()
|
||||
.setTitle("Invalid Permissions!")
|
||||
.setDescription(
|
||||
`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``
|
||||
)
|
||||
.setColor(supportbot.Embed.Colours.Warn);
|
||||
|
||||
if (
|
||||
!interaction.member.roles.cache.has(SupportStaff.id) &&
|
||||
!interaction.member.roles.cache.has(Admin.id)
|
||||
)
|
||||
return interaction.reply({ embeds: [NoPerms] });
|
||||
|
||||
const userToRemove = interaction.options.getUser("user");
|
||||
const ticketChannel = interaction.channel;
|
||||
const ticketDataPath = "./Data/TicketData.json";
|
||||
|
||||
// Check if the channel is a ticket thread
|
||||
if (!ticketChannel.isThread()) {
|
||||
const onlyInTicket = new EmbedBuilder()
|
||||
.setTitle(msgconfig.RemoveUser.NotInTicket_Title)
|
||||
.setDescription(msgconfig.RemoveUser.NotInTicket_Description)
|
||||
.setColor(supportbot.Embed.Colours.Error);
|
||||
|
||||
return interaction.reply({
|
||||
embeds: [onlyInTicket],
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await ticketChannel.members.remove(userToRemove.id);
|
||||
|
||||
const ticketData = JSON.parse(fs.readFileSync(ticketDataPath, "utf8"));
|
||||
const ticketIndex = ticketData.tickets.findIndex((t) => t.id === ticketChannel.id);
|
||||
if (ticketIndex !== -1) {
|
||||
const subUsers = ticketData.tickets[ticketIndex].subUsers;
|
||||
const userIndex = subUsers.indexOf(userToRemove.id);
|
||||
if (userIndex !== -1) {
|
||||
subUsers.splice(userIndex, 1);
|
||||
fs.writeFileSync(ticketDataPath, JSON.stringify(ticketData, null, 4));
|
||||
}
|
||||
}
|
||||
|
||||
const removedEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.RemoveUser.Removed_Title)
|
||||
.setDescription(msgconfig.RemoveUser.Removed_Message)
|
||||
.setColor(supportbot.Embed.Colours.Success);
|
||||
|
||||
await interaction.reply({
|
||||
embeds: [removedEmbed],
|
||||
ephemeral: true,
|
||||
});
|
||||
|
||||
const removedFromTicketEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.RemoveUser.RemovedFromTicket_Title)
|
||||
.setDescription(msgconfig.RemoveUser.RemovedFromTicket_Description.replace(
|
||||
"%channel_link%",
|
||||
`[${ticketChannel.name}](https://discord.com/channels/${ticketChannel.guild.id}/${ticketChannel.id})`
|
||||
))
|
||||
.setColor(supportbot.Embed.Colours.General);
|
||||
|
||||
await userToRemove.send({
|
||||
embeds: [removedFromTicketEmbed],
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error("Error removing user from the ticket:", err);
|
||||
|
||||
const errorEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.RemoveUser.Error_Title)
|
||||
.setDescription(msgconfig.RemoveUser.Error_Removing)
|
||||
.setColor(supportbot.Embed.Colours.Error);
|
||||
|
||||
await interaction.reply({
|
||||
embeds: [errorEmbed],
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
+387
-234
@@ -8,7 +8,7 @@ const {
|
||||
ButtonBuilder,
|
||||
StringSelectMenuBuilder,
|
||||
StringSelectMenuOptionBuilder,
|
||||
GuildMemberRoleManager,
|
||||
ButtonStyle,
|
||||
} = require("discord.js");
|
||||
const yaml = require("js-yaml");
|
||||
|
||||
@@ -20,6 +20,187 @@ const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||
const Command = require("../Structures/Command.js");
|
||||
const TicketNumberID = require("../Structures/TicketID.js");
|
||||
|
||||
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 assignTicketToUser(ticketChannel, Staff, Admin, interaction, attempts = 0) {
|
||||
console.log(`Assigning ticket attempt ${attempts}`);
|
||||
|
||||
try {
|
||||
const clockedInUsers = await getClockedInUsers(interaction.guild);
|
||||
console.log(`Clocked in users: ${Array.from(clockedInUsers).join(', ')}`);
|
||||
|
||||
if (clockedInUsers.size === 0 || attempts >= 2) {
|
||||
console.log("No clocked in users or max attempts reached");
|
||||
const claimChannel = await interaction.guild.channels.cache.get(supportbot.Ticket.ClaimTickets.Channel);
|
||||
if (claimChannel) {
|
||||
const claimEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimTitle || 'Default Claim Title')
|
||||
.setDescription(msgconfig.Ticket.ClaimTickets.ClaimMessage || 'Default Claim Message')
|
||||
.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 => {
|
||||
console.log(`Ticket claimed by user ${i.user.id}`);
|
||||
await ticketChannel.send({ content: `<@${i.user.id}> has claimed the ticket.` });
|
||||
});
|
||||
|
||||
collector.on('end', async collected => {
|
||||
if (collected.size === 0) {
|
||||
console.log("No one claimed the ticket, notifying admins");
|
||||
await claimMessage.delete();
|
||||
|
||||
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)],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
console.log(`Assigned user: ${assignedUserId}`);
|
||||
|
||||
const claimEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimTitle || 'Default Claim Title')
|
||||
.setDescription(msgconfig.Ticket.ClaimTickets.ClaimMessage.replace('%user%', interaction.user.id) || 'Default Claim Message')
|
||||
.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 => {
|
||||
console.log(`Ticket claimed by user ${i.user.id}`);
|
||||
await ticketChannel.send({ content: `<@${assignedUserId}>` });
|
||||
});
|
||||
|
||||
collector.on('end', async collected => {
|
||||
if (collected.size === 0) {
|
||||
console.log("No one claimed the ticket, attempting reassignment");
|
||||
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)],
|
||||
});
|
||||
|
||||
// Add a claim button for any staff member to click
|
||||
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({
|
||||
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 => {
|
||||
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,
|
||||
@@ -34,248 +215,227 @@ module.exports = new Command({
|
||||
permissions: cmdconfig.OpenTicket.Permission,
|
||||
|
||||
async run(interaction) {
|
||||
let department = interaction.customId?.split("-")[1] || null;
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
if (User.roles.cache.has(supportbot.Roles.ModRoles.Blacklisted)) {
|
||||
return interaction.reply({
|
||||
content: msgconfig.Ticket.Blacklisted,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (User.roles.cache.has(supportbot.Roles.ModRoles.Muted)) {
|
||||
return interaction.reply({
|
||||
content: msgconfig.Ticket.Muted,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
let ticketNumberID = await TicketNumberID.pad();
|
||||
const TicketSubject = interaction.options?.getString("reason") || 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,
|
||||
});
|
||||
|
||||
const TicketCategory = interaction.guild.channels.cache.find(
|
||||
(c) => c.name === supportbot.Ticket.TicketCategory || c.id === supportbot.Ticket.TicketCategory
|
||||
);
|
||||
|
||||
const channel = await getChannel(supportbot.Ticket.TicketCategory, interaction.guild);
|
||||
const ticketChannel = await channel.threads.create({
|
||||
name: `${supportbot.Ticket.Channel}${ticketNumberID}`,
|
||||
type: ChannelType.PrivateThread,
|
||||
parent: TicketCategory,
|
||||
autoArchiveDuration: 60,
|
||||
reason: 'support ticket',
|
||||
});
|
||||
|
||||
if (supportbot.Ticket.ClaimTickets.Enabled === false) {
|
||||
const InvStaff = await ticketChannel.send(`<@&${Staff.id}> <@&${Admin.id}>`)
|
||||
|
||||
setTimeout(() => {
|
||||
InvStaff.delete();
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
// TICKET CLAIMING SYSTEM [START]
|
||||
|
||||
if (supportbot.Ticket.ClaimTickets.Enabled) {
|
||||
const InvStaff1 = await ticketChannel.send(`<@&${Admin.id}>`)
|
||||
|
||||
setTimeout(() => {
|
||||
InvStaff1.delete();
|
||||
}, 2000)
|
||||
|
||||
const claimChannel = await getChannel(
|
||||
supportbot.Ticket.ClaimTickets.Channel,
|
||||
interaction.guild
|
||||
);
|
||||
|
||||
const claimEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimTitle)
|
||||
.setDescription(msgconfig.Ticket.ClaimTickets.ClaimMessage
|
||||
.replace('%user%', interaction.user.id)
|
||||
)
|
||||
.setColor(supportbot.Embed.Colours.General);
|
||||
|
||||
const claimButton = new ButtonBuilder()
|
||||
.setCustomId(`claimticket-${ticketChannel.id}`)
|
||||
.setLabel(supportbot.Ticket.ClaimTickets.ButtonTitle)
|
||||
.setStyle(supportbot.Ticket.ClaimTickets.Button);
|
||||
|
||||
const row = new ActionRowBuilder().addComponents(claimButton);
|
||||
|
||||
await claimChannel.send({
|
||||
content: `<@&${Staff.id}>`,
|
||||
embeds: [claimEmbed],
|
||||
components: [row]
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// TICKET CLAIMING SYSTEM [END]
|
||||
|
||||
if (!department) {
|
||||
await ticketChannel.members.add(interaction.user.id);
|
||||
}
|
||||
|
||||
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, // Will be updated when claimed
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
"./Data/TicketData.json",
|
||||
JSON.stringify(TicketData, null, 4),
|
||||
(err) => {
|
||||
if (err) console.error(err);
|
||||
try {
|
||||
let TicketReason = null;
|
||||
if (supportbot.Ticket.TicketReason) {
|
||||
TicketReason = interaction.reason || null; // Retrieve the reason from the interaction object
|
||||
}
|
||||
);
|
||||
|
||||
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)
|
||||
)
|
||||
.setColor(supportbot.Embed.Colours.General);
|
||||
await interaction.reply({ embeds: [CreatedTicket], ephemeral: true });
|
||||
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.AllowMentions) {
|
||||
await ticketChannel.send(`${interaction.user}`);
|
||||
}
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
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)
|
||||
)
|
||||
.setColor(supportbot.Embed.Colours.General);
|
||||
if (User.roles.cache.has(supportbot.Roles.ModRoles.Blacklisted)) {
|
||||
return interaction.reply({
|
||||
content: msgconfig.Ticket.Blacklisted,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
const SelectMenus = new StringSelectMenuBuilder()
|
||||
.setCustomId("ticketcontrolpanel")
|
||||
.setPlaceholder("Ticket Control Panel")
|
||||
.addOptions(
|
||||
new StringSelectMenuOptionBuilder()
|
||||
.setLabel("Add User")
|
||||
.setDescription("Add a user to the ticket.")
|
||||
.setEmoji(supportbot.SelectMenus.Tickets.AddUserEmoji)
|
||||
.setValue("ticketadduser"),
|
||||
new StringSelectMenuOptionBuilder()
|
||||
.setLabel("Remove User")
|
||||
.setDescription("Remove a user from the ticket.")
|
||||
.setEmoji(supportbot.SelectMenus.Tickets.RemoveUserEmoji)
|
||||
.setValue("ticketremoveuser"),
|
||||
new StringSelectMenuOptionBuilder()
|
||||
.setLabel("Close")
|
||||
.setDescription("Close the ticket.")
|
||||
.setEmoji(supportbot.SelectMenus.Tickets.CloseEmoji)
|
||||
.setValue("ticketclose"),
|
||||
new StringSelectMenuOptionBuilder()
|
||||
.setLabel("Enable Invites")
|
||||
.setDescription("Enable invites.")
|
||||
.setEmoji(supportbot.SelectMenus.Tickets.EnableInvitesEmoji)
|
||||
.setValue("enableinvites"),
|
||||
new StringSelectMenuOptionBuilder()
|
||||
.setLabel("Disable Invites")
|
||||
.setDescription("Disable invites.")
|
||||
.setEmoji(supportbot.SelectMenus.Tickets.DisableInvitesEmoji)
|
||||
.setValue("disableinvites"),
|
||||
);
|
||||
if (User.roles.cache.has(supportbot.Roles.ModRoles.Muted)) {
|
||||
return interaction.reply({
|
||||
content: msgconfig.Ticket.Muted,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
const row2 = new ActionRowBuilder().addComponents(SelectMenus);
|
||||
let ticketNumberID = await TicketNumberID.pad();
|
||||
const TicketSubject = TicketReason || msgconfig.Ticket.InvalidSubject;
|
||||
|
||||
if (!department) {
|
||||
try {
|
||||
let buttons = supportbot.Departments.map((x) =>
|
||||
new ButtonBuilder()
|
||||
.setCustomId("Department" + supportbot.Departments.indexOf(x))
|
||||
.setLabel(x.title)
|
||||
.setStyle(x.color)
|
||||
.setEmoji(x.emoji)
|
||||
);
|
||||
const TicketExists = new EmbedBuilder()
|
||||
.setTitle("Ticket Exists!")
|
||||
.setDescription(msgconfig.Ticket.TicketExists);
|
||||
|
||||
if (supportbot.Ticket.AllowMentions) {
|
||||
await ticketChannel.send("<@&" + supportbot.Ticket.RoleMention + ">");
|
||||
}
|
||||
if (
|
||||
await interaction.guild.channels.cache.find(
|
||||
(ticketChannel) => ticketChannel.name === `${supportbot.Ticket.Channel}${ticketNumberID}`
|
||||
)
|
||||
) {
|
||||
return await interaction.reply({
|
||||
embeds: [TicketExists],
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
const row = new ActionRowBuilder().addComponents(buttons);
|
||||
const m = await ticketChannel.send({
|
||||
embeds: [TicketMessage],
|
||||
components: [row2],
|
||||
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,
|
||||
});
|
||||
|
||||
const TicketCategory = interaction.guild.channels.cache.find(
|
||||
(c) => c.name === supportbot.Ticket.TicketCategory || c.id === supportbot.Ticket.TicketCategory
|
||||
);
|
||||
|
||||
const channel = await getChannel(supportbot.Ticket.TicketCategory, interaction.guild);
|
||||
const ticketChannel = await channel.threads.create({
|
||||
name: `${supportbot.Ticket.Channel}${ticketNumberID}`,
|
||||
type: ChannelType.PrivateThread,
|
||||
parent: TicketCategory,
|
||||
autoArchiveDuration: 60,
|
||||
reason: 'support ticket',
|
||||
});
|
||||
|
||||
// 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);
|
||||
await claimChannel.send(`<@&${Staff.id}> <@&${Admin.id}>`);
|
||||
}
|
||||
}
|
||||
|
||||
// Add user to the ticket channel
|
||||
await ticketChannel.members.add(interaction.user.id);
|
||||
|
||||
// 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);
|
||||
|
||||
// Add reason field if ticket reason is enabled
|
||||
if (supportbot.Ticket.TicketReason && TicketReason) {
|
||||
TicketMessage.addFields(
|
||||
{ name: "Reason", value: TicketReason, inline: false }
|
||||
);
|
||||
}
|
||||
|
||||
// Create the control panel
|
||||
const SelectMenus = new StringSelectMenuBuilder()
|
||||
.setCustomId("ticketcontrolpanel")
|
||||
.setPlaceholder("Ticket Control Panel")
|
||||
.addOptions(
|
||||
new StringSelectMenuOptionBuilder()
|
||||
.setLabel("Close")
|
||||
.setDescription("Close the ticket.")
|
||||
.setEmoji(supportbot.SelectMenus.Tickets.CloseEmoji)
|
||||
.setValue("ticketclose"),
|
||||
new StringSelectMenuOptionBuilder()
|
||||
.setLabel("Archive")
|
||||
.setDescription("Acrhive the ticket.")
|
||||
.setEmoji(supportbot.SelectMenus.Tickets.ArchiveEmoji)
|
||||
.setValue("archiveticket"),
|
||||
new StringSelectMenuOptionBuilder()
|
||||
.setLabel("Lock Ticket")
|
||||
.setDescription("Lock the ticket.")
|
||||
.setEmoji(supportbot.SelectMenus.Tickets.LockEmoji)
|
||||
.setValue("lockticket"),
|
||||
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);
|
||||
|
||||
// Send the ticket message and control panel
|
||||
await ticketChannel.send({
|
||||
embeds: [TicketMessage],
|
||||
components: [row2],
|
||||
});
|
||||
|
||||
// Handle department selection if not specified
|
||||
if (!department) {
|
||||
try {
|
||||
const buttons = supportbot.Departments.map((x, index) =>
|
||||
new ButtonBuilder()
|
||||
.setCustomId("Department" + index)
|
||||
.setLabel(x.title)
|
||||
.setStyle(x.color)
|
||||
.setEmoji(x.emoji)
|
||||
);
|
||||
|
||||
const row = new ActionRowBuilder().addComponents(buttons);
|
||||
|
||||
const message = await ticketChannel.send({
|
||||
content: "Please select a department:",
|
||||
components: [row],
|
||||
});
|
||||
|
||||
const filter = (i) => i.user.id === interaction.user.id;
|
||||
await m.awaitMessageComponent({
|
||||
await message.awaitMessageComponent({
|
||||
filter,
|
||||
max: 1,
|
||||
componentType: "BUTTON",
|
||||
time: supportbot.Ticket.Timeout * 60000,
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
if (e.code === "COLLECTOR_ERROR") {
|
||||
try {
|
||||
let ticket = TicketData.tickets.findIndex((t) => t.id === ticketChannel.id);
|
||||
const ticket = TicketData.tickets.findIndex((t) => t.id === ticketChannel.id);
|
||||
TicketData.tickets[ticket].open = false;
|
||||
fs.writeFileSync(
|
||||
"./Data/TicketData.json",
|
||||
@@ -284,25 +444,18 @@ module.exports = new Command({
|
||||
if (err) console.error(err);
|
||||
}
|
||||
);
|
||||
interaction.user.send(
|
||||
"Your ticket has timed out. Please open a new one, and select a department."
|
||||
await interaction.user.send(
|
||||
"Your ticket has timed out. Please open a new one and select a department."
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("An error occurred while handling collector:", error);
|
||||
}
|
||||
return await ticketChannel.delete();
|
||||
await ticketChannel.delete();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error sending message:", error);
|
||||
}
|
||||
} else {
|
||||
await ticketChannel.send({
|
||||
embeds: [TicketMessage],
|
||||
components: [row2],
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error in run method:", error);
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
const { EmbedBuilder, ApplicationCommandType } = require("discord.js");
|
||||
const fs = require("fs");
|
||||
const yaml = require("js-yaml");
|
||||
|
||||
const supportbot = yaml.load(fs.readFileSync("./Configs/supportbot.yml", "utf8"));
|
||||
const cmdconfig = yaml.load(fs.readFileSync("./Configs/commands.yml", "utf8"));
|
||||
const msgconfig = yaml.load(fs.readFileSync("./Configs/messages.yml", "utf8"));
|
||||
|
||||
const Command = require("../Structures/Command.js");
|
||||
|
||||
module.exports = new Command({
|
||||
name: cmdconfig.TicketStats.Command,
|
||||
description: cmdconfig.TicketStats.Description,
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
permissions: ["SendMessages"], // Adjust permissions as needed
|
||||
|
||||
async run(interaction) {
|
||||
|
||||
if (supportbot.Ticket.ClaimTickets.Enabled) {
|
||||
|
||||
const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||
const userId = interaction.user.id;
|
||||
|
||||
const ticketsClaimed = TicketData.tickets.filter(t => t.claimedBy === userId);
|
||||
const ticketsOpen = ticketsClaimed.filter(t => t.open);
|
||||
const totalTickets = ticketsClaimed.length;
|
||||
|
||||
let totalResponseTime = 0;
|
||||
let responseCount = 0;
|
||||
|
||||
ticketsClaimed.forEach(ticket => {
|
||||
if (ticket.claimedAt && ticket.createdAt) {
|
||||
const responseTime = new Date(ticket.claimedAt) - new Date(ticket.createdAt);
|
||||
totalResponseTime += responseTime;
|
||||
responseCount++;
|
||||
}
|
||||
});
|
||||
|
||||
const averageResponseTime = responseCount ? totalResponseTime / responseCount : 0;
|
||||
const averageResponseTimeMinutes = Math.round(averageResponseTime / 60000); // Convert to minutes
|
||||
|
||||
const statsEmbed = new EmbedBuilder()
|
||||
.setTitle(msgconfig.TicketStats.Title)
|
||||
.setDescription(`> Ticket stats for <@${interaction.user.id}>`)
|
||||
.setColor(supportbot.Embed.Colours.General)
|
||||
.addFields(
|
||||
{ name: msgconfig.TicketStats.OpenTickets, value: `${ticketsOpen.length}`, inline: true },
|
||||
{ name: msgconfig.TicketStats.TotalTickets, value: `${totalTickets}`, inline: true },
|
||||
{ name: msgconfig.TicketStats.ResponseTime, value: `${averageResponseTimeMinutes} minutes`, inline: false }
|
||||
);
|
||||
|
||||
await interaction.reply({ embeds: [statsEmbed], ephemeral: true });
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
@@ -1,137 +0,0 @@
|
||||
// SupportBot | Emerald Services
|
||||
// User Info Command
|
||||
|
||||
const fs = require("fs");
|
||||
const moment = require("moment");
|
||||
|
||||
const Discord = require("discord.js");
|
||||
const yaml = require("js-yaml");
|
||||
|
||||
const supportbot = yaml.load(
|
||||
fs.readFileSync("./Configs/supportbot.yml", "utf8")
|
||||
);
|
||||
|
||||
const cmdconfig = yaml.load(
|
||||
fs.readFileSync("./Configs/commands.yml", "utf8")
|
||||
);
|
||||
|
||||
const msgconfig = yaml.load(
|
||||
fs.readFileSync("./Configs/messages.yml", "utf8")
|
||||
)
|
||||
|
||||
const Command = require("../Structures/Command.js");
|
||||
|
||||
module.exports = new Command({
|
||||
name: cmdconfig.UserInfo.Command,
|
||||
description: cmdconfig.UserInfo.Description,
|
||||
type: Discord.ApplicationCommandType.ChatInput,
|
||||
options: [
|
||||
{
|
||||
type: Discord.ApplicationCommandOptionType.User,
|
||||
name: "user",
|
||||
description: "The user you want to get info about.",
|
||||
required: true,
|
||||
}, // The user input
|
||||
],
|
||||
permissions: cmdconfig.UserInfo.Permission,
|
||||
|
||||
async run(interaction) {
|
||||
let disableCommand = true;
|
||||
|
||||
const { getRole } = interaction.client;
|
||||
let SupportStaff = await getRole(supportbot.Roles.StaffMember.Staff, interaction.guild);
|
||||
let Admin = await getRole(supportbot.Roles.StaffMember.Admin, interaction.guild);
|
||||
if (!SupportStaff || !Admin)
|
||||
|
||||
return interaction.reply(
|
||||
"Some roles seem to be missing!\nPlease check for errors when starting the bot."
|
||||
);
|
||||
|
||||
const NoPerms = new Discord.EmbedBuilder()
|
||||
.setTitle("Invalid Permissions!")
|
||||
.setDescription(
|
||||
`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``
|
||||
)
|
||||
.setColor(supportbot.Embed.Colours.Warn);
|
||||
|
||||
if (
|
||||
!interaction.member.roles.cache.has(SupportStaff.id) &&
|
||||
!interaction.member.roles.cache.has(Admin.id)
|
||||
)
|
||||
return interaction.reply({ embeds: [NoPerms] });
|
||||
|
||||
let user = await interaction.options.getUser("user") || interaction.author; // Grab the mentioned user
|
||||
let member = await interaction.guild.members.cache.get(user.id) // Check for user and his ID
|
||||
|
||||
const UserNotExist = new Discord.EmbedBuilder()
|
||||
.setTitle("User Not Found!")
|
||||
.setDescription(
|
||||
`${msgconfig.Error.UserNotFound}\n\nTry Again:\`/${cmdconfig.UserInfoCommand} <@!User_ID> or @User\``
|
||||
)
|
||||
.setColor(supportbot.ErrorColour);
|
||||
|
||||
if (!user) return interaction.reply({ embeds: [UserNotExist] });
|
||||
|
||||
// Flags a user/bot can have
|
||||
const flags = {
|
||||
DISCORD_EMPLOYEE: 'Discord Employee',
|
||||
DISCORD_PARTNER: 'Discord Partner',
|
||||
BUGHUNTER_LEVEL_1: 'Bug Hunter (Level 1)',
|
||||
BUGHUNTER_LEVEL_2: 'Bug Hunter (Level 2)',
|
||||
HYPESQUAD_EVENTS: 'HypeSquad Events',
|
||||
HOUSE_BRAVERY: 'House of Bravery',
|
||||
HOUSE_BRILLIANCE: 'House of Brilliance',
|
||||
HOUSE_BALANCE: 'House of Balance',
|
||||
EARLY_SUPPORTER: 'Early Supporter',
|
||||
TEAM_USER: 'Team User',
|
||||
SYSTEM: 'System',
|
||||
VERIFIED_BOT: 'Verified Bot',
|
||||
VERIFIED_DEVELOPER: 'Verified Bot Developer'
|
||||
};
|
||||
|
||||
// Status message with icon
|
||||
let status = {
|
||||
online: "🟢Online",
|
||||
idle: "🟡Idle",
|
||||
dnd: "🔴Do Not Disturb",
|
||||
offline: "⚫Offline"
|
||||
};
|
||||
|
||||
const userFlags = user.flags.toArray();
|
||||
|
||||
// Embed containing the userinfo
|
||||
let userembed = new Discord.EmbedBuilder()
|
||||
.setTitle(`User Info for User: ${user.tag}`)
|
||||
.setThumbnail(member.displayAvatarURL({ dynamic: true, size: 512 }))
|
||||
.setColor(member.roles.highest.hexColor)
|
||||
.addFields(
|
||||
{ name: "Name:", value: `${user.tag}\n<@${member.id}>`, inline: true },
|
||||
{ name: "ID:", value: `${member.id}`, inline: true },
|
||||
{ name: "Is Bot:", value: user.bot ? "Yes" : "No", inline: true },
|
||||
{ name: "House/Badge:", value: `${userFlags.length ? userFlags.map(flag => flags[flag]).join("\n") : "None"}`, inline: true },
|
||||
{ name: "Current Status:", value: `${status[member.presence ? member.presence.status : "offline"]}`, inline: true },
|
||||
{ name: "Avatar URL:", value: `[Click Here](${member.displayAvatarURL()})`, inline: true },
|
||||
{ name: "\u200b", value: "\u200b", inline: false}
|
||||
)
|
||||
.addFields(
|
||||
{ name: "Creation Date:", value: `${moment(user.createdAt).format("MMMM Do YYYY, h:mm:ss a")}\n> ${moment(user.createdAt).startOf("day").fromNow()}`, inline: true },
|
||||
{ name: "Joined Date:", value: `${moment(member.joinedAt).format("MMMM Do YYYY, h:mm:ss a")}\n> ${moment(member.joinedAt).startOf("day").fromNow()}`, inline: true },
|
||||
{ name: "Roles Total:", value: `${member.roles.cache.size -1}`, inline: false },
|
||||
{ name: "Highest Role:", value: `${member.roles.highest.id === interaction.guild.id ? "None" : member.roles.highest.toString()}`, inline: true },
|
||||
{ name: "Roles:", value: `${member.roles.cache.map(r => r).join(" ").replace("@everyone", " ") || "None"}`, inline: false },
|
||||
)
|
||||
.setFooter({ text: supportbot.Footer })
|
||||
.setTimestamp();
|
||||
|
||||
// Send embed [userembed]
|
||||
await interaction.reply({ embeds: [userembed] }).catch((err) => console.error("An error has occured: ", err));
|
||||
|
||||
},
|
||||
})
|
||||
|
||||
/**
|
||||
* @INFO
|
||||
* UserInfo command by Sypher#3415 | 321332200668790786
|
||||
* @INFO
|
||||
* Solely created for SupportBot | https://github.com/Emerald-Services/SupportBot/
|
||||
**/
|
||||
+17
-11
@@ -19,12 +19,6 @@ Help:
|
||||
Permission: ["SendMessages"]
|
||||
Enabled: true
|
||||
|
||||
EnableAI:
|
||||
Command: "enableai"
|
||||
Description: "Talk with SupportBot"
|
||||
Permission: ["SendMessages"]
|
||||
Enabled: true
|
||||
|
||||
Info:
|
||||
Command: "info"
|
||||
Description: "Get information about the **ServerName**."
|
||||
@@ -37,9 +31,9 @@ TicketPanel:
|
||||
Permission: ["Administrator"]
|
||||
Enabled: true
|
||||
|
||||
TicketStats:
|
||||
Command: "ticketstats"
|
||||
Description: "Shows staff members their ticket statistics"
|
||||
Profile:
|
||||
Command: "profile"
|
||||
Description: "Shows the profile for a discord member."
|
||||
Permission: ["SendMessages"]
|
||||
# Command is automatically disabled when the TicketClaims is disabled.
|
||||
|
||||
@@ -49,9 +43,21 @@ OpenTicket:
|
||||
Permission: ["SendMessages"]
|
||||
Enabled: true
|
||||
|
||||
Add:
|
||||
AddUser:
|
||||
Command: "add"
|
||||
Description: "Add a user to the ticket."
|
||||
Description: "Add a user to a support ticket."
|
||||
Permission: ["SendMessages"]
|
||||
Enabled: true
|
||||
|
||||
ForceAddUser:
|
||||
Command: "forceadd"
|
||||
Description: "Add a user to a support ticket by bypassing the invite system."
|
||||
Permission: ["SendMessages"]
|
||||
Enabled: true
|
||||
|
||||
RemoveUser:
|
||||
Command: "remove"
|
||||
Description: "Remove a user from a support ticket."
|
||||
Permission: ["SendMessages"]
|
||||
Enabled: true
|
||||
|
||||
|
||||
+92
-32
@@ -24,7 +24,7 @@ Welcome:
|
||||
Embed:
|
||||
Colour: "#f74343"
|
||||
Title: "Welcome to ServerName"
|
||||
Message: "> :smile: %joined_user% has just landed!"
|
||||
Message: ":smile: %joined_user% has just landed!"
|
||||
Thumbnail: "BOT"
|
||||
|
||||
ImageEnabled: false
|
||||
@@ -34,7 +34,7 @@ Leave:
|
||||
Embed:
|
||||
Colour: "#f74343"
|
||||
Title: "Goodbye!"
|
||||
Message: "> :slight_frown: %joined_user% has recently dropped out!"
|
||||
Message: ":slight_frown: %joined_user% has recently dropped out!"
|
||||
Thumbnail: "BOT"
|
||||
|
||||
ImageEnabled: false
|
||||
@@ -42,8 +42,8 @@ Leave:
|
||||
|
||||
Suggestions:
|
||||
Sent_Title: "Suggestion Sent!"
|
||||
Sent: "> :white_check_mark: **You have successfully sent a suggestion.**"
|
||||
NoSelfVote: "> :x: **You cannot vote on your own suggestion.**"
|
||||
Sent: ":white_check_mark: **You have successfully sent a suggestion.**"
|
||||
NoSelfVote: ":x: **You cannot vote on your own suggestion.**"
|
||||
RemoveVoteButton: "Remove Vote"
|
||||
|
||||
Ticket:
|
||||
@@ -56,47 +56,47 @@ Ticket:
|
||||
|
||||
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."
|
||||
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
|
||||
TicketCreatedAlert: ":ticket: Ticked Created: <#%ticketid%>"
|
||||
TicketExists: "❌ Ticket already exists"
|
||||
TicketClaim: ":white_check_mark: Ticket claimed by" #The user who claimed the ticket will be added to the end of this message
|
||||
TicketUnclaim: ":white_check_mark: Ticket unclaimed by" #The user who claimed the ticket will be added to the end of this message
|
||||
|
||||
DisableInvites: "> 🔒 Invites have been disabled for this ticket."
|
||||
EnableInvites: "> 🔓 Invites have been enabled for this ticket."
|
||||
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.
|
||||
|
||||
AddUserToTicket_Title: "➕ Add User!"
|
||||
AddUserToTicket: "> To add a user to this ticket, Tag them."
|
||||
|
||||
RemovedUserFromTicket_Title: "➖ Removed User!"
|
||||
RemovedUserFromTicket: "> <@%user%> has been `Removed` from this ticket"
|
||||
|
||||
Blacklisted: "> :x: You are not allowed to open a ticket"
|
||||
Muted: "> :x: You are `Muted` and therefore not allowed to open any tickets"
|
||||
InvalidSubject: "> No Reason Provided!"
|
||||
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!"
|
||||
|
||||
TranscriptSavedMessage: "📝 **Transcript Saved!**"
|
||||
TicketLockMessage: "❌ **Ticket Locked!**"
|
||||
TicketDeleteMessage: "⚠ **Ticket Deleting!**"
|
||||
|
||||
ClosingTicket: "> :warning: You have requested to close your support ticket."
|
||||
ConfirmClose: "> Please confirm closing the ticket by clicking the button below."
|
||||
CloseTimeout: "> Ticket close confirmation timed out."
|
||||
ClosingTicket: ":warning: You have requested to close your support ticket."
|
||||
ConfirmClose: "Please confirm closing the ticket by clicking the button below."
|
||||
CloseTimeout: "Ticket close confirmation timed out."
|
||||
|
||||
ClaimTickets:
|
||||
ClaimTitle: "Incoming Support Request!"
|
||||
ClaimMessage: "> A new ticket has been created by <@!%user%>. Click the button below to claim this ticket."
|
||||
ClaimMessage_Edit: "> <#%channel%> was claimed by <@!%user%>."
|
||||
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%>"
|
||||
Claimed: "You have successfully claimed this ticket. <#%channel%>"
|
||||
NoPermsToClaimTitle: "Error, no permissions!"
|
||||
NoPermsToClaim: "> :x: **Err!** You do not permissions to claim this ticket."
|
||||
NoPermsToClaim: ":x: **Err!** You do not permissions to claim this ticket."
|
||||
|
||||
ReassigningTitle: "Reassigning!..."
|
||||
ReassigningMessage: "<@%user%> did not claim the ticket. **Reassigning...**"
|
||||
|
||||
TicketStats:
|
||||
OpenTickets: "✅ Open Tickets"
|
||||
@@ -105,12 +105,72 @@ TicketStats:
|
||||
|
||||
Title: "Your Ticket Stats"
|
||||
|
||||
AddUser:
|
||||
NotInTicket_Title: "Ticket Invitation"
|
||||
NotInTicket_Description: "This command can only be used within a ticket thread."
|
||||
|
||||
Invite_Title: "User Invited"
|
||||
Invite_Description: "%username% has been invited to join the ticket."
|
||||
|
||||
DM_Title: "Ticket Invitation"
|
||||
DM_Description: "You have been invited to join the ticket %channelname%. Do you accept?"
|
||||
|
||||
Accept_Label: "Accept"
|
||||
Reject_Label: "Reject"
|
||||
ViewTicket_Label: "Go to Ticket"
|
||||
|
||||
Accepted_Title: "Invitation Accepted"
|
||||
Accepted_Message: "You have been added to the ticket."
|
||||
AddedToTicket_Title: "Added to Ticket"
|
||||
AddedToTicket_Description: "You have been added to the ticket %channel_link%."
|
||||
|
||||
Declined_Title: "Invitation Declined"
|
||||
Declined_Message: "You have declined the invitation."
|
||||
|
||||
NoResponse_Title: "No Response"
|
||||
NoResponse_Message: "You did not respond in time. Please contact staff if you wish to join the ticket."
|
||||
|
||||
Error_Title: "Error"
|
||||
Error_Adding: "There was an error adding you to the ticket. Please try again."
|
||||
|
||||
DM_Error_Title: "Error"
|
||||
DM_Error_Description: "Unable to send a DM to %username%. Please ensure your DMs are enabled."
|
||||
|
||||
Unexpected_Error_Title: "Error"
|
||||
Unexpected_Error_Description: "An unexpected error occurred: %error%"
|
||||
|
||||
RemoveUser:
|
||||
NotInTicket_Title: "Error"
|
||||
NotInTicket_Description: "This command can only be used in ticket threads."
|
||||
|
||||
Removed_Title: "User Removed"
|
||||
Removed_Message: "The user has been successfully removed from the ticket."
|
||||
|
||||
RemovedFromTicket_Title: "Removed from Ticket"
|
||||
RemovedFromTicket_Description: "You have been removed from the ticket channel %channel_link%."
|
||||
|
||||
Error_Title: "Error"
|
||||
Error_Removing: "There was an error removing the user from the ticket."
|
||||
|
||||
ForceAddUser:
|
||||
NotInTicket_Title: "Not a Ticket"
|
||||
NotInTicket_Description: "This command can only be used within a ticket thread."
|
||||
|
||||
Added_Title: "User Added"
|
||||
Added_Description: "Successfully added %username% to the ticket."
|
||||
|
||||
AddedToTicket_Title: "You have been added to a Ticket"
|
||||
AddedToTicket_Description: "You have been added to the ticket channel [%channel_link%]."
|
||||
|
||||
Error_Title: "Error"
|
||||
Error_Adding: "There was an error adding the user to the ticket."
|
||||
|
||||
Error:
|
||||
IncorrectPerms: "> :x: **Err!** You do not have the correct permissions to use this."
|
||||
InvalidChannel: "> :x: **Err!** Channel not found. Please create it!"
|
||||
UserNotFound: "> :x: **Err!** This user doesn't exist, Are they in this server?"
|
||||
NoValidTicket: "> :warning: You cannot execute this command here."
|
||||
TicketExists: "> :warning: This ticket cannot be opened, It already exists!"
|
||||
IncorrectPerms: ":x: **Err!** You do not have the correct permissions to use this."
|
||||
InvalidChannel: ":x: **Err!** Channel not found. Please create it!"
|
||||
UserNotFound: ":x: **Err!** This user doesn't exist, Are they in this server?"
|
||||
NoValidTicket: ":warning: You cannot execute this command here."
|
||||
TicketExists: ":warning: This ticket cannot be opened, It already exists!"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -16,17 +16,16 @@ General:
|
||||
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"
|
||||
OpenAI_Key: "OPEN_AI_KEY_HERE"
|
||||
# To create an OpenAI API key, go to https://platform.openai.com/api-keys
|
||||
|
||||
|
||||
PastebinAPI_Key: "PASTEBIN_API_KEY"
|
||||
PastebinAPI_Key: "PASTEBIN_API_KEY_HERE"
|
||||
# You can get your Pastebin API Key from https://pastebin.com
|
||||
PastebinAPI_URL: "https://pastebin.com/api/api_post.php"
|
||||
|
||||
Channels:
|
||||
AIChannel: "0000000000000000000"
|
||||
AIChannel: "1250190338954498048"
|
||||
# This is the channel where AI will respond in without needing to mention the bot.
|
||||
|
||||
Embed:
|
||||
|
||||
+31
-8
@@ -11,7 +11,7 @@
|
||||
# Official Documentation: https://github.com/Emerald-Services/SupportBot/wiki
|
||||
# Third-Party Documentation: COMING SOON
|
||||
|
||||
SupportBot_Version: "v8.0"
|
||||
SupportBot_Version: "v8.0.1"
|
||||
# Do not change the version number
|
||||
|
||||
# -------------------------
|
||||
@@ -24,7 +24,7 @@ General:
|
||||
# To get your Discord Bot Token, Go to https://discord.com/developers/applications
|
||||
|
||||
Addons:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# -------------------------
|
||||
# Activity
|
||||
@@ -145,17 +145,32 @@ Ticket:
|
||||
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
|
||||
|
||||
LockedTickets:
|
||||
Channel: "1267856939275124809"
|
||||
|
||||
ClaimTickets:
|
||||
Enabled: true
|
||||
Channel: "1249723473757077624"
|
||||
# Channel name or Channel ID
|
||||
|
||||
ClaimAcceptTime: 120000
|
||||
# How long the assigned user has to accept the ticket before it gets re-assigned to someone else.
|
||||
|
||||
ButtonTitle: "Claim Ticket"
|
||||
ButtonEmoji: "🎫"
|
||||
Button: "1"
|
||||
|
||||
# Available Button Styles
|
||||
@@ -184,6 +199,15 @@ Buttons:
|
||||
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
|
||||
@@ -198,14 +222,13 @@ Buttons:
|
||||
SelectMenus:
|
||||
Tickets:
|
||||
PanelEmoji: "⚙️"
|
||||
|
||||
CloseEmoji: "🗑️"
|
||||
ArchiveEmoji: "♻️"
|
||||
LockTicketEmoji: "🔒"
|
||||
UnLockTicketEmoji: "🔓"
|
||||
EnableInvitesEmoji: "🔒"
|
||||
DisableInvitesEmoji: "🔓"
|
||||
AddUserEmoji: "➕"
|
||||
RemoveUserEmoji: "➖"
|
||||
LockEmoji: "🔐"
|
||||
|
||||
EnableInvitesEmoji: "📤"
|
||||
DisableInvitesEmoji: "📥"
|
||||
|
||||
|
||||
# -------------------------
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"bio": "",
|
||||
"timezone": "",
|
||||
"clockedIn": false
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"id": 0,
|
||||
"TicketPanelID": "0000000000000000000"
|
||||
"TicketPanelID": "000000000000000000"
|
||||
}
|
||||
+253
-66
@@ -16,7 +16,8 @@ try {
|
||||
}
|
||||
|
||||
module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
if (interaction.type == Discord.InteractionType.ApplicationCommand) {
|
||||
|
||||
if (interaction.type === Discord.InteractionType.ApplicationCommand) {
|
||||
const command = client.commands.find(
|
||||
(cmd) => cmd.name.toLowerCase() === interaction.commandName
|
||||
);
|
||||
@@ -24,12 +25,13 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
if (interaction.user.bot || !interaction.guild) return;
|
||||
|
||||
const NotValid = new Discord.EmbedBuilder()
|
||||
.setDescription(`:x: \`Invalid Command\` `)
|
||||
.setDescription(`:x: \`Invalid Command\``)
|
||||
.setColor(supportbot.Embed.Colours.Error);
|
||||
|
||||
if (!command)
|
||||
return interaction.reply({
|
||||
embeds: [NotValid],
|
||||
ephemeral: true,
|
||||
});
|
||||
|
||||
const permission = interaction.member.permissions.has(command.permissions);
|
||||
@@ -43,8 +45,50 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
if (!permission)
|
||||
return interaction.reply({
|
||||
embeds: [ValidPerms],
|
||||
ephemeral: true,
|
||||
});
|
||||
command.run(interaction);
|
||||
|
||||
try {
|
||||
if (command.name === cmdconfig.OpenTicket.Command && supportbot.Ticket.TicketReason) {
|
||||
const modal = new Discord.ModalBuilder()
|
||||
.setCustomId("ticketReasonModal")
|
||||
.setTitle("Ticket Reason")
|
||||
.addComponents(
|
||||
new Discord.ActionRowBuilder().addComponents(
|
||||
new Discord.TextInputBuilder()
|
||||
.setCustomId("reasonInput")
|
||||
.setLabel("Reason")
|
||||
.setStyle(Discord.TextInputStyle.Paragraph)
|
||||
.setRequired(true)
|
||||
)
|
||||
);
|
||||
|
||||
await interaction.showModal(modal);
|
||||
} else {
|
||||
console.log("\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.isStringSelectMenu()) {
|
||||
@@ -52,31 +96,60 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
const selectedOption = interaction.values[0];
|
||||
const { getRole, getChannel } = interaction.client;
|
||||
switch (selectedOption) {
|
||||
case "ticketadduser":
|
||||
const AddUserThreadTicket = new Discord.EmbedBuilder()
|
||||
.setTitle(`${msgconfig.Ticket.AddUserToTicket}`)
|
||||
.setDescription(`${msgconfig.Ticket.AddUserToTicket}`)
|
||||
.setColor(supportbot.Embed.Colours.General);
|
||||
|
||||
await interaction.reply({
|
||||
embeds: [AddUserThreadTicket],
|
||||
ephemeral: true,
|
||||
});
|
||||
break;
|
||||
|
||||
case "ticketremoveuser":
|
||||
await removeUserFromThread(interaction);
|
||||
break;
|
||||
|
||||
case "ticketclose":
|
||||
const closeCommand = client.commands.get(cmdconfig.CloseTicket.Command);
|
||||
if (closeCommand) {
|
||||
closeCommand.run(interaction);
|
||||
await closeCommand.run(interaction);
|
||||
} else {
|
||||
console.error("[X] Close Command Not Found");
|
||||
}
|
||||
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],
|
||||
});
|
||||
|
||||
await interaction.channel.setArchived(true);
|
||||
|
||||
break;
|
||||
|
||||
case "lockticket":
|
||||
const lockembed = new Discord.EmbedBuilder()
|
||||
.setDescription(msgconfig.Ticket.TicketLocked)
|
||||
.setColor(supportbot.Embed.Colours.Success);
|
||||
|
||||
await interaction.channel.send({
|
||||
embeds: [lockembed],
|
||||
components: [],
|
||||
ephemeral: true,s
|
||||
});
|
||||
|
||||
await interaction.channel.setLocked(true);
|
||||
|
||||
break;
|
||||
|
||||
case "enableinvites":
|
||||
await handleInvites(interaction, true);
|
||||
break;
|
||||
@@ -89,32 +162,80 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
}
|
||||
|
||||
if (interaction.isButton()) {
|
||||
if (interaction.customId === 'createticket') {
|
||||
try {
|
||||
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
|
||||
if (!cmd) return;
|
||||
cmd.run(interaction);
|
||||
} catch (error) {
|
||||
console.error("Error executing the ticket command:", error);
|
||||
await interaction.reply({
|
||||
content: "An error occurred while creating the ticket.",
|
||||
ephemeral: true,
|
||||
});
|
||||
if (interaction.customId === "unarchiveTicket") {
|
||||
await interaction.channel.setArchived(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") {
|
||||
try {
|
||||
const cmd = client.commands.get(cmdconfig.OpenTicket);
|
||||
if (!cmd) return;
|
||||
cmd.run(interaction);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (supportbot.Ticket.TicketReason) {
|
||||
const modal = new Discord.ModalBuilder()
|
||||
.setCustomId("ticketReasonModal")
|
||||
.setTitle("Ticket Reason")
|
||||
.addComponents(
|
||||
new Discord.ActionRowBuilder().addComponents(
|
||||
new Discord.TextInputBuilder()
|
||||
.setCustomId("reasonInput")
|
||||
.setLabel("Reason")
|
||||
.setStyle(Discord.TextInputStyle.Paragraph)
|
||||
.setRequired(true)
|
||||
)
|
||||
);
|
||||
|
||||
await interaction.showModal(modal);
|
||||
} else {
|
||||
try {
|
||||
const cmd = client.commands.get(cmdconfig.OpenTicket.Command);
|
||||
if (!cmd) return;
|
||||
await cmd.run(interaction);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interaction.customId.startsWith('claimticket-')) {
|
||||
const ticketChannelId = interaction.customId.split('-')[1];
|
||||
if (interaction.customId.startsWith("claimticket-")) {
|
||||
const ticketChannelId = interaction.customId.split("-")[1];
|
||||
const ticketChannel = interaction.guild.channels.cache.get(ticketChannelId);
|
||||
if (!ticketChannel) {
|
||||
return interaction.reply({
|
||||
@@ -144,7 +265,7 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
const NoPermsClaim = new Discord.EmbedBuilder()
|
||||
.setTitle(msgconfig.Ticket.ClaimTickets.NoPermsToClaimTitle)
|
||||
.setDescription(
|
||||
msgconfig.Ticket.ClaimTickets.NoPermsToClaim.replace('%channel%', ticketChannel.name)
|
||||
msgconfig.Ticket.ClaimTickets.NoPermsToClaim.replace("%channel%", ticketChannel.name)
|
||||
)
|
||||
.setColor(supportbot.Embed.Colours.Error);
|
||||
|
||||
@@ -160,7 +281,7 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
|
||||
setTimeout(() => {
|
||||
pingclaimedstaff.delete();
|
||||
}, 2000)
|
||||
}, 2000);
|
||||
|
||||
const TicketData = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8"));
|
||||
const ticketIndex = TicketData.tickets.findIndex((t) => t.id === ticketChannelId);
|
||||
@@ -174,13 +295,13 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
const claimedEmbed = new Discord.EmbedBuilder(claimMessage.embeds[0].data)
|
||||
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimedTitle)
|
||||
.setDescription(
|
||||
msgconfig.Ticket.ClaimTickets.ClaimMessage_Edit.replace('%user%', interaction.user.id).replace('%channel%', ticketChannel.id)
|
||||
msgconfig.Ticket.ClaimTickets.ClaimMessage_Edit.replace("%user%", interaction.user.id).replace("%channel%", ticketChannel.id)
|
||||
)
|
||||
.setColor(supportbot.Embed.Colours.Success);
|
||||
|
||||
const successfullyClaimed = new Discord.EmbedBuilder()
|
||||
.setTitle(msgconfig.Ticket.ClaimTickets.ClaimedTitle)
|
||||
.setDescription(msgconfig.Ticket.ClaimTickets.Claimed.replace('%channel%', ticketChannel.id))
|
||||
.setDescription(msgconfig.Ticket.ClaimTickets.Claimed.replace("%channel%", ticketChannel.id))
|
||||
.setColor(supportbot.Embed.Colours.Success);
|
||||
|
||||
await claimMessage.edit({ embeds: [claimedEmbed], components: [] });
|
||||
@@ -191,36 +312,41 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
}
|
||||
|
||||
// SUGGESTION INTERACTIONS [START]
|
||||
|
||||
if (interaction.customId === 'upvote' || interaction.customId === 'downvote' || interaction.customId === 'removevote') {
|
||||
|
||||
if (
|
||||
interaction.customId === "upvote" ||
|
||||
interaction.customId === "downvote" ||
|
||||
interaction.customId === "removevote"
|
||||
) {
|
||||
const suggestion = suggestions[interaction.message.id];
|
||||
if (!suggestion) return interaction.reply({ content: 'Suggestion not found.', ephemeral: true });
|
||||
if (!suggestion)
|
||||
return interaction.reply({ content: "Suggestion not found.", ephemeral: true });
|
||||
|
||||
const userId = interaction.user.id;
|
||||
const hasUpvoted = suggestion.upvotes.includes(userId);
|
||||
const hasDownvoted = suggestion.downvotes.includes(userId);
|
||||
|
||||
if (interaction.customId === 'upvote') {
|
||||
if (interaction.customId === "upvote") {
|
||||
if (hasUpvoted) {
|
||||
suggestion.upvotes = suggestion.upvotes.filter(id => id !== userId);
|
||||
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
|
||||
} else {
|
||||
suggestion.upvotes.push(userId);
|
||||
if (hasDownvoted) {
|
||||
suggestion.downvotes = suggestion.downvotes.filter(id => id !== userId);
|
||||
suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId);
|
||||
}
|
||||
}
|
||||
} else if (interaction.customId === 'downvote') {
|
||||
} else if (interaction.customId === "downvote") {
|
||||
if (hasDownvoted) {
|
||||
suggestion.downvotes = suggestion.downvotes.filter(id => id !== userId);
|
||||
suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId);
|
||||
} else {
|
||||
suggestion.downvotes.push(userId);
|
||||
if (hasUpvoted) {
|
||||
suggestion.upvotes = suggestion.upvotes.filter(id => id !== userId);
|
||||
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
|
||||
}
|
||||
}
|
||||
} else if (interaction.customId === 'removevote') {
|
||||
suggestion.upvotes = suggestion.upvotes.filter(id => id !== userId);
|
||||
suggestion.downvotes = suggestion.downvotes.filter(id => id !== userId);
|
||||
} else if (interaction.customId === "removevote") {
|
||||
suggestion.upvotes = suggestion.upvotes.filter((id) => id !== userId);
|
||||
suggestion.downvotes = suggestion.downvotes.filter((id) => id !== userId);
|
||||
}
|
||||
|
||||
fs.writeFileSync("./Data/SuggestionData.json", JSON.stringify(suggestions, null, 2));
|
||||
@@ -228,13 +354,20 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
const upvoteCount = suggestion.upvotes.length;
|
||||
const downvoteCount = suggestion.downvotes.length;
|
||||
|
||||
const updatedEmbed = new Discord.EmbedBuilder(interaction.message.embeds[0].data)
|
||||
.setFields([
|
||||
{ name: 'Suggestion', value: suggestion.suggestion, inline: true },
|
||||
{ name: 'From', value: `<@${suggestion.author}>` },
|
||||
{ name: `${supportbot.Suggestions.UpvoteEmoji} ${supportbot.Suggestions.UpvoteTitle}`, value: `${upvoteCount}`, inline: true },
|
||||
{ name: `${supportbot.Suggestions.DownvoteEmoji} ${supportbot.Suggestions.DownvoteTitle}`, value: `${downvoteCount}`, inline: true }
|
||||
]);
|
||||
const updatedEmbed = new Discord.EmbedBuilder(interaction.message.embeds[0].data).setFields([
|
||||
{ name: "Suggestion", value: suggestion.suggestion, inline: true },
|
||||
{ name: "From", value: `<@${suggestion.author}>` },
|
||||
{
|
||||
name: `${supportbot.Suggestions.UpvoteEmoji} ${supportbot.Suggestions.UpvoteTitle}`,
|
||||
value: `${upvoteCount}`,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: `${supportbot.Suggestions.DownvoteEmoji} ${supportbot.Suggestions.DownvoteTitle}`,
|
||||
value: `${downvoteCount}`,
|
||||
inline: true,
|
||||
},
|
||||
]);
|
||||
|
||||
await interaction.update({ embeds: [updatedEmbed] });
|
||||
}
|
||||
@@ -242,11 +375,14 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
|
||||
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.");
|
||||
return interaction.reply(
|
||||
"Some roles seem to be missing!\nPlease check for errors when starting the bot."
|
||||
);
|
||||
}
|
||||
|
||||
const NoPerms = new Discord.EmbedBuilder()
|
||||
@@ -256,7 +392,10 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
)
|
||||
.setColor(supportbot.Embed.Colours.Warn);
|
||||
|
||||
if (!interaction.member.roles.cache.has(SupportStaff.id) && !interaction.member.roles.cache.has(Admin.id)) {
|
||||
if (
|
||||
!interaction.member.roles.cache.has(SupportStaff.id) &&
|
||||
!interaction.member.roles.cache.has(Admin.id)
|
||||
) {
|
||||
return interaction.reply({ embeds: [NoPerms] });
|
||||
}
|
||||
}
|
||||
@@ -264,9 +403,7 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
await interaction.channel.setInvitable(enable);
|
||||
|
||||
const message = enable ? msgconfig.Ticket.EnableInvites : msgconfig.Ticket.DisableInvites;
|
||||
const embed = new Discord.EmbedBuilder()
|
||||
.setDescription(message)
|
||||
.setColor(supportbot.Embed.Colours.General);
|
||||
const embed = new Discord.EmbedBuilder().setDescription(message).setColor(supportbot.Embed.Colours.General);
|
||||
|
||||
await interaction.reply({
|
||||
embeds: [embed],
|
||||
@@ -274,5 +411,55 @@ module.exports = new Event("interactionCreate", async (client, interaction) => {
|
||||
});
|
||||
}
|
||||
|
||||
// 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,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
+25
-80
@@ -59,7 +59,7 @@ module.exports = new Event("ready", async (client, interaction) => {
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`\u001b[32m`, `――――――――――――――――――――――――――――――――――――――――――――`);
|
||||
console.log(`\u001b[33m`, `――――――――――――――――――――――――――――――――――――――――――――`);
|
||||
console.log(` `);
|
||||
console.log(`\u001b[31m`, `┏━━━┓╋╋╋╋╋╋╋╋╋╋╋╋╋┏┓┏━━┓╋╋╋┏┓`);
|
||||
console.log(`\u001b[31m`, `┃┏━┓┃╋╋╋╋╋╋╋╋╋╋╋╋┏┛┗┫┏┓┃╋╋┏┛┗┓`);
|
||||
@@ -70,60 +70,22 @@ module.exports = new Event("ready", async (client, interaction) => {
|
||||
console.log(`\u001b[31m`, `┗╋╋╋╋╋╋╋┃┃╋┃┃`);
|
||||
console.log(`\u001b[31m`, `╋╋╋╋╋╋╋┗┛╋┗┛`);
|
||||
console.log(` `);
|
||||
console.log(`\u001b[32m`, `――――――――――――――――――――――――――――――――――――――――――――`);
|
||||
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[31m`,
|
||||
`${supportbot.General.Name} | [${supportbot.SupportBot_Version}]`,
|
||||
`\u001b[32m`,
|
||||
`Connected to Discord`,
|
||||
);
|
||||
|
||||
console.log(`\u001b[31m`, `SupportBot proudly created by Emerald Development`);
|
||||
|
||||
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[31m`,
|
||||
`Discord`,
|
||||
`\u001b[32m`,
|
||||
`https://dsc.gg/emerald-dev`,
|
||||
);
|
||||
|
||||
console.log(
|
||||
`\u001b[31m`,
|
||||
`Website`,
|
||||
`\u001b[32m`,
|
||||
`https://emeraldsrv.com`,
|
||||
);
|
||||
|
||||
console.log(
|
||||
`\u001b[31m`,
|
||||
`Marketplace`,
|
||||
`\u001b[32m`,
|
||||
`https://market.emeraldsrv.com`,
|
||||
);
|
||||
|
||||
console.log(
|
||||
`\u001b[31m`,
|
||||
`Documentation`,
|
||||
`\u001b[32m`,
|
||||
`https://emeraldsrv.com/third-party`,
|
||||
);
|
||||
|
||||
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[31m`,
|
||||
`Invite URL:`,
|
||||
`\u001b[36m`,
|
||||
`https://discord.com/api/oauth2/authorize?client_id=` +
|
||||
client.user.id +
|
||||
`&permissions=8&scope=bot%20applications.commands`
|
||||
);
|
||||
|
||||
console.log(` `);
|
||||
console.log(`\u001b[32m`, `――――――――――――――――――――――――――――――――――――――――――――`);
|
||||
console.log(`\u001b[33m`, `――――――――――――――――― [Config Check] ――――――――――――――――――`);
|
||||
console.log("\u001b[32m", "Config initialization...");
|
||||
|
||||
const roles = [
|
||||
supportbot.Roles.StaffMember.Admin,
|
||||
@@ -168,35 +130,18 @@ module.exports = new Event("ready", async (client, interaction) => {
|
||||
// if (!find) missingCat.push(cat);
|
||||
// }
|
||||
|
||||
if (missingR.length > 0) {
|
||||
console.log(
|
||||
"\u001b[31m",
|
||||
`[MISSING CONFIGURATION]`,
|
||||
"\u001b[33m",
|
||||
`The following Roles could not be found in your server.\n`, `\u001b[31m`, `[${missingR.join(
|
||||
", "
|
||||
)}]`, `\n `,
|
||||
);
|
||||
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 (missingC.length > 0) {
|
||||
console.log(
|
||||
"\u001b[31m",
|
||||
`[MISSING CONFIGURATION]`,
|
||||
"\u001b[33m",
|
||||
`The following Channels could not be found in your server.\n`, `\u001b[31m`, `[${missingC.join(
|
||||
", "
|
||||
)}]`, `\n `
|
||||
);
|
||||
}
|
||||
if (missingCat.length > 0) {
|
||||
console.log(
|
||||
"\u001b[31m",
|
||||
`[MISSING CONFIGURATION]`,
|
||||
"\u001b[33m",
|
||||
`The following Categories could not be found in your server.\n`, `\u001b[31m`, `[${missingCat.join(
|
||||
", "
|
||||
)}]`, `\n `,
|
||||
);
|
||||
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
-1
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Emerald Services
|
||||
Copyright (c) 2024 Emerald Services
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -84,5 +84,13 @@ Released under the [MIT](https://opensource.org/licenses/MIT) license.
|
||||
<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
|
||||
)
|
||||
|
||||
|
||||
|
||||
+36
-25
@@ -1,12 +1,8 @@
|
||||
// C:\Users\ollie\Documents\GitHub\SupportBot\Structures\Client.js
|
||||
|
||||
// SupportBot | Emerald Services
|
||||
// Client Structure
|
||||
|
||||
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"));
|
||||
@@ -89,39 +85,48 @@ class Client extends Discord.Client {
|
||||
tempCommandFiles = tempCommandFiles.filter(item => item !== "Ping.js");
|
||||
}
|
||||
|
||||
if (cmdconfig.Ping.Enabled === false) {
|
||||
tempCommandFiles = tempCommandFiles.filter(item => item !== "Ping.js");
|
||||
if (cmdconfig.AddUser.Enabled === false) {
|
||||
tempCommandFiles = tempCommandFiles.filter(item => item !== "addUser.js");
|
||||
}
|
||||
|
||||
if (supportbot.Ticket.ClaimTickets.Enabled === false) {
|
||||
tempCommandFiles = tempCommandFiles.filter(item => item !== "ticketstats.js");
|
||||
}
|
||||
if (cmdconfig.RemoveUser.Enabled === false) {
|
||||
tempCommandFiles = tempCommandFiles.filter(item => item !== "removeUser.js");
|
||||
}
|
||||
|
||||
if (cmdconfig.ForceAddUser.Enabled === false) {
|
||||
tempCommandFiles = tempCommandFiles.filter(item => item !== "forceaddUser.js");
|
||||
}
|
||||
|
||||
if (cmdconfig.Profile.Enabled === false) {
|
||||
tempCommandFiles = tempCommandFiles.filter(item => item !== "Profile.js");
|
||||
}
|
||||
|
||||
const commandFiles = tempCommandFiles;
|
||||
const commands = commandFiles.map((file) => require(`../Commands/${file}`));
|
||||
|
||||
// Commands
|
||||
console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Commands ▬▬▬▬▬▬▬");
|
||||
// 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);
|
||||
});
|
||||
|
||||
console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Commands ▬▬▬▬▬▬▬");
|
||||
// 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) => {
|
||||
let addon = require(`../Addons/${file}`);
|
||||
const addon = require(`../Addons/${file}`);
|
||||
addon.name = file.split(".")[0];
|
||||
return addon;
|
||||
});
|
||||
|
||||
// Addons
|
||||
console.log(" ");
|
||||
console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Addons ▬▬▬▬▬▬▬");
|
||||
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Addons ▬▬▬▬▬▬▬");
|
||||
|
||||
addons.forEach((addon) => {
|
||||
console.log(
|
||||
@@ -132,18 +137,24 @@ class Client extends Discord.Client {
|
||||
`\u001b[32;1m`,
|
||||
"Loaded"
|
||||
);
|
||||
addon.commands?.forEach((command) => {
|
||||
this.commands.set(command.name, command);
|
||||
});
|
||||
addon.events?.forEach((event) => {
|
||||
this.on(event.event, (...args) => event.run(this, ...args));
|
||||
});
|
||||
|
||||
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[34;1m`, "▬▬▬▬▬▬▬ Addons ▬▬▬▬▬▬▬");
|
||||
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Addons ▬▬▬▬▬▬▬");
|
||||
}
|
||||
|
||||
// Slash Commands
|
||||
// Register Slash Commands
|
||||
|
||||
this.once("ready", async () => {
|
||||
await this.guilds.cache.first()?.commands.set(this.commands);
|
||||
@@ -156,7 +167,7 @@ class Client extends Discord.Client {
|
||||
});
|
||||
|
||||
console.log(" ");
|
||||
console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Events ▬▬▬▬▬▬▬");
|
||||
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Events ▬▬▬▬▬▬▬");
|
||||
|
||||
fs.readdirSync("./Events").filter((file) => file.endsWith(".js")).forEach((file) => {
|
||||
const event = require(`../Events/${file}`);
|
||||
@@ -164,7 +175,7 @@ class Client extends Discord.Client {
|
||||
this.on(event.event, (...args) => event.run(this, ...args));
|
||||
});
|
||||
|
||||
console.log(`\u001b[34;1m`, "▬▬▬▬▬▬▬ Events ▬▬▬▬▬▬▬");
|
||||
console.log(`\u001b[33m`, "▬▬▬▬▬▬▬ Events ▬▬▬▬▬▬▬");
|
||||
if (process.argv[2] !== "test") {
|
||||
await this.login(token);
|
||||
} else {
|
||||
|
||||
Generated
+1593
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user