feat: add bot autorole configuration and migrate interaction handling to interactionCreate event

This commit is contained in:
이정수 2026-04-06 15:36:45 +09:00
parent 26cfd356ff
commit d941daf005
3 changed files with 77 additions and 33 deletions

View File

@ -17,6 +17,7 @@ export class KordClient extends Client {
GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent, GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildInvites, GatewayIntentBits.GuildInvites,
GatewayIntentBits.GuildMembers,
], ],
partials: [Partials.Message, Partials.Channel, Partials.GuildMember], partials: [Partials.Message, Partials.Channel, Partials.GuildMember],
}); });

View File

@ -50,14 +50,26 @@ class AutoRoleCommand extends Command {
name: t(locale, 'commands.autorole.statusLabel'), name: t(locale, 'commands.autorole.statusLabel'),
value: config?.isEnabled ? `${t(locale, 'commands.autorole.enabled')}` : `${t(locale, 'commands.autorole.disabled')}`, value: config?.isEnabled ? `${t(locale, 'commands.autorole.enabled')}` : `${t(locale, 'commands.autorole.disabled')}`,
inline: true inline: true
},
{
name: t(locale, 'commands.autorole.botStatusLabel'),
value: config?.botEnabled ? `${t(locale, 'commands.autorole.enabled')}` : `${t(locale, 'commands.autorole.disabled')}`,
inline: true
} }
); );
const row1 = new ActionRowBuilder<ButtonBuilder>().addComponents( const row1 = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder() new ButtonBuilder()
.setCustomId('autorole_toggle') .setCustomId('autorole_toggle')
.setLabel(config?.isEnabled ? t(locale, 'commands.autorole.disabled') : t(locale, 'commands.autorole.enabled')) .setLabel(t(locale, 'commands.autorole.statusLabel'))
.setStyle(config?.isEnabled ? ButtonStyle.Danger : ButtonStyle.Success), .setStyle(config?.isEnabled ? ButtonStyle.Danger : ButtonStyle.Success),
new ButtonBuilder()
.setCustomId('autorole_toggle_bot')
.setLabel(t(locale, 'commands.autorole.botStatusLabel'))
.setStyle(config?.botEnabled ? ButtonStyle.Danger : ButtonStyle.Success)
);
const row2 = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder() new ButtonBuilder()
.setCustomId('autorole_set_user') .setCustomId('autorole_set_user')
.setLabel(t(locale, 'commands.autorole.userRoleLabel')) .setLabel(t(locale, 'commands.autorole.userRoleLabel'))
@ -68,7 +80,7 @@ class AutoRoleCommand extends Command {
.setStyle(ButtonStyle.Primary) .setStyle(ButtonStyle.Primary)
); );
const row2 = new ActionRowBuilder<ButtonBuilder>().addComponents( const row3 = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder() new ButtonBuilder()
.setCustomId('autorole_retroactive') .setCustomId('autorole_retroactive')
.setLabel(t(locale, 'commands.autorole.retroactiveBtn')) .setLabel(t(locale, 'commands.autorole.retroactiveBtn'))
@ -80,40 +92,11 @@ class AutoRoleCommand extends Command {
.setStyle(ButtonStyle.Secondary) .setStyle(ButtonStyle.Secondary)
); );
const response = await interaction.reply({ await interaction.reply({
embeds: [embed], embeds: [embed],
components: [row1, row2], components: [row1, row2, row3],
ephemeral: true, ephemeral: true,
}); });
const collector = response.createMessageComponentCollector({
componentType: ComponentType.Button,
time: 300000, // 5분
});
collector.on('collect', async (i) => {
if (i.customId === 'autorole_toggle') {
const newEnabled = !config?.isEnabled;
await autoRoleService.setEnabled(guild.id, newEnabled);
await i.update({ content: t(locale, 'commands.autorole.updateSuccess'), embeds: [], components: [] });
collector.stop();
} else if (i.customId === 'autorole_set_user' || i.customId === 'autorole_set_bot') {
const isBot = i.customId === 'autorole_set_bot';
const roleSelect = new RoleSelectMenuBuilder()
.setCustomId(`autorole_select_${isBot ? 'bot' : 'user'}`)
.setPlaceholder(isBot ? t(locale, 'commands.autorole.botRoleLabel') : t(locale, 'commands.autorole.userRoleLabel'))
.setMaxValues(1);
const selectRow = new ActionRowBuilder<RoleSelectMenuBuilder>().addComponents(roleSelect);
await i.update({ components: [selectRow] });
} else if (i.customId === 'autorole_retroactive') {
if (!config?.userRoleId) return;
await autoRoleService.applyRetroactively(guild, config.userRoleId, i.user.id);
await i.update({ content: t(locale, 'commands.autorole.retroactiveStarted'), embeds: [], components: [] });
collector.stop();
}
// exclude 등 추가 인터랙션 구현 예정
});
} }
} }

