Add Sentinel anti-nuke listeners, federation role syncing, ticket system, and admin commands to the unified AeThex bot, consolidating functionality and enhancing security monitoring. Replit-Commit-Author: Agent Replit-Commit-Session-Id: e72fc1b7-94bd-4d6c-801f-cbac2fae245c Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 00c4494a-b436-4e48-b794-39cd745fb604 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/e72fc1b7-94bd-4d6c-801f-cbac2fae245c/7DQc4BR Replit-Helium-Checkpoint-Created: true
128 lines
4.1 KiB
JavaScript
128 lines
4.1 KiB
JavaScript
const { SlashCommandBuilder, EmbedBuilder, ChannelType, PermissionFlagsBits, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
|
|
|
|
module.exports = {
|
|
data: new SlashCommandBuilder()
|
|
.setName('ticket')
|
|
.setDescription('Ticket management system')
|
|
.addSubcommand(subcommand =>
|
|
subcommand
|
|
.setName('create')
|
|
.setDescription('Create a new support ticket')
|
|
.addStringOption(option =>
|
|
option.setName('reason')
|
|
.setDescription('Brief reason for opening this ticket')
|
|
.setRequired(true)
|
|
)
|
|
)
|
|
.addSubcommand(subcommand =>
|
|
subcommand
|
|
.setName('close')
|
|
.setDescription('Close the current ticket')
|
|
),
|
|
|
|
async execute(interaction, supabase, client) {
|
|
const subcommand = interaction.options.getSubcommand();
|
|
|
|
if (subcommand === 'create') {
|
|
const reason = interaction.options.getString('reason');
|
|
const guild = interaction.guild;
|
|
const user = interaction.user;
|
|
|
|
const existingTicket = client.activeTickets.get(user.id);
|
|
if (existingTicket) {
|
|
return interaction.reply({
|
|
content: `You already have an open ticket: <#${existingTicket}>`,
|
|
ephemeral: true,
|
|
});
|
|
}
|
|
|
|
try {
|
|
const ticketChannel = await guild.channels.create({
|
|
name: `ticket-${user.username}`,
|
|
type: ChannelType.GuildText,
|
|
permissionOverwrites: [
|
|
{
|
|
id: guild.id,
|
|
deny: [PermissionFlagsBits.ViewChannel],
|
|
},
|
|
{
|
|
id: user.id,
|
|
allow: [PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages],
|
|
},
|
|
{
|
|
id: client.user.id,
|
|
allow: [PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages, PermissionFlagsBits.ManageChannels],
|
|
},
|
|
],
|
|
});
|
|
|
|
client.activeTickets.set(user.id, ticketChannel.id);
|
|
|
|
const closeButton = new ActionRowBuilder()
|
|
.addComponents(
|
|
new ButtonBuilder()
|
|
.setCustomId(`ticket_close_${ticketChannel.id}`)
|
|
.setLabel('Close Ticket')
|
|
.setStyle(ButtonStyle.Danger)
|
|
);
|
|
|
|
const ticketEmbed = new EmbedBuilder()
|
|
.setColor(0x7c3aed)
|
|
.setTitle('Support Ticket')
|
|
.setDescription(`Ticket created by ${user}`)
|
|
.addFields(
|
|
{ name: 'Reason', value: reason },
|
|
{ name: 'User ID', value: user.id, inline: true },
|
|
{ name: 'Created', value: `<t:${Math.floor(Date.now() / 1000)}:F>`, inline: true }
|
|
)
|
|
.setFooter({ text: 'A staff member will assist you shortly.' });
|
|
|
|
await ticketChannel.send({ embeds: [ticketEmbed], components: [closeButton] });
|
|
|
|
await interaction.reply({
|
|
content: `Ticket created: ${ticketChannel}`,
|
|
ephemeral: true,
|
|
});
|
|
|
|
client.sendAlert(`New ticket opened by ${user.tag}: ${reason}`);
|
|
|
|
} catch (error) {
|
|
console.error('[Ticket] Create error:', error);
|
|
await interaction.reply({
|
|
content: 'Failed to create ticket. Please try again.',
|
|
ephemeral: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
if (subcommand === 'close') {
|
|
const channel = interaction.channel;
|
|
|
|
if (!channel.name.startsWith('ticket-')) {
|
|
return interaction.reply({
|
|
content: 'This command can only be used in ticket channels.',
|
|
ephemeral: true,
|
|
});
|
|
}
|
|
|
|
const userId = [...client.activeTickets.entries()].find(([k, v]) => v === channel.id)?.[0];
|
|
if (userId) {
|
|
client.activeTickets.delete(userId);
|
|
}
|
|
|
|
await interaction.reply({
|
|
content: 'Closing ticket in 5 seconds...',
|
|
});
|
|
|
|
client.sendAlert(`Ticket ${channel.name} closed by ${interaction.user.tag}`);
|
|
|
|
setTimeout(async () => {
|
|
try {
|
|
await channel.delete();
|
|
} catch (err) {
|
|
console.error('[Ticket] Delete error:', err);
|
|
}
|
|
}, 5000);
|
|
}
|
|
},
|
|
};
|