/** * Random channels command - control where spontaneous random posts are allowed */ import { eq } from "drizzle-orm"; import { ChannelType, PermissionFlagsBits, SlashCommandBuilder } from "discord.js"; import type { Command } from "../types"; import { db } from "../../database"; import { botOptions } from "../../database/schema"; function parseChannelIds(raw: string | null | undefined): string[] { if (!raw) { return []; } try { const parsed = JSON.parse(raw); if (!Array.isArray(parsed)) { return []; } return parsed.filter((value): value is string => typeof value === "string"); } catch { return []; } } async function saveChannelIds(guildId: string, channelIds: string[] | null): Promise { const now = new Date().toISOString(); await db .insert(botOptions) .values({ guild_id: guildId, spontaneous_channel_ids: channelIds && channelIds.length > 0 ? JSON.stringify(channelIds) : null, updated_at: now, }) .onConflictDoUpdate({ target: botOptions.guild_id, set: { spontaneous_channel_ids: channelIds && channelIds.length > 0 ? JSON.stringify(channelIds) : null, updated_at: now, }, }); } const command: Command = { data: new SlashCommandBuilder() .setName("random-channels") .setDescription("Control which channels Joel can use for spontaneous random posts") .setDMPermission(false) .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild) .addSubcommand((subcommand) => subcommand .setName("add") .setDescription("Allow random posts in one channel") .addChannelOption((option) => option .setName("channel") .setDescription("Channel to allow for random posts") .addChannelTypes(ChannelType.GuildText) .setRequired(true) ) ) .addSubcommand((subcommand) => subcommand .setName("remove") .setDescription("Remove one channel from random post allowlist") .addChannelOption((option) => option .setName("channel") .setDescription("Channel to remove") .addChannelTypes(ChannelType.GuildText) .setRequired(true) ) ) .addSubcommand((subcommand) => subcommand .setName("clear") .setDescription("Clear allowlist so random posts can use any channel") ) .addSubcommand((subcommand) => subcommand .setName("status") .setDescription("Show current random post channel settings") ) as SlashCommandBuilder, category: "moderation", execute: async (interaction) => { if (!interaction.inGuild()) { await interaction.reply({ content: "This command can only be used in a server.", ephemeral: true }); return; } const guildId = interaction.guildId; const subcommand = interaction.options.getSubcommand(); const existing = await db .select({ spontaneous_channel_ids: botOptions.spontaneous_channel_ids }) .from(botOptions) .where(eq(botOptions.guild_id, guildId)) .limit(1); const currentIds = parseChannelIds(existing[0]?.spontaneous_channel_ids); if (subcommand === "add") { const channel = interaction.options.getChannel("channel", true); if (currentIds.includes(channel.id)) { await interaction.reply({ content: `<#${channel.id}> is already allowed for random posts.`, ephemeral: true, }); return; } const updatedIds = [...currentIds, channel.id]; await saveChannelIds(guildId, updatedIds); await interaction.reply({ content: `✅ Added <#${channel.id}> to Joel's random post channels.`, ephemeral: true, }); return; } if (subcommand === "remove") { const channel = interaction.options.getChannel("channel", true); if (!currentIds.includes(channel.id)) { await interaction.reply({ content: `<#${channel.id}> is not currently in the random post allowlist.`, ephemeral: true, }); return; } const updatedIds = currentIds.filter((channelId) => channelId !== channel.id); await saveChannelIds(guildId, updatedIds.length > 0 ? updatedIds : null); await interaction.reply({ content: `✅ Removed <#${channel.id}> from Joel's random post channels.`, ephemeral: true, }); return; } if (subcommand === "clear") { await saveChannelIds(guildId, null); await interaction.reply({ content: "✅ Random post channel allowlist cleared. Joel can now randomly post in any writable text channel.", ephemeral: true, }); return; } if (currentIds.length === 0) { await interaction.reply({ content: "🌐 No random post channel allowlist is set. Joel can randomly post in any writable text channel.", ephemeral: true, }); return; } const list = currentIds.map((channelId) => `<#${channelId}>`).join(", "); await interaction.reply({ content: `📍 Joel can randomly post in: ${list}`, ephemeral: true, }); }, }; export default command;