View File

@ -143,6 +143,66 @@ export default {
}, locale); }, locale);
} }
} }
else if (interaction.isButton() && interaction.customId.startsWith('autorole_')) {
const locale = await getInteractionLocale(interaction);
const { autoRoleService } = require('../services/AutoRoleService');
await withErrorHandler(interaction, async () => {
// 타임아웃 방지를 위해 즉시 승인
await interaction.deferUpdate();
const guild = interaction.guild!;
if (interaction.customId === 'autorole_toggle') {
const config = await autoRoleService.getConfig(guild.id);
const newEnabled = !config?.isEnabled;
await autoRoleService.setEnabled(guild.id, newEnabled);
await interaction.editReply({ content: t(locale, 'commands.autorole.updateSuccess'), embeds: [], components: [] });
} else if (interaction.customId === 'autorole_toggle_bot') {
const config = await autoRoleService.getConfig(guild.id);
const newBotEnabled = !config?.botEnabled;
await autoRoleService.updateConfig(guild.id, { botEnabled: newBotEnabled });
await interaction.editReply({ content: t(locale, 'commands.autorole.updateSuccess'), embeds: [], components: [] });
} else if (interaction.customId === 'autorole_retroactive') {
const config = await autoRoleService.getConfig(guild.id);
if (config?.userRoleId) {
await autoRoleService.applyRetroactively(guild, config.userRoleId, interaction.user.id);
await interaction.editReply({ content: t(locale, 'commands.autorole.retroactiveStarted'), embeds: [], components: [] });
}
} else if (interaction.customId === 'autorole_set_user' || interaction.customId === 'autorole_set_bot') {
const isBot = interaction.customId === 'autorole_set_bot';
const { RoleSelectMenuBuilder } = require('discord.js');
const roleSelect = new RoleSelectMenuBuilder()
.setCustomId(`autorole_select_${isBot ? 'bot' : 'user'}`)
.setPlaceholder(isBot ? t(locale, 'commands.autorole.botRoleLabel') : t(locale, 'commands.autorole.userRoleLabel'))
.setMaxValues(1);
const selectRow = new ActionRowBuilder<any>().addComponents(roleSelect);
await interaction.editReply({ components: [selectRow] });
}
// 나머지 버튼 처리
}, locale);
}
else if (interaction.isRoleSelectMenu() && interaction.customId.startsWith('autorole_select_')) {
const locale = await getInteractionLocale(interaction);
const { autoRoleService } = require('../services/AutoRoleService');
await withErrorHandler(interaction, async () => {
// 타임아웃 방지를 위해 즉시 승인
await interaction.deferUpdate();
const guild = interaction.guild!;
const isBot = interaction.customId.includes('bot');
const roleId = interaction.values[0];
await autoRoleService.updateConfig(guild.id, {
[isBot ? 'botRoleId' : 'userRoleId']: roleId
});
await interaction.editReply({
content: t(locale, 'commands.autorole.updateSuccess'),
embeds: [],
components: []
});
}, locale);
}
else if (interaction.isModalSubmit()) { else if (interaction.isModalSubmit()) {
const customId = interaction.customId; const customId = interaction.customId;
if (customId.startsWith('modal_vc_')) { if (customId.startsWith('modal_vc_')) {