summaryrefslogtreecommitdiff
path: root/packages/interactions
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-10-01 20:32:10 -0700
committerFuwn <[email protected]>2025-10-01 20:32:10 -0700
commitd5276c2368820bff20cbdda46abdd66d3041ae1a (patch)
tree20836da068d04e44b8129668d7a47251cf007b94 /packages/interactions
parentrefactor(listeners): Move clientReady listeners to clientReady module (diff)
downloadumabotdiscord-d5276c2368820bff20cbdda46abdd66d3041ae1a.tar.xz
umabotdiscord-d5276c2368820bff20cbdda46abdd66d3041ae1a.zip
feat(interactions): Add age-verify command
Diffstat (limited to 'packages/interactions')
-rw-r--r--packages/interactions/discord/commands/index.ts50
-rw-r--r--packages/interactions/register.ts2
-rw-r--r--packages/interactions/server.ts154
3 files changed, 206 insertions, 0 deletions
diff --git a/packages/interactions/discord/commands/index.ts b/packages/interactions/discord/commands/index.ts
index b4c6721..a69e786 100644
--- a/packages/interactions/discord/commands/index.ts
+++ b/packages/interactions/discord/commands/index.ts
@@ -124,3 +124,53 @@ export const ROLEPLAY_VERIFY_COMMAND: DiscordCommand = {
},
],
};
+
+export const AGE_VERIFY_COMMAND: DiscordCommand = {
+ name: "age-verify",
+ description:
+ "Manage the verified age role (Staff only)",
+ options: [
+ {
+ type: 3,
+ name: "action",
+ description: "Action to perform on the role",
+ required: true,
+ choices: [
+ {
+ name: "Add Role",
+ value: "add",
+ },
+ {
+ name: "Remove Role",
+ value: "remove",
+ },
+ {
+ name: "Toggle Role",
+ value: "toggle",
+ },
+ ],
+ },
+ {
+ type: 6,
+ name: "user",
+ description: "User to perform the action on",
+ required: true,
+ },
+ {
+ type: 3,
+ name: "access",
+ description: "Type of access to grant",
+ required: true,
+ choices: [
+ {
+ name: "Art & Media",
+ value: "art_media",
+ },
+ {
+ name: "Roleplay NSFW",
+ value: "roleplay_nsfw",
+ },
+ ],
+ },
+ ],
+};
diff --git a/packages/interactions/register.ts b/packages/interactions/register.ts
index 9ba9d90..00f4f9b 100644
--- a/packages/interactions/register.ts
+++ b/packages/interactions/register.ts
@@ -7,6 +7,7 @@ import {
APPEAL_COMMAND,
COLOURS_COMMAND,
ROLEPLAY_VERIFY_COMMAND,
+ AGE_VERIFY_COMMAND,
type DiscordCommand,
} from "./discord/commands";
import dotenv from "dotenv";
@@ -36,6 +37,7 @@ const commands: DiscordCommand[] = [
APPEAL_COMMAND,
COLOURS_COMMAND,
ROLEPLAY_VERIFY_COMMAND,
+ AGE_VERIFY_COMMAND,
];
const response = await fetch(url, {
diff --git a/packages/interactions/server.ts b/packages/interactions/server.ts
index 8c8d3db..3a9651e 100644
--- a/packages/interactions/server.ts
+++ b/packages/interactions/server.ts
@@ -9,6 +9,7 @@ import {
APPEAL_COMMAND,
COLOURS_COMMAND,
ROLEPLAY_VERIFY_COMMAND,
+ AGE_VERIFY_COMMAND,
} from "./discord/commands";
import {
getCutePost,
@@ -33,6 +34,12 @@ const COMPLAINT_CHANNEL_ID = "1415868433714778204";
const APPEAL_CHANNEL_ID = "1420340807931531385";
const VERIFIED_ROLEPLAY_ROLE_ID = "1418311833303122021";
const ROLE_MANAGER_ROLE_ID = "1410993207608873070";
+const ART_MEDIA_ROLE_ID = "1410333831281643630";
+const ROLEPLAY_NSFW_ROLE_ID = "1418391675050528879";
+const OWNER_ROLE_ID = "1406422617765712095";
+const ADMINISTRATOR_ROLE_ID = "1406422617765712094";
+const MODERATOR_ROLE_ID = "1406422617765712093";
+const TRIAL_MODERATOR_ROLE_ID = "1406422617724026910";
const sendComplaintToChannel = async (
environment: Environment,
@@ -692,6 +699,153 @@ router.post("/", async (request: Request, environment: Environment) => {
}
}
+ case AGE_VERIFY_COMMAND.name.toLowerCase(): {
+ try {
+ const member = interaction.member;
+ const hasAdminPermission =
+ member?.permissions && (parseInt(member.permissions) & 0x8) === 0x8;
+ const hasOwnerRole = member?.roles?.includes(OWNER_ROLE_ID);
+ const hasAdministratorRole = member?.roles?.includes(ADMINISTRATOR_ROLE_ID);
+ const hasModeratorRole = member?.roles?.includes(MODERATOR_ROLE_ID);
+ const hasTrialModeratorRole = member?.roles?.includes(TRIAL_MODERATOR_ROLE_ID);
+
+ if (!hasAdminPermission && !hasOwnerRole && !hasAdministratorRole && !hasModeratorRole && !hasTrialModeratorRole)
+ return new JSONResponse({
+ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
+ data: {
+ content:
+ "❌ You don't have permission to use this command. Only administrators and moderators can use this command.",
+ flags: 64,
+ },
+ });
+
+ const action = interaction.data.options?.[0]?.value as string;
+ const targetUserID = interaction.data.options?.[1]?.value as string;
+ const access = interaction.data.options?.[2]?.value as string;
+
+ if (!action || !targetUserID || !access)
+ return new JSONResponse({
+ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
+ data: {
+ content:
+ "❌ Missing required parameters. Please provide action, user, and access type.",
+ flags: 64,
+ },
+ });
+
+ const guild = await fetch(
+ `https://discord.com/api/v10/guilds/${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 || [];
+ const targetRoleId = access === "art_media" ? ART_MEDIA_ROLE_ID : ROLEPLAY_NSFW_ROLE_ID;
+ const hasRole = currentRoles.includes(targetRoleId);
+ let actionTaken = "";
+ let newRoles = [...currentRoles];
+
+ if (action === "add") {
+ if (hasRole)
+ return new JSONResponse({
+ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
+ data: {
+ content: `❌ <@${targetUserID}> already has the ${access === "art_media" ? "Art & Media" : "Roleplay NSFW"} role.`,
+ flags: 64,
+ },
+ });
+
+ newRoles.push(targetRoleId);
+
+ actionTaken = "added";
+ } else if (action === "remove") {
+ if (!hasRole)
+ return new JSONResponse({
+ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
+ data: {
+ content: `❌ <@${targetUserID}> doesn't have the ${access === "art_media" ? "Art & Media" : "Roleplay NSFW"} role.`,
+ flags: 64,
+ },
+ });
+
+ newRoles = newRoles.filter((roleId) => roleId !== targetRoleId);
+ actionTaken = "removed";
+ } else if (action === "toggle") {
+ if (hasRole) {
+ newRoles = newRoles.filter((roleId) => roleId !== targetRoleId);
+ actionTaken = "removed";
+ } else {
+ newRoles.push(targetRoleId);
+
+ actionTaken = "added";
+ }
+ }
+
+ const updateResponse = await fetch(
+ `https://discord.com/api/v10/guilds/${GUILD_ID}/members/${targetUserID}`,
+ {
+ method: "PATCH",
+ headers: {
+ Authorization: `Bot ${environment.DISCORD_TOKEN}`,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ roles: newRoles,
+ }),
+ },
+ );
+
+ if (!updateResponse.ok) {
+ console.error(
+ "Failed to update user roles:",
+ await updateResponse.text(),
+ );
+
+ 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 accessTypeName = access === "art_media" ? "Art & Media" : "Roleplay NSFW";
+
+ return new JSONResponse({
+ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
+ data: {
+ content: `✅ Successfully ${actionTaken} the ${accessTypeName} role for <@${targetUserID}>.`,
+ },
+ });
+ } catch (error) {
+ console.error("Error in age-verify 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 });
}