diff options
| author | Mathias Magnusson <mathias@magnusson.space> | 2025-12-13 01:35:27 +0100 |
|---|---|---|
| committer | Mathias Magnusson <mathias@magnusson.space> | 2025-12-13 01:45:10 +0100 |
| commit | a744bcd5eb06ce6a7bc39c0ef675d22c29c39ba9 (patch) | |
| tree | bac041722e2b788e343f7b5fe617ff082e985968 /commands.ts | |
| parent | af5e4c78b5d67186797c06252401f1bb755fd96d (diff) | |
| download | challe-anka-a744bcd5eb06ce6a7bc39c0ef675d22c29c39ba9.tar.gz | |
add commands to add and remove another person to/from a ctf category
Diffstat (limited to 'commands.ts')
| -rw-r--r-- | commands.ts | 188 |
1 files changed, 137 insertions, 51 deletions
diff --git a/commands.ts b/commands.ts index df78f60..f887cf1 100644 --- a/commands.ts +++ b/commands.ts @@ -2,10 +2,12 @@ import { ActionRowBuilder, ButtonBuilder, ButtonStyle, + CategoryChannel, ChannelType, PermissionFlagsBits, SlashCommandBuilder, SlashCommandStringOption, + SlashCommandUserOption, type ButtonInteraction, type ChatInputCommandInteraction, } from "discord.js"; @@ -27,7 +29,31 @@ export let slashCommands = [ slashCommand: new SlashCommandBuilder() .setName("archive") .setDescription("Make this CTF category read-only for everyone"), - handler: makeCtfCategoryReadonly, + handler: archiveCtf, + }, + { + slashCommand: new SlashCommandBuilder() + .setName("add") + .setDescription("Add a user to this CTF category") + .addUserOption( + new SlashCommandUserOption() + .setName("user") + .setDescription("The user to add") + .setRequired(true) + ), + handler: addToCtf, + }, + { + slashCommand: new SlashCommandBuilder() + .setName("remove") + .setDescription("Remove a user from this CTF category") + .addUserOption( + new SlashCommandUserOption() + .setName("user") + .setDescription("The user to remove") + .setRequired(true) + ), + handler: removeFromCtf, }, ]; @@ -103,7 +129,7 @@ async function newCtf(interaction: ChatInputCommandInteraction) { ); } -async function makeCtfCategoryReadonly(interaction: ChatInputCommandInteraction) { +async function archiveCtf(interaction: ChatInputCommandInteraction) { if (!interaction.guild) { await interaction.reply({ content: "This command can only be used inside a server.", @@ -112,84 +138,102 @@ async function makeCtfCategoryReadonly(interaction: ChatInputCommandInteraction) return; } - if (!interaction.channel || interaction.channel.type !== ChannelType.GuildText - || !["general", "info"].includes(interaction.channel.name) - || !interaction.channel.parentId - ) { + let category = await getCategory(interaction); + + 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)) + ); + + await interaction.reply({ + content: `Updated ${category.name}: @everyone can read, (mostly) no-one can write.`, + flags: "Ephemeral", + }); +} + +async function addToCtf(interaction: ChatInputCommandInteraction) { + if (!interaction.guild) { await interaction.reply({ - content: "This command can only be used in the `general` or `info` channel of a CTF category.", + content: "This command can only be used inside a server.", flags: "Ephemeral", }); return; } - let category = interaction.channel.parentId && await interaction.guild.channels.fetch(interaction.channel.parentId); - if (!category || category.type !== ChannelType.GuildCategory) { + let user = interaction.options.getUser("user", true); + let category = await getCategory(interaction); + + let member = await interaction.guild.members.fetch(interaction.user.id); + let permissions = category.permissionsFor(member); + + if (!permissions?.has(PermissionFlagsBits.ManageChannels)) { await interaction.reply({ - content: "This command can only be used in the `general` or `info` channel of a CTF category.", + content: `You don't have permission to update permissions in ${category.name}.`, 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; + await category.permissionOverwrites.edit(user, { + ViewChannel: true, + SendMessages: true, }); - let infoChannel = categoryChildren.find((channel) => channel?.name === "info"); - let generalChannel = categoryChildren.find((channel) => channel?.name === "general"); - let challsChannel = categoryChildren.find((channel) => channel?.name === "challs"); + await interaction.reply({ + content: `Granted ${user} access to ${category.name}.`, + flags: "Ephemeral", + }); +} - 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."); +async function removeFromCtf(interaction: ChatInputCommandInteraction) { + if (!interaction.guild) { + await interaction.reply({ + content: "This command can only be used inside a server.", + flags: "Ephemeral", + }); 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, - }); + let user = interaction.options.getUser("user", true); + let category = await getCategory(interaction); - await Promise.all( - category.permissionOverwrites.cache - .filter(overwrite => overwrite.id !== everyoneRoleId) - .map(overwrite => category.permissionOverwrites.delete(overwrite.id)) - ); + let member = await interaction.guild.members.fetch(interaction.user.id); + let permissions = category.permissionsFor(member); - for (let channel of [infoChannel, generalChannel, challsChannel]) { - if (channel && "lockPermissions" in channel && typeof channel.lockPermissions === "function") { - await channel.lockPermissions(); - } + if (!permissions?.has(PermissionFlagsBits.ManageChannels)) { + await interaction.reply({ + content: `You don't have permission to update permissions in ${category.name}.`, + flags: "Ephemeral", + }); + return; } - await interaction.editReply( - `Updated ${category.name}: @everyone can read, (mostly) no-one can write.`, - ); + await category.permissionOverwrites.delete(user.id); + + await interaction.reply({ + content: `Removed ${user} from ${category.name}.`, + flags: "Ephemeral", + }); } async function handleJoinCtfButton(interaction: ButtonInteraction, categoryId: string) { if (!interaction.guild) { - await interaction.reply({ + return await interaction.reply({ content: "This button only works inside a server.", flags: "Ephemeral", }); - return; } let categoryChannel = await interaction.guild.channels.fetch(categoryId); @@ -213,3 +257,45 @@ async function handleJoinCtfButton(interaction: ButtonInteraction, categoryId: s }); } +async function getCategory(interaction: ButtonInteraction | ChatInputCommandInteraction): Promise<CategoryChannel> { + let errorMsg = "This command can only be used in the `general` or `info` channel of a CTF category."; + + if (!interaction.guild) { + await interaction.reply({ content: errorMsg, flags: "Ephemeral" }); + throw "done"; + } + + if (!interaction.channel || interaction.channel.type !== ChannelType.GuildText + || !["general", "info"].includes(interaction.channel.name) + || !interaction.channel.parentId + ) { + await interaction.reply({ content: errorMsg, flags: "Ephemeral" }); + throw "done"; + } + + let category = interaction.channel.parentId && await interaction.guild.channels.fetch(interaction.channel.parentId); + if (!category || category.type !== ChannelType.GuildCategory) { + await interaction.reply({ content: errorMsg, flags: "Ephemeral" }); + throw "done"; + } + + let allChannels = await interaction.guild.channels.fetch(); + let categoryChildren = [...allChannels.values()].filter((channel) => { + return channel !== null && "parentId" in channel && channel.parentId === category.id; + }); + + let info = categoryChildren.find((channel) => channel?.name === "info"); + let general = categoryChildren.find((channel) => channel?.name === "general"); + let challs = categoryChildren.find((channel) => channel?.name === "challs"); + + if ( + !info || info.type !== ChannelType.GuildText || + !general || general.type !== ChannelType.GuildText || + !challs || challs.type !== ChannelType.GuildForum + ) { + await interaction.reply({ content: errorMsg, flags: "Ephemeral" }); + throw "done"; + } + + return category; +} |
