add discossiate command & fixes
This commit is contained in:
parent
d6b3b6830a
commit
80fd2ac842
3 changed files with 77 additions and 16 deletions
55
src/bot.ts
55
src/bot.ts
|
@ -13,6 +13,7 @@ import {
|
||||||
SlashCommandRoleOption,
|
SlashCommandRoleOption,
|
||||||
SlashCommandStringOption,
|
SlashCommandStringOption,
|
||||||
SlashCommandSubcommandBuilder,
|
SlashCommandSubcommandBuilder,
|
||||||
|
SlashCommandUserOption,
|
||||||
} from "npm:discord.js@14.14.1";
|
} from "npm:discord.js@14.14.1";
|
||||||
import { RuleSet } from "./rules.ts";
|
import { RuleSet } from "./rules.ts";
|
||||||
import { channel, log_from, SimpleResult, split_promise, try_ } from "./utils.ts";
|
import { channel, log_from, SimpleResult, split_promise, try_ } from "./utils.ts";
|
||||||
|
@ -35,9 +36,7 @@ export class EpitlsBot {
|
||||||
this.bot.on("interactionCreate", (interaction) => this.handle_interaction(interaction));
|
this.bot.on("interactionCreate", (interaction) => this.handle_interaction(interaction));
|
||||||
this.rest = new REST().setToken(bot_token);
|
this.rest = new REST().setToken(bot_token);
|
||||||
this.rules = rules;
|
this.rules = rules;
|
||||||
this.assoc_channel = channel<
|
this.assoc_channel = channel<Association | Dissociation>();
|
||||||
{ cri_login: string; discord_user_id: string; callback: (success: SimpleResult) => void }
|
|
||||||
>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -116,7 +115,7 @@ export class EpitlsBot {
|
||||||
private async register_commands() {
|
private async register_commands() {
|
||||||
const assoc_cmd = new SlashCommandBuilder()
|
const assoc_cmd = new SlashCommandBuilder()
|
||||||
.setName("associate")
|
.setName("associate")
|
||||||
.setDescription("Associates a cri account to your discord account.")
|
.setDescription("Associes un utilisateur cri avec votre compte discord.")
|
||||||
.addStringOption(
|
.addStringOption(
|
||||||
new SlashCommandStringOption()
|
new SlashCommandStringOption()
|
||||||
.setName("cri_email")
|
.setName("cri_email")
|
||||||
|
@ -124,10 +123,21 @@ export class EpitlsBot {
|
||||||
.setRequired(true),
|
.setRequired(true),
|
||||||
).toJSON();
|
).toJSON();
|
||||||
|
|
||||||
|
const ADMIN_PERMISSIONS = 0x0000000000000008n;
|
||||||
|
const dissoc_cmd = new SlashCommandBuilder()
|
||||||
|
.setName("dissociate")
|
||||||
|
.setDescription("Dissocies un utilisateur cri de votre compte discord.")
|
||||||
|
.setDefaultMemberPermissions(ADMIN_PERMISSIONS)
|
||||||
|
.addUserOption(
|
||||||
|
new SlashCommandUserOption()
|
||||||
|
.setName("user")
|
||||||
|
.setRequired(true),
|
||||||
|
).toJSON();
|
||||||
|
|
||||||
const rule_cmd = new SlashCommandBuilder()
|
const rule_cmd = new SlashCommandBuilder()
|
||||||
.setName("rule")
|
.setName("rule")
|
||||||
.setDescription("Gestion des règles d'associations groupes cri / rôles.")
|
.setDescription("Gestion des règles d'associations groupes cri / rôles.")
|
||||||
.setDefaultMemberPermissions(0x0000000000000008n)
|
.setDefaultMemberPermissions(ADMIN_PERMISSIONS)
|
||||||
.addSubcommand(
|
.addSubcommand(
|
||||||
new SlashCommandSubcommandBuilder()
|
new SlashCommandSubcommandBuilder()
|
||||||
.setName("list")
|
.setName("list")
|
||||||
|
@ -172,7 +182,7 @@ export class EpitlsBot {
|
||||||
for (const guild_id of this.bot.guilds.cache.keys()) {
|
for (const guild_id of this.bot.guilds.cache.keys()) {
|
||||||
await this.rest.put(
|
await this.rest.put(
|
||||||
Routes.applicationGuildCommands(this.bot.application!.id, guild_id),
|
Routes.applicationGuildCommands(this.bot.application!.id, guild_id),
|
||||||
{ body: [assoc_cmd, rule_cmd] },
|
{ body: [assoc_cmd, dissoc_cmd, rule_cmd] },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,6 +190,7 @@ export class EpitlsBot {
|
||||||
private async handle_interaction(interaction: Interaction<CacheType>) {
|
private async handle_interaction(interaction: Interaction<CacheType>) {
|
||||||
if (!interaction.isChatInputCommand()) return;
|
if (!interaction.isChatInputCommand()) return;
|
||||||
if (interaction.commandName === "associate") await this.handle_command_associate(interaction);
|
if (interaction.commandName === "associate") await this.handle_command_associate(interaction);
|
||||||
|
if (interaction.commandName === "dissociate") await this.handle_command_dissociate(interaction);
|
||||||
if (interaction.commandName === "rule") {
|
if (interaction.commandName === "rule") {
|
||||||
const subcommand = interaction.options.getSubcommand();
|
const subcommand = interaction.options.getSubcommand();
|
||||||
if (subcommand === "list") await this.handle_command_rule_list(interaction);
|
if (subcommand === "list") await this.handle_command_rule_list(interaction);
|
||||||
|
@ -198,7 +209,7 @@ export class EpitlsBot {
|
||||||
const discord_user_id = interaction.user.id;
|
const discord_user_id = interaction.user.id;
|
||||||
const { promise, resolver } = split_promise<SimpleResult>();
|
const { promise, resolver } = split_promise<SimpleResult>();
|
||||||
|
|
||||||
this.assoc_channel.send({ cri_login, discord_user_id, callback: resolver });
|
this.assoc_channel.send({ kind: "associate", cri_login, discord_user_id, callback: resolver });
|
||||||
await interaction.reply(message_command_response_assoc_pending(email));
|
await interaction.reply(message_command_response_assoc_pending(email));
|
||||||
log(`Started verification for discord id '${discord_user_id}' with cri login '${cri_login}'.`);
|
log(`Started verification for discord id '${discord_user_id}' with cri login '${cri_login}'.`);
|
||||||
const result = await promise;
|
const result = await promise;
|
||||||
|
@ -206,6 +217,16 @@ export class EpitlsBot {
|
||||||
else interaction.editReply(message_command_response_assoc_error(result));
|
else interaction.editReply(message_command_response_assoc_error(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async handle_command_dissociate(interaction: ChatInputCommandInteraction<CacheType>) {
|
||||||
|
const user = interaction.options.getUser("user");
|
||||||
|
if (user === null) throw new Error("Unreachable.");
|
||||||
|
const discord_user_id = user.id;
|
||||||
|
const { promise, resolver } = split_promise<SimpleResult>();
|
||||||
|
this.assoc_channel.send({ kind: "dissociate", discord_user_id, callback: resolver });
|
||||||
|
await promise;
|
||||||
|
await interaction.reply(message_command_response_dissoc_success());
|
||||||
|
}
|
||||||
|
|
||||||
private async handle_command_rule_list(interaction: ChatInputCommandInteraction<CacheType>) {
|
private async handle_command_rule_list(interaction: ChatInputCommandInteraction<CacheType>) {
|
||||||
const guild_id = interaction.guildId;
|
const guild_id = interaction.guildId;
|
||||||
if (guild_id === null) {
|
if (guild_id === null) {
|
||||||
|
@ -261,6 +282,19 @@ export class EpitlsBot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Association = {
|
||||||
|
kind: "associate";
|
||||||
|
cri_login: string;
|
||||||
|
discord_user_id: string;
|
||||||
|
callback: (success: SimpleResult) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Dissociation = {
|
||||||
|
kind: "dissociate";
|
||||||
|
discord_user_id: string;
|
||||||
|
callback: (success: SimpleResult) => void;
|
||||||
|
};
|
||||||
|
|
||||||
function message_command_response_assoc_pending(email: string) {
|
function message_command_response_assoc_pending(email: string) {
|
||||||
const embed = new EmbedBuilder()
|
const embed = new EmbedBuilder()
|
||||||
.setTitle("`🟡`| Association")
|
.setTitle("`🟡`| Association")
|
||||||
|
@ -328,6 +362,13 @@ function to_comparable(input: string) {
|
||||||
.replace(/\p{Diacritic}/gu, ""); // remotes accents
|
.replace(/\p{Diacritic}/gu, ""); // remotes accents
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function message_command_response_dissoc_success() {
|
||||||
|
const embed = new EmbedBuilder()
|
||||||
|
.setTitle("`✅`| Dissociation")
|
||||||
|
.setDescription("Votre compte Discord a bien été dissocié de votre compte CRI.");
|
||||||
|
return { embeds: [embed] };
|
||||||
|
}
|
||||||
|
|
||||||
function display_rule(rule: GuildRule) {
|
function display_rule(rule: GuildRule) {
|
||||||
if (rule.include_historical) return `- \`${rule.group_id}\` [H] → \`@${rule.role_name}\``;
|
if (rule.include_historical) return `- \`${rule.group_id}\` [H] → \`@${rule.role_name}\``;
|
||||||
else return `- \`${rule.group_id}\` → \`@${rule.role_name}\``;
|
else return `- \`${rule.group_id}\` → \`@${rule.role_name}\``;
|
||||||
|
|
10
src/main.ts
10
src/main.ts
|
@ -61,8 +61,9 @@ class Service {
|
||||||
|
|
||||||
// for all received associations, trigger the association procedure.
|
// for all received associations, trigger the association procedure.
|
||||||
(async () => {
|
(async () => {
|
||||||
for await (const { discord_user_id, cri_login, callback } of this.bot.receive_associations()) {
|
for await (const req of this.bot.receive_associations()) {
|
||||||
this.association_procedure(discord_user_id, cri_login).then(callback);
|
if (req.kind === "associate") this.association_procedure(req.discord_user_id, req.cri_login).then(req.callback);
|
||||||
|
if (req.kind === "dissociate") this.dissociation_procedure(req.discord_user_id).then(req.callback);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -121,6 +122,11 @@ class Service {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async dissociation_procedure(discord_user_id: string): Promise<SimpleResult> {
|
||||||
|
await this.state.remove_user(discord_user_id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// bot.assign_role_to_member("358338548174159873", "871777993922588712", "1202346358867238952");
|
// bot.assign_role_to_member("358338548174159873", "871777993922588712", "1202346358867238952");
|
||||||
|
|
28
src/state.ts
28
src/state.ts
|
@ -1,6 +1,6 @@
|
||||||
import { v1 as uuid } from "https://deno.land/std@0.213.0/uuid/mod.ts";
|
import { v1 as uuid } from "https://deno.land/std@0.213.0/uuid/mod.ts";
|
||||||
|
|
||||||
export type StoredUser = { discord_user_id: string; cri_login: string };
|
export type StoredUser = { discord_user_id: string; cri_login: string; uuid: string };
|
||||||
/**
|
/**
|
||||||
* Wraps the persistent state, containing user associaitons.
|
* Wraps the persistent state, containing user associaitons.
|
||||||
*/
|
*/
|
||||||
|
@ -44,32 +44,46 @@ export class State {
|
||||||
/**
|
/**
|
||||||
* Get the association of a user given its discord user id.
|
* Get the association of a user given its discord user id.
|
||||||
*/
|
*/
|
||||||
public async get_user(discord_user_id: string) {
|
public async get_user_by_discord_id(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;
|
||||||
const { value: stored } = await this.kv.get(["users/", user_uuid as string]);
|
const { value: stored } = await this.kv.get(["users/", user_uuid as string]);
|
||||||
return stored as StoredUser;
|
return stored as StoredUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the association of a user given its cri login.
|
||||||
|
*/
|
||||||
|
public async get_user_by_cri_login(cri_login: string) {
|
||||||
|
const { value: user_uuid } = await this.kv.get(["users_by_cri_login/", cri_login]);
|
||||||
|
if (user_uuid === null) return undefined;
|
||||||
|
const { value: stored } = await this.kv.get(["users/", user_uuid as string]);
|
||||||
|
return stored as StoredUser;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends a new user association.
|
* Appends a new user association.
|
||||||
*/
|
*/
|
||||||
public async set_user(discord_user_id: string, cri_login: string) {
|
public async set_user(discord_user_id: string, cri_login: string) {
|
||||||
|
const old_discord = await this.get_user_by_cri_login(cri_login);
|
||||||
|
if (old_discord !== undefined) await this.remove_user(old_discord.discord_user_id);
|
||||||
await this.remove_user(discord_user_id);
|
await this.remove_user(discord_user_id);
|
||||||
await this.add_user(discord_user_id, cri_login);
|
await this.add_user(discord_user_id, cri_login);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async add_user(discord_user_id: string, cri_login: string) {
|
private async add_user(discord_user_id: string, cri_login: string) {
|
||||||
const user_uuid = uuid.generate() as string;
|
const user_uuid = uuid.generate() as string;
|
||||||
const stored: StoredUser = { discord_user_id, cri_login };
|
const stored: StoredUser = { discord_user_id, cri_login, uuid: user_uuid };
|
||||||
await this.kv.set(["users/", user_uuid], stored);
|
await this.kv.set(["users/", user_uuid], stored);
|
||||||
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);
|
||||||
|
await this.kv.set(["users_by_cri_login/", cri_login], user_uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async remove_user(discord_user_id: string) {
|
public async remove_user(discord_user_id: string) {
|
||||||
const { value: user_uuid } = await this.kv.get(["users_by_discord_id/", discord_user_id]);
|
const user = await this.get_user_by_discord_id(discord_user_id);
|
||||||
if (user_uuid === null) return undefined;
|
if (user === undefined) return;
|
||||||
await this.kv.delete(["users/", user_uuid as string]);
|
await this.kv.delete(["users/", user.uuid]);
|
||||||
await this.kv.delete(["users_by_discord_id/", discord_user_id]);
|
await this.kv.delete(["users_by_discord_id/", discord_user_id]);
|
||||||
|
await this.kv.delete(["users_by_cri_login/", user.cri_login]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue