import { SlashCommandBuilder, PermissionFlagsBits, ChannelType, ChatInputCommandInteraction, NewsChannel, TextBasedChannel, CategoryChannel, StageChannel, TextChannel, PrivateThreadChannel, PublicThreadChannel, VoiceChannel, APIInteractionDataResolvedChannel, ForumChannel } from "discord.js"; import getDefaultEmbed, { getFailedEmbed, getSuccessEmbed } from "../tools/defaultEmbeds"; import { database, GuildSetting } from "../data"; import { getGuildSetting } from "../tools/data"; import { getGuildChannel, getChannelPermission } from "../tools/discord"; import { Emoji } from "../tools/design"; const builder = new SlashCommandBuilder(); builder.setName("logchannel"); builder.setDescription("Configures the log channel"); builder.setDMPermission(false); builder.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild); builder.addChannelOption((option) => { option.addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement); option.setName("channel"); option.setDescription("The channel to send notifications to"); option.setRequired(false); return option; }); async function resetNotificationChannel(guildSetting: GuildSetting, interaction: ChatInputCommandInteraction): Promise { const logChannel = guildSetting.notificationChannelID ? await getGuildChannel(guildSetting.id, guildSetting.notificationChannelID) : null; guildSetting.notificationChannelID = null; await database.getRepository(GuildSetting).save(guildSetting); const logEmbed = getDefaultEmbed(); logEmbed.setTitle("Settings changed"); logEmbed.setDescription("Log channel has been disabled"); logEmbed.addFields({ name: "This action was performed by", value: `${interaction.user.tag} (${interaction.user.id})` }); if (logChannel && logChannel.isTextBased()) { logChannel.send({ embeds: [logEmbed] }).catch(() => {}); } const embed = getSuccessEmbed(); embed.setDescription("Log channel has been disabled"); interaction.reply({ embeds: [embed], ephemeral: true }).catch(() => {}); } const execute = async (interaction: ChatInputCommandInteraction) => { if (!interaction.guildId) throw new Error("Command can only be used inside a guild"); const optionVal = interaction.options.getChannel("channel", false); const guildSetting = await getGuildSetting(interaction.guildId); if (!optionVal) return await resetNotificationChannel(guildSetting, interaction); const channel = getTextBasedChannel(optionVal); if (channel.isDMBased()) return; const permissions = await getChannelPermission(channel); if (!permissions || !permissions.has(PermissionFlagsBits.ViewChannel) || !permissions.has(PermissionFlagsBits.SendMessages)) { const embed = getFailedEmbed(); embed.setDescription(`Bot doesn't have permission to view and/or write in channel <#${channel.id}>`); interaction.reply({ embeds: [ embed ], ephemeral: true }).catch(() => {}); return; } if (guildSetting.notificationChannelID) { const oldLogChannel = await getGuildChannel(guildSetting.id, guildSetting.notificationChannelID); const embed = getDefaultEmbed(); embed.setTitle(`${Emoji.SETTINGS} Settings changed`); embed.setDescription(`Log channel has been switched to <#${channel.id}>`); embed.addFields({ name: "This action was performed by", value: `${interaction.user.tag} (${interaction.user.id})` }); if (oldLogChannel && oldLogChannel.isTextBased()) { oldLogChannel.send({ embeds: [embed] }).catch(() => {}); } } guildSetting.notificationChannelID = channel.id; await database.getRepository(GuildSetting).save(guildSetting); const embed = getDefaultEmbed(); embed.setTitle(`${Emoji.SETTINGS} Settings changed`); embed.setDescription("This channel has been set as the log channel"); embed.addFields({ name: "This action was performed by", value: `${interaction.user.tag} (${interaction.user.id})` }); channel.send({ embeds: [embed] }).catch(() => {}); const reply = getSuccessEmbed(); reply.setDescription(`Log channel was set to <#${channel.id}>`); interaction.reply({ embeds: [reply], ephemeral: true }).catch(() => {}); return; } function getTextBasedChannel(channel: CategoryChannel | NewsChannel | StageChannel | TextChannel | PrivateThreadChannel | PublicThreadChannel | VoiceChannel | ForumChannel | APIInteractionDataResolvedChannel): TextBasedChannel { if (channel.type === ChannelType.GuildAnnouncement || channel.type === ChannelType.GuildText || channel.type === ChannelType.PublicThread || channel.type === ChannelType.PrivateThread || channel.type === ChannelType.GuildVoice) { return channel as TextBasedChannel; } throw new TypeError("Channel is not a text based channel"); } export { builder, execute }