123 lines
3.6 KiB
TypeScript
123 lines
3.6 KiB
TypeScript
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<AuditLog>('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<StringSelectMenuBuilder>().addComponents(
|
|
new StringSelectMenuBuilder()
|
|
.addOptions(
|
|
...opt
|
|
)
|
|
.setMinValues(0)
|
|
.setMaxValues(opt.length)
|
|
.setCustomId(`auditlog-select-events-${i}`)
|
|
)
|
|
);
|
|
|
|
const components = [
|
|
...selectRows,
|
|
new ActionRowBuilder<ButtonBuilder>().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<AuditLog>('auditLogs')
|
|
.where('channel', channel)
|
|
.update({
|
|
eventTypes: types.join(','),
|
|
});
|
|
} else {
|
|
await db<AuditLog>('auditLogs')
|
|
.insert({
|
|
guild: interaction.guildId!,
|
|
channel: channel,
|
|
eventTypes: types.join(','),
|
|
});
|
|
}
|
|
|
|
await buttonInteraction.reply({
|
|
content: 'Audit log successfully created.',
|
|
components: [],
|
|
ephemeral: true,
|
|
});
|
|
}
|
|
} satisfies Command; |