174 lines
5.1 KiB
TypeScript
174 lines
5.1 KiB
TypeScript
/**
|
|
* 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<void> {
|
|
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;
|