refactor(cmd/administration): adding the tsconfig + eslint correction

This commit is contained in:
Raphael 2025-10-14 00:17:23 +02:00 committed by Raphaël
parent e911f3b2e0
commit 8d41ef8f7a
4 changed files with 434 additions and 273 deletions

View file

@ -1,71 +1,94 @@
import { MessageFlags, ChannelType, SlashCommandBuilder, CommandInteraction } from 'discord.js'; import { SlashCommandBuilder } from '@discordjs/builders';
import {
MessageFlags,
ChannelType,
ChatInputCommandInteraction,
type SlashCommandChannelOption,
CategoryChannel,
} from 'discord.js';
import emoji from '../../../assets/emoji.json' assert { type: 'json' }; import emoji from '../../../assets/emoji.json' assert { type: 'json' };
import { prisma } from '../../lib/prisma.ts'; import { prisma } from '@lib/prisma';
import { User as UserPrisma } from '@prisma/client'; import { User as UserPrisma } from '@prisma/client';
export default { export default {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName('deletecat') .setName('deletecat')
.setDescription('Delete the categorie given in parameter') .setDescription('Delete the category given in parameter')
.addChannelOption((opt) => .addChannelOption((opt: SlashCommandChannelOption) =>
opt opt
.setName('category') .setName('category')
.setDescription('Choose the categorie you want to delete') .setDescription('Choose the category you want to delete')
.setRequired(true) .setRequired(true)
.addChannelTypes(ChannelType.GuildCategory), .addChannelTypes(ChannelType.GuildCategory),
), ),
async execute(interaction: CommandInteraction) {
let userData: UserPrisma; async execute(interaction: ChatInputCommandInteraction) {
let userData: UserPrisma | null = null;
try { try {
userData = await prisma.user.findUnique({ userData = await prisma.user.findUnique({
where: { where: { id: interaction.user.id },
id: interaction.user.id,
},
}); });
} }
catch (err) { catch (err: unknown) {
console.error( if (err instanceof Error) {
`\t⚠ | Whitelist => Cannot get the database connection!\n\t\t(${err}).`, console.error(`${err.name}: ${err.message}`);
); console.error(err.stack);
}
else {
console.error('❌ Unknown error:', err);
}
await interaction.reply({ await interaction.reply({
content: `${emoji.answer.error} | Cannot connect to the database`, content: `${emoji.answer.error} | Cannot connect to the database`,
flags: MessageFlags.Ephemeral, flags: MessageFlags.Ephemeral,
}); });
console.error(`Cannot connect to the database:\n\t${err}`);
return; return;
} }
if (!userData.isOwner) {
if (!userData?.isOwner) {
await interaction.reply({ await interaction.reply({
content: `${emoji.answer.no} | This command is only for owner`, content: `${emoji.answer.no} | This command is only for owners`,
flags: MessageFlags.Ephemeral, flags: MessageFlags.Ephemeral,
}); });
return; return;
} }
const category: ChannelType.GuildCategory = interaction.options.getChannel(
'category', const categoryOption = interaction.options.getChannel('category', true);
true,
); if (categoryOption.type !== ChannelType.GuildCategory) {
await interaction.reply({
content: `${emoji.answer.no} | Please choose a valid category.`,
flags: MessageFlags.Ephemeral,
});
return;
}
const category = categoryOption as CategoryChannel;
try { try {
for (const channel of category.children.cache.values()) { for (const channel of category.children.cache.values()) {
await channel.delete( await channel.delete(
`Delete cat of ${channel.name} (by ${interaction.username})`, `Deleted ${channel.name} (requested by ${interaction.user.username})`,
); );
} }
await category.delete( await category.delete(
`Delete cat of ${category.name} (by ${interaction.username})`, `Deleted ${category.name} (requested by ${interaction.user.username})`,
); );
await interaction.reply({ await interaction.reply({
content: `${emoji.answer.yes} | Suppressed the ${category.name}`, content: `${emoji.answer.yes} | Deleted category **${category.name}** and its channels.`,
flags: MessageFlags.Ephemeral, flags: MessageFlags.Ephemeral,
}); });
} }
catch (err) { catch (err: unknown) {
const errorMessage = err instanceof Error ? err.message : String(err);
console.error(
`Cannot delete category or its channels:\n\t${errorMessage}`,
);
await interaction.reply({ await interaction.reply({
content: `${emoji.answer.error} | Cannot suppress the category's channels`, content: `${emoji.answer.error} | Failed to delete the category or its channels.`,
flags: MessageFlags.Ephemeral, flags: MessageFlags.Ephemeral,
}); });
console.error(`Cannot suppress the category's channel:\n\t${err}`);
return;
} }
}, },
}; };

