import { CacheType, Client, EmbedBuilder, GatewayIntentBits, Interaction, REST, Routes, SlashCommandBuilder, SlashCommandStringOption, } from "npm:discord.js@14.14.1"; import { channel, log_from, SimpleResult, split_promise } from "./utils.ts"; const log = (...args: unknown[]) => log_from(import.meta.url, ...args); export class EpitlsBot { bot; token; rest; assoc_channel; constructor(bot_token: string) { this.token = bot_token; const intents = [GatewayIntentBits.Guilds]; this.bot = new Client({ intents }); this.bot.on("interactionCreate", (interaction) => this.handle_interaction(interaction)); this.rest = new REST().setToken(bot_token); this.assoc_channel = channel< { cri_login: string; discord_user_id: string; callback: (success: SimpleResult) => void } >(); } async start() { const { promise, resolver } = split_promise(); this.bot.on("ready", () => resolver()); this.bot.login(this.token); await promise; await this.register_commands(); } private async register_commands() { const cmd = new SlashCommandBuilder() .setName("associate") .setDescription("Associates a cri account to your discord account.") .addStringOption( new SlashCommandStringOption() .setName("cri_email") .setDescription("claude.nougaro@epita.fr") .setRequired(true), ).toJSON(); for (const guild_id of this.bot.guilds.cache.keys()) { await this.rest.put( Routes.applicationGuildCommands(this.bot.application!.id, guild_id), { body: [cmd] }, ); } } private async handle_interaction(interaction: Interaction) { if (!interaction.isChatInputCommand()) return; if (interaction.commandName != "associate") return; const email = interaction.options.getString("cri_email")!; if (!email.endsWith("@epita.fr")) { await interaction.reply(message_command_response_error("invalid cri email " + email)); return; } const [cri_login] = email.split("@epita.fr"); const discord_user_id = interaction.user.id; const { promise, resolver } = split_promise(); this.assoc_channel.send({ cri_login, discord_user_id, callback: resolver }); await interaction.reply(message_command_response_sending_email(email)); const result = await promise; if (result === true) interaction.editReply(message_command_response_success()); else interaction.editReply(message_command_response_error(result)); } async assign_role(user_id: string, guild_id: string, role_id: string) { const guild = await this.bot.guilds.fetch(guild_id); const member = await guild.members.fetch({ user: user_id }); const role = await guild.roles.fetch(role_id); if (role === null) return console.error("Role", role_id, "not found in guild", guild_id); member.roles.add(role_id); log(`Assigned role '${role.name}' to user '${member.displayName}'.`); } async *receive_associations() { while (true) yield await this.assoc_channel.receive(); } } function message_command_response_sending_email(email: string) { const embed = new EmbedBuilder() .setTitle("`🟡`| Verification") .setDescription(`Sending a verification link to your email \`${email}\`.`); return { embeds: [embed] }; } function message_command_response_error(msg: string) { const embed = new EmbedBuilder() .setTitle("`❌`| Verification") .setDescription(`An error occured\n\`${msg}\``); return { embeds: [embed] }; } function message_command_response_success() { const embed = new EmbedBuilder() .setTitle("`✅`| Verification") .setDescription("Your email was associated with this account."); return { embeds: [embed] }; }