diff --git a/src/bot.ts b/src/bot.ts index a641adb..af3a38a 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -13,12 +13,12 @@ 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; + private bot; + private token; + private rest; + private assoc_channel; - constructor(bot_token: string) { + public constructor(bot_token: string) { this.token = bot_token; const intents = [GatewayIntentBits.Guilds]; this.bot = new Client({ intents }); @@ -29,7 +29,7 @@ export class EpitlsBot { >(); } - async start() { + public async start() { const { promise, resolver } = split_promise(); this.bot.on("ready", () => resolver()); this.bot.login(this.token); @@ -37,6 +37,23 @@ export class EpitlsBot { await this.register_commands(); } + public 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}'.`); + } + + public async *receive_associations() { + while (true) yield await this.assoc_channel.receive(); + } + + public bot_name() { + return this.bot.user?.displayName; + } + private async register_commands() { const cmd = new SlashCommandBuilder() .setName("associate") @@ -74,19 +91,6 @@ export class EpitlsBot { 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) { diff --git a/src/cri.ts b/src/cri.ts index ec98ab6..de83883 100644 --- a/src/cri.ts +++ b/src/cri.ts @@ -1,12 +1,13 @@ import { z } from "https://deno.land/x/zod@v3.22.4/mod.ts"; export class CriApi { - token; - constructor(token: string) { + private token; + + public constructor(token: string) { this.token = token; } - async groups_of(login: string) { + public async groups_of(login: string) { const response = await fetch(`https://cri.epita.fr/api/v2/users/${login}/`, { headers: { accept: "application/json", @@ -31,7 +32,7 @@ export class CriApi { return Array.from(result.values()); } - async user_exists(login: string) { + public async user_exists(login: string) { const response = await fetch(`https://cri.epita.fr/api/v2/users/${login}/`, { headers: { accept: "application/json", diff --git a/src/main.ts b/src/main.ts index b07657d..2039526 100755 --- a/src/main.ts +++ b/src/main.ts @@ -10,12 +10,12 @@ const log = (...args: unknown[]) => log_from(import.meta.url, ...args); async function main() { const secrets = await read_secrets(root_path() + "/secrets.json"); const rules = await RuleSet.from_file(root_path() + "/rules.json"); - log("Loaded rules for", rules.rules.size, "groups."); + log("Loaded rules for", rules.size(), "roles."); const state = await State.from_dir(root_path() + "/local"); log("Loaded state with", await state.users_count(), "users."); const bot = new EpitlsBot(secrets.discord_bot_token); await bot.start(); - log(`Started bot '${bot.bot.user?.displayName}' .`); + log(`Started bot '${bot.bot_name()}' .`); const cri_api = new CriApi(secrets.cri_token); const service = new Service(state, bot, cri_api, rules); diff --git a/src/rules.ts b/src/rules.ts index 1f5cac0..2a1b0b5 100644 --- a/src/rules.ts +++ b/src/rules.ts @@ -1,12 +1,14 @@ -type SerializedRule = { group_id: string; target_role: TargetRole }; export type TargetRole = { guild_id: string; role_id: string }; +type SerializedRule = { group_id: string; target_role: TargetRole }; + export class RuleSet { - rules; - constructor() { + private rules; + + public constructor() { this.rules = new Map(); } - static async from_file(path: string) { + public static async from_file(path: string) { const result = new RuleSet(); const file_content = await Deno.readTextFile(path); const parsed = JSON.parse(file_content) as SerializedRule[]; @@ -14,6 +16,16 @@ export class RuleSet { return result; } + public roles_for_group(group_id: string) { + return this.rules.get(group_id) ?? []; + } + + public size() { + let result = 0; + for (const roles of this.rules.values()) result += roles.length; + return result; + } + private append_rule(group_id: string, target_role: TargetRole) { let roles = this.rules.get(group_id); if (roles === undefined) { @@ -22,8 +34,4 @@ export class RuleSet { } roles.push(target_role); } - - roles_for_group(group_id: string) { - return this.rules.get(group_id) ?? []; - } } diff --git a/src/state.ts b/src/state.ts index 498b7a8..c8e699b 100644 --- a/src/state.ts +++ b/src/state.ts @@ -43,9 +43,10 @@ export class State { await this.kv.set(["users_by_discord_id/", discord_user_id], user_uuid); } - async remove_user(discord_user_id: string) { + private async remove_user(discord_user_id: string) { const { value: user_uuid } = await this.kv.get(["users_by_discord_id/", discord_user_id]); if (user_uuid === null) return undefined; await this.kv.delete(["users/", user_uuid as string]); + await this.kv.delete(["users_by_discord_id/", discord_user_id]); } }