fix: fix/archive (#56)

Checklist:

- [x] Suivre les indications de `CONTRIBUTING.md`
- [x] Référence aux tickets (par exemple `Closes #xyz`)

- add scope to commands
- fix issues with #55

Since the commands added with #55 are only for specific guilds, they are now scoped only for thoses guilds

Co-authored-by: Mylloon <kennel.anri@tutanota.com>
Reviewed-on: https://git.kennel.ml/ConfrerieDuKassoulait/Botanique/pulls/56
Co-authored-by: Anri <anri@noreply.git.kennel.ml>
Co-committed-by: Anri <anri@noreply.git.kennel.ml>
This commit is contained in:
Anri 2023-01-17 22:05:38 +01:00 committed by loonatiny
parent e380cb908a
commit 42b4257ac0
9 changed files with 121 additions and 61 deletions

View file

@ -116,6 +116,8 @@ import { getLocale, getLocalizations } from "../../utils/locales";
import { getFilename } from "../../utils/misc"; import { getFilename } from "../../utils/misc";
export default { export default {
scope: () => [],
data: (client: Client) => { data: (client: Client) => {
const filename = getFilename(__filename); const filename = getFilename(__filename);
return new SlashCommandBuilder() return new SlashCommandBuilder()
@ -144,6 +146,13 @@ export default {
}; };
``` ```
Rapidement, cette structure comporte 3 éléments :
- `scope` : une liste de guildId où la commande est disponible, si la liste est
est vide, la commande est disponible partout
- `data` : représente les données envoyées à l'API de Discord
- `interaction` : représente le comportement de la commande
Ce template vous permet de commencé rapidement votre commande car il contient Ce template vous permet de commencé rapidement votre commande car il contient
déjà tout ce qu'il faut pour le support des langues. Pensez bien à ne pas écrire déjà tout ce qu'il faut pour le support des langues. Pensez bien à ne pas écrire
directement vos chaînes de caractères ici mais bien dans directement vos chaînes de caractères ici mais bien dans

8
package-lock.json generated
View file

@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"@discordjs/rest": "^1.1.0", "@discordjs/rest": "^1.1.0",
"@types/sqlite3": "^3.1.8", "@types/sqlite3": "^3.1.8",
"@types/uuid": "^9.0.0",
"discord-api-types": "^0.36.3", "discord-api-types": "^0.36.3",
"discord.js": "^14.3.0", "discord.js": "^14.3.0",
"sqlite3": "^5.0.11", "sqlite3": "^5.0.11",
@ -18,7 +19,6 @@
"uuid": "^9.0.0" "uuid": "^9.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/uuid": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/eslint-plugin": "^5.30.7",
"@typescript-eslint/parser": "^5.30.7", "@typescript-eslint/parser": "^5.30.7",
"dotenv": "^16.0.1", "dotenv": "^16.0.1",
@ -372,8 +372,7 @@
"node_modules/@types/uuid": { "node_modules/@types/uuid": {
"version": "9.0.0", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q=="
"dev": true
}, },
"node_modules/@types/ws": { "node_modules/@types/ws": {
"version": "8.5.4", "version": "8.5.4",
@ -3594,8 +3593,7 @@
"@types/uuid": { "@types/uuid": {
"version": "9.0.0", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q=="
"dev": true
}, },
"@types/ws": { "@types/ws": {
"version": "8.5.4", "version": "8.5.4",

View file

@ -35,15 +35,43 @@ export default async (client: Client) => {
command.data = command.data(client); command.data = command.data(client);
client.commands.list.set(command.data.name, command); client.commands.list.set(command.data.name, command);
return command.data.toJSON(); return command;
}), }),
); );
}), }),
) )
).flat(2); ).flat(2);
// Send commands to Discord // Send guilds commands to Discord
return await rest.put(Routes.applicationCommands(client.user?.id ?? ''), { const scopedCommands = new Map<string, unknown[]>();
body: commands,
// Add commands to guild where the bot is
const allowedGuilds = client.guilds.cache;
// Assign each commands to the guilds
commands.filter((c) => c.scope().length > 0).forEach((c) => {
c.scope().forEach((guild: string) => {
if (allowedGuilds.get(guild) !== undefined) {
const guildCommands = scopedCommands.get(guild);
if (guildCommands === undefined) {
scopedCommands.set(guild, [c.data.toJSON()]);
} else {
guildCommands.push(c.data.toJSON());
scopedCommands.set(guild, guildCommands);
}
}
});
});
scopedCommands
.forEach(async (command, guild) => await rest.put(
Routes.applicationGuildCommands(client.user?.id as string, guild), {
body: command,
}));
// Send global commands to Discord
const globalCommands = commands.filter((c) => c.scope().length == 0);
return await rest.put(Routes.applicationCommands(client.user?.id as string), {
body: globalCommands.map((c) => c.data.toJSON()),
}); });
}; };

