diff options
| author | Fuwn <[email protected]> | 2025-11-23 19:12:43 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2025-11-23 19:12:43 -0800 |
| commit | a846ff2547f807a68522b36e447df6990e024aa2 (patch) | |
| tree | 568112ab71d5c2965c18022a9ccc83a4862065cf | |
| parent | feat(gateway:reactionRoles): Add additional handler (diff) | |
| download | umabotdiscord-a846ff2547f807a68522b36e447df6990e024aa2.tar.xz umabotdiscord-a846ff2547f807a68522b36e447df6990e024aa2.zip | |
feat(interactions): Add role slash command
| -rw-r--r-- | packages/interactions/discord/commands/index.ts | 19 | ||||
| -rw-r--r-- | packages/interactions/register.ts | 2 | ||||
| -rw-r--r-- | packages/interactions/server.ts | 153 |
3 files changed, 174 insertions, 0 deletions
diff --git a/packages/interactions/discord/commands/index.ts b/packages/interactions/discord/commands/index.ts index b3d0d84..f5fda7a 100644 --- a/packages/interactions/discord/commands/index.ts +++ b/packages/interactions/discord/commands/index.ts @@ -147,3 +147,22 @@ export const TOGGLE_PRIVILEGED_ACCESS_COMMAND: DiscordCommand = { }, ], }; + +export const ROLE_COMMAND: DiscordCommand = { + name: "role", + description: "Toggle a role for a user", + options: [ + { + type: DISCORD_APPLICATION_COMMAND_OPTION_TYPES.USER, + name: "user", + description: "User to toggle the role for", + required: true, + }, + { + type: DISCORD_APPLICATION_COMMAND_OPTION_TYPES.ROLE, + name: "role", + description: "Role to toggle for the user", + required: true, + }, + ], +}; diff --git a/packages/interactions/register.ts b/packages/interactions/register.ts index d5b0eb6..c864577 100644 --- a/packages/interactions/register.ts +++ b/packages/interactions/register.ts @@ -8,6 +8,7 @@ import { COLOURS_COMMAND, ROLEPLAY_VERIFY_COMMAND, TOGGLE_PRIVILEGED_ACCESS_COMMAND, + ROLE_COMMAND, type DiscordCommand, } from "./discord/commands"; import dotenv from "dotenv"; @@ -38,6 +39,7 @@ const commands: DiscordCommand[] = [ COLOURS_COMMAND, ROLEPLAY_VERIFY_COMMAND, TOGGLE_PRIVILEGED_ACCESS_COMMAND, + ROLE_COMMAND, ]; const response = await fetch(url, { diff --git a/packages/interactions/server.ts b/packages/interactions/server.ts index a6cef92..c840bc1 100644 --- a/packages/interactions/server.ts +++ b/packages/interactions/server.ts @@ -12,6 +12,7 @@ import { COLOURS_COMMAND, ROLEPLAY_VERIFY_COMMAND, TOGGLE_PRIVILEGED_ACCESS_COMMAND, + ROLE_COMMAND, } from "./discord/commands"; import { getCutePost, @@ -49,6 +50,25 @@ const ADMINISTRATOR_ROLE_ID = "1406422617765712094"; const MODERATOR_ROLE_ID = "1406422617765712093"; const TRIAL_MODERATOR_ROLE_ID = "1406422617724026910"; +const ALLOWED_ROLE_IDS: readonly string[] = [ + // MODERATOR_ROLE_ID, + // TRIAL_MODERATOR_ROLE_ID, + // "1436486313770483812", // Probationary Staff + // "1411116123302400010", // Reddit Moderator + "1410993207608873070", // Minecraft Server Staff + "1416917764546756618", // Quote Curator + "1419243376938582057", // Event Planner + "1423510107685261354", // Moderation Team Staging + "1428143899712426084", // Tracen Academy Joint Staff + "1417624486345179187", // Top Buddy of the Month + // "1435764652591022144", // Staff + "1425706904478289928", // Removed from Privileged Access + "1435760220805660713", // Removed from Vent Access + "1423213971422580736", // Privileged Access + "1410333831281643630", // Art & Media NSFW + "1418391675050528879", // Roleplay NSFW +]; + const sendComplaintToChannel = async ( environment: Environment, embed: DiscordEmbed, @@ -823,6 +843,139 @@ router.post("/", async (request: Request, environment: Environment) => { } } + case ROLE_COMMAND.name.toLowerCase(): { + try { + const member = interaction.member; + const hasAdminPermission = + member?.permissions && (parseInt(member.permissions) & 0x8) === 0x8; + + if (!hasAdminPermission) + return new JSONResponse({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: + "❌ You don't have permission to use this command. Only server administrators can use this command.", + flags: 64, + }, + }); + + if (!interaction.guild_id) + return new JSONResponse({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: "❌ This command can only be used in server channels.", + flags: 64, + }, + }); + + const targetUserID = interaction.data.options?.find( + (opt) => opt.name === "user", + )?.value as string; + const targetRoleID = interaction.data.options?.find( + (opt) => opt.name === "role", + )?.value as string; + + if (!targetUserID || !targetRoleID) + return new JSONResponse({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: + "❌ Missing required parameters. Please provide both user and role.", + flags: 64, + }, + }); + + if (!ALLOWED_ROLE_IDS.includes(targetRoleID)) + return new JSONResponse({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: + "❌ This role is not allowed to be added via this command.", + flags: 64, + }, + }); + + const guild = await fetch( + `https://discord.com/api/v10/guilds/${interaction.guild_id}/members/${targetUserID}`, + { + headers: { + Authorization: `Bot ${environment.DISCORD_TOKEN}`, + }, + }, + ); + + if (!guild.ok) + return new JSONResponse({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: + "❌ Unable to fetch user information. The user may not be in this server.", + flags: 64, + }, + }); + + const targetMember = await guild.json(); + const currentRoles = (targetMember.roles || []) as string[]; + const hasRole = currentRoles.includes(targetRoleID); + const newRoles = hasRole + ? currentRoles.filter((roleId: string) => roleId !== targetRoleID) + : [...currentRoles, targetRoleID]; + + const updateResponse = await fetch( + `https://discord.com/api/v10/guilds/${interaction.guild_id}/members/${targetUserID}`, + { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bot ${environment.DISCORD_TOKEN}`, + }, + body: JSON.stringify({ + roles: newRoles, + }), + }, + ); + + if (!updateResponse.ok) { + const errorText = await updateResponse.text(); + + console.error( + "Error updating member roles:", + updateResponse.status, + errorText, + ); + + return new JSONResponse({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: + "❌ Failed to update user roles. The bot may not have sufficient permissions.", + flags: 64, + }, + }); + } + + const action = hasRole ? "removed" : "added"; + + return new JSONResponse({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `✅ Successfully ${action} <@&${targetRoleID}> for <@${targetUserID}>.`, + flags: 64, + }, + }); + } catch (error) { + console.error("Error in role command:", error); + + return new JSONResponse({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: "❌ An error occurred while managing the role.", + flags: 64, + }, + }); + } + } + default: return new JSONResponse({ error: "Unknown Type" }, { status: 400 }); } |