summaryrefslogtreecommitdiff
path: root/index.ts
diff options
context:
space:
mode:
authorMathias Magnusson <mathias@magnusson.space>2025-12-13 01:08:57 +0100
committerMathias Magnusson <mathias@magnusson.space>2025-12-13 01:35:14 +0100
commitaf5e4c78b5d67186797c06252401f1bb755fd96d (patch)
treef4c96cf689902c98cd02857fa349b9f7ff2d7e14 /index.ts
parent2dd1bfa26f6cc4dd221891b81e93e91c7636516a (diff)
downloadchalle-anka-af5e4c78b5d67186797c06252401f1bb755fd96d.tar.gz
refactor
Diffstat (limited to 'index.ts')
-rw-r--r--index.ts226
1 files changed, 13 insertions, 213 deletions
diff --git a/index.ts b/index.ts
index 6728910..57e7ba9 100644
--- a/index.ts
+++ b/index.ts
@@ -1,21 +1,14 @@
import {
- ActionRowBuilder,
- ButtonBuilder,
- ButtonStyle,
- ChannelType,
Client,
CommandInteraction,
Events,
GatewayIntentBits,
- PermissionFlagsBits,
REST,
Routes,
- SlashCommandBuilder,
- SlashCommandStringOption,
- type ButtonInteraction,
- type ChatInputCommandInteraction,
} from "discord.js";
+import { buttonCommands, slashCommands } from "./commands.ts";
+
function requireEnv(key: string): string {
let value = process.env[key];
if (!value) {
@@ -30,211 +23,11 @@ let guildId = requireEnv("DISCORD_GUILD_ID");
let client = new Client({ intents: [GatewayIntentBits.Guilds] });
-let commands = [
- {
- slashCommand: new SlashCommandBuilder()
- .setName("new")
- .setDescription("Create a new CTF")
- .addStringOption(
- new SlashCommandStringOption()
- .setName("name")
- .setDescription("Name for the new CTF")
- .setRequired(true)
- ),
- handler: newCtf,
- },
- {
- slashCommand: new SlashCommandBuilder()
- .setName("archive")
- .setDescription("Make this CTF category read-only for everyone"),
- handler: makeCtfCategoryReadonly,
- },
-];
-
-let CATEGORY_BUTTON_PREFIX = "ctf-category:";
-
-async function newCtf(interaction: ChatInputCommandInteraction) {
- if (!interaction.guild) {
- await interaction.reply({
- content: "This command can only be used inside a server.",
- flags: "Ephemeral",
- });
- return;
- }
-
- let name = interaction.options.getString("name", true);
- await interaction.deferReply({ flags: "Ephemeral" });
-
- let category = await interaction.guild.channels.create({
- name,
- type: ChannelType.GuildCategory,
- permissionOverwrites: [
- {
- id: interaction.guild.roles.everyone,
- deny: [PermissionFlagsBits.ViewChannel],
- }
- ],
- });
-
- await Promise.all([
- await interaction.guild.channels.create({
- name: "info",
- type: ChannelType.GuildText,
- parent: category.id,
- position: 1,
- }),
- await interaction.guild.channels.create({
- name: "general",
- type: ChannelType.GuildText,
- parent: category.id,
- position: 2,
- }),
- await interaction.guild.channels.create({
- name: "challs",
- type: ChannelType.GuildForum,
- parent: category.id,
- position: 3,
- }),
- ]);
-
- let commandChannel = (interaction.channelId && await interaction.guild.channels.fetch(interaction.channelId));
-
- if (!commandChannel || !commandChannel.isTextBased())
- throw new Error("Wth is this channel?");
-
- await commandChannel.send({
- components: [
- new ActionRowBuilder<ButtonBuilder>().addComponents(
- new ButtonBuilder()
- .setCustomId(`${CATEGORY_BUTTON_PREFIX}${category.id}`)
- .setLabel(`Join ${name}`)
- .setStyle(ButtonStyle.Primary),
- ),
- ],
- });
-
- await interaction.editReply(
- `Created ${category.name}.`,
- );
-}
-
-async function makeCtfCategoryReadonly(interaction: ChatInputCommandInteraction) {
- if (!interaction.guild) {
- await interaction.reply({
- content: "This command can only be used inside a server.",
- flags: "Ephemeral",
- });
- return;
- }
-
- if (!interaction.channel || interaction.channel.type !== ChannelType.GuildText
- || !["general", "info"].includes(interaction.channel.name)
- || !interaction.channel.parentId
- ) {
- await interaction.reply({
- content: "This command can only be used in the `general` or `info` channel of a CTF category.",
- flags: "Ephemeral",
- });
- return;
- }
-
- let category = interaction.channel.parentId && await interaction.guild.channels.fetch(interaction.channel.parentId);
- if (!category || category.type !== ChannelType.GuildCategory) {
- await interaction.reply({
- content: "This command can only be used in the `general` or `info` channel of a CTF category.",
- flags: "Ephemeral",
- });
- return;
- }
-
- await interaction.deferReply({ flags: "Ephemeral" });
-
- let allChannels = await interaction.guild.channels.fetch();
- let categoryChildren = [...allChannels.values()].filter((channel) => {
- return channel !== null && "parentId" in channel && channel.parentId === category.id;
- });
-
- let infoChannel = categoryChildren.find((channel) => channel?.name === "info");
- let generalChannel = categoryChildren.find((channel) => channel?.name === "general");
- let challsChannel = categoryChildren.find((channel) => channel?.name === "challs");
-
- if (
- !infoChannel ||
- !generalChannel ||
- !challsChannel ||
- infoChannel.type !== ChannelType.GuildText ||
- generalChannel.type !== ChannelType.GuildText ||
- challsChannel.type !== ChannelType.GuildForum
- ) {
- await interaction.editReply("This command can only be used in the `general` or `info` channel of a CTF category.");
- return;
- }
-
- let everyoneRoleId = interaction.guild.roles.everyone.id;
-
- await category.permissionOverwrites.edit(everyoneRoleId, {
- ViewChannel: true,
- ReadMessageHistory: true,
- SendMessages: false,
- SendMessagesInThreads: false,
- CreatePublicThreads: false,
- CreatePrivateThreads: false,
- });
-
- await Promise.all(
- category.permissionOverwrites.cache
- .filter(overwrite => overwrite.id !== everyoneRoleId)
- .map(overwrite => category.permissionOverwrites.delete(overwrite.id))
- );
-
- for (let channel of [infoChannel, generalChannel, challsChannel]) {
- if (channel && "lockPermissions" in channel && typeof channel.lockPermissions === "function") {
- await channel.lockPermissions();
- }
- }
-
- await interaction.editReply(
- `Updated ${category.name}: @everyone can read, (mostly) no-one can write.`,
- );
-}
-
-async function handleJoinCtfButton(interaction: ButtonInteraction) {
- if (!interaction.guild) {
- await interaction.reply({
- content: "This button only works inside a server.",
- flags: "Ephemeral",
- });
- return;
- }
-
- let categoryId = interaction.customId.slice(CATEGORY_BUTTON_PREFIX.length);
-
- let categoryChannel = await interaction.guild.channels.fetch(categoryId);
-
- if (!categoryChannel || categoryChannel.type !== ChannelType.GuildCategory) {
- await interaction.reply({
- content: "That category no longer exists.",
- flags: "Ephemeral",
- });
- return;
- }
-
- await categoryChannel.permissionOverwrites.edit(interaction.user.id, {
- ViewChannel: true,
- SendMessages: true,
- });
-
- await interaction.reply({
- content: `Granted you access to ${categoryChannel.name}.`,
- flags: "Ephemeral",
- });
-}
-
let rest = new REST({ version: "10" }).setToken(token);
async function registerSlashCommands() {
await rest.put(Routes.applicationGuildCommands(clientId, guildId), {
- body: commands.map(command => command.slashCommand.toJSON()),
+ body: slashCommands.map(command => command.slashCommand.toJSON()),
});
}
@@ -245,16 +38,23 @@ client.once(Events.ClientReady, (readyClient) => {
client.on(Events.InteractionCreate, async (interaction) => {
try {
if (interaction.isChatInputCommand()) {
- for (let command of commands) {
+ for (let command of slashCommands) {
if (interaction.commandName === command.slashCommand.name) {
await command.handler(interaction);
break;
}
}
- } else if (interaction.isButton() && interaction.customId.startsWith(CATEGORY_BUTTON_PREFIX)) {
- await handleJoinCtfButton(interaction);
+ } else if (interaction.isButton()) {
+ for (let button of Object.values(buttonCommands)) {
+ if (interaction.customId.startsWith(button.prefix)) {
+ let id = interaction.customId.slice(button.prefix.length);
+ await button.handler(interaction, id);
+ break;
+ }
+ }
}
} catch (error) {
+ if (error === "done") return;
if (interaction instanceof CommandInteraction) {
console.error("Error while handling interaction", error);
if (interaction.deferred || interaction.replied) {