import { ButtonInteraction, MessageFlags } from "discord.js"; import { config } from "@shared/lib/config"; import { getEnrollmentSuccessMessage } from "./enrollment.view"; import { classService } from "@shared/modules/class/class.service"; import { userService } from "@shared/modules/user/user.service"; import { UserError } from "@/lib/errors"; import { sendWebhookMessage } from "@/lib/webhookUtils"; export async function handleEnrollmentInteraction(interaction: ButtonInteraction) { if (!interaction.inCachedGuild()) { throw new UserError("This action can only be performed in a server."); } const { studentRole, visitorRole } = config; if (!studentRole || !visitorRole) { throw new UserError("No student or visitor role configured for enrollment."); } // 1. Ensure user exists in DB and check current enrollment status const user = await userService.getOrCreateUser(interaction.user.id, interaction.user.username); if (!user) { throw new UserError("User profiles could not be loaded. Please try again later."); } // Check DB enrollment if (user.class) { throw new UserError("You are already enrolled in a class."); } const member = interaction.member; // Check Discord role enrollment (Double safety) if (member.roles.cache.has(studentRole)) { throw new UserError("You already have the student role."); } // 2. Get available classes const allClasses = await classService.getAllClasses(); const validClasses = allClasses.filter((c: any) => c.roleId); if (validClasses.length === 0) { throw new UserError("No classes with specified roles found in database."); } // 3. Pick random class const selectedClass = validClasses[Math.floor(Math.random() * validClasses.length)]!; const classRoleId = selectedClass.roleId!; // Check if the role exists in the guild const classRole = interaction.guild.roles.cache.get(classRoleId); if (!classRole) { throw new UserError(`The configured role ID \`${classRoleId}\` for class **${selectedClass.name}** does not exist in this server.`); } // 4. Perform Enrollment Actions await member.roles.remove(visitorRole); await member.roles.add(studentRole); await member.roles.add(classRole); // Persist to DB await classService.assignClass(user.id.toString(), selectedClass.id); await interaction.reply({ ...getEnrollmentSuccessMessage(classRole.name), flags: MessageFlags.Ephemeral }); // 5. Send Welcome Message (if configured) if (config.welcomeChannelId) { const welcomeChannel = interaction.guild.channels.cache.get(config.welcomeChannelId); if (welcomeChannel && welcomeChannel.isTextBased()) { const rawMessage = config.welcomeMessage || "Welcome to Aurora, {user}! You have been enrolled as a **{class}**."; const processedMessage = rawMessage .replace(/{user}/g, member.toString()) .replace(/{username}/g, member.user.username) .replace(/{class}/g, selectedClass.name) .replace(/{guild}/g, interaction.guild.name); let payload; try { payload = JSON.parse(processedMessage); } catch { payload = processedMessage; } // Fire and forget webhook sendWebhookMessage(welcomeChannel, payload, interaction.client.user, "New Student Enrollment") .catch((err: any) => console.error("Failed to send welcome message:", err)); } } }