import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, ComponentType, SlashCommandBuilder, StringSelectMenuBuilder } from 'discord.js'; import { Command } from '../types/index'; import { AuditLog, db } from '../lib/db'; import { EventType } from '../lib/events'; import { chunks } from '../lib/util'; export default { data: new SlashCommandBuilder() .setName('auditlog') .setDescription('[ADMIN] Set up an audit logger, or edit an existing one') .setDefaultMemberPermissions('0'), execute: async (interaction: CommandInteraction) => { if (!interaction.isChatInputCommand()) return; const channel = interaction.channelId; if (!channel) return; const log = await db('auditLogs') .select('eventTypes') .where('channel', channel) .first(); let types = log ? log.eventTypes.split(',') : []; const options = Object.values(EventType) .map(event => ({ label: event, value: event, })); const chunked = [...chunks(options, 25)]; const selectRows = chunked.map( (opt, i) => new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() .addOptions( ...opt ) .setMinValues(0) .setMaxValues(opt.length) .setCustomId(`auditlog-select-events-${i}`) ) ); const components = [ ...selectRows, new ActionRowBuilder().addComponents( new ButtonBuilder() .setCustomId('auditlog-select-events-done') .setLabel('Done') .setStyle(ButtonStyle.Primary) .setDisabled(true) ), ]; const formatContent = () => `${log ? `Editing audit log in <#${channel}>` : `Creating audit log in <#${channel}>`}\n` + 'Select the types of events to be reported on' + ((types.length > 0) ? `\n**Current events**: ${types.map(s => '`' + s + '`').join(', ')}` : ''); const msg = await interaction.reply({ ephemeral: true, content: formatContent(), components, }); const selectCollector = msg.createMessageComponentCollector({ componentType: ComponentType.StringSelect, time: 60_000 * 5, }); selectCollector.on('collect', async selectInteraction => { const possibleTypes = selectInteraction.component.options.map(opt => opt.value); const selectedTypes = selectInteraction.values; types = types.filter(t => !possibleTypes.includes(t)); types = [...types, ...selectedTypes]; components[components.length - 1].components[0].setDisabled(types.length === 0); await selectInteraction.reply({ content: 'Hit "Done" when finished', ephemeral: true, }); await msg.edit({ content: formatContent(), components, }); }); selectCollector.on('end', async () => { await msg.edit({ content: formatContent(), components: [], }); }); const buttonInteraction = await msg.awaitMessageComponent({ componentType: ComponentType.Button, time: 60_000 * 5 }); selectCollector.stop(); if (log) { await db('auditLogs') .where('channel', channel) .update({ eventTypes: types.join(','), }); } else { await db('auditLogs') .insert({ guild: interaction.guildId!, channel: channel, eventTypes: types.join(','), }); } await buttonInteraction.reply({ content: 'Audit log successfully created.', components: [], ephemeral: true, }); } } satisfies Command;