summaryrefslogtreecommitdiff
path: root/commands.ts
diff options
context:
space:
mode:
Diffstat (limited to 'commands.ts')
-rw-r--r--commands.ts188
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;
+}