Files
AuroraBot-discord/src/modules/user/enrollment.interaction.ts

121 lines
4.7 KiB
TypeScript

import { ButtonInteraction, MessageFlags } from "discord.js";
import { config } from "@/lib/config";
import { createErrorEmbed } from "@/lib/embeds";
import { classService } from "@modules/class/class.service";
import { userService } from "@modules/user/user.service";
import { sendWebhookMessage } from "@/lib/webhookUtils";
export async function handleEnrollmentInteraction(interaction: ButtonInteraction) {
if (!interaction.inCachedGuild()) {
await interaction.reply({ content: "This action can only be performed in a server.", flags: MessageFlags.Ephemeral });
return;
}
const { studentRole, visitorRole } = config;
if (!studentRole || !visitorRole) {
await interaction.reply({
embeds: [createErrorEmbed("No student or visitor role configured for enrollment.", "Configuration Error")],
flags: MessageFlags.Ephemeral
});
return;
}
try {
// 1. Ensure user exists in DB and check current enrollment status
const user = await userService.getOrCreateUser(interaction.user.id, interaction.user.username);
// Check DB enrollment
if (user.class) {
await interaction.reply({
embeds: [createErrorEmbed("You are already enrolled in a class.", "Enrollment Failed")],
flags: MessageFlags.Ephemeral
});
return;
}
const member = interaction.member;
// Check Discord role enrollment (Double safety)
if (member.roles.cache.has(studentRole)) {
await interaction.reply({
embeds: [createErrorEmbed("You already have the student role.", "Enrollment Failed")],
flags: MessageFlags.Ephemeral
});
return;
}
// 2. Get available classes
const allClasses = await classService.getAllClasses();
const validClasses = allClasses.filter(c => c.roleId);
if (validClasses.length === 0) {
await interaction.reply({
embeds: [createErrorEmbed("No classes with specified roles found in database.", "Configuration Error")],
flags: MessageFlags.Ephemeral
});
return;
}
// 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) {
await interaction.reply({
embeds: [createErrorEmbed(`The configured role ID \`${classRoleId}\` for class **${selectedClass.name}** does not exist in this server.`, "Configuration Error")],
flags: MessageFlags.Ephemeral
});
return;
}
// 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({
content: `🎉 You have been successfully enrolled! You received the **${classRole.name}** role.`,
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));
}
}
} catch (error) {
console.error("Enrollment error:", error);
await interaction.reply({
embeds: [createErrorEmbed("An unexpected error occurred during enrollment. Please contact an administrator.", "System Error")],
flags: MessageFlags.Ephemeral
});
}
}