View file

@ -1,10 +1,12 @@
import { SlashCommandBuilder } from '@discordjs/builders'; import { SlashCommandBuilder } from '@discordjs/builders';
import { ChannelType, Client, CommandInteraction, EmbedBuilder } from 'discord.js'; import { ChannelType, Client, Colors, CommandInteraction, EmbedBuilder, NonThreadGuildBasedChannel } from 'discord.js';
import '../../modules/string';
import { getLocale, getLocalizations } from '../../utils/locales'; import { getLocale, getLocalizations } from '../../utils/locales';
import { getFilename } from '../../utils/misc'; import { getFilename } from '../../utils/misc';
import '../../modules/string';
export default { export default {
scope: () => ['807244911350906920'],
data: (client: Client) => { data: (client: Client) => {
const filename = getFilename(__filename); const filename = getFilename(__filename);
return new SlashCommandBuilder() return new SlashCommandBuilder()
@ -32,19 +34,19 @@ export default {
interaction: async (interaction: CommandInteraction, client: Client) => { interaction: async (interaction: CommandInteraction, client: Client) => {
const loc = getLocale(client, interaction.locale); const loc = getLocale(client, interaction.locale);
const desired_cat = interaction.options.get(client const desiredCat = interaction.options.get(client
.locales .locales
.get(client.config.default_lang) .get(client.config.default_lang)
?.get(`c_${getFilename(__filename)}_opt1_name`) ?? '')?.value as string; ?.get(`c_${getFilename(__filename)}_opt1_name`) ?? '')?.value as string;
// If a category isn't specified // If a category isn't specified
if (!desired_cat) { if (!desiredCat) {
// Sends a list of commands sorted into categories // Sends a list of commands sorted into categories
return interaction.reply({ return interaction.reply({
embeds: [ embeds: [
new EmbedBuilder() new EmbedBuilder()
.setColor('Blurple') .setColor(Colors.Blurple)
.setTitle(loc.get('c_archive1')) .setTitle(loc.get('c_archive1'))
.setDescription(loc.get('c_archive2')), .setDescription(loc.get('c_archive2')),
], ],
@ -52,58 +54,73 @@ export default {
} }
// If a category is specified // If a category is specified
const clean_cat = ['L1', 'L2', 'L3', 'M1', 'M2']; const cleanCat = ['L1', 'L2', 'L3', 'M1', 'M2'];
const channel = clean_cat.includes(desired_cat); const channel = cleanCat.includes(desiredCat);
if (!channel) { if (!channel) {
// Category doesn't exist or is not included // Category doesn't exist or is not included
return interaction.reply({ return interaction.reply({
content: `${loc.get('c_archive3')} \`${desired_cat}\``, content: `${loc.get('c_archive3')} \`${desiredCat}\``,
ephemeral: true, ephemeral: true,
}); });
} }
// Send information about the command
const allChannel = interaction.guild?.channels.fetch(); const allChannel = interaction.guild?.channels.fetch();
allChannel?.then(channel_guild => { allChannel?.then(async channelGuild => {
const cat_to_archive = channel_guild.filter(chan => chan.type == ChannelType.GuildCategory).filter(chan => chan.name == desired_cat); // Retrieve category to archive
const cat_to_archive_id = cat_to_archive.map(cat => cat.id); const catToArchive = channelGuild
const cat_to_archive_name = cat_to_archive.map(cat => cat.name); .filter(chan => chan?.type == ChannelType.GuildCategory)
.filter(chan => chan?.name == desiredCat);
const cat_archived = channel_guild.filter(chan => chan.type == ChannelType.GuildCategory).filter(chan => chan.name == 'archive - ' + desired_cat); // Create/Retrieve the archive category
const cat_archived_id = cat_archived.map(cat => cat.id); const catArchivedName = 'archive - ' + desiredCat;
const cat_archived_name = cat_archived.map(cat => cat.name); const catArchivedMap = channelGuild
.filter(chan => chan?.type == ChannelType.GuildCategory)
.filter(chan => chan?.name == catArchivedName);
const all_channel_desired = channel_guild.filter(chan => chan.type == 0).filter(chan => chan.parentId == cat_to_archive_id[0]); let catArchived: NonThreadGuildBasedChannel | null | undefined;
if (all_channel_desired.size == 0) { if (catArchivedMap.size > 0) {
catArchived = catArchivedMap.at(0);
} else {
catArchived = await interaction.guild?.channels
.create({ name: catArchivedName, type: ChannelType.GuildCategory });
}
const allChannelDesired = channelGuild
.filter(chan => chan?.type == 0)
.filter(chan => chan?.parentId == catToArchive.map(cat => cat?.id)[0]);
// If no channels in the source category
if (allChannelDesired.size == 0) {
return interaction.reply({ return interaction.reply({
embeds: [ embeds: [
new EmbedBuilder() new EmbedBuilder()
.setColor('Blurple') .setColor(Colors.Blurple)
.setTitle(loc.get('c_archive6')) .setTitle(loc.get('c_archive6'))
.setDescription( .setDescription(
// Loads the description
// according to the user's locals
loc.get('c_archive7') loc.get('c_archive7')
), ),
], ],
}); });
} }
const all_channel_desired_name = all_channel_desired.map(cg_d => cg_d.name);
console.log(all_channel_desired_name);
all_channel_desired.forEach(elem =>
elem.setParent(cat_archived_id[0])
);
const list_cg_moved = all_channel_desired_name.toString().replaceAll(',', '\n'); // Move channels to the archived categoryx
allChannelDesired.forEach(elem => elem?.setParent(catArchived?.id as string));
return interaction.reply({ return interaction.reply({
embeds: [ embeds: [
new EmbedBuilder() new EmbedBuilder()
.setColor('Blurple') .setColor(Colors.Blurple)
.setTitle(loc.get('c_archive4') + cat_to_archive_name + loc.get('c_archive5') + cat_archived_name + '`') .setTitle(loc.get('c_archive4')
+ ' `'
+ catToArchive.map(cat => cat?.name)
+ '` '
+ loc.get('c_archive5')
+ ' `'
+ catArchivedName
+ '`')
.setDescription( .setDescription(
// Loads the description allChannelDesired
// according to the user's locals .map(cgD => cgD?.name).toString().replaceAll(',', '\n')
list_cg_moved
), ),
], ],
}); });

View file

@ -1,11 +1,13 @@
import { SlashCommandBuilder } from '@discordjs/builders'; import { SlashCommandBuilder } from '@discordjs/builders';
import { Locale } from 'discord-api-types/v9'; import { Locale } from 'discord-api-types/v9';
import { Client, ChatInputCommandInteraction, EmbedBuilder } from 'discord.js'; import { Client, ChatInputCommandInteraction, EmbedBuilder, Colors } from 'discord.js';
import { getLocale, getLocalizations } from '../../utils/locales'; import { getLocale, getLocalizations } from '../../utils/locales';
import { getFilename } from '../../utils/misc'; import { getFilename } from '../../utils/misc';
import '../../modules/string'; import '../../modules/string';
export default { export default {
scope: () => [],
data: (client: Client) => { data: (client: Client) => {
const filename = getFilename(__filename); const filename = getFilename(__filename);
return new SlashCommandBuilder() return new SlashCommandBuilder()
@ -46,6 +48,7 @@ export default {
}[] = []; }[] = [];
// Load all the command per categories // Load all the command per categories
// TODO: Check if the command exist in the context (guild)
client.commands.categories.forEach((commands_name, category) => { client.commands.categories.forEach((commands_name, category) => {
const commands = commands_name.reduce((data, command_name) => { const commands = commands_name.reduce((data, command_name) => {
return data + `\`/${command_name}\`, `; return data + `\`/${command_name}\`, `;
@ -60,7 +63,7 @@ export default {
// Sends a list of commands sorted into categories // Sends a list of commands sorted into categories
return interaction.reply({ embeds: [ return interaction.reply({ embeds: [
new EmbedBuilder() new EmbedBuilder()
.setColor('Blurple') .setColor(Colors.Blurple)
.setTitle(loc.get('c_help1')) .setTitle(loc.get('c_help1'))
.setDescription(loc.get('c_help2')) .setDescription(loc.get('c_help2'))
.addFields(fields), .addFields(fields),
@ -68,6 +71,7 @@ export default {
} }
// If a command is specified // If a command is specified
// TODO: Check if the command exist in the context (guild)
const command = client.commands.list.get(desired_command); const command = client.commands.list.get(desired_command);
if (!command) { if (!command) {
// Command don't exist // Command don't exist
@ -80,7 +84,7 @@ export default {
// Send information about the command // Send information about the command
return interaction.reply({ embeds: [ return interaction.reply({ embeds: [
new EmbedBuilder() new EmbedBuilder()
.setColor('Blurple') .setColor(Colors.Blurple)
.setTitle('`/' + command.data.name + '`') .setTitle('`/' + command.data.name + '`')
.setDescription( .setDescription(
// Loads the description // Loads the description

View file

@ -4,6 +4,8 @@ import { getLocale, getLocalizations } from '../../utils/locales';
import { getFilename } from '../../utils/misc'; import { getFilename } from '../../utils/misc';
export default { export default {
scope: () => [],
data: (client: Client) => { data: (client: Client) => {
const filename = getFilename(__filename); const filename = getFilename(__filename);
return new SlashCommandBuilder() return new SlashCommandBuilder()

View file

@ -1,10 +1,12 @@
import { SlashCommandBuilder } from '@discordjs/builders'; import { SlashCommandBuilder } from '@discordjs/builders';
import { ChannelType, Client, CommandInteraction, EmbedBuilder } from 'discord.js'; import { ChannelType, Client, Colors, CommandInteraction, EmbedBuilder } from 'discord.js';
import '../../modules/string';
import { getLocale, getLocalizations } from '../../utils/locales'; import { getLocale, getLocalizations } from '../../utils/locales';
import { getFilename } from '../../utils/misc'; import { getFilename } from '../../utils/misc';
import '../../modules/string';
export default { export default {
scope: () => ['807244911350906920'],
data: (client: Client) => { data: (client: Client) => {
const filename = getFilename(__filename); const filename = getFilename(__filename);
return new SlashCommandBuilder() return new SlashCommandBuilder()
@ -44,7 +46,7 @@ export default {
return interaction.reply({ return interaction.reply({
embeds: [ embeds: [
new EmbedBuilder() new EmbedBuilder()
.setColor('Blurple') .setColor(Colors.Blurple)
.setTitle(loc.get('c_prep1')) .setTitle(loc.get('c_prep1'))
.setDescription(loc.get('c_prep2')), .setDescription(loc.get('c_prep2')),
], ],
@ -52,10 +54,10 @@ export default {
} }
// If a category is specified // If a category is specified
const clean_cat = ['L1', 'L2', 'L3', 'M1', 'M2']; const allowedCategories = ['L1', 'L2', 'L3', 'M1', 'M2'];
const channel = clean_cat.includes(desired_cat); const channel = allowedCategories.includes(desired_cat);
if (!channel) { if (!channel) {
// Category doesn't exist or is not included // Category doesn't exist or is not allowed
return interaction.reply({ return interaction.reply({
content: `${loc.get('c_prep3')} \`${desired_cat}\``, content: `${loc.get('c_prep3')} \`${desired_cat}\``,
ephemeral: true, ephemeral: true,
@ -65,13 +67,13 @@ export default {
// Send information about the command // Send information about the command
const allChannel = interaction.guild?.channels.fetch(); const allChannel = interaction.guild?.channels.fetch();
allChannel?.then(channel_guild => { allChannel?.then(channel_guild => {
const cat_to_prep = channel_guild.filter(chan => chan.type == ChannelType.GuildCategory).filter(chan => chan.name == desired_cat); const cat_to_prep = channel_guild.filter(chan => chan?.type == ChannelType.GuildCategory).filter(chan => chan?.name == desired_cat);
const cat_to_prep_id = cat_to_prep.map(cat => cat.id); const cat_to_prep_id = cat_to_prep.map(cat => cat?.id);
const cat_to_prep_name = cat_to_prep.map(cat => cat.name); const cat_to_prep_name = cat_to_prep.map(cat => cat?.name);
// console.log(cat_to_prep); // console.log(cat_to_prep);
const all_channel_desired = channel_guild.filter(chan => chan.type == 0).filter(chan => chan.parentId == cat_to_prep_id[0]); const all_channel_desired = channel_guild.filter(chan => chan?.type == 0).filter(chan => chan?.parentId == cat_to_prep_id[0]);
const all_channel_desired_name = all_channel_desired.map(c_d => c_d.name); const all_channel_desired_name = all_channel_desired.map(c_d => c_d?.name);
let desc = ''; let desc = '';
@ -93,7 +95,7 @@ export default {
parent: cat_to_prep_id[0], parent: cat_to_prep_id[0],
}); });
desc += info + loc.get('c_prep5') + '\n'; desc += '`' + info + '` ' + loc.get('c_prep5') + '\n';
} }
if (desc == '') { if (desc == '') {
@ -103,11 +105,9 @@ export default {
return interaction.reply({ return interaction.reply({
embeds: [ embeds: [
new EmbedBuilder() new EmbedBuilder()
.setColor('Blurple') .setColor(Colors.Blurple)
.setTitle(loc.get('c_prep4') + cat_to_prep_name) .setTitle(loc.get('c_prep4') + cat_to_prep_name)
.setDescription( .setDescription(
// Loads the description
// according to the user's locals
desc, desc,
), ),
], ],

View file

@ -7,6 +7,8 @@ import { getFilename } from '../../utils/misc';
import { checkOwnershipReminder, deleteReminder, embedListReminders, getReminderInfo, newReminder } from '../../utils/reminder'; import { checkOwnershipReminder, deleteReminder, embedListReminders, getReminderInfo, newReminder } from '../../utils/reminder';
export default { export default {
scope: () => [],
data: (client: Client) => { data: (client: Client) => {
const filename = getFilename(__filename); const filename = getFilename(__filename);
const loc_default = client.locales.get(client.config.default_lang); const loc_default = client.locales.get(client.config.default_lang);

View file

@ -23,8 +23,8 @@
"c_archive1": "Liste des catégories soumis au nettoyage", "c_archive1": "Liste des catégories soumis au nettoyage",
"c_archive2": "`L1`, `L2`, `L3`, `M1`, `M2`", "c_archive2": "`L1`, `L2`, `L3`, `M1`, `M2`",
"c_archive3": "Impossible de trouver/nettoyer le salon :", "c_archive3": "Impossible de trouver/nettoyer le salon :",
"c_archive4": "Listes des Salons archivés de la catégorie `", "c_archive4": "Liste des salons archivés de la catégorie",
"c_archive5": "` vers `", "c_archive5": "vers",
"c_archive6": "Nettoyage", "c_archive6": "Nettoyage",
"c_archive7": "Catégorie déjà nettoyée", "c_archive7": "Catégorie déjà nettoyée",