View file

@ -1,11 +1,10 @@
import { ActionRowBuilder, SlashCommandBuilder } from '@discordjs/builders';
import { import {
SlashCommandBuilder,
ChatInputCommandInteraction,
EmbedBuilder,
ActionRowBuilder,
ButtonBuilder,
ButtonStyle, ButtonStyle,
ChatInputCommandInteraction,
ComponentType, ComponentType,
EmbedBuilder,
Interaction,
MessageFlags, MessageFlags,
ModalBuilder, ModalBuilder,
TextInputBuilder, TextInputBuilder,
@ -43,22 +42,16 @@ function getPlaceholdersEmbed(guildData: GuildPrisma): EmbedBuilder {
.setColor(guildData.color); .setColor(guildData.color);
} }
export const data = new SlashCommandBuilder() function createMainRow(
.setName('join') guildData: GuildPrisma,
.setDescription('Configure welcome and leave messages'); ): ActionRowBuilder<ButtonBuilder> {
return new ActionRowBuilder<ButtonBuilder>().addComponents(
export async function execute(interaction: ChatInputCommandInteraction) {
const guildId = interaction.guildId!;
let guildData = await prisma.guild.findUnique({ where: { id: guildId } });
if (!guildData) {
guildData = await prisma.guild.create({ data: { id: guildId } });
}
const mainRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder() new ButtonBuilder()
.setCustomId('toggle_welcome') .setCustomId('toggle_welcome')
.setLabel(guildData.welcomeEnabled ? 'Disable welcome' : 'Enable welcome') .setLabel(guildData.welcomeEnabled ? 'Disable welcome' : 'Enable welcome')
.setStyle(guildData.welcomeEnabled ? ButtonStyle.Danger : ButtonStyle.Success), .setStyle(
guildData.welcomeEnabled ? ButtonStyle.Danger : ButtonStyle.Success,
),
new ButtonBuilder() new ButtonBuilder()
.setCustomId('edit_welcome') .setCustomId('edit_welcome')
.setLabel('Edit welcome message') .setLabel('Edit welcome message')
@ -66,7 +59,9 @@ export async function execute(interaction: ChatInputCommandInteraction) {
new ButtonBuilder() new ButtonBuilder()
.setCustomId('toggle_leave') .setCustomId('toggle_leave')
.setLabel(guildData.leaveEnabled ? 'Disable leave' : 'Enable leave') .setLabel(guildData.leaveEnabled ? 'Disable leave' : 'Enable leave')
.setStyle(guildData.leaveEnabled ? ButtonStyle.Danger : ButtonStyle.Success), .setStyle(
guildData.leaveEnabled ? ButtonStyle.Danger : ButtonStyle.Success,
),
new ButtonBuilder() new ButtonBuilder()
.setCustomId('edit_leave') .setCustomId('edit_leave')
.setLabel('Edit leave message') .setLabel('Edit leave message')
@ -77,132 +72,188 @@ export async function execute(interaction: ChatInputCommandInteraction) {
.setEmoji('') .setEmoji('')
.setStyle(ButtonStyle.Secondary), .setStyle(ButtonStyle.Secondary),
); );
}
export const data = new SlashCommandBuilder()
.setName('join')
.setDescription('Configure welcome and leave messages');
export async function execute(interaction: ChatInputCommandInteraction) {
const guildId = interaction.guildId;
if (!guildId) {
await interaction.reply({
content: '❌ This command can only be used in a guild.',
flags: MessageFlags.Ephemeral,
});
return;
}
let currentGuildData: GuildPrisma | null = await prisma.guild.findUnique({
where: { id: guildId },
});
if (!currentGuildData) {
currentGuildData = await prisma.guild.create({ data: { id: guildId } });
}
const mainRow : ActionRowBuilder = createMainRow(currentGuildData);
await interaction.reply({ await interaction.reply({
embeds: [getEmbed(guildData)], embeds: [getEmbed(currentGuildData)],
components: [mainRow], components: [mainRow],
flags: MessageFlags.Ephemeral, flags: MessageFlags.Ephemeral,
}); });
const collector = interaction.channel!.createMessageComponentCollector({ const collector = interaction.channel?.createMessageComponentCollector({
componentType: ComponentType.Button, componentType: ComponentType.Button,
time: 60_000, time: 60_000,
}); });
collector.on('collect', async (i) => { if (!collector) {
if (i.user.id !== interaction.user.id) { return;
return i.reply({ }
content: '❌ You are not allowed to use this panel.',
ephemeral: true,
});
}
// Show placeholders collector.on('collect', (i) => {
if (i.customId === 'placeholders') { void (async () => {
const backRow = new ActionRowBuilder<ButtonBuilder>().addComponents( if (i.user.id !== interaction.user.id) {
new ButtonBuilder() await i.reply({
.setCustomId('back_to_main') content: '❌ You are not allowed to use this panel.',
.setLabel('↩️ Back') flags: MessageFlags.Ephemeral,
.setStyle(ButtonStyle.Secondary), });
); return;
await interaction.editReply({ }
embeds: [getPlaceholdersEmbed(guildData)],
components: [backRow],
});
return;
}
// ↩️ Back to main panel // Show placeholders
if (i.customId === 'back_to_main') { if (i.customId === 'placeholders') {
await interaction.editReply({ const backRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
embeds: [getEmbed(guildData)], new ButtonBuilder()
components: [mainRow], .setCustomId('back_to_main')
}); .setLabel('↩️ Back')
return; .setStyle(ButtonStyle.Secondary),
}
// 🟢 Toggle welcome
if (i.customId === 'toggle_welcome') {
guildData = await prisma.guild.update({
where: { id: guildId },
data: { welcomeEnabled: !guildData.welcomeEnabled },
});
await interaction.editReply({
embeds: [getEmbed(guildData)],
components: [mainRow],
});
return;
}
// 🟢 Toggle leave
if (i.customId === 'toggle_leave') {
guildData = await prisma.guild.update({
where: { id: guildId },
data: { leaveEnabled: !guildData.leaveEnabled },
});
await interaction.editReply({
embeds: [getEmbed(guildData)],
components: [mainRow],
});
return;
}
// ✏️ Open modal for editing messages
if (i.customId === 'edit_welcome' || i.customId === 'edit_leave') {
const modal = new ModalBuilder()
.setCustomId(i.customId + '_modal')
.setTitle('Edit Message');
const input = new TextInputBuilder()
.setCustomId('message')
.setLabel('Message content (placeholders allowed)')
.setStyle(TextInputStyle.Paragraph)
.setPlaceholder('Ex: Welcome {user.mention} to {server.name}!')
.setValue(
i.customId === 'edit_welcome'
? guildData.welcomeMessage || ''
: guildData.leaveMessage || '',
); );
await interaction.editReply({
embeds: [getPlaceholdersEmbed(currentGuildData)],
components: [backRow],
});
return;
}
modal.addComponents(new ActionRowBuilder<TextInputBuilder>().addComponents(input)); // ↩️ Back to main panel
await i.showModal(modal); if (i.customId === 'back_to_main') {
} await interaction.editReply({
embeds: [getEmbed(currentGuildData)],
components: [createMainRow(currentGuildData)],
});
return;
}
// 🟢 Toggle welcome
if (i.customId === 'toggle_welcome') {
const updatedGuildData = await prisma.guild.update({
where: { id: guildId },
data: { welcomeEnabled: !currentGuildData.welcomeEnabled },
});
currentGuildData = updatedGuildData;
const newMainRow = createMainRow(updatedGuildData);
await interaction.editReply({
embeds: [getEmbed(updatedGuildData)],
components: [newMainRow],
});
return;
}
// 🟢 Toggle leave
if (i.customId === 'toggle_leave') {
const updatedGuildData = await prisma.guild.update({
where: { id: guildId },
data: { leaveEnabled: !currentGuildData.leaveEnabled },
});
currentGuildData = updatedGuildData;
const newMainRow = createMainRow(updatedGuildData);
await interaction.editReply({
embeds: [getEmbed(updatedGuildData)],
components: [newMainRow],
});
return;
}
// ✏️ Open modal for editing messages
if (i.customId === 'edit_welcome' || i.customId === 'edit_leave') {
const modal = new ModalBuilder()
.setCustomId(`${i.customId}_modal`)
.setTitle('Edit Message');
const input = new TextInputBuilder()
.setCustomId('message')
.setLabel({ name: 'Message content (placeholders allowed)' })
.setStyle(TextInputStyle.Paragraph)
.setPlaceholder('Ex: Welcome {user.mention} to {server.name}!')
.setValue(
i.customId === 'edit_welcome'
? currentGuildData.welcomeMessage || ''
: currentGuildData.leaveMessage || '',
);
modal.addComponents(
new ActionRowBuilder<TextInputBuilder>().addComponents(input),
);
await i.showModal(modal);
}
})();
}); });
// Handle modal submissions // Handle modal submissions
interaction.client.on('interactionCreate', async (modalInt) => { const modalHandler = (modalInt: Interaction) => {
if (!modalInt.isModalSubmit()) return; void (async () => {
if (
!modalInt.isModalSubmit() ||
modalInt.user.id !== interaction.user.id
) {
return;
}
if (modalInt.customId === 'edit_welcome_modal') { const typedModalInt = modalInt;
const msg = modalInt.fields.getTextInputValue('message');
guildData = await prisma.guild.update({
where: { id: guildId },
data: { welcomeMessage: msg },
});
await modalInt.reply({
content: '✅ | Welcome message updated!',
ephemeral: true,
});
await interaction.editReply({
embeds: [getEmbed(guildData)],
components: [mainRow],
});
}
if (modalInt.customId === 'edit_leave_modal') { if (typedModalInt.customId === 'edit_welcome_modal') {
const msg = modalInt.fields.getTextInputValue('message'); const msg = typedModalInt.fields.getTextInputValue('message');
guildData = await prisma.guild.update({ const updatedGuildData = await prisma.guild.update({
where: { id: guildId }, where: { id: guildId },
data: { leaveMessage: msg }, data: { welcomeMessage: msg },
}); });
await modalInt.reply({ currentGuildData = updatedGuildData;
content: '✅ | Leave message updated!', await typedModalInt.reply({
ephemeral: true, content: '✅ | Welcome message updated!',
}); ephemeral: true,
await interaction.editReply({ });
embeds: [getEmbed(guildData)], const newMainRow = createMainRow(updatedGuildData);
components: [mainRow], await interaction.editReply({
}); embeds: [getEmbed(updatedGuildData)],
} components: [newMainRow],
});
}
if (typedModalInt.customId === 'edit_leave_modal') {
const msg = typedModalInt.fields.getTextInputValue('message');
const updatedGuildData = await prisma.guild.update({
where: { id: guildId },
data: { leaveMessage: msg },
});
currentGuildData = updatedGuildData;
await typedModalInt.reply({
content: '✅ | Leave message updated!',
ephemeral: true,
});
const newMainRow = createMainRow(updatedGuildData);
await interaction.editReply({
embeds: [getEmbed(updatedGuildData)],
components: [newMainRow],
});
}
})();
};
interaction.client.on('interactionCreate', modalHandler);
collector.on('end', () => {
interaction.client.off('interactionCreate', modalHandler);
}); });
} }

View file

@ -1,6 +1,6 @@
import { prisma } from '../../lib/prisma.ts'; import { prisma } from '@lib/prisma';
import { ActionRowBuilder, SlashCommandBuilder } from '@discordjs/builders';
import { import {
ActionRowBuilder,
ChannelType, ChannelType,
PermissionsBitField, PermissionsBitField,
ComponentType, ComponentType,
@ -8,12 +8,13 @@ import {
StringSelectMenuBuilder, StringSelectMenuBuilder,
StringSelectMenuInteraction, StringSelectMenuInteraction,
StringSelectMenuOptionBuilder, StringSelectMenuOptionBuilder,
SlashCommandBuilder,
MessageFlags, MessageFlags,
EmbedBuilder, EmbedBuilder,
CommandInteraction, ChatInputCommandInteraction,
CategoryChannel,
} from 'discord.js'; } from 'discord.js';
import emoji from '../../../assets/emoji.json' assert { type: 'json' }; import emoji from '../../../assets/emoji.json' assert { type: 'json' };
import { Guild, User } from '@prisma/client';
export default { export default {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
@ -43,8 +44,16 @@ export default {
}, },
), ),
), ),
async execute(interaction: CommandInteraction) { async execute(interaction: ChatInputCommandInteraction) {
let guildData: Guild; if (!interaction.guild) {
await interaction.reply({
content: `${emoji.answer.error} | This command can only be used in a guild`,
flags: MessageFlags.Ephemeral,
});
return;
}
let guildData: Guild | null;
try { try {
guildData = await prisma.guild.findUnique({ guildData = await prisma.guild.findUnique({
where: { where: {
@ -52,9 +61,10 @@ export default {
}, },
}); });
} }
catch (err) { catch (err: unknown) {
const errorMessage = err instanceof Error ? err.message : String(err);
console.error( console.error(
`\t⚠ | Cannot get the database connection!\n\t\t(${err}).`, `\t⚠ | Cannot get the database connection!\n\t\t(${errorMessage}).`,
); );
await interaction.reply({ await interaction.reply({
content: `${emoji.answer.error} | Cannot connect to the database`, content: `${emoji.answer.error} | Cannot connect to the database`,
@ -62,7 +72,16 @@ export default {
}); });
return; return;
} }
let userData: User;
if (!guildData) {
await interaction.reply({
content: `${emoji.answer.error} | Guild data not found`,
flags: MessageFlags.Ephemeral,
});
return;
}
let userData: User | null;
try { try {
userData = await prisma.user.findUnique({ userData = await prisma.user.findUnique({
where: { where: {
@ -70,10 +89,23 @@ export default {
}, },
}); });
} }
catch (err) { catch (err: unknown) {
throw `\t⚠ | Cannot get the database connection!\n\t\t(${err}).`; const errorMessage = err instanceof Error ? err.message : String(err);
throw new Error(
`\t⚠ | Cannot get the database connection!\n\t\t(${errorMessage}).`,
);
} }
const choice: string = interaction.options.getString('action');
if (!userData) {
await interaction.reply({
content: `${emoji.answer.error} | User data not found`,
flags: MessageFlags.Ephemeral,
});
return;
}
const choice = interaction.options.getString('action', true);
switch (choice) { switch (choice) {
case 'logs_show': { case 'logs_show': {
if (!userData.isOwner) { if (!userData.isOwner) {
@ -86,7 +118,7 @@ export default {
if (guildData.logEnable) { if (guildData.logEnable) {
const logsData: EmbedBuilder = new EmbedBuilder() const logsData: EmbedBuilder = new EmbedBuilder()
.setTitle(`Logs for ${interaction.guild.name}`) .setTitle(`Logs for ${interaction.guild.name}`)
.setColor(`${guildData.color}`) .setColor(guildData.color)
.setFooter({ .setFooter({
text: guildData.footer, text: guildData.footer,
}).setDescription(` }).setDescription(`
@ -128,8 +160,8 @@ export default {
return; return;
} }
const roles = interaction.guild?.roles.cache const roles = interaction.guild.roles.cache
.filter((role) => !role.managed && role.id !== interaction.guild?.id) .filter((role) => !role.managed && role.id !== interaction.guild.id)
.sort((a, b) => b.position - a.position); .sort((a, b) => b.position - a.position);
const menu = new StringSelectMenuBuilder() const menu = new StringSelectMenuBuilder()
@ -150,7 +182,7 @@ export default {
const permSelector: EmbedBuilder = new EmbedBuilder() const permSelector: EmbedBuilder = new EmbedBuilder()
.setTitle('Which role will have access') .setTitle('Which role will have access')
.setColor(`${guildData.color}`) .setColor(guildData.color)
.setFooter({ .setFooter({
text: guildData.footer, text: guildData.footer,
}); });
@ -158,27 +190,29 @@ export default {
const msg = await interaction.reply({ const msg = await interaction.reply({
embeds: [permSelector], embeds: [permSelector],
components: [roleSelection], components: [roleSelection],
flags: MessageFlags.fetchReply,
}); });
const collector = msg.createMessageComponentCollector({ const collector = msg.createMessageComponentCollector({
componentType: ComponentType.StringSelect, componentType: ComponentType.StringSelect,
time: 60_000, time: 60_000,
max: 25, max: 25,
}); });
collector.on('end', async (collected) => { collector.on('end', (collected) => {
if (collected.size === 0) { void (async () => {
await interaction.editReply({ if (collected.size === 0) {
content: '⏰ | Too many time to select roles allowed to see the logs', await interaction.editReply({
embeds: [], content:
components: [], '⏰ | Too many time to select roles allowed to see the logs',
}); embeds: [],
} components: [],
});
}
})();
}); });
collector.on( collector.on(
'collect', 'collect',
async (selectInteraction: StringSelectMenuInteraction) => { async (selectInteraction: StringSelectMenuInteraction) => {
if (selectInteraction.user.id !== interaction.user.id) { if (selectInteraction.user.id !== interaction.user.id) {
selectInteraction.reply({ void selectInteraction.reply({
content: `${emoji.answer.no} | You cannot use this selector !`, content: `${emoji.answer.no} | You cannot use this selector !`,
ephemeral: true, ephemeral: true,
}); });
@ -199,53 +233,53 @@ export default {
})), })),
]; ];
const category = (await interaction.guild.channels.create({ const category = await interaction.guild.channels.create({
name: 'Logs', name: 'Logs',
type: ChannelType.GuildCategory, type: ChannelType.GuildCategory,
permissionOverwrites, permissionOverwrites,
})) as CategoryChannel; });
const logBot = (await interaction.guild.channels.create({ const logBot = await interaction.guild.channels.create({
name: 'bot-logs', name: 'bot-logs',
type: ChannelType.GuildText, type: ChannelType.GuildText,
parent: category, parent: category,
permissionOverwrites, permissionOverwrites,
})) as TextChannel; });
const logChannels = (await interaction.guild.channels.create({ const logChannels = await interaction.guild.channels.create({
name: 'channel-logs', name: 'channel-logs',
type: ChannelType.GuildText, type: ChannelType.GuildText,
parent: category, parent: category,
permissionOverwrites, permissionOverwrites,
})) as TextChannel; });
const logMember = (await interaction.guild.channels.create({ const logMember = await interaction.guild.channels.create({
name: 'member-logs', name: 'member-logs',
type: ChannelType.GuildText, type: ChannelType.GuildText,
parent: category, parent: category,
permissionOverwrites, permissionOverwrites,
})) as TextChannel; });
const logMod = (await interaction.guild.channels.create({ const logMod = await interaction.guild.channels.create({
name: 'mod-logs', name: 'mod-logs',
type: ChannelType.GuildText, type: ChannelType.GuildText,
parent: category, parent: category,
permissionOverwrites, permissionOverwrites,
})) as TextChannel; });
const logMsg = (await interaction.guild.channels.create({ const logMsg = await interaction.guild.channels.create({
name: 'message-logs', name: 'message-logs',
type: ChannelType.GuildText, type: ChannelType.GuildText,
parent: category, parent: category,
permissionOverwrites, permissionOverwrites,
})) as TextChannel; });
const logServer = (await interaction.guild.channels.create({ const logServer = await interaction.guild.channels.create({
name: 'server-logs', name: 'server-logs',
type: ChannelType.GuildText, type: ChannelType.GuildText,
parent: category, parent: category,
permissionOverwrites, permissionOverwrites,
})) as TextChannel; });
await prisma.guild.update({ await prisma.guild.update({
where: { where: {
@ -273,7 +307,7 @@ export default {
${mentionList} ${mentionList}
`, `,
) )
.setColor(`${guildData.color}`) .setColor(guildData.color)
.setFooter({ .setFooter({
text: guildData.footer, text: guildData.footer,
}); });
@ -301,27 +335,47 @@ export default {
}); });
return; return;
} }
const category: GuildCategory = await interaction.guild.channels.fetch(guildData.logCategory); if (!guildData.logCategory) {
await interaction.reply({
content: `${emoji.answer.error} | No log category found`,
flags: MessageFlags.Ephemeral,
});
return;
}
const category = (await interaction.guild.channels.fetch(
guildData.logCategory,
)) as CategoryChannel | null;
if (!category) {
await interaction.reply({
content: `${emoji.answer.error} | Category not found`,
flags: MessageFlags.Ephemeral,
});
return;
}
try { try {
for (const channel of category.children.cache.values()) { for (const channel of category.children.cache.values()) {
await channel.delete( await channel.delete(
`Delete cat of ${channel.name} (by ${interaction.username})`, `Delete cat of ${channel.name} (by ${interaction.user.username})`,
); );
} }
await category.delete( await category.delete(
`Delete cat of ${category.name} (by ${interaction.username})`, `Delete cat of ${category.name} (by ${interaction.user.username})`,
); );
await interaction.reply({ await interaction.reply({
content: `${emoji.answer.yes} | Disabled the logs of the guild`, content: `${emoji.answer.yes} | Disabled the logs of the guild`,
flags: MessageFlags.Ephemeral, flags: MessageFlags.Ephemeral,
}); });
} }
catch (err) { catch (err: unknown) {
const errorMessage =
err instanceof Error ? err.message : (err as string);
await interaction.reply({ await interaction.reply({
content: `${emoji.answer.error} | Cannot suppress the category's channels`, content: `${emoji.answer.error} | Cannot suppress the category's channels`,
flags: MessageFlags.Ephemeral, flags: MessageFlags.Ephemeral,
}); });
console.error(`Cannot suppress the category's channel:\n\t${err}`); console.error(
`Cannot suppress the category's channel:\n\t${errorMessage}`,
);
return; return;
} }
await prisma.guild.update({ await prisma.guild.update({
@ -343,6 +397,10 @@ export default {
} }
default: default:
console.error(`no choice on logs command ${choice}`); console.error(`no choice on logs command ${choice}`);
await interaction.reply({
content: `${emoji.answer.error} | Invalid choice`,
flags: MessageFlags.Ephemeral,
});
return; return;
} }
}, },

View file

@ -1,8 +1,6 @@
import { ButtonBuilder, ActionRowBuilder, SlashCommandBuilder } from '@discordjs/builders';
import { import {
SlashCommandBuilder,
ActionRowBuilder,
StringSelectMenuBuilder, StringSelectMenuBuilder,
ButtonBuilder,
ButtonStyle, ButtonStyle,
EmbedBuilder, EmbedBuilder,
ComponentType, ComponentType,
@ -45,7 +43,10 @@ function getEmbed(guildData: GuildPrisma): EmbedBuilder {
return baseEmbed; return baseEmbed;
} }
function getButton(selected: string, active: boolean): ActionRowBuilder<ButtonBuilder> { function getButton(
selected: string,
active: boolean,
): ActionRowBuilder<ButtonBuilder> {
const button = new ActionRowBuilder<ButtonBuilder>().addComponents( const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder() new ButtonBuilder()
.setCustomId(`enable_${selected}`) .setCustomId(`enable_${selected}`)
@ -74,8 +75,16 @@ export default {
.setDescription('Manage guild protections interactively'), .setDescription('Manage guild protections interactively'),
async execute(interaction: ChatInputCommandInteraction) { async execute(interaction: ChatInputCommandInteraction) {
const guildId: string | null = interaction.guildId!; const guildId = interaction.guildId;
let guildData: GuildPrisma = await prisma.guild.findUnique({ if (!guildId) {
await interaction.reply({
content: 'This command can only be used in a guild.',
flags: MessageFlags.Ephemeral,
});
return;
}
let guildData = await prisma.guild.findUnique({
where: { where: {
id: guildId, id: guildId,
}, },
@ -98,87 +107,107 @@ export default {
); );
const msg = await interaction.reply({ const msg = await interaction.reply({
embeds: [getEmbed(guildData)], embeds: [getEmbed(guildData)],
components: [new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(menu)], components: [
new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(menu),
],
flags: MessageFlags.Ephemeral, flags: MessageFlags.Ephemeral,
}); });
const collector = msg.createMessageComponentCollector({ const collector = msg.createMessageComponentCollector({
componentType: ComponentType.StringSelect, componentType: ComponentType.StringSelect,
time: 5 * 60 * 1000, time: 5 * 60 * 1000,
}); });
collector.on('collect', async (selectInteraction) => { collector.on('collect', (selectInteraction) => {
if (selectInteraction.user.id !== interaction.user.id) { void (async () => {
return selectInteraction.reply({ if (selectInteraction.user.id !== interaction.user.id) {
content: '❌ You cannot use this menu.', await selectInteraction.reply({
flags: MessageFlags.Ephemeral, content: '❌ You cannot use this menu.',
flags: MessageFlags.Ephemeral,
});
return;
}
const selected: string = selectInteraction
.values[0] as keyof typeof modules;
const enabled = guildData[
`protect${camel(selected)}` as keyof GuildPrisma
] as boolean;
const moduleEmbed = new EmbedBuilder()
.setTitle(`⚙️ | Manage ${modules[selected as keyof typeof modules]}`)
.setFooter({
text: guildData.footer,
})
.setDescription(
`This module is currently: **${enabled ? 'Enabled ✅' : 'Disabled ❌'}**`,
)
.setColor(enabled ? '#00ff00' : '#ff0000');
await selectInteraction.update({
embeds: [moduleEmbed],
components: [getButton(selected, true)],
}); });
} })();
const selected: string = selectInteraction.values[0] as keyof typeof modules;
const enabled = guildData![`protect${camel(selected)}`];
const moduleEmbed = new EmbedBuilder()
.setTitle(`⚙️ | Manage ${modules[selected]}`)
.setFooter({
text: guildData.footer,
})
.setDescription(
`This module is currently: **${enabled ? 'Enabled ✅' : 'Disabled ❌'}**`,
)
.setColor(enabled ? '#00ff00' : '#ff0000');
await selectInteraction.update({
embeds: [moduleEmbed],
components: [getButton(selected, true)],
});
}); });
const buttonCollector = msg.createMessageComponentCollector({ const buttonCollector = msg.createMessageComponentCollector({
componentType: ComponentType.Button, componentType: ComponentType.Button,
time: 5 * 60 * 1000, time: 5 * 60 * 1000,
}); });
buttonCollector.on('collect', async (btnInteraction) => { buttonCollector.on('collect', (btnInteraction) => {
if (btnInteraction.user.id !== interaction.user.id) { void (async () => {
return btnInteraction.reply({ if (btnInteraction.user.id !== interaction.user.id) {
content: '❌ | You cannot use these buttons.', await btnInteraction.reply({
flags: MessageFlags.Ephemeral, content: '❌ | You cannot use these buttons.',
flags: MessageFlags.Ephemeral,
});
return;
}
if (btnInteraction.customId === 'return') {
await btnInteraction.update({
embeds: [getEmbed(guildData)],
components: [
new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
menu,
),
],
});
return;
}
const [action, moduleName] = btnInteraction.customId.split('_');
if (!moduleName) return;
const field = `protect${camel(moduleName)}`;
await prisma.guild.update({
where: {
id: guildId,
},
data: {
[field]: action === 'enable',
},
}); });
} const updatedGuildData = await prisma.guild.findUnique({
if (btnInteraction.customId === 'return') { where: {
return btnInteraction.update({ id: guildId,
embeds: [getEmbed(guildData)], },
components: [ });
new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(menu), if (!updatedGuildData) return;
guildData = updatedGuildData;
await btnInteraction.update({
embeds: [
new EmbedBuilder()
.setTitle(
`⚙️ | Manage ${modules[moduleName as keyof typeof modules]}`,
)
.setFooter({
text: updatedGuildData.footer,
})
.setDescription(
`This module is now: **${
action === 'enable' ? '✅ Enabled' : '❌ Disabled'
}**`,
)
.setColor(action === 'enable' ? '#00ff00' : '#ff0000'),
], ],
components: [getButton(moduleName, false)],
}); });
} })();
const [action, moduleName] = btnInteraction.customId.split('_');
const field = `protect${camel(moduleName)}`;
await prisma.guild.update({
where: {
id: guildId,
},
data: {
[field]: action === 'enable',
},
});
guildData = await prisma.guild.findUnique({
where: {
id: guildId,
},
});
await btnInteraction.update({
embeds: [
new EmbedBuilder()
.setTitle(`⚙️ | Manage ${modules[moduleName as keyof typeof modules]}`)
.setFooter({
text: guildData.footer,
})
.setDescription(
`This module is now: **${
action === 'enable' ? '✅ Enabled' : '❌ Disabled'
}**`,
)
.setColor(action === 'enable' ? '#00ff00' : '#ff0000'),
],
components: [getButton(null, false)],
});
}); });
}, },
}; };