add API constraints
This commit is contained in:
parent
431c184690
commit
fe34c8a91c
5 changed files with 48 additions and 34 deletions
42
src/bot.ts
42
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);
|
const log = (...args: unknown[]) => log_from(import.meta.url, ...args);
|
||||||
|
|
||||||
export class EpitlsBot {
|
export class EpitlsBot {
|
||||||
bot;
|
private bot;
|
||||||
token;
|
private token;
|
||||||
rest;
|
private rest;
|
||||||
assoc_channel;
|
private assoc_channel;
|
||||||
|
|
||||||
constructor(bot_token: string) {
|
public constructor(bot_token: string) {
|
||||||
this.token = bot_token;
|
this.token = bot_token;
|
||||||
const intents = [GatewayIntentBits.Guilds];
|
const intents = [GatewayIntentBits.Guilds];
|
||||||
this.bot = new Client({ intents });
|
this.bot = new Client({ intents });
|
||||||
|
@ -29,7 +29,7 @@ export class EpitlsBot {
|
||||||
>();
|
>();
|
||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
public async start() {
|
||||||
const { promise, resolver } = split_promise<void>();
|
const { promise, resolver } = split_promise<void>();
|
||||||
this.bot.on("ready", () => resolver());
|
this.bot.on("ready", () => resolver());
|
||||||
this.bot.login(this.token);
|
this.bot.login(this.token);
|
||||||
|
@ -37,6 +37,23 @@ export class EpitlsBot {
|
||||||
await this.register_commands();
|
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() {
|
private async register_commands() {
|
||||||
const cmd = new SlashCommandBuilder()
|
const cmd = new SlashCommandBuilder()
|
||||||
.setName("associate")
|
.setName("associate")
|
||||||
|
@ -74,19 +91,6 @@ export class EpitlsBot {
|
||||||
if (result === true) interaction.editReply(message_command_response_success());
|
if (result === true) interaction.editReply(message_command_response_success());
|
||||||
else interaction.editReply(message_command_response_error(result));
|
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) {
|
function message_command_response_sending_email(email: string) {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { z } from "https://deno.land/x/zod@v3.22.4/mod.ts";
|
import { z } from "https://deno.land/x/zod@v3.22.4/mod.ts";
|
||||||
|
|
||||||
export class CriApi {
|
export class CriApi {
|
||||||
token;
|
private token;
|
||||||
constructor(token: string) {
|
|
||||||
|
public constructor(token: string) {
|
||||||
this.token = token;
|
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}/`, {
|
const response = await fetch(`https://cri.epita.fr/api/v2/users/${login}/`, {
|
||||||
headers: {
|
headers: {
|
||||||
accept: "application/json",
|
accept: "application/json",
|
||||||
|
@ -31,7 +32,7 @@ export class CriApi {
|
||||||
return Array.from(result.values());
|
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}/`, {
|
const response = await fetch(`https://cri.epita.fr/api/v2/users/${login}/`, {
|
||||||
headers: {
|
headers: {
|
||||||
accept: "application/json",
|
accept: "application/json",
|
||||||
|
|
|
@ -10,12 +10,12 @@ const log = (...args: unknown[]) => log_from(import.meta.url, ...args);
|
||||||
async function main() {
|
async function main() {
|
||||||
const secrets = await read_secrets(root_path() + "/secrets.json");
|
const secrets = await read_secrets(root_path() + "/secrets.json");
|
||||||
const rules = await RuleSet.from_file(root_path() + "/rules.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");
|
const state = await State.from_dir(root_path() + "/local");
|
||||||
log("Loaded state with", await state.users_count(), "users.");
|
log("Loaded state with", await state.users_count(), "users.");
|
||||||
const bot = new EpitlsBot(secrets.discord_bot_token);
|
const bot = new EpitlsBot(secrets.discord_bot_token);
|
||||||
await bot.start();
|
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 cri_api = new CriApi(secrets.cri_token);
|
||||||
|
|
||||||
const service = new Service(state, bot, cri_api, rules);
|
const service = new Service(state, bot, cri_api, rules);
|
||||||
|
|
24
src/rules.ts
24
src/rules.ts
|
@ -1,12 +1,14 @@
|
||||||
type SerializedRule = { group_id: string; target_role: TargetRole };
|
|
||||||
export type TargetRole = { guild_id: string; role_id: string };
|
export type TargetRole = { guild_id: string; role_id: string };
|
||||||
|
type SerializedRule = { group_id: string; target_role: TargetRole };
|
||||||
|
|
||||||
export class RuleSet {
|
export class RuleSet {
|
||||||
rules;
|
private rules;
|
||||||
constructor() {
|
|
||||||
|
public constructor() {
|
||||||
this.rules = new Map<string, TargetRole[]>();
|
this.rules = new Map<string, TargetRole[]>();
|
||||||
}
|
}
|
||||||
|
|
||||||
static async from_file(path: string) {
|
public static async from_file(path: string) {
|
||||||
const result = new RuleSet();
|
const result = new RuleSet();
|
||||||
const file_content = await Deno.readTextFile(path);
|
const file_content = await Deno.readTextFile(path);
|
||||||
const parsed = JSON.parse(file_content) as SerializedRule[];
|
const parsed = JSON.parse(file_content) as SerializedRule[];
|
||||||
|
@ -14,6 +16,16 @@ export class RuleSet {
|
||||||
return result;
|
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) {
|
private append_rule(group_id: string, target_role: TargetRole) {
|
||||||
let roles = this.rules.get(group_id);
|
let roles = this.rules.get(group_id);
|
||||||
if (roles === undefined) {
|
if (roles === undefined) {
|
||||||
|
@ -22,8 +34,4 @@ export class RuleSet {
|
||||||
}
|
}
|
||||||
roles.push(target_role);
|
roles.push(target_role);
|
||||||
}
|
}
|
||||||
|
|
||||||
roles_for_group(group_id: string) {
|
|
||||||
return this.rules.get(group_id) ?? [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,10 @@ export class State {
|
||||||
await this.kv.set(["users_by_discord_id/", discord_user_id], user_uuid);
|
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]);
|
const { value: user_uuid } = await this.kv.get(["users_by_discord_id/", discord_user_id]);
|
||||||
if (user_uuid === null) return undefined;
|
if (user_uuid === null) return undefined;
|
||||||
await this.kv.delete(["users/", user_uuid as string]);
|
await this.kv.delete(["users/", user_uuid as string]);
|
||||||
|
await this.kv.delete(["users_by_discord_id/", discord_user_id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue