forked from epita/ruche-manager
move commands to separate module
This commit is contained in:
parent
ba1479acbe
commit
a3178942af
2 changed files with 189 additions and 183 deletions
187
src/bot.ts
187
src/bot.ts
|
@ -1,18 +1,12 @@
|
||||||
#!/bin/env -S deno run -A --unstable-kv
|
#!/bin/env -S deno run -A --unstable-kv
|
||||||
|
|
||||||
import {
|
import { Client } from "npm:discord.js";
|
||||||
AutocompleteInteraction,
|
|
||||||
ChatInputCommandInteraction,
|
|
||||||
Client,
|
|
||||||
EmbedBuilder,
|
|
||||||
SlashCommandBuilder,
|
|
||||||
TextChannel,
|
|
||||||
} from "npm:discord.js";
|
|
||||||
|
|
||||||
import { Storage } from "./lib/storage.ts";
|
import { Storage } from "./lib/storage.ts";
|
||||||
import { _1d, _1min, Channel, channel, collect, days_to_ms, log_from, trimmed } from "./lib/utils.ts";
|
import { channel, log_from } from "./lib/utils.ts";
|
||||||
import { update_loop } from "./lib/board.ts";
|
import { update_loop } from "./lib/board.ts";
|
||||||
import { notification_loop } from "./lib/notification.ts";
|
import { notification_loop } from "./lib/notification.ts";
|
||||||
|
import { declare_commands, handle_autocomplete, handle_command } from "./lib/commands/commands.ts";
|
||||||
|
|
||||||
const log = log_from(import.meta);
|
const log = log_from(import.meta);
|
||||||
|
|
||||||
|
@ -46,7 +40,7 @@ async function main() {
|
||||||
await bot.login(token);
|
await bot.login(token);
|
||||||
log("Logged in as", bot.user?.username);
|
log("Logged in as", bot.user?.username);
|
||||||
|
|
||||||
const commands = build_api_commands(subjects);
|
const commands = declare_commands(subjects);
|
||||||
if (debug_server !== undefined) {
|
if (debug_server !== undefined) {
|
||||||
for (const command of commands) command.setName("dbg-" + command.name);
|
for (const command of commands) command.setName("dbg-" + command.name);
|
||||||
await bot.application?.commands.set(commands, debug_server);
|
await bot.application?.commands.set(commands, debug_server);
|
||||||
|
@ -62,177 +56,4 @@ async function main() {
|
||||||
log("Oki.");
|
log("Oki.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_api_commands(subjects: Set<string>) {
|
|
||||||
const subjects_as_choices = [...subjects.values()].map((name) => ({ name, value: name }));
|
|
||||||
const devoir_command = new SlashCommandBuilder()
|
|
||||||
.setName("devoir")
|
|
||||||
.setDescription("Manipuler les devoirs à effectuer.")
|
|
||||||
.addSubcommand((command) =>
|
|
||||||
command.setName("ajouter")
|
|
||||||
.setDescription("Ajouter un nouveau devoir à effectuer.")
|
|
||||||
.addStringOption((option) =>
|
|
||||||
option.setName("matière")
|
|
||||||
.setDescription("Matière du devoir à effectuer.")
|
|
||||||
.addChoices(...subjects_as_choices)
|
|
||||||
.setRequired(true)
|
|
||||||
)
|
|
||||||
.addNumberOption((option) =>
|
|
||||||
option.setName("jours")
|
|
||||||
.setMinValue(0)
|
|
||||||
.setDescription("Nombre de jours avant la date du rendu.")
|
|
||||||
.setRequired(true)
|
|
||||||
)
|
|
||||||
.addStringOption((option) =>
|
|
||||||
option.setName("description")
|
|
||||||
.setDescription("Description du devoir à effectuer.")
|
|
||||||
.setRequired(true)
|
|
||||||
)
|
|
||||||
).addSubcommand((command) =>
|
|
||||||
command.setName("retirer")
|
|
||||||
.setDescription("Retirer un devoir.")
|
|
||||||
.addStringOption((option) =>
|
|
||||||
option.setName("devoir")
|
|
||||||
.setDescription("Devoir à retirer.")
|
|
||||||
.setAutocomplete(true)
|
|
||||||
.setRequired(true)
|
|
||||||
)
|
|
||||||
).addSubcommand((command) =>
|
|
||||||
command.setName("éditer")
|
|
||||||
.setDescription("Éditer un devoir.")
|
|
||||||
.addStringOption((option) =>
|
|
||||||
option.setName("devoir")
|
|
||||||
.setDescription("Devoir à éditer.")
|
|
||||||
.setAutocomplete(true)
|
|
||||||
.setRequired(true)
|
|
||||||
)
|
|
||||||
.addStringOption((option) =>
|
|
||||||
option.setName("matière")
|
|
||||||
.setDescription("Nouvelle matière.")
|
|
||||||
.addChoices(...subjects_as_choices)
|
|
||||||
.setRequired(false)
|
|
||||||
)
|
|
||||||
.addNumberOption((option) =>
|
|
||||||
option.setName("jours")
|
|
||||||
.setMinValue(0)
|
|
||||||
.setDescription("Nouveau nombre de jours avant la date du rendu.")
|
|
||||||
.setRequired(false)
|
|
||||||
)
|
|
||||||
.addStringOption((option) =>
|
|
||||||
option.setName("description")
|
|
||||||
.setDescription("Nouvelle description.")
|
|
||||||
.setRequired(false)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const adm_command = new SlashCommandBuilder().setName("adm")
|
|
||||||
.setDescription("Commandes d'administration.")
|
|
||||||
.addSubcommand((command) =>
|
|
||||||
command.setName("ajouter-feed")
|
|
||||||
.setDescription("Ajoute un salon comme feed de notifications.")
|
|
||||||
.addChannelOption((option) =>
|
|
||||||
option.setName("salon")
|
|
||||||
.setDescription("Salon du nouveau feed.")
|
|
||||||
.setRequired(true)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return [devoir_command, adm_command];
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handle_command(
|
|
||||||
interaction: ChatInputCommandInteraction,
|
|
||||||
storage: Storage,
|
|
||||||
update_display: Channel,
|
|
||||||
) {
|
|
||||||
log("Received command", interaction.commandName);
|
|
||||||
if (interaction.commandName === "devoir") {
|
|
||||||
const subcommand = interaction.options.getSubcommand(true);
|
|
||||||
if (subcommand === "ajouter") {
|
|
||||||
const subject = interaction.options.getString("matière", true);
|
|
||||||
const days = interaction.options.getNumber("jours", true);
|
|
||||||
const description = interaction.options.getString("description", true);
|
|
||||||
const date = Date.now() + days_to_ms(days);
|
|
||||||
const { id } = await storage.devoirs.add({ date, description, subject });
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle("`🌟` Ajouté")
|
|
||||||
.setDescription(`Nouveau devoir ajouté avec succès.`)
|
|
||||||
.setFooter({ text: `(devoir id:${id})` });
|
|
||||||
await interaction.reply({ embeds: [embed], ephemeral: true });
|
|
||||||
update_display.send();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (subcommand === "retirer") {
|
|
||||||
const id = interaction.options.getString("devoir", true);
|
|
||||||
await storage.devoirs.delete({ id });
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle("`🗑️` Retiré")
|
|
||||||
.setDescription(`Devoir supprimé avec succès.`)
|
|
||||||
.setFooter({ text: `(devoir id:${id})` });
|
|
||||||
await interaction.reply({ embeds: [embed], ephemeral: true });
|
|
||||||
update_display.send();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (subcommand === "éditer") {
|
|
||||||
const id = interaction.options.getString("devoir", true);
|
|
||||||
const subject = interaction.options.getString("matière", false);
|
|
||||||
if (subject !== null) storage.devoirs.update({ id }, (d) => d.subject = subject);
|
|
||||||
const description = interaction.options.getString("description", false);
|
|
||||||
if (description !== null) storage.devoirs.update({ id }, (d) => d.description = description);
|
|
||||||
const days = interaction.options.getNumber("jours", false);
|
|
||||||
if (days !== null) storage.devoirs.update({ id }, (d) => d.date = Date.now() + days_to_ms(days));
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle("`🔧` Édité")
|
|
||||||
.setDescription(`Devoir mis à jour avec succès.`)
|
|
||||||
.setFooter({ text: `(devoir id:${id})` });
|
|
||||||
await interaction.reply({ embeds: [embed], ephemeral: true });
|
|
||||||
update_display.send();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return log("Unknown devoir sub command", subcommand);
|
|
||||||
}
|
|
||||||
if (interaction.commandName === "adm") {
|
|
||||||
const subcommand = interaction.options.getSubcommand(true);
|
|
||||||
if (subcommand === "ajouter-feed") {
|
|
||||||
const channel = interaction.options.getChannel("salon", true);
|
|
||||||
const is_text_channel = channel instanceof TextChannel;
|
|
||||||
if (!is_text_channel) {
|
|
||||||
await interaction.reply("Channel must be text.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const board_message = await channel.send("[board]");
|
|
||||||
const feed_id = await storage.feeds.add({
|
|
||||||
channel_id: channel.id,
|
|
||||||
board_message_id: board_message.id,
|
|
||||||
notification_ids: new Set(),
|
|
||||||
});
|
|
||||||
await interaction.reply("Added feed " + feed_id.id);
|
|
||||||
}
|
|
||||||
return log("Unknown adm sub command", subcommand);
|
|
||||||
}
|
|
||||||
log("Unknown command", interaction.commandName);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handle_autocomplete(interaction: AutocompleteInteraction, storage: Storage) {
|
|
||||||
log("Auto completing.");
|
|
||||||
if (interaction.commandName === "devoir") {
|
|
||||||
const subcommand = interaction.options.getSubcommand(true);
|
|
||||||
if (subcommand === "retirer") {
|
|
||||||
const devoirs = await collect(storage.devoirs.list());
|
|
||||||
const mapped = devoirs.map(([{ id }, value]) => ({
|
|
||||||
name: trimmed(`[${value.subject}] ${value.description}`, 100),
|
|
||||||
value: id,
|
|
||||||
}));
|
|
||||||
return await interaction.respond(mapped);
|
|
||||||
}
|
|
||||||
if (subcommand === "éditer") {
|
|
||||||
const devoirs = await collect(storage.devoirs.list());
|
|
||||||
const mapped = devoirs.map(([{ id }, value]) => ({
|
|
||||||
name: trimmed(`[${value.subject}] ${value.description}`, 100),
|
|
||||||
value: id,
|
|
||||||
}));
|
|
||||||
return await interaction.respond(mapped);
|
|
||||||
}
|
|
||||||
return log("Unknown devoir sub command", subcommand);
|
|
||||||
}
|
|
||||||
log("Unknown command", interaction.commandName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (import.meta.main) await main();
|
if (import.meta.main) await main();
|
||||||
|
|
185
src/lib/commands/commands.ts
Normal file
185
src/lib/commands/commands.ts
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
import {
|
||||||
|
AutocompleteInteraction,
|
||||||
|
ChatInputCommandInteraction,
|
||||||
|
EmbedBuilder,
|
||||||
|
SlashCommandBuilder,
|
||||||
|
TextChannel,
|
||||||
|
} from "npm:discord.js";
|
||||||
|
|
||||||
|
import { Storage } from "../storage.ts";
|
||||||
|
import { _1d, _1min, Channel, collect, days_to_ms, log_from, trimmed } from "../utils.ts";
|
||||||
|
|
||||||
|
const log = log_from(import.meta);
|
||||||
|
|
||||||
|
export function declare_commands(subjects: Set<string>) {
|
||||||
|
const subjects_as_choices = [...subjects.values()].map((name) => ({ name, value: name }));
|
||||||
|
const devoir_command = new SlashCommandBuilder()
|
||||||
|
.setName("devoir")
|
||||||
|
.setDescription("Manipuler les devoirs à effectuer.")
|
||||||
|
.addSubcommand((command) =>
|
||||||
|
command.setName("ajouter")
|
||||||
|
.setDescription("Ajouter un nouveau devoir à effectuer.")
|
||||||
|
.addStringOption((option) =>
|
||||||
|
option.setName("matière")
|
||||||
|
.setDescription("Matière du devoir à effectuer.")
|
||||||
|
.addChoices(...subjects_as_choices)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
.addNumberOption((option) =>
|
||||||
|
option.setName("jours")
|
||||||
|
.setMinValue(0)
|
||||||
|
.setDescription("Nombre de jours avant la date du rendu.")
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
.addStringOption((option) =>
|
||||||
|
option.setName("description")
|
||||||
|
.setDescription("Description du devoir à effectuer.")
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
).addSubcommand((command) =>
|
||||||
|
command.setName("retirer")
|
||||||
|
.setDescription("Retirer un devoir.")
|
||||||
|
.addStringOption((option) =>
|
||||||
|
option.setName("devoir")
|
||||||
|
.setDescription("Devoir à retirer.")
|
||||||
|
.setAutocomplete(true)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
).addSubcommand((command) =>
|
||||||
|
command.setName("éditer")
|
||||||
|
.setDescription("Éditer un devoir.")
|
||||||
|
.addStringOption((option) =>
|
||||||
|
option.setName("devoir")
|
||||||
|
.setDescription("Devoir à éditer.")
|
||||||
|
.setAutocomplete(true)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
.addStringOption((option) =>
|
||||||
|
option.setName("matière")
|
||||||
|
.setDescription("Nouvelle matière.")
|
||||||
|
.addChoices(...subjects_as_choices)
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
.addNumberOption((option) =>
|
||||||
|
option.setName("jours")
|
||||||
|
.setMinValue(0)
|
||||||
|
.setDescription("Nouveau nombre de jours avant la date du rendu.")
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
.addStringOption((option) =>
|
||||||
|
option.setName("description")
|
||||||
|
.setDescription("Nouvelle description.")
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const adm_command = new SlashCommandBuilder().setName("adm")
|
||||||
|
.setDescription("Commandes d'administration.")
|
||||||
|
.addSubcommand((command) =>
|
||||||
|
command.setName("ajouter-feed")
|
||||||
|
.setDescription("Ajoute un salon comme feed de notifications.")
|
||||||
|
.addChannelOption((option) =>
|
||||||
|
option.setName("salon")
|
||||||
|
.setDescription("Salon du nouveau feed.")
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return [devoir_command, adm_command];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function handle_command(
|
||||||
|
interaction: ChatInputCommandInteraction,
|
||||||
|
storage: Storage,
|
||||||
|
update_display: Channel,
|
||||||
|
) {
|
||||||
|
log("Received command", interaction.commandName);
|
||||||
|
if (interaction.commandName === "devoir") {
|
||||||
|
const subcommand = interaction.options.getSubcommand(true);
|
||||||
|
if (subcommand === "ajouter") {
|
||||||
|
const subject = interaction.options.getString("matière", true);
|
||||||
|
const days = interaction.options.getNumber("jours", true);
|
||||||
|
const description = interaction.options.getString("description", true);
|
||||||
|
const date = Date.now() + days_to_ms(days);
|
||||||
|
const { id } = await storage.devoirs.add({ date, description, subject });
|
||||||
|
const embed = new EmbedBuilder()
|
||||||
|
.setTitle("`🌟` Ajouté")
|
||||||
|
.setDescription(`Nouveau devoir ajouté avec succès.`)
|
||||||
|
.setFooter({ text: `(devoir id:${id})` });
|
||||||
|
await interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
update_display.send();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (subcommand === "retirer") {
|
||||||
|
const id = interaction.options.getString("devoir", true);
|
||||||
|
await storage.devoirs.delete({ id });
|
||||||
|
const embed = new EmbedBuilder()
|
||||||
|
.setTitle("`🗑️` Retiré")
|
||||||
|
.setDescription(`Devoir supprimé avec succès.`)
|
||||||
|
.setFooter({ text: `(devoir id:${id})` });
|
||||||
|
await interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
update_display.send();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (subcommand === "éditer") {
|
||||||
|
const id = interaction.options.getString("devoir", true);
|
||||||
|
const subject = interaction.options.getString("matière", false);
|
||||||
|
if (subject !== null) storage.devoirs.update({ id }, (d) => d.subject = subject);
|
||||||
|
const description = interaction.options.getString("description", false);
|
||||||
|
if (description !== null) storage.devoirs.update({ id }, (d) => d.description = description);
|
||||||
|
const days = interaction.options.getNumber("jours", false);
|
||||||
|
if (days !== null) storage.devoirs.update({ id }, (d) => d.date = Date.now() + days_to_ms(days));
|
||||||
|
const embed = new EmbedBuilder()
|
||||||
|
.setTitle("`🔧` Édité")
|
||||||
|
.setDescription(`Devoir mis à jour avec succès.`)
|
||||||
|
.setFooter({ text: `(devoir id:${id})` });
|
||||||
|
await interaction.reply({ embeds: [embed], ephemeral: true });
|
||||||
|
update_display.send();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return log("Unknown devoir sub command", subcommand);
|
||||||
|
}
|
||||||
|
if (interaction.commandName === "adm") {
|
||||||
|
const subcommand = interaction.options.getSubcommand(true);
|
||||||
|
if (subcommand === "ajouter-feed") {
|
||||||
|
const channel = interaction.options.getChannel("salon", true);
|
||||||
|
const is_text_channel = channel instanceof TextChannel;
|
||||||
|
if (!is_text_channel) {
|
||||||
|
await interaction.reply("Channel must be text.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const board_message = await channel.send("[board]");
|
||||||
|
const feed_id = await storage.feeds.add({
|
||||||
|
channel_id: channel.id,
|
||||||
|
board_message_id: board_message.id,
|
||||||
|
notification_ids: new Set(),
|
||||||
|
});
|
||||||
|
await interaction.reply("Added feed " + feed_id.id);
|
||||||
|
}
|
||||||
|
return log("Unknown adm sub command", subcommand);
|
||||||
|
}
|
||||||
|
log("Unknown command", interaction.commandName);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function handle_autocomplete(interaction: AutocompleteInteraction, storage: Storage) {
|
||||||
|
log("Auto completing.");
|
||||||
|
if (interaction.commandName === "devoir") {
|
||||||
|
const subcommand = interaction.options.getSubcommand(true);
|
||||||
|
if (subcommand === "retirer") {
|
||||||
|
const devoirs = await collect(storage.devoirs.list());
|
||||||
|
const mapped = devoirs.map(([{ id }, value]) => ({
|
||||||
|
name: trimmed(`[${value.subject}] ${value.description}`, 100),
|
||||||
|
value: id,
|
||||||
|
}));
|
||||||
|
return await interaction.respond(mapped);
|
||||||
|
}
|
||||||
|
if (subcommand === "éditer") {
|
||||||
|
const devoirs = await collect(storage.devoirs.list());
|
||||||
|
const mapped = devoirs.map(([{ id }, value]) => ({
|
||||||
|
name: trimmed(`[${value.subject}] ${value.description}`, 100),
|
||||||
|
value: id,
|
||||||
|
}));
|
||||||
|
return await interaction.respond(mapped);
|
||||||
|
}
|
||||||
|
return log("Unknown devoir sub command", subcommand);
|
||||||
|
}
|
||||||
|
log("Unknown command", interaction.commandName);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue