diff --git a/.eslintrc.json b/.eslintrc.json
index 10787ca..5d752e9 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,54 +1,43 @@
{
-
- "extends": [
- "eslint:recommended",
- "plugin:@typescript-eslint/recommended"
- ],
- "parser": "@typescript-eslint/parser",
- "parserOptions": {
- "project": ["./tsconfig.json"]
- },
- "plugins": [
- "@typescript-eslint"
- ],
- "rules": {
- "arrow-spacing": ["warn", { "before": true, "after": true }],
- "brace-style": ["error"],
- "comma-dangle": ["error", "always-multiline"],
- "comma-spacing": "error",
- "comma-style": "error",
- "curly": ["error", "multi-line", "consistent"],
- "dot-location": ["error", "property"],
- "handle-callback-err": "off",
- "indent": ["error", "tab", { "SwitchCase": 1 }],
- "keyword-spacing": "error",
- "max-nested-callbacks": ["error", { "max": 4 }],
- "max-statements-per-line": ["error", { "max": 2 }],
- "no-console": "off",
- "no-empty-function": "error",
- "no-floating-decimal": "error",
- "no-inline-comments": "error",
- "no-lonely-if": "error",
- "no-multi-spaces": "error",
- "no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }],
- "no-shadow": "off",
- "@typescript-eslint/no-shadow": ["error", { "allow": ["err", "resolve", "reject"] }],
- "no-trailing-spaces": ["error"],
- "no-var": "error",
- "object-curly-spacing": ["error", "always"],
- "prefer-const": "error",
- "quotes": ["error", "single"],
- "semi": ["error", "always"],
- "space-before-blocks": "error",
- "space-before-function-paren": ["error", {
- "anonymous": "never",
- "named": "never",
- "asyncArrow": "always"
- }],
- "space-in-parens": "error",
- "space-infix-ops": "error",
- "space-unary-ops": "error",
- "spaced-comment": "error",
- "yoda": "error"
- }
+ "extends": [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "prettier"
+ ],
+ "parser": "@typescript-eslint/parser",
+ "parserOptions": {
+ "project": ["./tsconfig.json"]
+ },
+ "plugins": ["@typescript-eslint"],
+ "rules": {
+ "arrow-spacing": ["warn", { "before": true, "after": true }],
+ "comma-style": "error",
+ "curly": ["error", "multi-line", "consistent"],
+ "dot-location": ["error", "property"],
+ "handle-callback-err": "off",
+ "max-nested-callbacks": ["error", { "max": 4 }],
+ "max-statements-per-line": ["error", { "max": 2 }],
+ "no-console": "off",
+ "no-empty-function": "error",
+ "no-floating-decimal": "error",
+ "no-inline-comments": "error",
+ "no-lonely-if": "error",
+ "no-multi-spaces": "error",
+ "no-multiple-empty-lines": [
+ "error",
+ { "max": 2, "maxEOF": 1, "maxBOF": 0 }
+ ],
+ "no-shadow": "off",
+ "@typescript-eslint/no-shadow": [
+ "error",
+ { "allow": ["err", "resolve", "reject"] }
+ ],
+ "no-trailing-spaces": ["error"],
+ "no-var": "error",
+ "prefer-const": "error",
+ "space-in-parens": "error",
+ "space-unary-ops": "error",
+ "spaced-comment": "error",
+ "yoda": "error"
+ }
}
diff --git a/.gitea/issue_template/BUG.md b/.gitea/issue_template/BUG.md
index 699f95b..cf83544 100644
--- a/.gitea/issue_template/BUG.md
+++ b/.gitea/issue_template/BUG.md
@@ -1,13 +1,10 @@
---
-
name: "🐞 Rapport d'un bug"
about: "Signal un problème rencontré"
ref: "main"
labels:
-
-- bug
-- "help wanted"
-
+ - bug
+ - "help wanted"
---
Bot version: v`X.Y.Z`
diff --git a/.gitea/issue_template/FEATURE.md b/.gitea/issue_template/FEATURE.md
index be5e348..dc8411f 100644
--- a/.gitea/issue_template/FEATURE.md
+++ b/.gitea/issue_template/FEATURE.md
@@ -1,10 +1,7 @@
---
-
name: "💫 Demande une fonctionnalitée"
about: "Propose une nouvelle fonctionnalité à ajouter"
ref: "main"
labels:
-
-- enhancement
-
+ - enhancement
---
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..1521c8b
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1 @@
+dist
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1 @@
+{}
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 978d630..1d7ac85 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,5 +1,3 @@
{
- "recommendations": [
- "dbaeumer.vscode-eslint"
- ]
+ "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 00426da..f9604d4 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,8 +1,8 @@
{
- "editor.tabSize": 4,
- "editor.insertSpaces": false,
+ "editor.tabSize": 2,
+ "editor.insertSpaces": false,
- "files.insertFinalNewline": true,
- "files.trimFinalNewlines": true,
- "files.trimTrailingWhitespace": true
+ "files.insertFinalNewline": true,
+ "files.trimFinalNewlines": true,
+ "files.trimTrailingWhitespace": true
}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7d1db25..d40e86b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -40,26 +40,26 @@ contient toujours toutes les chaînes de caractère dont le bot a besoin.
La norme pour les nom dans les fichiers est la suivante :
-- Chaîne de charactère des commandes :
- `c` est utilisé pour `C`ommande.
+- Chaîne de charactère des commandes :
+ `c` est utilisé pour `C`ommande.
- - `c_NOM-COMMANDE_name` : Nom de la commande
- - `c_NOM-COMMANDE_desc` : Description de la commande
- - `c_NOM-COMMANDE_optX_name` : Nom de l'option X
- - `c_NOM-COMMANDE_optX_desc` : Description de l'option X
- - `c_NOM-COMMANDE_subX_name` : Nom de la sous-commande X
- - `c_NOM-COMMANDE_subX_desc` : Description de la sous-commande X
- - `c_NOM-COMMANDEX` : `X` le numéro de la chaîne de caractère
+ - `c_NOM-COMMANDE_name` : Nom de la commande
+ - `c_NOM-COMMANDE_desc` : Description de la commande
+ - `c_NOM-COMMANDE_optX_name` : Nom de l'option X
+ - `c_NOM-COMMANDE_optX_desc` : Description de l'option X
+ - `c_NOM-COMMANDE_subX_name` : Nom de la sous-commande X
+ - `c_NOM-COMMANDE_subX_desc` : Description de la sous-commande X
+ - `c_NOM-COMMANDEX` : `X` le numéro de la chaîne de caractère
- Évidemment ça peut s'additionner,
- par exemple : `c_NOM-COMMANDE_subX_optX_desc`.
+ Évidemment ça peut s'additionner,
+ par exemple : `c_NOM-COMMANDE_subX_optX_desc`.
-- Chaîne de charactère des évènements :
- `e` est utilisé pour `E`vènements.
- - `e_NOM-EVENEMENT_N` : `N` le nom de la chaîne de caractère
-- Chaîne de charactère des utils :
- `u` est utilisé pour `U`tilitaires.
- - `u_NOM-FICHIER-UTILS_N` : `N` le nom de la chaîne de caractère
+- Chaîne de charactère des évènements :
+ `e` est utilisé pour `E`vènements.
+ - `e_NOM-EVENEMENT_N` : `N` le nom de la chaîne de caractère
+- Chaîne de charactère des utils :
+ `u` est utilisé pour `U`tilitaires.
+ - `u_NOM-FICHIER-UTILS_N` : `N` le nom de la chaîne de caractère
### Ajouter une langue
@@ -70,8 +70,8 @@ La norme pour les nom dans les fichiers est la suivante :
[cf. au dessus](#langues).
3. Ce sont les valeurs des clés (le texte à gauche des `:`) qui doivent
être traduits. Merci par avance !
- > Ne vous forcez pas à tout traduire. Même une contribution avec
- > une seule variable de modifiée compte !
+ > Ne vous forcez pas à tout traduire. Même une contribution avec
+ > une seule variable de modifiée compte !
4. Une fois terminée, [ouvrez une Pull Request](#soumettre-ses-modifications).
### Mettre à jour une langue
@@ -79,23 +79,23 @@ La norme pour les nom dans les fichiers est la suivante :
1. Rechercher la langue dans le dossier [src/locales/](./src/locales/).
2. Modifier/Ajouter des traductions comme
[expliquer au dessus](#ajouter-une-langue) (à partir du `3.`).
- > Pensez à vérifier si de nouvelles valeurs n'ont pas été ajouté dans
- > le fichier langue par défaut, [cf. au dessus](#langues).
+ > Pensez à vérifier si de nouvelles valeurs n'ont pas été ajouté dans
+ > le fichier langue par défaut, [cf. au dessus](#langues).
## Projet
Le code se trouve dans le dosier [src/](./src/). Dans ce dossier il y a :
-- [commands/](./src/commands/) qui contient toutes les commandes, rangés par
- catégories
-- [events/](./src/events/) qui contient tous les évènements, rangés par
- catégories
-- [locales/](./src/locales/) qui contient tous les fichiers de langue
-- [modules/](./src/modules/) qui contient les extensions utilisé,
- par exemple, pour utiliser la fonction `capitalize()` d'un string, il faut
- importer le fichier `string.ts` qui se trouve dans le dossier
-- [utils/](./src/utils/) qui contient toutes les fonctions utilitaires, rangés
- par fichiers
+- [commands/](./src/commands/) qui contient toutes les commandes, rangés par
+ catégories
+- [events/](./src/events/) qui contient tous les évènements, rangés par
+ catégories
+- [locales/](./src/locales/) qui contient tous les fichiers de langue
+- [modules/](./src/modules/) qui contient les extensions utilisé,
+ par exemple, pour utiliser la fonction `capitalize()` d'un string, il faut
+ importer le fichier `string.ts` qui se trouve dans le dossier
+- [utils/](./src/utils/) qui contient toutes les fonctions utilitaires, rangés
+ par fichiers
Les dossiers [commands/](./src/commands/) et [events/](./src/events/)
contiennent chaquin un fichier `loader.js` qui charge respectivement
@@ -116,42 +116,42 @@ import { getLocale, getLocalizations } from "../../utils/locales";
import { getFilename } from "../../utils/misc";
export default {
- scope: () => [],
+ scope: () => [],
- data: (client: Client) => {
- const filename = getFilename(__filename);
- return new SlashCommandBuilder()
- .setName(filename.toLowerCase())
- .setDescription(
- client.locales
- .get(client.config.default_lang)
- ?.get(`c_${filename}_desc`) ?? ""
- )
- .setNameLocalizations(
- getLocalizations(client, `c_${filename}_name`, true)
- )
- .setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_desc`)
- );
- },
+ data: (client: Client) => {
+ const filename = getFilename(__filename);
+ return new SlashCommandBuilder()
+ .setName(filename.toLowerCase())
+ .setDescription(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${filename}_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_desc`)
+ );
+ },
- interaction: async (
- interaction: ChatInputCommandInteraction,
- client: Client
- ) => {
- const loc = getLocale(client, interaction.locale);
+ interaction: async (
+ interaction: ChatInputCommandInteraction,
+ client: Client
+ ) => {
+ const loc = getLocale(client, interaction.locale);
- /* Votre code ici */
- },
+ /* Votre code ici */
+ },
};
```
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
+- `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
déjà tout ce qu'il faut pour le support des langues. Pensez bien à ne pas écrire
@@ -161,10 +161,10 @@ les [fichiers de langues](./src/locales/), c'est à ça que la variable
Vous devez aussi ajouter **obligatoirement** :
-- `"c_COMMANDE_name": "NOM"` au fichier de langue, avec `COMMANDE` le nom de
- la commande et `NOM` le nom de votre commande.
-- `"c_COMMANDE_desc": "DESCRIPTION"` au fichier de langue, avec `COMMANDE`
- le nom de la commande et `DESCRIPTION` la description de votre commande.
+- `"c_COMMANDE_name": "NOM"` au fichier de langue, avec `COMMANDE` le nom de
+ la commande et `NOM` le nom de votre commande.
+- `"c_COMMANDE_desc": "DESCRIPTION"` au fichier de langue, avec `COMMANDE`
+ le nom de la commande et `DESCRIPTION` la description de votre commande.
## Ajouter un évènement
@@ -203,14 +203,14 @@ Quand vous modifiez quelque chose, pensez à mettre-à-jour les langues. Si vous
ne savez pas traduire dans une langue, ne vous forcez pas, supprimer simplement
la traduction.
-- [Créez un fork](https://git.kennel.ml/repo/fork/76) et poussez
- vos modifications dans ce dernier.
+- [Créez un fork](https://git.kennel.ml/repo/fork/76) et poussez
+ vos modifications dans ce dernier.
Pour commencer, vous pouvez jeté un oeil aux
[tickets facilement résolvable](https://git.kennel.ml/ConfrerieDuKassoulait/Botanique/issues?state=open&labels=82).
-- De préférences, les fonctions, méthodes et variables seront écrites
- en anglais, ainsi que les commits afin que chacun puisse contribuer.
+- De préférences, les fonctions, méthodes et variables seront écrites
+ en anglais, ainsi que les commits afin que chacun puisse contribuer.
## Soumettre ses modifications
@@ -243,10 +243,10 @@ Pour commencer, vous pouvez jeté un oeil aux
## Gestion du dépôt
-- On ne push jamais directement sur la branche `main`.
-- Quand on merge des modifications vers `main`, on fait un _squash_,
- l'historique des modifications reste disponible dans
- [le graph](https://git.kennel.ml/ConfrerieDuKassoulait/Botanique/graph).
-- De préférences, suivre les indications de
- [ce post](https://gist.github.com/revett/88ee5abf5a9a097b4c88) (c'est un peu la
- même que dans le `4.` de [la partie précédente](#soumettre-ses-modifications)).
+- On ne push jamais directement sur la branche `main`.
+- Quand on merge des modifications vers `main`, on fait un _squash_,
+ l'historique des modifications reste disponible dans
+ [le graph](https://git.kennel.ml/ConfrerieDuKassoulait/Botanique/graph).
+- De préférences, suivre les indications de
+ [ce post](https://gist.github.com/revett/88ee5abf5a9a097b4c88) (c'est un peu la
+ même que dans le `4.` de [la partie précédente](#soumettre-ses-modifications)).
diff --git a/README.md b/README.md
index 5cd5d24..e2b0a7b 100644
--- a/README.md
+++ b/README.md
@@ -3,23 +3,29 @@
[**Ajoute le bot à ton serveur**](https://discord.com/api/oauth2/authorize?client_id=965598852407230494&permissions=8&scope=bot%20applications.commands)
## Lancer le bot
+
### En local
+
> Cloner le repo.
> Spécifier un fichier `.env` en suivant [l'exemple](config/example.env).
> Installer les dépendences du bot.
+
```bash
npm install
```
> Lancer le bot.
+
```bash
npm run main
```
### Avec Docker (Recommandé)
+
> Facile avec `docker-compose`
+
```docker
version: "3.9"
services:
@@ -34,23 +40,28 @@ services:
```
## Variables d'environnements
-| Nom | Description | Par défaut | Commentaire
-| :-----------: | :--------------: | :--------: | :-:
-| TOKEN_DISCORD | Token Discord | Aucune |
-| DEFAULT_LANG | Langue par défaut | `fr` | Expérimental, si la langue par défaut n'est pas complète (càd 100%), le bot pourrait ne pas fonctionner correctement.
Liste des traductions disponibles [ici](./src/locales/).
+
+| Nom | Description | Par défaut | Commentaire |
+| :-----------: | :---------------: | :--------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| TOKEN_DISCORD | Token Discord | Aucune |
+| DEFAULT_LANG | Langue par défaut | `fr` | Expérimental, si la langue par défaut n'est pas complète (càd 100%), le bot pourrait ne pas fonctionner correctement.
Liste des traductions disponibles [ici](./src/locales/). |
## Volumes
-| Chemin | Description
-| :-------: | :-:
-| `/config` | Dossier de configuration, par exemple, c'est ici que la base de donnée est.
+
+| Chemin | Description |
+| :-------: | :-------------------------------------------------------------------------: |
+| `/config` | Dossier de configuration, par exemple, c'est ici que la base de donnée est. |
# Contribuer
+
Toute contribution est la bienvenue !
Pour commencer, lis le [fichier de contribution](./CONTRIBUTING.md).
# Licence
+
Voir le [fichier LICENCE](./LICENCE).
# Références
+
[Photo de profil](https://picrew.me/image_maker/1497656)
diff --git a/package-lock.json b/package-lock.json
index ee38fad..e3a3fb0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,6 +23,7 @@
"@typescript-eslint/parser": "^5.30.7",
"dotenv": "^16.0.1",
"eslint": "^8.20.0",
+ "prettier": "2.8.3",
"ts-node-dev": "^2.0.0"
}
},
@@ -2438,6 +2439,21 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prettier": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz",
+ "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin-prettier.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
"node_modules/promise-inflight": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@@ -5110,6 +5126,12 @@
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true
},
+ "prettier": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz",
+ "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==",
+ "dev": true
+ },
"promise-inflight": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
diff --git a/package.json b/package.json
index 1ef6342..5b8e30f 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,8 @@
"scripts": {
"main": "rm -r dist 2> /dev/null; npx tsc && node ./dist/index.js",
"debug": "npx tsnd --respawn ./src/index.ts",
- "lint": "npx eslint src"
+ "lint": "npx eslint src",
+ "format": "npx prettier --check src"
},
"repository": {
"type": "git",
@@ -17,18 +18,19 @@
"dependencies": {
"@discordjs/rest": "^1.1.0",
"@types/sqlite3": "^3.1.8",
+ "@types/uuid": "^9.0.0",
"discord-api-types": "^0.36.3",
"discord.js": "^14.3.0",
"sqlite3": "^5.0.11",
"typescript": "^4.7.4",
- "uuid": "^9.0.0",
- "@types/uuid": "^9.0.0"
+ "uuid": "^9.0.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.30.7",
"@typescript-eslint/parser": "^5.30.7",
"dotenv": "^16.0.1",
"eslint": "^8.20.0",
+ "prettier": "2.8.3",
"ts-node-dev": "^2.0.0"
}
}
diff --git a/src/buttons/loader.ts b/src/buttons/loader.ts
index 0dbad68..83f79b5 100644
--- a/src/buttons/loader.ts
+++ b/src/buttons/loader.ts
@@ -1,39 +1,44 @@
-import { readdir } from 'fs/promises';
-import { removeExtension } from '../utils/misc';
-import { ChatInputCommandInteraction, Client, MessageComponentInteraction } from 'discord.js';
-import { getLocale } from '../utils/locales';
+import { readdir } from "fs/promises";
+import { removeExtension } from "../utils/misc";
+import {
+ ChatInputCommandInteraction,
+ Client,
+ MessageComponentInteraction,
+} from "discord.js";
+import { getLocale } from "../utils/locales";
export default async (client: Client) => {
- // Dossier des buttons
- const buttons_categories = (await readdir(__dirname))
- .filter(element => !element.endsWith('.js') && !element.endsWith('.ts'));
+ // Dossier des buttons
+ const buttons_categories = (await readdir(__dirname)).filter(
+ (element) => !element.endsWith(".js") && !element.endsWith(".ts")
+ );
- await Promise.all(
- // For each categorie
- buttons_categories.map(async buttons_category => {
- // Retrieve all the commands
- const button_files = await readdir(`${__dirname}/${buttons_category}`);
+ await Promise.all(
+ // For each categorie
+ buttons_categories.map(async (buttons_category) => {
+ // Retrieve all the commands
+ const button_files = await readdir(`${__dirname}/${buttons_category}`);
- // Add the category to the collection for the help command
- client.buttons.categories.set(
- buttons_category,
- button_files.map(removeExtension),
- );
+ // Add the category to the collection for the help command
+ client.buttons.categories.set(
+ buttons_category,
+ button_files.map(removeExtension)
+ );
- // Add the button
- return Promise.all(
- button_files.map(async button_file => {
- const button = (
- await import(`../buttons/${buttons_category}/${button_file}`)
- ).default;
+ // Add the button
+ return Promise.all(
+ button_files.map(async (button_file) => {
+ const button = (
+ await import(`../buttons/${buttons_category}/${button_file}`)
+ ).default;
- // Add it to the collection so the interaction will work
- client.buttons.list.set(button.data.name, button);
- return button.data;
- }),
- );
- }),
- );
+ // Add it to the collection so the interaction will work
+ client.buttons.list.set(button.data.name, button);
+ return button.data;
+ })
+ );
+ })
+ );
};
/**
@@ -43,26 +48,34 @@ export default async (client: Client) => {
* @param id Button ID
* @param deferUpdate defer update in case update take time
*/
-export const collect = (client: Client, interaction: ChatInputCommandInteraction | MessageComponentInteraction, id: string, deferUpdate = false) => {
- const loc = getLocale(client, interaction.locale);
- const button = client.buttons.list.get(id.split('_')[0]);
+export const collect = (
+ client: Client,
+ interaction: ChatInputCommandInteraction | MessageComponentInteraction,
+ id: string,
+ deferUpdate = false
+) => {
+ const loc = getLocale(client, interaction.locale);
+ const button = client.buttons.list.get(id.split("_")[0]);
- if (!button) {
- interaction.reply({
- content: loc.get('e_interacreate_no_button'),
- ephemeral: true,
- });
- }
+ if (!button) {
+ interaction.reply({
+ content: loc.get("e_interacreate_no_button"),
+ ephemeral: true,
+ });
+ }
- const filter = (i: MessageComponentInteraction) => i.customId === id;
- const collector = interaction.channel?.createMessageComponentCollector({ filter, max: 1 });
- collector?.on('collect', async (i) => {
- if (deferUpdate) {
- await i.deferUpdate();
- }
- const msg = await button?.interaction(i, client);
- if (msg !== undefined) {
- await i.update(msg);
- }
- });
+ const filter = (i: MessageComponentInteraction) => i.customId === id;
+ const collector = interaction.channel?.createMessageComponentCollector({
+ filter,
+ max: 1,
+ });
+ collector?.on("collect", async (i) => {
+ if (deferUpdate) {
+ await i.deferUpdate();
+ }
+ const msg = await button?.interaction(i, client);
+ if (msg !== undefined) {
+ await i.update(msg);
+ }
+ });
};
diff --git a/src/buttons/misc/reminderList-next.ts b/src/buttons/misc/reminderList-next.ts
index 76cc5ae..0b1a64f 100644
--- a/src/buttons/misc/reminderList-next.ts
+++ b/src/buttons/misc/reminderList-next.ts
@@ -1,56 +1,73 @@
-import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Client, MessageComponentInteraction, User } from 'discord.js';
-import { v4 as uuidv4 } from 'uuid';
-import { getLocale } from '../../utils/locales';
-import { getFilename } from '../../utils/misc';
-import { embedListReminders } from '../../utils/reminder';
-import { collect } from '../loader';
+import {
+ ActionRowBuilder,
+ ButtonBuilder,
+ ButtonStyle,
+ Client,
+ MessageComponentInteraction,
+ User,
+} from "discord.js";
+import { v4 as uuidv4 } from "uuid";
+import { getLocale } from "../../utils/locales";
+import { getFilename } from "../../utils/misc";
+import { embedListReminders } from "../../utils/reminder";
+import { collect } from "../loader";
export default {
- data: {
- name: getFilename(__filename),
- },
- interaction: async (interaction: MessageComponentInteraction, client: Client) => {
- const loc = getLocale(client, interaction.locale);
- const embed_desc = interaction.message.embeds.at(0)?.description as string;
+ data: {
+ name: getFilename(__filename),
+ },
+ interaction: async (
+ interaction: MessageComponentInteraction,
+ client: Client
+ ) => {
+ const loc = getLocale(client, interaction.locale);
+ const embed_desc = interaction.message.embeds.at(0)?.description as string;
- // Retrieve Pages
- const pageMax = Number(/(\d+)(?!.*\d)/gm.exec(embed_desc)?.[0]);
- let page = Number(/(?!• \s+)\d(?=\/)/gm.exec(embed_desc)?.[0]);
- if (page + 1 > pageMax) {
- page = 1;
- } else {
- page++;
- }
+ // Retrieve Pages
+ const pageMax = Number(/(\d+)(?!.*\d)/gm.exec(embed_desc)?.[0]);
+ let page = Number(/(?!• \s+)\d(?=\/)/gm.exec(embed_desc)?.[0]);
+ if (page + 1 > pageMax) {
+ page = 1;
+ } else {
+ page++;
+ }
- // Retrieve user
- const userId = /(?!<@)\d+(?=>)/gm.exec(embed_desc)?.[0] as string;
- const user = client.users.cache.get(userId) as User;
+ // Retrieve user
+ const userId = /(?!<@)\d+(?=>)/gm.exec(embed_desc)?.[0] as string;
+ const user = client.users.cache.get(userId) as User;
- // Fetch list
- const list = await embedListReminders(client, user, interaction.guildId, page, interaction.locale);
+ // Fetch list
+ const list = await embedListReminders(
+ client,
+ user,
+ interaction.guildId,
+ page,
+ interaction.locale
+ );
- const idPrec = 'reminderList-prec_' + uuidv4();
- const idNext = 'reminderList-next_' + uuidv4();
- const row = new ActionRowBuilder()
- .addComponents(
- new ButtonBuilder()
- .setCustomId(idPrec)
- .setLabel(loc.get('c_reminder12'))
- .setStyle(ButtonStyle.Primary))
- .addComponents(
- new ButtonBuilder()
- .setCustomId(idNext)
- .setLabel(loc.get('c_reminder13'))
- .setStyle(ButtonStyle.Primary),
- );
+ const idPrec = "reminderList-prec_" + uuidv4();
+ const idNext = "reminderList-next_" + uuidv4();
+ const row = new ActionRowBuilder()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId(idPrec)
+ .setLabel(loc.get("c_reminder12"))
+ .setStyle(ButtonStyle.Primary)
+ )
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId(idNext)
+ .setLabel(loc.get("c_reminder13"))
+ .setStyle(ButtonStyle.Primary)
+ );
- // Buttons interactions
- collect(client, interaction, idPrec);
- collect(client, interaction, idNext);
+ // Buttons interactions
+ collect(client, interaction, idPrec);
+ collect(client, interaction, idNext);
- return {
- embeds: [list],
- components: [row],
- };
- },
+ return {
+ embeds: [list],
+ components: [row],
+ };
+ },
};
diff --git a/src/buttons/misc/reminderList-prec.ts b/src/buttons/misc/reminderList-prec.ts
index 06a1019..33c91fd 100644
--- a/src/buttons/misc/reminderList-prec.ts
+++ b/src/buttons/misc/reminderList-prec.ts
@@ -1,56 +1,73 @@
-import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Client, MessageComponentInteraction, User } from 'discord.js';
-import { v4 as uuidv4 } from 'uuid';
-import { getLocale } from '../../utils/locales';
-import { getFilename } from '../../utils/misc';
-import { embedListReminders } from '../../utils/reminder';
-import { collect } from '../loader';
+import {
+ ActionRowBuilder,
+ ButtonBuilder,
+ ButtonStyle,
+ Client,
+ MessageComponentInteraction,
+ User,
+} from "discord.js";
+import { v4 as uuidv4 } from "uuid";
+import { getLocale } from "../../utils/locales";
+import { getFilename } from "../../utils/misc";
+import { embedListReminders } from "../../utils/reminder";
+import { collect } from "../loader";
export default {
- data: {
- name: getFilename(__filename),
- },
- interaction: async (interaction: MessageComponentInteraction, client: Client) => {
- const loc = getLocale(client, interaction.locale);
- const embed_desc = interaction.message.embeds.at(0)?.description as string;
+ data: {
+ name: getFilename(__filename),
+ },
+ interaction: async (
+ interaction: MessageComponentInteraction,
+ client: Client
+ ) => {
+ const loc = getLocale(client, interaction.locale);
+ const embed_desc = interaction.message.embeds.at(0)?.description as string;
- // Retrieve Pages
- const pageMax = Number(/(\d+)(?!.*\d)/gm.exec(embed_desc)?.[0]);
- let page = Number(/(?!• \s+)\d(?=\/)/gm.exec(embed_desc)?.[0]);
- if (page - 1 == 0) {
- page = pageMax;
- } else {
- page--;
- }
+ // Retrieve Pages
+ const pageMax = Number(/(\d+)(?!.*\d)/gm.exec(embed_desc)?.[0]);
+ let page = Number(/(?!• \s+)\d(?=\/)/gm.exec(embed_desc)?.[0]);
+ if (page - 1 == 0) {
+ page = pageMax;
+ } else {
+ page--;
+ }
- // Retrieve user
- const userId = /(?!<@)\d+(?=>)/gm.exec(embed_desc)?.[0] as string;
- const user = client.users.cache.get(userId) as User;
+ // Retrieve user
+ const userId = /(?!<@)\d+(?=>)/gm.exec(embed_desc)?.[0] as string;
+ const user = client.users.cache.get(userId) as User;
- // Fetch list
- const list = await embedListReminders(client, user, interaction.guildId, page, interaction.locale);
+ // Fetch list
+ const list = await embedListReminders(
+ client,
+ user,
+ interaction.guildId,
+ page,
+ interaction.locale
+ );
- const idPrec = 'reminderList-prec_' + uuidv4();
- const idNext = 'reminderList-next_' + uuidv4();
- const row = new ActionRowBuilder()
- .addComponents(
- new ButtonBuilder()
- .setCustomId(idPrec)
- .setLabel(loc.get('c_reminder12'))
- .setStyle(ButtonStyle.Primary))
- .addComponents(
- new ButtonBuilder()
- .setCustomId(idNext)
- .setLabel(loc.get('c_reminder13'))
- .setStyle(ButtonStyle.Primary),
- );
+ const idPrec = "reminderList-prec_" + uuidv4();
+ const idNext = "reminderList-next_" + uuidv4();
+ const row = new ActionRowBuilder()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId(idPrec)
+ .setLabel(loc.get("c_reminder12"))
+ .setStyle(ButtonStyle.Primary)
+ )
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId(idNext)
+ .setLabel(loc.get("c_reminder13"))
+ .setStyle(ButtonStyle.Primary)
+ );
- // Buttons interactions
- collect(client, interaction, idPrec);
- collect(client, interaction, idNext);
+ // Buttons interactions
+ collect(client, interaction, idPrec);
+ collect(client, interaction, idNext);
- return {
- embeds: [list],
- components: [row],
- };
- },
+ return {
+ embeds: [list],
+ components: [row],
+ };
+ },
};
diff --git a/src/commands/loader.ts b/src/commands/loader.ts
index ca44dc2..8f02d48 100644
--- a/src/commands/loader.ts
+++ b/src/commands/loader.ts
@@ -1,77 +1,84 @@
-import { REST } from '@discordjs/rest';
-import { Routes } from 'discord-api-types/v9';
-import { Client } from 'discord.js';
-import { readdir } from 'fs/promises';
-import { removeExtension } from '../utils/misc';
+import { REST } from "@discordjs/rest";
+import { Routes } from "discord-api-types/v9";
+import { Client } from "discord.js";
+import { readdir } from "fs/promises";
+import { removeExtension } from "../utils/misc";
/** Load all the commands. */
export default async (client: Client) => {
- const rest = new REST({ version: '10' }).setToken(client.token ?? '');
+ const rest = new REST({ version: "10" }).setToken(client.token ?? "");
- const command_categories = (await readdir(__dirname))
- .filter(element => !element.endsWith('.js') && !element.endsWith('.ts'));
+ const command_categories = (await readdir(__dirname)).filter(
+ (element) => !element.endsWith(".js") && !element.endsWith(".ts")
+ );
- const commands = (
- await Promise.all(
- // For each categorie
- command_categories.map(async command_category => {
- // Retrieve all the commands
- const command_files = await readdir(`${__dirname}/${command_category}`);
+ const commands = (
+ await Promise.all(
+ // For each categorie
+ command_categories.map(async (command_category) => {
+ // Retrieve all the commands
+ const command_files = await readdir(`${__dirname}/${command_category}`);
- // Add the category to the collection for the help command
- client.commands.categories.set(
- command_category,
- command_files.map(removeExtension),
- );
+ // Add the category to the collection for the help command
+ client.commands.categories.set(
+ command_category,
+ command_files.map(removeExtension)
+ );
- // Add the command
- return Promise.all(
- command_files.map(async command_file => {
- const command = (
- await import(`../commands/${command_category}/${command_file}`)
- ).default;
+ // Add the command
+ return Promise.all(
+ command_files.map(async (command_file) => {
+ const command = (
+ await import(`../commands/${command_category}/${command_file}`)
+ ).default;
- // Add it to the collection so the interaction will work
- command.data = command.data(client);
- client.commands.list.set(command.data.name, command);
+ // Add it to the collection so the interaction will work
+ command.data = command.data(client);
+ client.commands.list.set(command.data.name, command);
- return command;
- }),
- );
- }),
- )
- ).flat(2);
+ return command;
+ })
+ );
+ })
+ )
+ ).flat(2);
- // Send guilds commands to Discord
- const scopedCommands = new Map();
+ // Send guilds commands to Discord
+ const scopedCommands = new Map();
- // Add commands to guild where the bot is
- const allowedGuilds = client.guilds.cache;
+ // 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);
- }
- }
- });
- });
+ // 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,
- }));
+ 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()),
- });
+ // 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()),
+ });
};
diff --git a/src/commands/misc/archive.ts b/src/commands/misc/archive.ts
index 46b3fb1..8d1ecbb 100644
--- a/src/commands/misc/archive.ts
+++ b/src/commands/misc/archive.ts
@@ -1,129 +1,159 @@
-import { SlashCommandBuilder } from '@discordjs/builders';
-import { ChannelType, Client, Colors, CommandInteraction, EmbedBuilder, NonThreadGuildBasedChannel } from 'discord.js';
-import '../../modules/string';
-import { getLocale, getLocalizations } from '../../utils/locales';
-import { getFilename } from '../../utils/misc';
+import { SlashCommandBuilder } from "@discordjs/builders";
+import {
+ ChannelType,
+ Client,
+ Colors,
+ CommandInteraction,
+ EmbedBuilder,
+ NonThreadGuildBasedChannel,
+} from "discord.js";
+import "../../modules/string";
+import { getLocale, getLocalizations } from "../../utils/locales";
+import { getFilename } from "../../utils/misc";
export default {
- scope: () => ['807244911350906920'],
+ scope: () => ["807244911350906920"],
- data: (client: Client) => {
- const filename = getFilename(__filename);
- return new SlashCommandBuilder()
- .setName(
- filename.toLowerCase())
- .setDescription(client.locales.get(client.config.default_lang)
- ?.get(`c_${filename}_desc`) ?? '')
- .setNameLocalizations(
- getLocalizations(client, `c_${filename}_name`, true))
- .setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_desc`))
+ data: (client: Client) => {
+ const filename = getFilename(__filename);
+ return (
+ new SlashCommandBuilder()
+ .setName(filename.toLowerCase())
+ .setDescription(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${filename}_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_desc`)
+ )
- // Command option
- .addStringOption(option => option
- .setName(client.locales.get(client.config.default_lang)
- ?.get(`c_${filename}_opt1_name`) ?? '')
- .setDescription(client.locales.get(client.config.default_lang)
- ?.get(`c_${filename}_opt1_desc`) ?? '')
- .setNameLocalizations(
- getLocalizations(client, `c_${filename}_opt1_name`, true))
- .setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_opt1_desc`))
- );
- },
+ // Command option
+ .addStringOption((option) =>
+ option
+ .setName(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${filename}_opt1_name`) ?? ""
+ )
+ .setDescription(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${filename}_opt1_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_opt1_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_opt1_desc`)
+ )
+ )
+ );
+ },
- interaction: async (interaction: CommandInteraction, client: Client) => {
- const loc = getLocale(client, interaction.locale);
- const desiredCat = interaction.options.get(client
- .locales
- .get(client.config.default_lang)
- ?.get(`c_${getFilename(__filename)}_opt1_name`) ?? '')?.value as string;
+ interaction: async (interaction: CommandInteraction, client: Client) => {
+ const loc = getLocale(client, interaction.locale);
+ const desiredCat = interaction.options.get(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${getFilename(__filename)}_opt1_name`) ?? ""
+ )?.value as string;
- // If a category isn't specified
- if (!desiredCat) {
+ // If a category isn't specified
+ if (!desiredCat) {
+ // Sends a list of commands sorted into categories
+ return interaction.reply({
+ embeds: [
+ new EmbedBuilder()
+ .setColor(Colors.Blurple)
+ .setTitle(loc.get("c_archive1"))
+ .setDescription(loc.get("c_archive2")),
+ ],
+ });
+ }
- // Sends a list of commands sorted into categories
- return interaction.reply({
- embeds: [
- new EmbedBuilder()
- .setColor(Colors.Blurple)
- .setTitle(loc.get('c_archive1'))
- .setDescription(loc.get('c_archive2')),
- ],
- });
- }
+ // If a category is specified
+ const cleanCat = ["L1", "L2", "L3", "M1", "M2"];
+ const channel = cleanCat.includes(desiredCat);
+ if (!channel) {
+ // Category doesn't exist or is not included
+ return interaction.reply({
+ content: `${loc.get("c_archive3")} \`${desiredCat}\``,
+ ephemeral: true,
+ });
+ }
- // If a category is specified
- const cleanCat = ['L1', 'L2', 'L3', 'M1', 'M2'];
- const channel = cleanCat.includes(desiredCat);
- if (!channel) {
- // Category doesn't exist or is not included
- return interaction.reply({
- content: `${loc.get('c_archive3')} \`${desiredCat}\``,
- ephemeral: true,
- });
- }
+ const allChannel = interaction.guild?.channels.fetch();
+ allChannel?.then(async (channelGuild) => {
+ // Retrieve category to archive
+ const catToArchive = channelGuild
+ .filter((chan) => chan?.type == ChannelType.GuildCategory)
+ .filter((chan) => chan?.name == desiredCat);
- const allChannel = interaction.guild?.channels.fetch();
- allChannel?.then(async channelGuild => {
- // Retrieve category to archive
- const catToArchive = channelGuild
- .filter(chan => chan?.type == ChannelType.GuildCategory)
- .filter(chan => chan?.name == desiredCat);
+ // Create/Retrieve the archive category
+ const catArchivedName = "archive - " + desiredCat;
+ const catArchivedMap = channelGuild
+ .filter((chan) => chan?.type == ChannelType.GuildCategory)
+ .filter((chan) => chan?.name == catArchivedName);
- // Create/Retrieve the archive category
- const catArchivedName = 'archive - ' + desiredCat;
- const catArchivedMap = channelGuild
- .filter(chan => chan?.type == ChannelType.GuildCategory)
- .filter(chan => chan?.name == catArchivedName);
+ let catArchived: NonThreadGuildBasedChannel | null | undefined;
+ if (catArchivedMap.size > 0) {
+ catArchived = catArchivedMap.at(0);
+ } else {
+ catArchived = await interaction.guild?.channels.create({
+ name: catArchivedName,
+ type: ChannelType.GuildCategory,
+ });
+ }
- let catArchived: NonThreadGuildBasedChannel | null | undefined;
- 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]
+ );
- 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({
+ embeds: [
+ new EmbedBuilder()
+ .setColor(Colors.Blurple)
+ .setTitle(loc.get("c_archive6"))
+ .setDescription(loc.get("c_archive7")),
+ ],
+ });
+ }
- // If no channels in the source category
- if (allChannelDesired.size == 0) {
- return interaction.reply({
- embeds: [
- new EmbedBuilder()
- .setColor(Colors.Blurple)
- .setTitle(loc.get('c_archive6'))
- .setDescription(
- loc.get('c_archive7')
- ),
- ],
- });
- }
+ // Move channels to the archived categoryx
+ allChannelDesired.forEach((elem) =>
+ elem?.setParent(catArchived?.id as string)
+ );
- // Move channels to the archived categoryx
- allChannelDesired.forEach(elem => elem?.setParent(catArchived?.id as string));
-
- return interaction.reply({
- embeds: [
- new EmbedBuilder()
- .setColor(Colors.Blurple)
- .setTitle(loc.get('c_archive4')
- + ' `'
- + catToArchive.map(cat => cat?.name)
- + '` '
- + loc.get('c_archive5')
- + ' `'
- + catArchivedName
- + '`')
- .setDescription(
- allChannelDesired
- .map(cgD => cgD?.name).toString().replaceAll(',', '\n')
- ),
- ],
- });
- });
- },
+ return interaction.reply({
+ embeds: [
+ new EmbedBuilder()
+ .setColor(Colors.Blurple)
+ .setTitle(
+ loc.get("c_archive4") +
+ " `" +
+ catToArchive.map((cat) => cat?.name) +
+ "` " +
+ loc.get("c_archive5") +
+ " `" +
+ catArchivedName +
+ "`"
+ )
+ .setDescription(
+ allChannelDesired
+ .map((cgD) => cgD?.name)
+ .toString()
+ .replaceAll(",", "\n")
+ ),
+ ],
+ });
+ });
+ },
};
diff --git a/src/commands/misc/help.ts b/src/commands/misc/help.ts
index 3593ab2..83f940e 100644
--- a/src/commands/misc/help.ts
+++ b/src/commands/misc/help.ts
@@ -1,98 +1,126 @@
-import { SlashCommandBuilder } from '@discordjs/builders';
-import { Locale } from 'discord-api-types/v9';
-import { Client, ChatInputCommandInteraction, EmbedBuilder, Colors } from 'discord.js';
-import { getLocale, getLocalizations } from '../../utils/locales';
-import { getFilename } from '../../utils/misc';
-import '../../modules/string';
+import { SlashCommandBuilder } from "@discordjs/builders";
+import { Locale } from "discord-api-types/v9";
+import {
+ Client,
+ ChatInputCommandInteraction,
+ EmbedBuilder,
+ Colors,
+} from "discord.js";
+import { getLocale, getLocalizations } from "../../utils/locales";
+import { getFilename } from "../../utils/misc";
+import "../../modules/string";
export default {
- scope: () => [],
+ scope: () => [],
- data: (client: Client) => {
- const filename = getFilename(__filename);
- return new SlashCommandBuilder()
- .setName(
- filename.toLowerCase())
- .setDescription(client.locales.get(client.config.default_lang)
- ?.get(`c_${filename}_desc`) ?? '')
- .setNameLocalizations(
- getLocalizations(client, `c_${filename}_name`, true))
- .setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_desc`))
+ data: (client: Client) => {
+ const filename = getFilename(__filename);
+ return (
+ new SlashCommandBuilder()
+ .setName(filename.toLowerCase())
+ .setDescription(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${filename}_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_desc`)
+ )
- // Command option
- .addStringOption(option => option
- .setName(client.locales.get(client.config.default_lang)
- ?.get(`c_${filename}_opt1_name`) ?? '')
- .setDescription(client.locales.get(client.config.default_lang)
- ?.get(`c_${filename}_opt1_desc`) ?? '')
- .setNameLocalizations(
- getLocalizations(client, `c_${filename}_opt1_name`, true))
- .setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_opt1_desc`))
- );
- },
+ // Command option
+ .addStringOption((option) =>
+ option
+ .setName(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${filename}_opt1_name`) ?? ""
+ )
+ .setDescription(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${filename}_opt1_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_opt1_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_opt1_desc`)
+ )
+ )
+ );
+ },
- interaction: async (interaction: ChatInputCommandInteraction, client: Client) => {
- const loc = getLocale(client, interaction.locale);
- const desired_command = interaction.options.getString(client
- .locales
- .get(client.config.default_lang)
- ?.get(`c_${getFilename(__filename)}_opt1_name`) ?? '');
+ interaction: async (
+ interaction: ChatInputCommandInteraction,
+ client: Client
+ ) => {
+ const loc = getLocale(client, interaction.locale);
+ const desired_command = interaction.options.getString(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${getFilename(__filename)}_opt1_name`) ?? ""
+ );
- // If a command isn't specified
- if (!desired_command) {
- const fields: {
- name: string;
- value: string;
- }[] = [];
+ // If a command isn't specified
+ if (!desired_command) {
+ const fields: {
+ name: string;
+ value: string;
+ }[] = [];
- // Load all the command per categories
- // TODO: Check if the command exist in the context (guild)
- client.commands.categories.forEach((commands_name, category) => {
- const commands = commands_name.reduce((data, command_name) => {
- return data + `\`/${command_name}\`, `;
- }, '');
+ // Load all the command per categories
+ // TODO: Check if the command exist in the context (guild)
+ client.commands.categories.forEach((commands_name, category) => {
+ const commands = commands_name.reduce((data, command_name) => {
+ return data + `\`/${command_name}\`, `;
+ }, "");
- fields.push({
- name: category.capitalize() + ` (${commands_name.length})`,
- value: commands.slice(0, -2),
- });
- });
+ fields.push({
+ name: category.capitalize() + ` (${commands_name.length})`,
+ value: commands.slice(0, -2),
+ });
+ });
- // Sends a list of commands sorted into categories
- return interaction.reply({ embeds: [
- new EmbedBuilder()
- .setColor(Colors.Blurple)
- .setTitle(loc.get('c_help1'))
- .setDescription(loc.get('c_help2'))
- .addFields(fields),
- ] });
- }
+ // Sends a list of commands sorted into categories
+ return interaction.reply({
+ embeds: [
+ new EmbedBuilder()
+ .setColor(Colors.Blurple)
+ .setTitle(loc.get("c_help1"))
+ .setDescription(loc.get("c_help2"))
+ .addFields(fields),
+ ],
+ });
+ }
- // If a command is specified
- // TODO: Check if the command exist in the context (guild)
- const command = client.commands.list.get(desired_command);
- if (!command) {
- // Command don't exist
- return interaction.reply({
- content: `${loc.get('c_help3')} \`${desired_command}\``,
- ephemeral: true,
- });
- }
+ // If a command is specified
+ // TODO: Check if the command exist in the context (guild)
+ const command = client.commands.list.get(desired_command);
+ if (!command) {
+ // Command don't exist
+ return interaction.reply({
+ content: `${loc.get("c_help3")} \`${desired_command}\``,
+ ephemeral: true,
+ });
+ }
- // Send information about the command
- return interaction.reply({ embeds: [
- new EmbedBuilder()
- .setColor(Colors.Blurple)
- .setTitle('`/' + command.data.name + '`')
- .setDescription(
- // Loads the description
- // according to the user's locals
- command.data.description_localizations
- ?.[interaction.locale as Locale]
- ?? command.data.description
- ),
- ] });
- },
+ // Send information about the command
+ return interaction.reply({
+ embeds: [
+ new EmbedBuilder()
+ .setColor(Colors.Blurple)
+ .setTitle("`/" + command.data.name + "`")
+ .setDescription(
+ // Loads the description
+ // according to the user's locals
+ command.data.description_localizations?.[
+ interaction.locale as Locale
+ ] ?? command.data.description
+ ),
+ ],
+ });
+ },
};
diff --git a/src/commands/misc/ping.ts b/src/commands/misc/ping.ts
index 90b5c2b..b46f9b1 100644
--- a/src/commands/misc/ping.ts
+++ b/src/commands/misc/ping.ts
@@ -1,36 +1,43 @@
-import { SlashCommandBuilder } from '@discordjs/builders';
-import { ChatInputCommandInteraction, Client, Message } from 'discord.js';
-import { getLocale, getLocalizations } from '../../utils/locales';
-import { getFilename } from '../../utils/misc';
+import { SlashCommandBuilder } from "@discordjs/builders";
+import { ChatInputCommandInteraction, Client, Message } from "discord.js";
+import { getLocale, getLocalizations } from "../../utils/locales";
+import { getFilename } from "../../utils/misc";
export default {
- scope: () => [],
+ scope: () => [],
- data: (client: Client) => {
- const filename = getFilename(__filename);
- return new SlashCommandBuilder()
- .setName(
- filename.toLowerCase())
- .setDescription(client.locales.get(client.config.default_lang)
- ?.get(`c_${filename}_desc`) ?? '')
- .setNameLocalizations(
- getLocalizations(client, `c_${filename}_name`, true))
- .setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_desc`)
- );
- },
+ data: (client: Client) => {
+ const filename = getFilename(__filename);
+ return new SlashCommandBuilder()
+ .setName(filename.toLowerCase())
+ .setDescription(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${filename}_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_desc`)
+ );
+ },
- interaction: async (interaction: ChatInputCommandInteraction, client: Client) => {
- const loc = getLocale(client, interaction.locale);
+ interaction: async (
+ interaction: ChatInputCommandInteraction,
+ client: Client
+ ) => {
+ const loc = getLocale(client, interaction.locale);
- const sent = await interaction.reply({
- content: 'Pinging...',
- fetchReply: true,
- }) as Message;
+ const sent = (await interaction.reply({
+ content: "Pinging...",
+ fetchReply: true,
+ })) as Message;
- interaction.editReply(
- `${loc?.get('c_ping1')}: \
+ interaction.editReply(
+ `${loc?.get("c_ping1")}: \
${sent.createdTimestamp - interaction.createdTimestamp}ms
-${loc?.get('c_ping2')}: ${client.ws.ping}ms.`);
- },
+${loc?.get("c_ping2")}: ${client.ws.ping}ms.`
+ );
+ },
};
diff --git a/src/commands/misc/prep.ts b/src/commands/misc/prep.ts
index 301ed0f..9f34fb0 100644
--- a/src/commands/misc/prep.ts
+++ b/src/commands/misc/prep.ts
@@ -1,117 +1,144 @@
-import { SlashCommandBuilder } from '@discordjs/builders';
-import { ChannelType, Client, Colors, CommandInteraction, EmbedBuilder } from 'discord.js';
-import '../../modules/string';
-import { getLocale, getLocalizations } from '../../utils/locales';
-import { getFilename } from '../../utils/misc';
+import { SlashCommandBuilder } from "@discordjs/builders";
+import {
+ ChannelType,
+ Client,
+ Colors,
+ CommandInteraction,
+ EmbedBuilder,
+} from "discord.js";
+import "../../modules/string";
+import { getLocale, getLocalizations } from "../../utils/locales";
+import { getFilename } from "../../utils/misc";
export default {
- scope: () => ['807244911350906920'],
+ scope: () => ["807244911350906920"],
- data: (client: Client) => {
- const filename = getFilename(__filename);
- return new SlashCommandBuilder()
- .setName(
- filename.toLowerCase())
- .setDescription(client.locales.get(client.config.default_lang)
- ?.get(`c_${filename}_desc`) ?? '')
- .setNameLocalizations(
- getLocalizations(client, `c_${filename}_name`, true))
- .setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_desc`))
+ data: (client: Client) => {
+ const filename = getFilename(__filename);
+ return (
+ new SlashCommandBuilder()
+ .setName(filename.toLowerCase())
+ .setDescription(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${filename}_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_desc`)
+ )
- // Command option
- .addStringOption(option => option
- .setName(client.locales.get(client.config.default_lang)
- ?.get(`c_${filename}_opt1_name`) ?? '')
- .setDescription(client.locales.get(client.config.default_lang)
- ?.get(`c_${filename}_opt1_desc`) ?? '')
- .setNameLocalizations(
- getLocalizations(client, `c_${filename}_opt1_name`, true))
- .setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_opt1_desc`))
- );
- },
+ // Command option
+ .addStringOption((option) =>
+ option
+ .setName(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${filename}_opt1_name`) ?? ""
+ )
+ .setDescription(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${filename}_opt1_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_opt1_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_opt1_desc`)
+ )
+ )
+ );
+ },
- interaction: async (interaction: CommandInteraction, client: Client) => {
- const loc = getLocale(client, interaction.locale);
- const desired_cat = interaction.options.get(client
- .locales
- .get(client.config.default_lang)
- ?.get(`c_${getFilename(__filename)}_opt1_name`) ?? '')?.value as string;
+ interaction: async (interaction: CommandInteraction, client: Client) => {
+ const loc = getLocale(client, interaction.locale);
+ const desired_cat = interaction.options.get(
+ client.locales
+ .get(client.config.default_lang)
+ ?.get(`c_${getFilename(__filename)}_opt1_name`) ?? ""
+ )?.value as string;
- // If a category isn't specified
- if (!desired_cat) {
+ // If a category isn't specified
+ if (!desired_cat) {
+ // Sends a list of commands sorted into categories
+ return interaction.reply({
+ embeds: [
+ new EmbedBuilder()
+ .setColor(Colors.Blurple)
+ .setTitle(loc.get("c_prep1"))
+ .setDescription(loc.get("c_prep2")),
+ ],
+ });
+ }
- // Sends a list of commands sorted into categories
- return interaction.reply({
- embeds: [
- new EmbedBuilder()
- .setColor(Colors.Blurple)
- .setTitle(loc.get('c_prep1'))
- .setDescription(loc.get('c_prep2')),
- ],
- });
- }
+ // If a category is specified
+ const allowedCategories = ["L1", "L2", "L3", "M1", "M2"];
+ const channel = allowedCategories.includes(desired_cat);
+ if (!channel) {
+ // Category doesn't exist or is not allowed
+ return interaction.reply({
+ content: `${loc.get("c_prep3")} \`${desired_cat}\``,
+ ephemeral: true,
+ });
+ }
- // If a category is specified
- const allowedCategories = ['L1', 'L2', 'L3', 'M1', 'M2'];
- const channel = allowedCategories.includes(desired_cat);
- if (!channel) {
- // Category doesn't exist or is not allowed
- return interaction.reply({
- content: `${loc.get('c_prep3')} \`${desired_cat}\``,
- ephemeral: true,
- });
- }
+ // Send information about the command
+ const allChannel = interaction.guild?.channels.fetch();
+ 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_id = cat_to_prep.map((cat) => cat?.id);
+ const cat_to_prep_name = cat_to_prep.map((cat) => cat?.name);
- // Send information about the command
- const allChannel = interaction.guild?.channels.fetch();
- 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_id = cat_to_prep.map(cat => cat?.id);
- const cat_to_prep_name = cat_to_prep.map(cat => cat?.name);
+ // 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_name = all_channel_desired.map(
+ (c_d) => c_d?.name
+ );
- // 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_name = all_channel_desired.map(c_d => c_d?.name);
+ let desc = "";
- let desc = '';
+ const general = "général";
+ if (
+ all_channel_desired_name.filter((cdn) => cdn == general).length == 0
+ ) {
+ interaction.guild?.channels.create({
+ name: general,
+ type: 0,
+ parent: cat_to_prep_id[0],
+ });
+ desc = general + loc.get("c_prep5") + "\n";
+ }
- const general = 'général';
- if (all_channel_desired_name.filter(cdn => cdn == general).length == 0) {
- interaction.guild?.channels.create({
- name: general,
- type: 0,
- parent: cat_to_prep_id[0],
- });
- desc = general + loc.get('c_prep5') + '\n';
- }
+ const info = "informations";
+ if (all_channel_desired_name.filter((cdn) => cdn == info).length == 0) {
+ interaction.guild?.channels.create({
+ name: info,
+ type: 0,
+ parent: cat_to_prep_id[0],
+ });
- const info = 'informations';
- if (all_channel_desired_name.filter(cdn => cdn == info).length == 0) {
- interaction.guild?.channels.create({
- name: info,
- type: 0,
- parent: cat_to_prep_id[0],
- });
+ desc += "`" + info + "` " + loc.get("c_prep5") + "\n";
+ }
- desc += '`' + info + '` ' + loc.get('c_prep5') + '\n';
- }
+ if (desc == "") {
+ desc = loc.get("c_prep6");
+ }
- if (desc == '') {
- desc = loc.get('c_prep6');
- }
-
- return interaction.reply({
- embeds: [
- new EmbedBuilder()
- .setColor(Colors.Blurple)
- .setTitle(loc.get('c_prep4') + cat_to_prep_name)
- .setDescription(
- desc,
- ),
- ],
- });
- });
- },
+ return interaction.reply({
+ embeds: [
+ new EmbedBuilder()
+ .setColor(Colors.Blurple)
+ .setTitle(loc.get("c_prep4") + cat_to_prep_name)
+ .setDescription(desc),
+ ],
+ });
+ });
+ },
};
diff --git a/src/commands/misc/reminder.ts b/src/commands/misc/reminder.ts
index 70e4a53..4d61cb5 100644
--- a/src/commands/misc/reminder.ts
+++ b/src/commands/misc/reminder.ts
@@ -1,277 +1,354 @@
-import { ModalActionRowComponentBuilder, SlashCommandBuilder } from '@discordjs/builders';
-import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle } from 'discord.js';
-import { v4 as uuidv4 } from 'uuid';
-import { collect } from '../../buttons/loader';
-import { getLocale, getLocalizations } from '../../utils/locales';
-import { getFilename } from '../../utils/misc';
-import { checkOwnershipReminder, deleteReminder, embedListReminders, getReminderInfo, newReminder } from '../../utils/reminder';
+import {
+ ModalActionRowComponentBuilder,
+ SlashCommandBuilder,
+} from "@discordjs/builders";
+import {
+ ActionRowBuilder,
+ ButtonBuilder,
+ ButtonStyle,
+ ChatInputCommandInteraction,
+ Client,
+ ModalBuilder,
+ TextInputBuilder,
+ TextInputStyle,
+} from "discord.js";
+import { v4 as uuidv4 } from "uuid";
+import { collect } from "../../buttons/loader";
+import { getLocale, getLocalizations } from "../../utils/locales";
+import { getFilename } from "../../utils/misc";
+import {
+ checkOwnershipReminder,
+ deleteReminder,
+ embedListReminders,
+ getReminderInfo,
+ newReminder,
+} from "../../utils/reminder";
export default {
- scope: () => [],
+ scope: () => [],
- data: (client: Client) => {
- const filename = getFilename(__filename);
- const loc_default = client.locales.get(client.config.default_lang);
- if (!loc_default) {
- return;
- }
+ data: (client: Client) => {
+ const filename = getFilename(__filename);
+ const loc_default = client.locales.get(client.config.default_lang);
+ if (!loc_default) {
+ return;
+ }
- return new SlashCommandBuilder()
- // Command
- .setName(filename.toLowerCase())
- .setDescription(loc_default.get(`c_${filename}_desc`) ?? '')
- .setNameLocalizations(
- getLocalizations(client, `c_${filename}_name`, true)
- ).setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_desc`)
- )
+ return (
+ new SlashCommandBuilder()
+ // Command
+ .setName(filename.toLowerCase())
+ .setDescription(loc_default.get(`c_${filename}_desc`) ?? "")
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_desc`)
+ )
- // New reminder
- .addSubcommand(subcommand => subcommand
- .setName(
- loc_default.get(`c_${filename}_sub1_name`)
- ?.toLowerCase() ?? ''
- ).setDescription(
- loc_default.get(`c_${filename}_sub1_desc`) ?? ''
- ).setNameLocalizations(
- getLocalizations(client, `c_${filename}_sub1_name`, true)
- ).setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_sub1_desc`)
- )
+ // New reminder
+ .addSubcommand((subcommand) =>
+ subcommand
+ .setName(
+ loc_default.get(`c_${filename}_sub1_name`)?.toLowerCase() ?? ""
+ )
+ .setDescription(loc_default.get(`c_${filename}_sub1_desc`) ?? "")
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_sub1_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_sub1_desc`)
+ )
- // Specified Time
- .addStringOption(option => option
- .setName(
- loc_default.get(`c_${filename}_sub1_opt1_name`)
- ?.toLowerCase() ?? ''
- ).setDescription(
- loc_default.get(`c_${filename}_sub1_opt1_desc`) ?? ''
- ).setNameLocalizations(
- getLocalizations(
- client,
- `c_${filename}_sub1_opt1_name`,
- true
- )
- ).setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_sub1_opt1_desc`)
- )
- )
+ // Specified Time
+ .addStringOption((option) =>
+ option
+ .setName(
+ loc_default
+ .get(`c_${filename}_sub1_opt1_name`)
+ ?.toLowerCase() ?? ""
+ )
+ .setDescription(
+ loc_default.get(`c_${filename}_sub1_opt1_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_sub1_opt1_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_sub1_opt1_desc`)
+ )
+ )
- // Specified message (not required)
- .addStringOption(option => option
- .setName(
- loc_default.get(`c_${filename}_sub1_opt2_name`)
- ?.toLowerCase() ?? ''
- ).setDescription(
- loc_default.get(`c_${filename}_sub1_opt2_desc`) ?? ''
- ).setNameLocalizations(
- getLocalizations(
- client,
- `c_${filename}_sub1_opt2_name`,
- true
- )
- ).setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_sub1_opt2_desc`)
- )
- )
- )
+ // Specified message (not required)
+ .addStringOption((option) =>
+ option
+ .setName(
+ loc_default
+ .get(`c_${filename}_sub1_opt2_name`)
+ ?.toLowerCase() ?? ""
+ )
+ .setDescription(
+ loc_default.get(`c_${filename}_sub1_opt2_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_sub1_opt2_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_sub1_opt2_desc`)
+ )
+ )
+ )
- // List reminders
- .addSubcommand(subcommand => subcommand
- .setName(
- loc_default.get(`c_${filename}_sub2_name`)
- ?.toLowerCase() ?? ''
- ).setDescription(
- loc_default.get(`c_${filename}_sub2_desc`) ?? ''
- ).setNameLocalizations(
- getLocalizations(client, `c_${filename}_sub2_name`, true)
- ).setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_sub2_desc`)
- )
+ // List reminders
+ .addSubcommand((subcommand) =>
+ subcommand
+ .setName(
+ loc_default.get(`c_${filename}_sub2_name`)?.toLowerCase() ?? ""
+ )
+ .setDescription(loc_default.get(`c_${filename}_sub2_desc`) ?? "")
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_sub2_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_sub2_desc`)
+ )
- // User
- .addUserOption(option => option
- .setName(
- loc_default.get(`c_${filename}_sub2_opt1_name`)
- ?.toLowerCase() ?? ''
- ).setDescription(
- loc_default.get(`c_${filename}_sub2_opt1_desc`) ?? ''
- ).setNameLocalizations(
- getLocalizations(
- client,
- `c_${filename}_sub2_opt1_name`,
- true
- )
- ).setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_sub2_opt1_desc`)
- )
- )
+ // User
+ .addUserOption((option) =>
+ option
+ .setName(
+ loc_default
+ .get(`c_${filename}_sub2_opt1_name`)
+ ?.toLowerCase() ?? ""
+ )
+ .setDescription(
+ loc_default.get(`c_${filename}_sub2_opt1_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_sub2_opt1_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_sub2_opt1_desc`)
+ )
+ )
- // Page
- .addIntegerOption(option => option
- .setName(
- loc_default.get(`c_${filename}_sub2_opt2_name`)
- ?.toLowerCase() ?? ''
- ).setDescription(
- loc_default.get(`c_${filename}_sub2_opt2_desc`) ?? ''
- ).setNameLocalizations(
- getLocalizations(
- client,
- `c_${filename}_sub2_opt2_name`,
- true
- )
- ).setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_sub2_opt2_desc`)
- )
- )
- )
+ // Page
+ .addIntegerOption((option) =>
+ option
+ .setName(
+ loc_default
+ .get(`c_${filename}_sub2_opt2_name`)
+ ?.toLowerCase() ?? ""
+ )
+ .setDescription(
+ loc_default.get(`c_${filename}_sub2_opt2_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_sub2_opt2_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_sub2_opt2_desc`)
+ )
+ )
+ )
- // Delete a reminder
- .addSubcommand(subcommand => subcommand
- .setName(
- loc_default.get(`c_${filename}_sub3_name`)
- ?.toLowerCase() ?? ''
- ).setDescription(
- loc_default.get(`c_${filename}_sub3_desc`) ?? ''
- ).setNameLocalizations(
- getLocalizations(client, `c_${filename}_sub3_name`, true)
- ).setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_sub3_desc`)
- )
+ // Delete a reminder
+ .addSubcommand((subcommand) =>
+ subcommand
+ .setName(
+ loc_default.get(`c_${filename}_sub3_name`)?.toLowerCase() ?? ""
+ )
+ .setDescription(loc_default.get(`c_${filename}_sub3_desc`) ?? "")
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_sub3_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_sub3_desc`)
+ )
- // ID
- .addIntegerOption(option => option
- .setName(
- loc_default.get(`c_${filename}_sub3_opt1_name`)
- ?.toLowerCase() ?? ''
- ).setDescription(
- loc_default.get(`c_${filename}_sub3_opt1_desc`) ?? ''
- ).setNameLocalizations(
- getLocalizations(
- client,
- `c_${filename}_sub3_opt1_name`,
- true
- )
- ).setDescriptionLocalizations(
- getLocalizations(client, `c_${filename}_sub3_opt1_desc`)
- ).setRequired(true)
- ),
- );
- },
+ // ID
+ .addIntegerOption((option) =>
+ option
+ .setName(
+ loc_default
+ .get(`c_${filename}_sub3_opt1_name`)
+ ?.toLowerCase() ?? ""
+ )
+ .setDescription(
+ loc_default.get(`c_${filename}_sub3_opt1_desc`) ?? ""
+ )
+ .setNameLocalizations(
+ getLocalizations(client, `c_${filename}_sub3_opt1_name`, true)
+ )
+ .setDescriptionLocalizations(
+ getLocalizations(client, `c_${filename}_sub3_opt1_desc`)
+ )
+ .setRequired(true)
+ )
+ )
+ );
+ },
- interaction: async (interaction: ChatInputCommandInteraction, client: Client) => {
- const loc_default = client.locales.get(client.config.default_lang);
- const filename = getFilename(__filename);
- const loc = getLocale(client, interaction.locale);
+ interaction: async (
+ interaction: ChatInputCommandInteraction,
+ client: Client
+ ) => {
+ const loc_default = client.locales.get(client.config.default_lang);
+ const filename = getFilename(__filename);
+ const loc = getLocale(client, interaction.locale);
- const subcommand = interaction.options.getSubcommand();
- switch (subcommand) {
- // New reminder
- case loc_default?.get(`c_${filename}_sub1_name`)
- ?.toLowerCase() ?? '': {
+ const subcommand = interaction.options.getSubcommand();
+ switch (subcommand) {
+ // New reminder
+ case loc_default?.get(`c_${filename}_sub1_name`)?.toLowerCase() ?? "": {
+ // If time is already renseigned
+ const time = interaction.options.getString(
+ loc_default?.get(`c_${filename}_sub1_opt1_name`) as string
+ );
+ if (time != null) {
+ // Use the cli because we already have enough data
+ return newReminder(client, time, {
+ locale: interaction.locale,
+ message: interaction.options.getString(
+ loc_default?.get(`c_${filename}_sub1_opt2_name`) as string
+ ),
+ createdAt: interaction.createdAt.getTime(),
+ channelId: interaction.channelId,
+ userId: interaction.user.id,
+ guildId: interaction.guildId,
+ }).then((msg) =>
+ interaction.reply({
+ content: msg as string,
+ ephemeral: true,
+ })
+ );
+ } else {
+ // Show modal to user to get at least the time
+ const modal = new ModalBuilder()
+ .setCustomId("reminderGUI")
+ .setTitle(loc.get(`c_${filename}_name`).capitalize());
- // If time is already renseigned
- const time = interaction.options.getString(loc_default?.get(`c_${filename}_sub1_opt1_name`) as string);
- if (time != null) {
- // Use the cli because we already have enough data
- return newReminder(client, time, {
- locale: interaction.locale,
- message: interaction.options.getString(loc_default?.get(`c_${filename}_sub1_opt2_name`) as string),
- createdAt: interaction.createdAt.getTime(),
- channelId: interaction.channelId,
- userId: interaction.user.id,
- guildId: interaction.guildId,
- }).then((msg) => interaction.reply({
- content: msg as string,
- ephemeral: true,
- }));
- } else {
- // Show modal to user to get at least the time
- const modal = new ModalBuilder()
- .setCustomId('reminderGUI')
- .setTitle(loc.get(`c_${filename}_name`).capitalize());
+ const timeGUI = new TextInputBuilder()
+ .setCustomId("reminderGUI-time")
+ .setLabel(loc.get(`c_${filename}_sub1_opt1_name`).capitalize())
+ .setStyle(TextInputStyle.Short)
+ .setPlaceholder("1h")
+ .setRequired(true);
- const timeGUI = new TextInputBuilder()
- .setCustomId('reminderGUI-time')
- .setLabel(loc.get(`c_${filename}_sub1_opt1_name`).capitalize())
- .setStyle(TextInputStyle.Short)
- .setPlaceholder('1h')
- .setRequired(true);
+ const messageGUI = new TextInputBuilder()
+ .setCustomId("reminderGUI-message")
+ .setLabel(loc.get(`c_${filename}_sub1_opt2_name`).capitalize())
+ .setStyle(TextInputStyle.Paragraph)
+ .setPlaceholder(loc.get(`c_${filename}_sub1_opt2_desc`))
+ .setRequired(false);
- const messageGUI = new TextInputBuilder()
- .setCustomId('reminderGUI-message')
- .setLabel(loc.get(`c_${filename}_sub1_opt2_name`).capitalize())
- .setStyle(TextInputStyle.Paragraph)
- .setPlaceholder(loc.get(`c_${filename}_sub1_opt2_desc`))
- .setRequired(false);
+ modal.addComponents(
+ new ActionRowBuilder().addComponents(
+ timeGUI
+ ),
+ new ActionRowBuilder().addComponents(
+ messageGUI
+ )
+ );
- modal.addComponents(
- new ActionRowBuilder().addComponents(timeGUI),
- new ActionRowBuilder().addComponents(messageGUI)
- );
+ return interaction.showModal(modal);
+ }
+ }
+ // List reminders
+ case loc_default?.get(`c_${filename}_sub2_name`)?.toLowerCase() ?? "": {
+ // Which user to show
+ let user = interaction.options.getUser(
+ loc_default?.get(`c_${filename}_sub2_opt1_name`) as string
+ );
+ if (user == null) {
+ user = interaction.user;
+ }
- return interaction.showModal(modal);
- }
- }
- // List reminders
- case loc_default?.get(`c_${filename}_sub2_name`)
- ?.toLowerCase() ?? '': {
- // Which user to show
- let user = interaction.options.getUser(loc_default?.get(`c_${filename}_sub2_opt1_name`) as string);
- if (user == null) {
- user = interaction.user;
- }
+ const page =
+ interaction.options.getInteger(
+ loc_default?.get(`c_${filename}_sub2_opt2_name`) as string
+ ) ?? 1;
+ const list = await embedListReminders(
+ client,
+ user,
+ interaction.guildId,
+ page,
+ interaction.locale
+ );
- const page = interaction.options.getInteger(loc_default?.get(`c_${filename}_sub2_opt2_name`) as string) ?? 1;
- const list = await embedListReminders(client, user, interaction.guildId, page, interaction.locale);
+ const idPrec = "reminderList-prec_" + uuidv4();
+ const idNext = "reminderList-next_" + uuidv4();
+ const row = new ActionRowBuilder()
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId(idPrec)
+ .setLabel(loc.get(`c_${filename}12`))
+ .setStyle(ButtonStyle.Primary)
+ )
+ .addComponents(
+ new ButtonBuilder()
+ .setCustomId(idNext)
+ .setLabel(loc.get(`c_${filename}13`))
+ .setStyle(ButtonStyle.Primary)
+ );
- const idPrec = 'reminderList-prec_' + uuidv4();
- const idNext = 'reminderList-next_' + uuidv4();
- const row = new ActionRowBuilder()
- .addComponents(
- new ButtonBuilder()
- .setCustomId(idPrec)
- .setLabel(loc.get(`c_${filename}12`))
- .setStyle(ButtonStyle.Primary))
- .addComponents(
- new ButtonBuilder()
- .setCustomId(idNext)
- .setLabel(loc.get(`c_${filename}13`))
- .setStyle(ButtonStyle.Primary),
- );
+ // Buttons interactions
+ collect(client, interaction, idPrec);
+ collect(client, interaction, idNext);
- // Buttons interactions
- collect(client, interaction, idPrec);
- collect(client, interaction, idNext);
+ return await interaction.reply({
+ ephemeral: true,
+ embeds: [list],
+ components: [row],
+ });
+ }
+ // Delete a reminder
+ case loc_default?.get(`c_${filename}_sub3_name`)?.toLowerCase() ?? "": {
+ const id = interaction.options.getInteger(
+ loc_default?.get(`c_${filename}_sub3_opt1_name`) as string
+ );
+ if (id === null) {
+ return interaction.reply({
+ content: loc.get(`c_${filename}2`),
+ ephemeral: true,
+ });
+ }
- return await interaction.reply({ ephemeral: true, embeds: [list], components: [row] });
- }
- // Delete a reminder
- case loc_default?.get(`c_${filename}_sub3_name`)
- ?.toLowerCase() ?? '': {
- const id = interaction.options.getInteger(loc_default?.get(`c_${filename}_sub3_opt1_name`) as string);
- if (id === null) {
- return interaction.reply({ content: loc.get(`c_${filename}2`), ephemeral: true });
- }
+ // Check if the ID exists and belongs to the user
+ if (
+ await checkOwnershipReminder(
+ client,
+ id,
+ interaction.user.id,
+ interaction.guildId ?? "0"
+ )
+ ) {
+ return interaction.reply({
+ content: loc.get(`c_${filename}3`),
+ ephemeral: true,
+ });
+ }
- // Check if the ID exists and belongs to the user
- if (await checkOwnershipReminder(client, id, interaction.user.id, interaction.guildId ?? '0')) {
- return interaction.reply({ content: loc.get(`c_${filename}3`), ephemeral: true });
- }
+ // Stop timeout
+ const reminderInfo = await getReminderInfo(client, id);
+ clearTimeout(reminderInfo.timeout_id);
- // Stop timeout
- const reminderInfo = await getReminderInfo(client, id);
- clearTimeout(reminderInfo.timeout_id);
-
- // Delete from database
- return deleteReminder(client, reminderInfo.creation_date, reminderInfo.user_id)
- .then(() => interaction.reply({ content: `Reminder **#${id}** supprimé !`, ephemeral: true }));
-
- }
- default: {
- console.error(`${__filename}: unknown subcommand (${subcommand})`);
- break;
- }
- }
- },
+ // Delete from database
+ return deleteReminder(
+ client,
+ reminderInfo.creation_date,
+ reminderInfo.user_id
+ ).then(() =>
+ interaction.reply({
+ content: `Reminder **#${id}** supprimé !`,
+ ephemeral: true,
+ })
+ );
+ }
+ default: {
+ console.error(`${__filename}: unknown subcommand (${subcommand})`);
+ break;
+ }
+ }
+ },
};
diff --git a/src/events/client/ready.ts b/src/events/client/ready.ts
index 764a4bd..f645667 100644
--- a/src/events/client/ready.ts
+++ b/src/events/client/ready.ts
@@ -1,59 +1,78 @@
-import { Client } from 'discord.js';
-import { logStart } from '../../utils/misc';
-import { dbReminder, deleteReminder, infoReminder, OptionReminder, sendReminder, setTimeoutReminder, updateReminder } from '../../utils/reminder';
+import { Client } from "discord.js";
+import { logStart } from "../../utils/misc";
+import {
+ dbReminder,
+ deleteReminder,
+ infoReminder,
+ OptionReminder,
+ sendReminder,
+ setTimeoutReminder,
+ updateReminder,
+} from "../../utils/reminder";
export const once = true;
/** https://discord.js.org/#/docs/discord.js/main/class/Client?scrollTo=e-ready */
export default async (client: Client) => {
- console.log(logStart('Connection', true));
+ console.log(logStart("Connection", true));
- // Restart all the timeout about reminders here
- new Promise((ok, ko) => {
- // Fetch all reminders
- client.db.all('SELECT * FROM reminder', [], (err, row) => {
- if (err) {
- ko(err);
- }
+ // Restart all the timeout about reminders here
+ new Promise((ok, ko) => {
+ // Fetch all reminders
+ client.db.all("SELECT * FROM reminder", [], (err, row) => {
+ if (err) {
+ ko(err);
+ }
- // Send all the current reminders
- ok(row);
- });
- }).then((data) => {
- const now = Date.now();
- (data as dbReminder[]).forEach((element) => {
- const info = {
- locale: element.locale,
- message: element.data,
- createdAt: Number(element.creation_date),
- channelId: `${element.channel_id}`,
- userId: `${element.user_id}`,
- guildId: `${element.guild_id}`,
- } as infoReminder;
+ // Send all the current reminders
+ ok(row);
+ });
+ })
+ .then((data) => {
+ const now = Date.now();
+ (data as dbReminder[]).forEach((element) => {
+ const info = {
+ locale: element.locale,
+ message: element.data,
+ createdAt: Number(element.creation_date),
+ channelId: `${element.channel_id}`,
+ userId: `${element.user_id}`,
+ guildId: `${element.guild_id}`,
+ } as infoReminder;
- if (element.expiration_date <= now) {
- // Reminder expired
- deleteReminder(client, element.creation_date, `${element.user_id}`).then((res) => {
- if (res != true) {
- throw res;
- }
- });
+ if (element.expiration_date <= now) {
+ // Reminder expired
+ deleteReminder(
+ client,
+ element.creation_date,
+ `${element.user_id}`
+ ).then((res) => {
+ if (res != true) {
+ throw res;
+ }
+ });
- sendReminder(client, info, element.option_id as OptionReminder);
- } else {
- // Restart timeout
- const timeoutId = setTimeoutReminder(client, info, element.option_id, (element.expiration_date - now) / 1000);
+ sendReminder(client, info, element.option_id as OptionReminder);
+ } else {
+ // Restart timeout
+ const timeoutId = setTimeoutReminder(
+ client,
+ info,
+ element.option_id,
+ (element.expiration_date - now) / 1000
+ );
- // Update timeout in database
- element.timeout_id = String(timeoutId);
- updateReminder(client, element).then((res) => {
- if (res != true) {
- throw res;
- }
- });
- }
- });
- }).catch(err => {
- throw err;
- });
+ // Update timeout in database
+ element.timeout_id = String(timeoutId);
+ updateReminder(client, element).then((res) => {
+ if (res != true) {
+ throw res;
+ }
+ });
+ }
+ });
+ })
+ .catch((err) => {
+ throw err;
+ });
};
diff --git a/src/events/interactions/interactionCreate.ts b/src/events/interactions/interactionCreate.ts
index cef1087..1e1e5b5 100644
--- a/src/events/interactions/interactionCreate.ts
+++ b/src/events/interactions/interactionCreate.ts
@@ -1,35 +1,35 @@
-import { Client, Interaction, InteractionType } from 'discord.js';
-import { getLocale } from '../../utils/locales';
+import { Client, Interaction, InteractionType } from "discord.js";
+import { getLocale } from "../../utils/locales";
/** https://discord.js.org/#/docs/discord.js/main/class/Client?scrollTo=e-interactionCreate */
export default (interaction: Interaction, client: Client) => {
- const loc = getLocale(client, interaction.locale);
- switch (interaction.type) {
- case InteractionType.ApplicationCommand: {
- const command = client.commands.list.get(interaction.commandName);
- if (!command) {
- return interaction.reply({
- content: loc.get('e_interacreate_no_command'),
- ephemeral: true,
- });
- }
+ const loc = getLocale(client, interaction.locale);
+ switch (interaction.type) {
+ case InteractionType.ApplicationCommand: {
+ const command = client.commands.list.get(interaction.commandName);
+ if (!command) {
+ return interaction.reply({
+ content: loc.get("e_interacreate_no_command"),
+ ephemeral: true,
+ });
+ }
- return command.interaction(interaction, client);
- }
+ return command.interaction(interaction, client);
+ }
- case InteractionType.ModalSubmit: {
- const modal = client.modals.list.get(interaction.customId);
- if (!modal) {
- return interaction.reply({
- content: loc.get('e_interacreate_no_modal'),
- ephemeral: true,
- });
- }
+ case InteractionType.ModalSubmit: {
+ const modal = client.modals.list.get(interaction.customId);
+ if (!modal) {
+ return interaction.reply({
+ content: loc.get("e_interacreate_no_modal"),
+ ephemeral: true,
+ });
+ }
- return modal.interaction(interaction, client);
- }
+ return modal.interaction(interaction, client);
+ }
- default:
- break;
- }
+ default:
+ break;
+ }
};
diff --git a/src/events/loader.ts b/src/events/loader.ts
index e8b2a69..9446bbf 100644
--- a/src/events/loader.ts
+++ b/src/events/loader.ts
@@ -1,40 +1,41 @@
-import { Client } from 'discord.js';
-import { readdir } from 'fs/promises';
+import { Client } from "discord.js";
+import { readdir } from "fs/promises";
/** Load all the events. */
export default async (client: Client) => {
- const events_categories = (await readdir(__dirname))
- .filter(element => !element.endsWith('.js') && !element.endsWith('.ts'));
+ const events_categories = (await readdir(__dirname)).filter(
+ (element) => !element.endsWith(".js") && !element.endsWith(".ts")
+ );
- events_categories.forEach(async event_category => {
- // Retrieve events
- const events = await readdir(`${__dirname}/${event_category}`);
+ events_categories.forEach(async (event_category) => {
+ // Retrieve events
+ const events = await readdir(`${__dirname}/${event_category}`);
- // Load them into the client
- Promise.all(
- events.map(async event_file => {
- const { once, default: execute } = await import(
- `../events/${event_category}/${event_file}`
- );
+ // Load them into the client
+ Promise.all(
+ events.map(async (event_file) => {
+ const { once, default: execute } = await import(
+ `../events/${event_category}/${event_file}`
+ );
- // Remove extension
- // TODO: use utils functions
- const event_type_ext = event_file.split('.');
- const ext = event_type_ext.pop();
- if (!(ext === 'js' || ext === 'ts')) {
- throw `Unknown file in ${event_category}: ${event_file}`;
- }
- const event_type = event_type_ext.join('.');
+ // Remove extension
+ // TODO: use utils functions
+ const event_type_ext = event_file.split(".");
+ const ext = event_type_ext.pop();
+ if (!(ext === "js" || ext === "ts")) {
+ throw `Unknown file in ${event_category}: ${event_file}`;
+ }
+ const event_type = event_type_ext.join(".");
- if (once) {
- return client.once(event_type, (...args) => {
- execute(...args, client);
- });
- }
- return client.on(event_type, (...args) => {
- execute(...args, client);
- });
- }),
- );
- });
+ if (once) {
+ return client.once(event_type, (...args) => {
+ execute(...args, client);
+ });
+ }
+ return client.on(event_type, (...args) => {
+ execute(...args, client);
+ });
+ })
+ );
+ });
};
diff --git a/src/events/message/messageCreate.ts b/src/events/message/messageCreate.ts
index 1dafda4..5d1527f 100644
--- a/src/events/message/messageCreate.ts
+++ b/src/events/message/messageCreate.ts
@@ -1,183 +1,191 @@
-import { Client, GuildMember, Message, TextBasedChannel, EmbedBuilder } from 'discord.js';
-import { getLocale } from '../../utils/locales';
-import { isImage, userWithNickname } from '../../utils/misc';
-import { showDate } from '../../utils/time';
+import {
+ Client,
+ GuildMember,
+ Message,
+ TextBasedChannel,
+ EmbedBuilder,
+} from "discord.js";
+import { getLocale } from "../../utils/locales";
+import { isImage, userWithNickname } from "../../utils/misc";
+import { showDate } from "../../utils/time";
/** https://discord.js.org/#/docs/discord.js/main/class/Client?scrollTo=e-messageCreate */
export default async (message: Message, client: Client) => {
- // Ignore message if
- if (
- // Author is a bot
- message.author.bot ||
- // Author is Discord
- message.author.system ||
- // Message isn't a message
- message.system ||
- // Message is in PM (future-proof if we add Intents.FLAGS.DIRECT_MESSAGES)
- !message.guild ||
- // Guild is offline
- !message.guild.available
- ) {
- return;
- }
+ // Ignore message if
+ if (
+ // Author is a bot
+ message.author.bot ||
+ // Author is Discord
+ message.author.system ||
+ // Message isn't a message
+ message.system ||
+ // Message is in PM (future-proof if we add Intents.FLAGS.DIRECT_MESSAGES)
+ !message.guild ||
+ // Guild is offline
+ !message.guild.available
+ ) {
+ return;
+ }
- /* Citation */
- const regex = 'https://(?:canary\\.|ptb\\.)?discord(?:app)?\\.com/channels/(\\d{17,19})/(\\d{17,19})/(\\d{17,19})';
- const urls = message.content.match(new RegExp(regex, 'g'));
+ /* Citation */
+ const regex =
+ "https://(?:canary\\.|ptb\\.)?discord(?:app)?\\.com/channels/(\\d{17,19})/(\\d{17,19})/(\\d{17,19})";
+ const urls = message.content.match(new RegExp(regex, "g"));
- // Ignore message if there is no URLs
- if (!urls) {
- return;
- }
+ // Ignore message if there is no URLs
+ if (!urls) {
+ return;
+ }
- const messages = (
- await Promise.all(
- urls.reduce(
- (data: {
- message_id: string;
- channel: TextBasedChannel;
- }[] = [], match) => {
- const [,
- guild_id,
- channel_id,
- message_id,
- ] = new RegExp(regex).exec(match) as RegExpExecArray;
+ const messages = (
+ await Promise.all(
+ urls
+ .reduce(
+ (
+ data: {
+ message_id: string;
+ channel: TextBasedChannel;
+ }[] = [],
+ match
+ ) => {
+ const [, guild_id, channel_id, message_id] = new RegExp(regex).exec(
+ match
+ ) as RegExpExecArray;
- // If message posted in another guild
- if (guild_id !== message.guild?.id) {
- return data;
- }
+ // If message posted in another guild
+ if (guild_id !== message.guild?.id) {
+ return data;
+ }
- const channel =
- message.guild.channels.cache.get(channel_id) as TextBasedChannel;
+ const channel = message.guild.channels.cache.get(
+ channel_id
+ ) as TextBasedChannel;
- // If channel doesn't exist in the guild and isn't text
- if (!channel) {
- return data;
- }
+ // If channel doesn't exist in the guild and isn't text
+ if (!channel) {
+ return data;
+ }
- data.push({ message_id, channel });
+ data.push({ message_id, channel });
- return data;
- }, []
- ).map(async ({ message_id, channel }) => {
- const quoted_message = await channel.messages
- .fetch(message_id)
- .catch(() => undefined);
+ return data;
+ },
+ []
+ )
+ .map(async ({ message_id, channel }) => {
+ const quoted_message = await channel.messages
+ .fetch(message_id)
+ .catch(() => undefined);
- // If message doesn't exist or empty
- if (!quoted_message || (
- !quoted_message.content &&
- quoted_message.attachments.size == 0)
- ) {
- return;
- }
+ // If message doesn't exist or empty
+ if (
+ !quoted_message ||
+ (!quoted_message.content && quoted_message.attachments.size == 0)
+ ) {
+ return;
+ }
- return quoted_message;
- })
- )
- // Remove undefined elements
- ).filter(Boolean);
+ return quoted_message;
+ })
+ )
+ )
+ // Remove undefined elements
+ .filter(Boolean);
- const loc = getLocale(client, client.config.default_lang);
+ const loc = getLocale(client, client.config.default_lang);
- // Remove duplicates then map the quoted posts
- [...new Set(messages)].map(quoted_post => {
- const embed = new EmbedBuilder()
- .setColor('#2f3136')
- .setAuthor({
- name: 'Citation',
- iconURL: quoted_post?.author.displayAvatarURL(),
- });
+ // Remove duplicates then map the quoted posts
+ [...new Set(messages)].map((quoted_post) => {
+ const embed = new EmbedBuilder().setColor("#2f3136").setAuthor({
+ name: "Citation",
+ iconURL: quoted_post?.author.displayAvatarURL(),
+ });
- // Handle attachments
- if (quoted_post?.attachments.size !== 0) {
- if (quoted_post?.attachments.size === 1 && isImage(
- quoted_post.attachments.first()?.name as string
- )) {
- // Only contains one image
- embed.setImage(quoted_post.attachments.first()?.url as string);
- } else {
- // Contains more than one image and/or other files
- let files = '';
- quoted_post?.attachments.forEach(file => files +=
- `[${file.name}](${file.url}), `
- );
- embed.addFields({
- // TODO: Don't pluralize when there is only one file.
- // TODO: Locales
- name: 'Fichiers joints',
- // TODO: Check if don't exceed char limit, if yes, split
- // files into multiples field.
- value: `${files.slice(0, -2)}.`,
- });
- }
- }
+ // Handle attachments
+ if (quoted_post?.attachments.size !== 0) {
+ if (
+ quoted_post?.attachments.size === 1 &&
+ isImage(quoted_post.attachments.first()?.name as string)
+ ) {
+ // Only contains one image
+ embed.setImage(quoted_post.attachments.first()?.url as string);
+ } else {
+ // Contains more than one image and/or other files
+ let files = "";
+ quoted_post?.attachments.forEach(
+ (file) => (files += `[${file.name}](${file.url}), `)
+ );
+ embed.addFields({
+ // TODO: Don't pluralize when there is only one file.
+ // TODO: Locales
+ name: "Fichiers joints",
+ // TODO: Check if don't exceed char limit, if yes, split
+ // files into multiples field.
+ value: `${files.slice(0, -2)}.`,
+ });
+ }
+ }
- // Description as post content
- embed.setDescription(quoted_post?.content ?? '');
+ // Description as post content
+ embed.setDescription(quoted_post?.content ?? "");
- // Footer
- let footer = `Posté le ${showDate(
- client.config.default_lang,
- loc,
- quoted_post?.createdAt as Date
- )}`;
- if (quoted_post?.editedAt) {
- footer += ` et modifié le ${showDate(
- client.config.default_lang,
- loc,
- quoted_post.editedAt
- )}`;
- }
+ // Footer
+ let footer = `Posté le ${showDate(
+ client.config.default_lang,
+ loc,
+ quoted_post?.createdAt as Date
+ )}`;
+ if (quoted_post?.editedAt) {
+ footer += ` et modifié le ${showDate(
+ client.config.default_lang,
+ loc,
+ quoted_post.editedAt
+ )}`;
+ }
- let author = 'Auteur';
- if (message.author == quoted_post?.author) {
- author += ' & Citateur';
- } else {
- footer += `\nCité par ${userWithNickname(
- message.member as GuildMember
- ) ?? '?'} le ${showDate(
- client.config.default_lang,
- loc,
- message.createdAt
- )}`;
- }
+ let author = "Auteur";
+ if (message.author == quoted_post?.author) {
+ author += " & Citateur";
+ } else {
+ footer += `\nCité par ${
+ userWithNickname(message.member as GuildMember) ?? "?"
+ } le ${showDate(client.config.default_lang, loc, message.createdAt)}`;
+ }
- embed.setFooter({
- text: footer,
- iconURL: message.author.avatarURL() ?? undefined,
- });
+ embed.setFooter({
+ text: footer,
+ iconURL: message.author.avatarURL() ?? undefined,
+ });
- // Location/author of the quoted post
- embed.addFields(
- {
- name: author,
- value: `${quoted_post?.author}`,
- inline: true,
- },
- {
- name: 'Message',
- value: `${quoted_post?.channel} - [Lien Message](${quoted_post?.url})`,
- inline: true,
- }
- );
+ // Location/author of the quoted post
+ embed.addFields(
+ {
+ name: author,
+ value: `${quoted_post?.author}`,
+ inline: true,
+ },
+ {
+ name: "Message",
+ value: `${quoted_post?.channel} - [Lien Message](${quoted_post?.url})`,
+ inline: true,
+ }
+ );
- // Delete source message if no content when removing links
- if (
- !message.content.replace(new RegExp(regex, 'g'), '').trim() &&
- messages.length === urls.length &&
- !message.mentions.repliedUser
- ) {
- message.delete();
- return message.channel.send({ embeds: [embed] });
- } else {
- return message.reply({
- embeds: [embed],
- allowedMentions: {
- repliedUser: false,
- },
- });
- }
- });
+ // Delete source message if no content when removing links
+ if (
+ !message.content.replace(new RegExp(regex, "g"), "").trim() &&
+ messages.length === urls.length &&
+ !message.mentions.repliedUser
+ ) {
+ message.delete();
+ return message.channel.send({ embeds: [embed] });
+ } else {
+ return message.reply({
+ embeds: [embed],
+ allowedMentions: {
+ repliedUser: false,
+ },
+ });
+ }
+ });
};
diff --git a/src/index.ts b/src/index.ts
index 7ce6835..0fa3d81 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,78 +1,80 @@
-import loadClient, { quit } from './utils/client';
-import loadEvents from './events/loader';
-import loadModals from './modals/loader';
-import loadButtons from './buttons/loader';
-import loadCommands from './commands/loader';
+import loadClient, { quit } from "./utils/client";
+import loadEvents from "./events/loader";
+import loadModals from "./modals/loader";
+import loadButtons from "./buttons/loader";
+import loadCommands from "./commands/loader";
-import { logStart } from './utils/misc';
+import { logStart } from "./utils/misc";
/** Run the bot. */
const run = async () => {
- console.log('Starting Botanique...');
+ console.log("Starting Botanique...");
- // Load .env if not in prod
- if (process.env.NODE_ENV !== 'production') {
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- (await import('dotenv')).config({ path: './config/.env' });
- }
+ // Load .env if not in prod
+ if (process.env.NODE_ENV !== "production") {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ (await import("dotenv")).config({ path: "./config/.env" });
+ }
- // Client Discord.JS
- const client_name = 'Client';
- await loadClient()
- .then(async client => {
- // Events Discord.JS
- const events_name = 'Events';
- await loadEvents(client)
- .then(() => console.log(logStart(events_name, true)))
- .catch((err) => {
- console.error(err);
- throw logStart(events_name, false);
- });
+ // Client Discord.JS
+ const client_name = "Client";
+ await loadClient()
+ .then(async (client) => {
+ // Events Discord.JS
+ const events_name = "Events";
+ await loadEvents(client)
+ .then(() => console.log(logStart(events_name, true)))
+ .catch((err) => {
+ console.error(err);
+ throw logStart(events_name, false);
+ });
- // Connect the bot to Discord.com
- await client.login(client.config.token_discord);
+ // Connect the bot to Discord.com
+ await client.login(client.config.token_discord);
- // Modals Discord.JS
- const modals_name = 'Modals';
- await loadModals(client)
- .then(() => console.log(logStart(modals_name, true)))
- .catch((err) => {
- console.error(err);
- throw logStart(modals_name, false);
- });
+ // Modals Discord.JS
+ const modals_name = "Modals";
+ await loadModals(client)
+ .then(() => console.log(logStart(modals_name, true)))
+ .catch((err) => {
+ console.error(err);
+ throw logStart(modals_name, false);
+ });
- // Buttons Discord.JS
- const buttons_name = 'Buttons';
- await loadButtons(client)
- .then(() => console.log(logStart(buttons_name, true)))
- .catch((err) => {
- console.error(err);
- throw logStart(buttons_name, false);
- });
+ // Buttons Discord.JS
+ const buttons_name = "Buttons";
+ await loadButtons(client)
+ .then(() => console.log(logStart(buttons_name, true)))
+ .catch((err) => {
+ console.error(err);
+ throw logStart(buttons_name, false);
+ });
- // Commands Slash Discord.JS
- const commands_name = 'Commands';
- await loadCommands(client)
- .then(() => console.log(logStart(commands_name, true)))
- .catch((err) => {
- console.error(err);
- throw logStart(commands_name, false);
- });
+ // Commands Slash Discord.JS
+ const commands_name = "Commands";
+ await loadCommands(client)
+ .then(() => console.log(logStart(commands_name, true)))
+ .catch((err) => {
+ console.error(err);
+ throw logStart(commands_name, false);
+ });
- console.log(logStart(client_name, true));
- console.log(`Botanique "${client.user?.username}" v${client.config.version} started!`);
+ console.log(logStart(client_name, true));
+ console.log(
+ `Botanique "${client.user?.username}" v${client.config.version} started!`
+ );
- // ^C
- process.on('SIGINT', () => quit(client));
+ // ^C
+ process.on("SIGINT", () => quit(client));
- // Container force closed
- process.on('SIGTERM', () => quit(client));
- })
- .catch((err) => {
- console.error(err);
- throw logStart(client_name, false);
- });
+ // Container force closed
+ process.on("SIGTERM", () => quit(client));
+ })
+ .catch((err) => {
+ console.error(err);
+ throw logStart(client_name, false);
+ });
};
-run().catch(error => console.error(error));
+run().catch((error) => console.error(error));
diff --git a/src/locales/en-US.json b/src/locales/en-US.json
index 2ed735a..44da063 100644
--- a/src/locales/en-US.json
+++ b/src/locales/en-US.json
@@ -1,18 +1,18 @@
{
- "e_interacreate_no_command": "Sorry, the command probably no longer exists...",
+ "e_interacreate_no_command": "Sorry, the command probably no longer exists...",
- "c_ping_name": "Ping",
- "c_ping_desc": "Pong!",
- "c_ping1": "Roundtrip latency",
- "c_ping2": "Websocket heartbeat",
+ "c_ping_name": "Ping",
+ "c_ping_desc": "Pong!",
+ "c_ping1": "Roundtrip latency",
+ "c_ping2": "Websocket heartbeat",
- "c_help_name": "Help",
- "c_help_desc": "Informations about commands",
- "c_help_opt1_name": "command",
- "c_help_opt1_desc": "Command wanted in depth.",
- "c_help1": "List of categories and associated commands",
- "c_help2": "`/help ` to get more information about a command.",
- "c_help3": "Can't find :",
+ "c_help_name": "Help",
+ "c_help_desc": "Informations about commands",
+ "c_help_opt1_name": "command",
+ "c_help_opt1_desc": "Command wanted in depth.",
+ "c_help1": "List of categories and associated commands",
+ "c_help2": "`/help ` to get more information about a command.",
+ "c_help3": "Can't find :",
- "u_time_at": "at"
+ "u_time_at": "at"
}
diff --git a/src/locales/fr.json b/src/locales/fr.json
index 05a1d16..81a30da 100644
--- a/src/locales/fr.json
+++ b/src/locales/fr.json
@@ -1,80 +1,80 @@
{
- "e_interacreate_no_command": "Désolé, la commande n'existe plus...",
- "e_interacreate_no_modal": "Désolé, le modèle n'existe plus...",
- "e_interacreate_no_button": "Désolé, le bouton n'existe plus...",
+ "e_interacreate_no_command": "Désolé, la commande n'existe plus...",
+ "e_interacreate_no_modal": "Désolé, le modèle n'existe plus...",
+ "e_interacreate_no_button": "Désolé, le bouton n'existe plus...",
- "c_ping_name": "Ping",
- "c_ping_desc": "Pong!",
- "c_ping1": "Latence totale",
- "c_ping2": "Latence du Websocket",
+ "c_ping_name": "Ping",
+ "c_ping_desc": "Pong!",
+ "c_ping1": "Latence totale",
+ "c_ping2": "Latence du Websocket",
- "c_help_name": "Aide",
- "c_help_desc": "Informations sur les commandes",
- "c_help_opt1_name": "commande",
- "c_help_opt1_desc": "Commande voulu en détail.",
- "c_help1": "Liste des catégories et des commandes associées",
- "c_help2": "`/help ` pour obtenir plus d'informations sur une commande.",
- "c_help3": "Impossible de trouver :",
+ "c_help_name": "Aide",
+ "c_help_desc": "Informations sur les commandes",
+ "c_help_opt1_name": "commande",
+ "c_help_opt1_desc": "Commande voulu en détail.",
+ "c_help1": "Liste des catégories et des commandes associées",
+ "c_help2": "`/help ` pour obtenir plus d'informations sur une commande.",
+ "c_help3": "Impossible de trouver :",
- "c_archive_name": "Nettoyer",
- "c_archive_desc": "Nettoyage pour le passage à niveau",
- "c_archive_opt1_name": "catégorie",
- "c_archive_opt1_desc": "Nom de la catégorie à nettoyer",
- "c_archive1": "Liste des catégories soumis au nettoyage",
- "c_archive2": "`L1`, `L2`, `L3`, `M1`, `M2`",
- "c_archive3": "Impossible de trouver/nettoyer le salon :",
- "c_archive4": "Liste des salons archivés de la catégorie",
- "c_archive5": "vers",
- "c_archive6": "Nettoyage",
- "c_archive7": "Catégorie déjà nettoyée",
+ "c_archive_name": "Nettoyer",
+ "c_archive_desc": "Nettoyage pour le passage à niveau",
+ "c_archive_opt1_name": "catégorie",
+ "c_archive_opt1_desc": "Nom de la catégorie à nettoyer",
+ "c_archive1": "Liste des catégories soumis au nettoyage",
+ "c_archive2": "`L1`, `L2`, `L3`, `M1`, `M2`",
+ "c_archive3": "Impossible de trouver/nettoyer le salon :",
+ "c_archive4": "Liste des salons archivés de la catégorie",
+ "c_archive5": "vers",
+ "c_archive6": "Nettoyage",
+ "c_archive7": "Catégorie déjà nettoyée",
- "c_prep_name": "Préparation",
- "c_prep_desc": "Préparation des salons généraux pour la nouvelle année",
- "c_prep_opt1_name": "année",
- "c_prep_opt1_desc": "Nom de l'année à préparer'",
- "c_prep1": "Liste des catégories soumis à la préparation",
- "c_prep2": "`L1`, `L2`, `L3`, `M1`, `M2`",
- "c_prep3": "Impossible de trouver/nettoyer le salon :",
- "c_prep4": "Listes des Salons préparés `",
- "c_prep5": "créé",
- "c_prep6": "Pas besoin de préparation",
+ "c_prep_name": "Préparation",
+ "c_prep_desc": "Préparation des salons généraux pour la nouvelle année",
+ "c_prep_opt1_name": "année",
+ "c_prep_opt1_desc": "Nom de l'année à préparer'",
+ "c_prep1": "Liste des catégories soumis à la préparation",
+ "c_prep2": "`L1`, `L2`, `L3`, `M1`, `M2`",
+ "c_prep3": "Impossible de trouver/nettoyer le salon :",
+ "c_prep4": "Listes des Salons préparés `",
+ "c_prep5": "créé",
+ "c_prep6": "Pas besoin de préparation",
- "u_time_at": "à",
+ "u_time_at": "à",
- "c_reminder_name": "rappel",
- "c_reminder_desc": "Commande relative aux rappels",
- "c_reminder_sub1_name": "nouveau",
- "c_reminder_sub1_desc": "Met en place un rappel",
- "c_reminder_sub1_opt1_name": "temps",
- "c_reminder_sub1_opt1_desc": "Temps désiré avant le rappel, accolez un @ pour activer la mention ou un p pour envoyer en DM",
- "c_reminder_sub1_opt2_name": "message",
- "c_reminder_sub1_opt2_desc": "Message du rappel",
- "c_reminder_sub2_name": "liste",
- "c_reminder_sub2_desc": "Affiche la liste des rappels d'un utilisateur",
- "c_reminder_sub2_opt1_name": "utilisateur",
- "c_reminder_sub2_opt1_desc": "Affiche la liste de l'utilisateur en question",
- "c_reminder_sub2_opt2_name": "page",
- "c_reminder_sub2_opt2_desc": "Page à afficher",
- "c_reminder_sub3_name": "efface",
- "c_reminder_sub3_desc": "Supprime un rappel",
- "c_reminder_sub3_opt1_name": "id",
- "c_reminder_sub3_opt1_desc": "Rappel à supprimé",
- "c_reminder1": "Un rappel a été configuré pour dans",
- "c_reminder2": "L'ID renseigné n'est pas valide.",
- "c_reminder3": "Rappel non trouvé, pas sur le bon serveur ou qui ne vous appartiens pas.",
- "c_reminder4": "Utilisateur inconnu.",
- "c_reminder5": "Rappels de",
- "c_reminder6": "Page",
- "c_reminder7": "Pas de message",
- "c_reminder8": "Expire dans",
- "c_reminder9": "Fais le",
- "c_reminder10": "L'utilisateur n'a aucun rappel en attente ou page n°",
- "c_reminder11": "vide",
- "c_reminder12": "Précédent",
- "c_reminder13": "Suivant",
- "c_reminder14": "Message envoyé en DM car le salon n'est plus disponible.",
- "c_reminder15": "Message envoyé en DM car vous avez quitté",
- "c_reminder16": "Message envoyé en DM car le serveur Discord n'est plus disponible.",
- "c_reminder17": "Message d'il y a",
- "c_reminder18": "Pas de message"
+ "c_reminder_name": "rappel",
+ "c_reminder_desc": "Commande relative aux rappels",
+ "c_reminder_sub1_name": "nouveau",
+ "c_reminder_sub1_desc": "Met en place un rappel",
+ "c_reminder_sub1_opt1_name": "temps",
+ "c_reminder_sub1_opt1_desc": "Temps désiré avant le rappel, accolez un @ pour activer la mention ou un p pour envoyer en DM",
+ "c_reminder_sub1_opt2_name": "message",
+ "c_reminder_sub1_opt2_desc": "Message du rappel",
+ "c_reminder_sub2_name": "liste",
+ "c_reminder_sub2_desc": "Affiche la liste des rappels d'un utilisateur",
+ "c_reminder_sub2_opt1_name": "utilisateur",
+ "c_reminder_sub2_opt1_desc": "Affiche la liste de l'utilisateur en question",
+ "c_reminder_sub2_opt2_name": "page",
+ "c_reminder_sub2_opt2_desc": "Page à afficher",
+ "c_reminder_sub3_name": "efface",
+ "c_reminder_sub3_desc": "Supprime un rappel",
+ "c_reminder_sub3_opt1_name": "id",
+ "c_reminder_sub3_opt1_desc": "Rappel à supprimé",
+ "c_reminder1": "Un rappel a été configuré pour dans",
+ "c_reminder2": "L'ID renseigné n'est pas valide.",
+ "c_reminder3": "Rappel non trouvé, pas sur le bon serveur ou qui ne vous appartiens pas.",
+ "c_reminder4": "Utilisateur inconnu.",
+ "c_reminder5": "Rappels de",
+ "c_reminder6": "Page",
+ "c_reminder7": "Pas de message",
+ "c_reminder8": "Expire dans",
+ "c_reminder9": "Fais le",
+ "c_reminder10": "L'utilisateur n'a aucun rappel en attente ou page n°",
+ "c_reminder11": "vide",
+ "c_reminder12": "Précédent",
+ "c_reminder13": "Suivant",
+ "c_reminder14": "Message envoyé en DM car le salon n'est plus disponible.",
+ "c_reminder15": "Message envoyé en DM car vous avez quitté",
+ "c_reminder16": "Message envoyé en DM car le serveur Discord n'est plus disponible.",
+ "c_reminder17": "Message d'il y a",
+ "c_reminder18": "Pas de message"
}
diff --git a/src/modals/loader.ts b/src/modals/loader.ts
index 56e2aea..268a1f0 100644
--- a/src/modals/loader.ts
+++ b/src/modals/loader.ts
@@ -1,36 +1,37 @@
-import { readdir } from 'fs/promises';
-import { removeExtension } from '../utils/misc';
-import { Client } from 'discord.js';
+import { readdir } from "fs/promises";
+import { removeExtension } from "../utils/misc";
+import { Client } from "discord.js";
export default async (client: Client) => {
- // Dossier des modals
- const modals_categories = (await readdir(__dirname))
- .filter(element => !element.endsWith('.js') && !element.endsWith('.ts'));
+ // Dossier des modals
+ const modals_categories = (await readdir(__dirname)).filter(
+ (element) => !element.endsWith(".js") && !element.endsWith(".ts")
+ );
- await Promise.all(
- // For each categorie
- modals_categories.map(async modals_category => {
- // Retrieve all the commands
- const modal_files = await readdir(`${__dirname}/${modals_category}`);
+ await Promise.all(
+ // For each categorie
+ modals_categories.map(async (modals_category) => {
+ // Retrieve all the commands
+ const modal_files = await readdir(`${__dirname}/${modals_category}`);
- // Add the category to the collection for the help command
- client.modals.categories.set(
- modals_category,
- modal_files.map(removeExtension),
- );
+ // Add the category to the collection for the help command
+ client.modals.categories.set(
+ modals_category,
+ modal_files.map(removeExtension)
+ );
- // Add the modal
- return Promise.all(
- modal_files.map(async modal_file => {
- const modal = (
- await import(`../modals/${modals_category}/${modal_file}`)
- ).default;
+ // Add the modal
+ return Promise.all(
+ modal_files.map(async (modal_file) => {
+ const modal = (
+ await import(`../modals/${modals_category}/${modal_file}`)
+ ).default;
- // Add it to the collection so the interaction will work
- client.modals.list.set(modal.data.name, modal);
- return modal.data;
- }),
- );
- }),
- );
+ // Add it to the collection so the interaction will work
+ client.modals.list.set(modal.data.name, modal);
+ return modal.data;
+ })
+ );
+ })
+ );
};
diff --git a/src/modals/misc/reminderGUI.ts b/src/modals/misc/reminderGUI.ts
index d848dd4..b74a496 100644
--- a/src/modals/misc/reminderGUI.ts
+++ b/src/modals/misc/reminderGUI.ts
@@ -1,21 +1,28 @@
-import { Client, ModalSubmitInteraction } from 'discord.js';
-import { getFilename } from '../../utils/misc';
-import { newReminder } from '../../utils/reminder';
+import { Client, ModalSubmitInteraction } from "discord.js";
+import { getFilename } from "../../utils/misc";
+import { newReminder } from "../../utils/reminder";
export default {
- data: {
- name: getFilename(__filename),
- },
- interaction: async (interaction: ModalSubmitInteraction, client: Client) =>
- newReminder(client, interaction.fields.fields.get('reminderGUI-time')?.value as string, {
- locale: interaction.locale,
- message: interaction.fields.fields.get('reminderGUI-message')?.value ?? null,
- createdAt: interaction.createdAt.getTime(),
- channelId: interaction.channelId,
- userId: interaction.user.id,
- guildId: interaction.guildId,
- }).then((msg) => interaction.reply({
- content: msg as string,
- ephemeral: true,
- })),
+ data: {
+ name: getFilename(__filename),
+ },
+ interaction: async (interaction: ModalSubmitInteraction, client: Client) =>
+ newReminder(
+ client,
+ interaction.fields.fields.get("reminderGUI-time")?.value as string,
+ {
+ locale: interaction.locale,
+ message:
+ interaction.fields.fields.get("reminderGUI-message")?.value ?? null,
+ createdAt: interaction.createdAt.getTime(),
+ channelId: interaction.channelId,
+ userId: interaction.user.id,
+ guildId: interaction.guildId,
+ }
+ ).then((msg) =>
+ interaction.reply({
+ content: msg as string,
+ ephemeral: true,
+ })
+ ),
};
diff --git a/src/modules/client.ts b/src/modules/client.ts
index 9af4913..559604a 100644
--- a/src/modules/client.ts
+++ b/src/modules/client.ts
@@ -1,87 +1,96 @@
-import { Collection } from 'discord.js';
-import { SlashCommandBuilder } from '@discordjs/builders';
-import { Database } from 'sqlite3';
+import { Collection } from "discord.js";
+import { SlashCommandBuilder } from "@discordjs/builders";
+import { Database } from "sqlite3";
-export { };
+export {};
-declare module 'discord.js' {
- // eslint-disable-next-line no-shadow
- export interface Client {
- /** Store the configuration */
- config: {
- /** Bot version */
- version: string,
- /** Bot token from env variable */
- token_discord: string | undefined,
- /** Default lang used */
- default_lang: string
- },
- /** Store all the modals */
- modals: {
- categories: Collection<
- /** Category name */
- string,
- /** Name of the modals in the category */
- string[]
- >,
- list: Collection<
- /** Modal name */
- string,
- /** Modal itself */
- {
- /** Data about the modal */
- data: {
- name: string
- },
- /** How the modal interact */
- interaction: (interaction: ModalSubmitInteraction, client: Client) => unknown
- }
- >,
- },
- /** Store all the buttons */
- buttons: {
- categories: Collection<
- /** Category name */
- string,
- /** Name of the buttons in the category */
- string[]
- >,
- list: Collection<
- /** Button name */
- string,
- /** Button itself */
- {
- /** Data about the button */
- data: {
- name: string
- },
- /** How the button interact */
- interaction: (interaction: MessageComponentInteraction, client: Client) => Promise
- }
- >,
- },
- /** Store all the slash commands */
- commands: {
- categories: Collection<
- /** Category name */
- string,
- /** Name of the commands in the category */
- string[]
- >,
- list: Collection<
- /** Command name */
- string,
- /** Command itself */
- {
- /** Data about the command */
- data: SlashCommandBuilder,
- /** How the command interact */
- interaction: (interaction: CommandInteraction, client: Client) => unknown
- }
- >,
- },
- /** Store all the localizations */
- locales: Map>,
- db: Database,
- }
+declare module "discord.js" {
+ // eslint-disable-next-line no-shadow
+ export interface Client {
+ /** Store the configuration */
+ config: {
+ /** Bot version */
+ version: string;
+ /** Bot token from env variable */
+ token_discord: string | undefined;
+ /** Default lang used */
+ default_lang: string;
+ };
+ /** Store all the modals */
+ modals: {
+ categories: Collection<
+ /** Category name */
+ string,
+ /** Name of the modals in the category */
+ string[]
+ >;
+ list: Collection<
+ /** Modal name */
+ string,
+ /** Modal itself */
+ {
+ /** Data about the modal */
+ data: {
+ name: string;
+ };
+ /** How the modal interact */
+ interaction: (
+ interaction: ModalSubmitInteraction,
+ client: Client
+ ) => unknown;
+ }
+ >;
+ };
+ /** Store all the buttons */
+ buttons: {
+ categories: Collection<
+ /** Category name */
+ string,
+ /** Name of the buttons in the category */
+ string[]
+ >;
+ list: Collection<
+ /** Button name */
+ string,
+ /** Button itself */
+ {
+ /** Data about the button */
+ data: {
+ name: string;
+ };
+ /** How the button interact */
+ interaction: (
+ interaction: MessageComponentInteraction,
+ client: Client
+ ) => Promise;
+ }
+ >;
+ };
+ /** Store all the slash commands */
+ commands: {
+ categories: Collection<
+ /** Category name */
+ string,
+ /** Name of the commands in the category */
+ string[]
+ >;
+ list: Collection<
+ /** Command name */
+ string,
+ /** Command itself */
+ {
+ /** Data about the command */
+ data: SlashCommandBuilder;
+ /** How the command interact */
+ interaction: (
+ interaction: CommandInteraction,
+ client: Client
+ ) => unknown;
+ }
+ >;
+ };
+ /** Store all the localizations */
+ locales: Map>;
+ db: Database;
+ }
}
diff --git a/src/modules/string.ts b/src/modules/string.ts
index 01bbe12..b0c5cf9 100644
--- a/src/modules/string.ts
+++ b/src/modules/string.ts
@@ -1,16 +1,16 @@
export {};
declare global {
- // Declarations
- interface String {
- /**
- * Returns a copy of the string with the first letter capitalized.
- */
- capitalize(): string,
- }
+ // Declarations
+ interface String {
+ /**
+ * Returns a copy of the string with the first letter capitalized.
+ */
+ capitalize(): string;
+ }
}
/** Capitalize definition */
-String.prototype.capitalize = function(this: string) {
- return this[0].toUpperCase() + this.substring(1);
+String.prototype.capitalize = function (this: string) {
+ return this[0].toUpperCase() + this.substring(1);
};
diff --git a/src/utils/client.ts b/src/utils/client.ts
index 916c85b..7a2a407 100644
--- a/src/utils/client.ts
+++ b/src/utils/client.ts
@@ -1,47 +1,46 @@
-import { Client, Collection, GatewayIntentBits } from 'discord.js';
-import { readFileSync } from 'fs';
-import { loadLocales } from './locales';
-import '../modules/client';
-import { Database } from 'sqlite3';
+import { Client, Collection, GatewayIntentBits } from "discord.js";
+import { readFileSync } from "fs";
+import { loadLocales } from "./locales";
+import "../modules/client";
+import { Database } from "sqlite3";
/** Creation of the client and definition of its properties. */
export default async () => {
- const client: Client = new Client({
- intents: [
- GatewayIntentBits.Guilds,
- GatewayIntentBits.GuildMessages,
- ],
- });
+ const client: Client = new Client({
+ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
+ });
- client.config = {
- version: JSON.parse(readFileSync('./package.json').toString()).version,
- token_discord: process.env.TOKEN_DISCORD,
- default_lang: process.env.DEFAULT_LANG ?? 'fr',
- };
+ client.config = {
+ version: JSON.parse(readFileSync("./package.json").toString()).version,
+ token_discord: process.env.TOKEN_DISCORD,
+ default_lang: process.env.DEFAULT_LANG ?? "fr",
+ };
- client.modals = {
- categories: new Collection(),
- list: new Collection(),
- };
+ client.modals = {
+ categories: new Collection(),
+ list: new Collection(),
+ };
- client.buttons = {
- categories: new Collection(),
- list: new Collection(),
- };
+ client.buttons = {
+ categories: new Collection(),
+ list: new Collection(),
+ };
- client.commands = {
- categories: new Collection(),
- list: new Collection(),
- };
+ client.commands = {
+ categories: new Collection(),
+ list: new Collection(),
+ };
- console.log('Translations progression :');
- client.locales = await loadLocales(client.config.default_lang);
+ console.log("Translations progression :");
+ client.locales = await loadLocales(client.config.default_lang);
- client.db = new Database(`${process.env.DOCKERIZED === '1' ? '/config' : './config'}/db.sqlite3`);
+ client.db = new Database(
+ `${process.env.DOCKERIZED === "1" ? "/config" : "./config"}/db.sqlite3`
+ );
- initDatabase(client.db);
+ initDatabase(client.db);
- return client;
+ return client;
};
/**
@@ -49,11 +48,11 @@ export default async () => {
* @param client Client
*/
export const quit = (client: Client) => {
- // Close DB
- client.db.close();
+ // Close DB
+ client.db.close();
- // Close client
- client.destroy();
+ // Close client
+ client.destroy();
};
/**
@@ -61,8 +60,9 @@ export const quit = (client: Client) => {
* @param db Database
*/
const initDatabase = (db: Database) => {
- // Table for reminders
- db.run('CREATE TABLE IF NOT EXISTS reminder ( \
+ // Table for reminders
+ db.run(
+ "CREATE TABLE IF NOT EXISTS reminder ( \
id INTEGER PRIMARY KEY, \
data TEXT, \
expiration_date TEXT, \
@@ -73,5 +73,6 @@ const initDatabase = (db: Database) => {
guild_id TEXT, \
locale TEXT, \
timeout_id TEXT \
- );');
+ );"
+ );
};
diff --git a/src/utils/locales.ts b/src/utils/locales.ts
index b960587..074b0cb 100644
--- a/src/utils/locales.ts
+++ b/src/utils/locales.ts
@@ -1,6 +1,6 @@
-import { Client } from 'discord.js';
-import { readdir } from 'fs/promises';
-import { removeExtension } from './misc';
+import { Client } from "discord.js";
+import { readdir } from "fs/promises";
+import { removeExtension } from "./misc";
/**
* Load the localizations files into memory.
@@ -10,40 +10,39 @@ import { removeExtension } from './misc';
* @returns Map of map with all the localizations
*/
export const loadLocales = async (default_lang: string) => {
- // Get files from locales/ directory
- const old_path = __dirname.split('/');
- old_path.pop();
- const files = await readdir(`${old_path.join('/')}/locales`);
+ // Get files from locales/ directory
+ const old_path = __dirname.split("/");
+ old_path.pop();
+ const files = await readdir(`${old_path.join("/")}/locales`);
- // Read JSON files content and load it into the memory
- const locales = new Map>();
- await Promise.all(
- files.map(async lang => {
- // Import file
- const content: {
- [key: string]: string
- } = await import(
- `../locales/${lang}`
- );
+ // Read JSON files content and load it into the memory
+ const locales = new Map>();
+ await Promise.all(
+ files.map(async (lang) => {
+ // Import file
+ const content: {
+ [key: string]: string;
+ } = await import(`../locales/${lang}`);
- // Add it to the memory
- locales.set(
- removeExtension(lang),
- new Map(Object.keys(content)
- // Ignore the default key
- .filter(str => str !== 'default')
- .map(str => {
- return [str, content[str]];
- }),
- )
- );
- })
- );
+ // Add it to the memory
+ locales.set(
+ removeExtension(lang),
+ new Map(
+ Object.keys(content)
+ // Ignore the default key
+ .filter((str) => str !== "default")
+ .map((str) => {
+ return [str, content[str]];
+ })
+ )
+ );
+ })
+ );
- // Check locales sanity
- checkLocales(locales, default_lang);
+ // Check locales sanity
+ checkLocales(locales, default_lang);
- return locales;
+ return locales;
};
/**
@@ -53,26 +52,31 @@ export const loadLocales = async (default_lang: string) => {
* @param text Name of string to fetch
* @returns the dictionary
*/
-export const getLocalizations = (client: Client, text: string, lowercase = false) => {
- const data: Record = {};
+export const getLocalizations = (
+ client: Client,
+ text: string,
+ lowercase = false
+) => {
+ const data: Record = {};
- // Load all the localizations
- client.locales.forEach((locale, lang) => {
- // Fetch the text and fallback to default lang if needed
- // See getLocale for more info on why we *can* fallback
- let str = locale.get(text)
- ?? client.locales.get(client.config.default_lang)?.get(text);
+ // Load all the localizations
+ client.locales.forEach((locale, lang) => {
+ // Fetch the text and fallback to default lang if needed
+ // See getLocale for more info on why we *can* fallback
+ let str =
+ locale.get(text) ??
+ client.locales.get(client.config.default_lang)?.get(text);
- // Store it if defined
- if (str !== undefined) {
- if (lowercase) {
- str = str.toLowerCase();
- }
- data[lang] = str;
- }
- });
+ // Store it if defined
+ if (str !== undefined) {
+ if (lowercase) {
+ str = str.toLowerCase();
+ }
+ data[lang] = str;
+ }
+ });
- return data;
+ return data;
};
/**
@@ -83,22 +87,22 @@ export const getLocalizations = (client: Client, text: string, lowercase = false
* @returns the map with the desired languaged clogged with the default one
*/
export const getLocale = (client: Client, lang: string) => {
- // Load default lang
- const default_locales = client.locales.get(client.config.default_lang);
- // Load desired lang
- const desired_locales = client.locales.get(lang);
+ // Load default lang
+ const default_locales = client.locales.get(client.config.default_lang);
+ // Load desired lang
+ const desired_locales = client.locales.get(lang);
- // Get text and fallback to default lang if needed
- //
- // We can fallback to the default one without any problem
- // because we make sure that the default language always contains
- // the desired text, and that the other languages are only translations
- const locales = new Map();
- default_locales?.forEach((_, key) => {
- locales.set(key, desired_locales?.get(key) ?? default_locales.get(key));
- });
+ // Get text and fallback to default lang if needed
+ //
+ // We can fallback to the default one without any problem
+ // because we make sure that the default language always contains
+ // the desired text, and that the other languages are only translations
+ const locales = new Map();
+ default_locales?.forEach((_, key) => {
+ locales.set(key, desired_locales?.get(key) ?? default_locales.get(key));
+ });
- return locales;
+ return locales;
};
/**
@@ -110,65 +114,72 @@ export const getLocale = (client: Client, lang: string) => {
* @param default_lang default lang
* @returns void
*/
-const checkLocales =
-async (locales: Map>, default_lang: string) => {
- // Associate each lang with the number of locale it has
- let locales_size = new Map();
- locales.forEach((locales_data, lang) => {
- locales_size.set(lang, locales_data.size);
- });
+const checkLocales = async (
+ locales: Map>,
+ default_lang: string
+) => {
+ // Associate each lang with the number of locale it has
+ let locales_size = new Map();
+ locales.forEach((locales_data, lang) => {
+ locales_size.set(lang, locales_data.size);
+ });
- // Sort the map
- locales_size = new Map([...locales_size.entries()]
- .sort((a, b) => b[1] - a[1]));
+ // Sort the map
+ locales_size = new Map(
+ [...locales_size.entries()].sort((a, b) => b[1] - a[1])
+ );
- // Check if default lang is 100%
- const [max_size_name] = locales_size.keys();
- const [max_size] = locales_size.values();
- const default_lang_size = locales_size.get(default_lang) ?? 0;
- if (max_size > default_lang_size) {
- // Throw error because in this case we are sure than the security
- // explained in getLocale isn't true.
- // However, it is possible that this condition is true
- // and the security is poor, but it's better than nothing.
- throw new Error(
- `The default locale (${default_lang} = ${default_lang_size}) isn't complete `
- + `(${max_size_name} = ${max_size}).`
- );
- }
+ // Check if default lang is 100%
+ const [max_size_name] = locales_size.keys();
+ const [max_size] = locales_size.values();
+ const default_lang_size = locales_size.get(default_lang) ?? 0;
+ if (max_size > default_lang_size) {
+ // Throw error because in this case we are sure than the security
+ // explained in getLocale isn't true.
+ // However, it is possible that this condition is true
+ // and the security is poor, but it's better than nothing.
+ throw new Error(
+ `The default locale (${default_lang} = ${default_lang_size}) isn't complete ` +
+ `(${max_size_name} = ${max_size}).`
+ );
+ }
- // Remove the default language as it is used as a reference
- locales_size.delete(default_lang);
+ // Remove the default language as it is used as a reference
+ locales_size.delete(default_lang);
- // Displays the percentages according to the default language
- // lower is bigger
- const bar_size = 4;
- locales_size.forEach((size, lang) => {
- const percentage = (size / max_size) * 100;
- // Colored bar part
- const blocks = ' '.repeat(Math.floor(percentage / bar_size));
- // Blank bar part
- const blank = ' '.repeat(Math.ceil((100 - percentage) / bar_size));
- const color = () => {
- switch (true) {
- case percentage <= 25:
- // Red
- return '\x1b[41m';
- case percentage <= 50:
- // Mangeta
- return '\x1b[45m';
- case percentage <= 75:
- // Cyan
- return '\x1b[46m';
- case percentage <= 100:
- // Green
- return '\x1b[42m';
- default:
- return '';
- }
- };
- const padding = ' '.repeat(lang.length === 5 ? 1 : 4);
+ // Displays the percentages according to the default language
+ // lower is bigger
+ const bar_size = 4;
+ locales_size.forEach((size, lang) => {
+ const percentage = (size / max_size) * 100;
+ // Colored bar part
+ const blocks = " ".repeat(Math.floor(percentage / bar_size));
+ // Blank bar part
+ const blank = " ".repeat(Math.ceil((100 - percentage) / bar_size));
+ const color = () => {
+ switch (true) {
+ case percentage <= 25:
+ // Red
+ return "\x1b[41m";
+ case percentage <= 50:
+ // Mangeta
+ return "\x1b[45m";
+ case percentage <= 75:
+ // Cyan
+ return "\x1b[46m";
+ case percentage <= 100:
+ // Green
+ return "\x1b[42m";
+ default:
+ return "";
+ }
+ };
+ const padding = " ".repeat(lang.length === 5 ? 1 : 4);
- console.log(`${padding}${lang} | ${color()}${blocks}\x1b[0m${blank} | ${percentage.toPrecision(3)}%`);
- });
+ console.log(
+ `${padding}${lang} | ${color()}${blocks}\x1b[0m${blank} | ${percentage.toPrecision(
+ 3
+ )}%`
+ );
+ });
};
diff --git a/src/utils/misc.ts b/src/utils/misc.ts
index ae42ef5..beac077 100644
--- a/src/utils/misc.ts
+++ b/src/utils/misc.ts
@@ -1,4 +1,4 @@
-import { GuildMember } from 'discord.js';
+import { GuildMember } from "discord.js";
/**
* Log module status.
@@ -7,8 +7,8 @@ import { GuildMember } from 'discord.js';
* @returns String
*/
export const logStart = (name: string, status: boolean) => {
- // TODO Handle precision about the error if status is false
- return `> ${name}\t${status === true ? '✅' : '❌'}`;
+ // TODO Handle precision about the error if status is false
+ return `> ${name}\t${status === true ? "✅" : "❌"}`;
};
/**
@@ -17,15 +17,15 @@ export const logStart = (name: string, status: boolean) => {
* @returns string
*/
export const getFilename = (path: string) => {
- const path_list = path.split('/');
+ const path_list = path.split("/");
- // Check if filename exist
- const filename_with_ext = path_list.pop();
- if (filename_with_ext === undefined) {
- throw new Error(`Filename error: don't exist in ${path}`);
- }
+ // Check if filename exist
+ const filename_with_ext = path_list.pop();
+ if (filename_with_ext === undefined) {
+ throw new Error(`Filename error: don't exist in ${path}`);
+ }
- return removeExtension(filename_with_ext);
+ return removeExtension(filename_with_ext);
};
/**
@@ -34,10 +34,10 @@ export const getFilename = (path: string) => {
* @returns string of the filename without an extension
*/
export const removeExtension = (filename: string) => {
- const array = filename.split('.');
- array.pop();
+ const array = filename.split(".");
+ array.pop();
- return array.join('.');
+ return array.join(".");
};
/**
@@ -46,9 +46,9 @@ export const removeExtension = (filename: string) => {
* @returns string of the extension if it exists
*/
export const getExtension = (filename: string) => {
- const array = filename.split('.');
+ const array = filename.split(".");
- return array.pop();
+ return array.pop();
};
/**
@@ -57,9 +57,7 @@ export const getExtension = (filename: string) => {
* @returns true is file is a media
*/
export const isImage = (filename: string) => {
- return Boolean(getExtension(filename)?.match(
- /jpg|jpeg|png|webp|gif/
- ));
+ return Boolean(getExtension(filename)?.match(/jpg|jpeg|png|webp|gif/));
};
/**
@@ -68,14 +66,14 @@ export const isImage = (filename: string) => {
* @returns string
*/
export const userWithNickname = (member: GuildMember) => {
- if (!member) {
- return undefined;
- }
- if (member.nickname) {
- return `${member.nickname} (${member.user.tag})`;
- } else {
- return member.user.tag;
- }
+ if (!member) {
+ return undefined;
+ }
+ if (member.nickname) {
+ return `${member.nickname} (${member.user.tag})`;
+ } else {
+ return member.user.tag;
+ }
};
/**
@@ -84,20 +82,23 @@ export const userWithNickname = (member: GuildMember) => {
* @returns Formatted text
*/
export const cleanCodeBlock = (text: string) => {
- text = `\`${text.trim()}\``;
+ text = `\`${text.trim()}\``;
- // Keep mentions
- text = text.replace(/(<@\d+>)/g, function(mention: string) {
- return `\`${mention}\``;
- });
+ // Keep mentions
+ text = text.replace(/(<@\d+>)/g, function (mention: string) {
+ return `\`${mention}\``;
+ });
- // Keep links
- text = text.replace(/(http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)/g, function(url: string) {
- return `\`${url}\``;
- });
+ // Keep links
+ text = text.replace(
+ /(http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)/g,
+ function (url: string) {
+ return `\`${url}\``;
+ }
+ );
- // Fix issues
- text = text.replace('``', '');
+ // Fix issues
+ text = text.replace("``", "");
- return text;
+ return text;
};
diff --git a/src/utils/reminder.ts b/src/utils/reminder.ts
index 7200bcd..1412cb5 100644
--- a/src/utils/reminder.ts
+++ b/src/utils/reminder.ts
@@ -1,44 +1,44 @@
-import { Client, Colors, EmbedBuilder, User } from 'discord.js';
-import { getLocale } from './locales';
-import { cleanCodeBlock } from './misc';
-import { showDate, strToSeconds, timeDeltaToString } from './time';
+import { Client, Colors, EmbedBuilder, User } from "discord.js";
+import { getLocale } from "./locales";
+import { cleanCodeBlock } from "./misc";
+import { showDate, strToSeconds, timeDeltaToString } from "./time";
/**
* Option possible for reminders
*/
export enum OptionReminder {
- /** No parameters */
- Nothing,
- /** @ */
- Mention,
- /** p */
- DirectMessage,
+ /** No parameters */
+ Nothing,
+ /** @ */
+ Mention,
+ /** p */
+ DirectMessage,
}
/**
* Store data about the remidner
*/
export type infoReminder = {
- locale: string,
- message: string | null,
- createdAt: number,
- channelId: string | null,
- userId: string,
- guildId: string | null
-}
+ locale: string;
+ message: string | null;
+ createdAt: number;
+ channelId: string | null;
+ userId: string;
+ guildId: string | null;
+};
export type dbReminder = {
- id: number,
- data: string | null,
- expiration_date: number,
- option_id: OptionReminder,
- channel_id: string | null,
- creation_date: string,
- user_id: string,
- guild_id: string | null,
- locale: string,
- timeout_id: string
-}
+ id: number;
+ data: string | null;
+ expiration_date: number;
+ option_id: OptionReminder;
+ channel_id: string | null;
+ creation_date: string;
+ user_id: string;
+ guild_id: string | null;
+ locale: string;
+ timeout_id: string;
+};
/**
* Split the time and the extra args `p` and `@`
@@ -46,13 +46,13 @@ export type dbReminder = {
* @returns An object with the time and the option
*/
const splitTime = (time: string) => {
- if (time?.endsWith('@')) {
- return { time: time.slice(0, -1), option: OptionReminder.Mention };
- } else if (time?.toLowerCase().endsWith('p')) {
- return { time: time.slice(0, -1), option: OptionReminder.DirectMessage };
- }
+ if (time?.endsWith("@")) {
+ return { time: time.slice(0, -1), option: OptionReminder.Mention };
+ } else if (time?.toLowerCase().endsWith("p")) {
+ return { time: time.slice(0, -1), option: OptionReminder.DirectMessage };
+ }
- return { time: time, option: OptionReminder.Nothing };
+ return { time: time, option: OptionReminder.Nothing };
};
/**
@@ -62,34 +62,43 @@ const splitTime = (time: string) => {
* @param info data about the context of the reminder
* @returns Promise resolution of the sql request
*/
-export const newReminder = async (client: Client, time: string, info: infoReminder) =>
- new Promise((ok, ko) => {
- const data = splitTime(time);
- const timeout = strToSeconds(data.time);
- const timeoutId = setTimeoutReminder(client, info, data.option, timeout);
+export const newReminder = async (
+ client: Client,
+ time: string,
+ info: infoReminder
+) =>
+ new Promise((ok, ko) => {
+ const data = splitTime(time);
+ const timeout = strToSeconds(data.time);
+ const timeoutId = setTimeoutReminder(client, info, data.option, timeout);
- // Add the remind to the db
- client.db.run('INSERT INTO reminder ( \
+ // Add the remind to the db
+ client.db.run(
+ "INSERT INTO reminder ( \
data, expiration_date, option_id, channel_id, creation_date, user_id, guild_id, locale, timeout_id \
- ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? );', [
- info.message,
- `${info.createdAt + (timeout * 1000)}`,
- data.option.valueOf(),
- info.channelId,
- `${info.createdAt}`,
- info.userId,
- info.guildId,
- info.locale,
- timeoutId], (err) => {
- if (err) {
- ko(err);
- }
+ ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? );",
+ [
+ info.message,
+ `${info.createdAt + timeout * 1000}`,
+ data.option.valueOf(),
+ info.channelId,
+ `${info.createdAt}`,
+ info.userId,
+ info.guildId,
+ info.locale,
+ timeoutId,
+ ],
+ (err) => {
+ if (err) {
+ ko(err);
+ }
- // Send confirmation to user
- const loc = getLocale(client, info.locale);
- ok(`${loc.get('c_reminder1')} ${data.time}.`);
- });
- });
+ // Send confirmation to user
+ const loc = getLocale(client, info.locale);
+ ok(`${loc.get("c_reminder1")} ${data.time}.`);
+ }
+ );
+ });
/**
* Delete a reminder from the database
@@ -98,83 +107,99 @@ export const newReminder = async (client: Client, time: string, info: infoRemind
* @param userId User ID who created the reminder
* @returns what the SQlite request sended
*/
-export const deleteReminder = (client: Client, createdAt: string, userId: string) => {
- // Delete the reminder for the database
- return new Promise((ok, ko) => {
- // Add the remind to the db
- client.db.run('DELETE FROM reminder WHERE creation_date = ? AND user_id = ?', [createdAt, userId], (err) => {
- if (err) {
- ko(err);
- }
+export const deleteReminder = (
+ client: Client,
+ createdAt: string,
+ userId: string
+) => {
+ // Delete the reminder for the database
+ return new Promise((ok, ko) => {
+ // Add the remind to the db
+ client.db.run(
+ "DELETE FROM reminder WHERE creation_date = ? AND user_id = ?",
+ [createdAt, userId],
+ (err) => {
+ if (err) {
+ ko(err);
+ }
- // Send confirmation to user
- ok(true);
- });
- });
+ // Send confirmation to user
+ ok(true);
+ }
+ );
+ });
};
-export const sendReminder = (client: Client, info: infoReminder, option: OptionReminder) => {
- const loc = getLocale(client, info.locale);
- // Send the message in the appropriate channel
- // TODO: Embed
- let message: string;
- if (info.message === null) {
- message = loc.get('c_reminder18');
- } else {
- message = cleanCodeBlock(info.message);
- }
- const embed = new EmbedBuilder()
- .setColor('Random')
- .setDescription(message)
- .setTimestamp(info.createdAt);
+export const sendReminder = (
+ client: Client,
+ info: infoReminder,
+ option: OptionReminder
+) => {
+ const loc = getLocale(client, info.locale);
+ // Send the message in the appropriate channel
+ // TODO: Embed
+ let message: string;
+ if (info.message === null) {
+ message = loc.get("c_reminder18");
+ } else {
+ message = cleanCodeBlock(info.message);
+ }
+ const embed = new EmbedBuilder()
+ .setColor("Random")
+ .setDescription(message)
+ .setTimestamp(info.createdAt);
- let channelOk = false;
- if (info.channelId !== null) {
- if (client.channels.cache.get(info.channelId) !== undefined) {
- channelOk = true;
- } else {
- embed.setFooter({ text: loc.get('c_reminder14') });
- }
- }
+ let channelOk = false;
+ if (info.channelId !== null) {
+ if (client.channels.cache.get(info.channelId) !== undefined) {
+ channelOk = true;
+ } else {
+ embed.setFooter({ text: loc.get("c_reminder14") });
+ }
+ }
- let guildOk = false;
- if (info.guildId !== null) {
- const guild = client.guilds.cache.get(info.guildId);
- if (guild !== undefined) {
- if (guild.members.cache.get(info.userId) !== undefined) {
- guildOk = true;
- } else {
- embed.setFooter({ text: `${loc.get('c_reminder15')} ${guild.name}.` });
- }
- } else {
- embed.setFooter({ text: loc.get('c_reminder16') });
- }
- }
+ let guildOk = false;
+ if (info.guildId !== null) {
+ const guild = client.guilds.cache.get(info.guildId);
+ if (guild !== undefined) {
+ if (guild.members.cache.get(info.userId) !== undefined) {
+ guildOk = true;
+ } else {
+ embed.setFooter({ text: `${loc.get("c_reminder15")} ${guild.name}.` });
+ }
+ } else {
+ embed.setFooter({ text: loc.get("c_reminder16") });
+ }
+ }
- if (option == OptionReminder.DirectMessage || !channelOk || !guildOk) {
- // Direct message
- const user = client.users.cache.get(info.userId);
- if (user !== undefined) {
- user.send({ embeds: [embed] });
- }
- } else {
- // Channel
- client.channels.fetch(info.channelId ?? '').then((channel) => {
- if (channel?.isTextBased()) {
- let content = `<@${info.userId}>`;
- embed.setFooter({ text: `${loc.get('c_reminder17')} ${timeDeltaToString(info.createdAt)}` });
+ if (option == OptionReminder.DirectMessage || !channelOk || !guildOk) {
+ // Direct message
+ const user = client.users.cache.get(info.userId);
+ if (user !== undefined) {
+ user.send({ embeds: [embed] });
+ }
+ } else {
+ // Channel
+ client.channels.fetch(info.channelId ?? "").then((channel) => {
+ if (channel?.isTextBased()) {
+ let content = `<@${info.userId}>`;
+ embed.setFooter({
+ text: `${loc.get("c_reminder17")} ${timeDeltaToString(
+ info.createdAt
+ )}`,
+ });
- // Mention everybody if needed
- if (option == OptionReminder.Mention) {
- (info.message?.match(/<@\d+>/g) ?? []).forEach(mention => {
- content += ' ' + mention;
- });
- }
+ // Mention everybody if needed
+ if (option == OptionReminder.Mention) {
+ (info.message?.match(/<@\d+>/g) ?? []).forEach((mention) => {
+ content += " " + mention;
+ });
+ }
- channel.send({ content, embeds: [embed] });
- }
- });
- }
+ channel.send({ content, embeds: [embed] });
+ }
+ });
+ }
};
/**
@@ -185,16 +210,25 @@ export const sendReminder = (client: Client, info: infoReminder, option: OptionR
* @param timeout Amout of time before the reminder ends
* @returns Timeout's ID
*/
-export const setTimeoutReminder = (client: Client, info: infoReminder, option: OptionReminder, timeout: number) => {
- return Number(setTimeout(() => {
- deleteReminder(client, String(info.createdAt), info.userId).then((val) => {
- if (val != true) {
- throw val;
- }
+export const setTimeoutReminder = (
+ client: Client,
+ info: infoReminder,
+ option: OptionReminder,
+ timeout: number
+) => {
+ return Number(
+ setTimeout(() => {
+ deleteReminder(client, String(info.createdAt), info.userId).then(
+ (val) => {
+ if (val != true) {
+ throw val;
+ }
- sendReminder(client, info, option);
- });
- }, timeout * 1000));
+ sendReminder(client, info, option);
+ }
+ );
+ }, timeout * 1000)
+ );
};
/**
@@ -204,26 +238,33 @@ export const setTimeoutReminder = (client: Client, info: infoReminder, option: O
* @param userId user ID to check
* @param guildId guild ID where the ownership request as been send, 0 if DM
*/
-export const checkOwnershipReminder = async (client: Client, id: number, userId: string, guildId: string) => {
- const data = await new Promise((ok, ko) => {
- // Check the ownership
- client.db.all('SELECT EXISTS ( \
+export const checkOwnershipReminder = async (
+ client: Client,
+ id: number,
+ userId: string,
+ guildId: string
+) => {
+ const data = (await new Promise((ok, ko) => {
+ // Check the ownership
+ client.db.all(
+ "SELECT EXISTS ( \
SELECT 1 FROM reminder \
WHERE id = ? \
AND user_id = ? \
AND (guild_id = ? OR guild_id = 0) \
- )', [
- id, userId, guildId,
- ], (err, row) => {
- if (err) {
- ko(err);
- }
+ )",
+ [id, userId, guildId],
+ (err, row) => {
+ if (err) {
+ ko(err);
+ }
- // Send all the current reminders
- ok(row[0]);
- });
- }) as { [key: string]: number };
- return Object.keys(data).map((key) => data[key])[0] === 0 ? true : false;
+ // Send all the current reminders
+ ok(row[0]);
+ }
+ );
+ })) as { [key: string]: number };
+ return Object.keys(data).map((key) => data[key])[0] === 0 ? true : false;
};
/**
@@ -232,19 +273,22 @@ export const checkOwnershipReminder = async (client: Client, id: number, userId:
* @param id Reminder's ID
*/
export const getReminderInfo = async (client: Client, id: number) => {
- return await new Promise((ok, ko) => {
- // Check the ownership
- client.db.all('SELECT * FROM reminder \
- WHERE id = ?', [
- id], (err, row) => {
- if (err) {
- ko(err);
- }
+ return (await new Promise((ok, ko) => {
+ // Check the ownership
+ client.db.all(
+ "SELECT * FROM reminder \
+ WHERE id = ?",
+ [id],
+ (err, row) => {
+ if (err) {
+ ko(err);
+ }
- // Send all the current reminders
- ok(row[0]);
- });
- }) as dbReminder;
+ // Send all the current reminders
+ ok(row[0]);
+ }
+ );
+ })) as dbReminder;
};
/**
@@ -253,10 +297,11 @@ export const getReminderInfo = async (client: Client, id: number) => {
* @param data Data who will override the data in database
*/
export const updateReminder = (client: Client, data: dbReminder) => {
- // Delete the reminder for the database
- return new Promise((ok, ko) => {
- // Update the db
- client.db.run('UPDATE reminder \
+ // Delete the reminder for the database
+ return new Promise((ok, ko) => {
+ // Update the db
+ client.db.run(
+ "UPDATE reminder \
SET data = ?, \
expiration_date = ?, \
option_id = ?, \
@@ -266,24 +311,28 @@ export const updateReminder = (client: Client, data: dbReminder) => {
guild_id = ?, \
locale = ?, \
timeout_id = ? \
- WHERE ID = ?', [
- data.data,
- data.expiration_date,
- data.option_id,
- data.channel_id,
- data.creation_date,
- data.user_id,
- data.guild_id,
- data.locale,
- data.timeout_id,
- data.id], (err) => {
- if (err) {
- ko(err);
- }
+ WHERE ID = ?",
+ [
+ data.data,
+ data.expiration_date,
+ data.option_id,
+ data.channel_id,
+ data.creation_date,
+ data.user_id,
+ data.guild_id,
+ data.locale,
+ data.timeout_id,
+ data.id,
+ ],
+ (err) => {
+ if (err) {
+ ko(err);
+ }
- ok(true);
- });
- });
+ ok(true);
+ }
+ );
+ });
};
/**
@@ -293,20 +342,27 @@ export const updateReminder = (client: Client, data: dbReminder) => {
* @param guildId guild ID
* @returns List of reminders of a user in a guild
*/
-const listReminders = async (client: Client, userId: string, guildId: string | null) => {
- return await new Promise((ok, ko) => {
- // Check the ownership
- client.db.all('SELECT data, creation_date, expiration_date, id FROM reminder \
- WHERE user_id = ? AND (guild_id = ? OR guild_id = 0)', [
- userId, guildId ?? 0], (err, row) => {
- if (err) {
- ko(err);
- }
+const listReminders = async (
+ client: Client,
+ userId: string,
+ guildId: string | null
+) => {
+ return (await new Promise((ok, ko) => {
+ // Check the ownership
+ client.db.all(
+ "SELECT data, creation_date, expiration_date, id FROM reminder \
+ WHERE user_id = ? AND (guild_id = ? OR guild_id = 0)",
+ [userId, guildId ?? 0],
+ (err, row) => {
+ if (err) {
+ ko(err);
+ }
- // Send all the current reminders
- ok(row);
- });
- }) as dbReminder[];
+ // Send all the current reminders
+ ok(row);
+ }
+ );
+ })) as dbReminder[];
};
/**
@@ -318,46 +374,65 @@ const listReminders = async (client: Client, userId: string, guildId: string | n
* @param local Lang
* @returns Pretty embed who list reminders
*/
-export const embedListReminders = async (client: Client, user: User, guildId: string | null, page: number, local: string) => {
- const loc = getLocale(client, local);
- const reminders = await listReminders(client, user.id, guildId);
+export const embedListReminders = async (
+ client: Client,
+ user: User,
+ guildId: string | null,
+ page: number,
+ local: string
+) => {
+ const loc = getLocale(client, local);
+ const reminders = await listReminders(client, user.id, guildId);
- const elementPerPage = 5;
- const pageMax = Math.ceil(reminders.length / elementPerPage);
+ const elementPerPage = 5;
+ const pageMax = Math.ceil(reminders.length / elementPerPage);
- if (pageMax <= 1) {
- page = 1;
- }
- // TODO: Use Random color or force a color from args
- const embed = new EmbedBuilder()
- .setColor(Colors.DarkGrey)
- .setDescription(`${loc.get('c_reminder5')} ${user} • ${loc.get('c_reminder6')} ${page}/${pageMax}`)
- .setThumbnail(user.displayAvatarURL());
+ if (pageMax <= 1) {
+ page = 1;
+ }
+ // TODO: Use Random color or force a color from args
+ const embed = new EmbedBuilder()
+ .setColor(Colors.DarkGrey)
+ .setDescription(
+ `${loc.get("c_reminder5")} ${user} • ${loc.get(
+ "c_reminder6"
+ )} ${page}/${pageMax}`
+ )
+ .setThumbnail(user.displayAvatarURL());
- const limit = elementPerPage * page;
+ const limit = elementPerPage * page;
- if (reminders.length > 0 && page <= pageMax) {
- let curseur = limit - elementPerPage;
- reminders.splice(0, limit - elementPerPage);
- reminders.forEach((remind) => {
- if (curseur < limit) {
- let text = remind.data ?? loc.get('c_reminder7');
- if (text.length > 1024) {
- text = `${text.substring(0, 1021)}...`;
- }
- const expiration = `${loc.get('c_reminder8')} ${timeDeltaToString(remind.expiration_date)}`;
- embed.addFields({
- name: `#${remind.id} • ${loc.get('c_reminder9')} ${showDate(local, loc, new Date(Number(remind.creation_date)))}\n${expiration}`,
- value: text,
- inline: false,
- });
+ if (reminders.length > 0 && page <= pageMax) {
+ let curseur = limit - elementPerPage;
+ reminders.splice(0, limit - elementPerPage);
+ reminders.forEach((remind) => {
+ if (curseur < limit) {
+ let text = remind.data ?? loc.get("c_reminder7");
+ if (text.length > 1024) {
+ text = `${text.substring(0, 1021)}...`;
+ }
+ const expiration = `${loc.get("c_reminder8")} ${timeDeltaToString(
+ remind.expiration_date
+ )}`;
+ embed.addFields({
+ name: `#${remind.id} • ${loc.get("c_reminder9")} ${showDate(
+ local,
+ loc,
+ new Date(Number(remind.creation_date))
+ )}\n${expiration}`,
+ value: text,
+ inline: false,
+ });
- curseur++;
- }
- });
- } else {
- embed.addFields({ name: '\u200b', value: `${loc.get('c_reminder10')}${page} ${loc.get('c_reminder11')}.` });
- }
+ curseur++;
+ }
+ });
+ } else {
+ embed.addFields({
+ name: "\u200b",
+ value: `${loc.get("c_reminder10")}${page} ${loc.get("c_reminder11")}.`,
+ });
+ }
- return embed;
+ return embed;
};
diff --git a/src/utils/time.ts b/src/utils/time.ts
index 6e54c22..eb713f6 100644
--- a/src/utils/time.ts
+++ b/src/utils/time.ts
@@ -6,20 +6,20 @@
* @returns String
*/
export const showDate = (
- tz: string,
- locale: Map,
- date: Date
+ tz: string,
+ locale: Map,
+ date: Date
) => {
- return date.toLocaleString(tz).replace(' ', ` ${locale.get('u_time_at')} `);
+ return date.toLocaleString(tz).replace(" ", ` ${locale.get("u_time_at")} `);
};
enum TimeSecond {
- Year = 31536000,
- Week = 604800,
- Day = 86400,
- Hour = 3600,
- Minute = 60,
- Second = 1
+ Year = 31536000,
+ Week = 604800,
+ Day = 86400,
+ Hour = 3600,
+ Minute = 60,
+ Second = 1,
}
/**
@@ -28,18 +28,26 @@ enum TimeSecond {
* @returns time in seconds
*/
export const strToSeconds = (time: string) => {
- const regex = new RegExp(`(?<${TimeSecond[TimeSecond.Year]}>[0-9]+(?=[y|a]))|(?<${TimeSecond[TimeSecond.Week]}>[0-9]+(?=[w]))|(?<${TimeSecond[TimeSecond.Day]}>[0-9]+(?=[d|j]))|(?<${TimeSecond[TimeSecond.Hour]}>[0-9]+(?=[h]))|(?<${TimeSecond[TimeSecond.Minute]}>[0-9]+(?=[m]))|(?<${TimeSecond[TimeSecond.Second]}>[0-9]+(?=[s]?))`);
+ const regex = new RegExp(
+ `(?<${TimeSecond[TimeSecond.Year]}>[0-9]+(?=[y|a]))|(?<${
+ TimeSecond[TimeSecond.Week]
+ }>[0-9]+(?=[w]))|(?<${TimeSecond[TimeSecond.Day]}>[0-9]+(?=[d|j]))|(?<${
+ TimeSecond[TimeSecond.Hour]
+ }>[0-9]+(?=[h]))|(?<${TimeSecond[TimeSecond.Minute]}>[0-9]+(?=[m]))|(?<${
+ TimeSecond[TimeSecond.Second]
+ }>[0-9]+(?=[s]?))`
+ );
- const data = Object.assign({}, regex.exec(time)?.groups);
+ const data = Object.assign({}, regex.exec(time)?.groups);
- let res = 0;
- Object.entries(data).forEach(([key, value]) => {
- if (value) {
- res += +value * TimeSecond[key as keyof typeof TimeSecond];
- }
- });
+ let res = 0;
+ Object.entries(data).forEach(([key, value]) => {
+ if (value) {
+ res += +value * TimeSecond[key as keyof typeof TimeSecond];
+ }
+ });
- return res;
+ return res;
};
/**
@@ -48,7 +56,7 @@ export const strToSeconds = (time: string) => {
* @returns Delta between the time and now
*/
export const timeDeltaToString = (time: number) => {
- const now = Date.now();
- // TODO adapt the output and not always parse the time as seconds
- return `${strToSeconds(`${(now - time) / 1000}`)} secs`;
+ const now = Date.now();
+ // TODO adapt the output and not always parse the time as seconds
+ return `${strToSeconds(`${(now - time) / 1000}`)} secs`;
};
diff --git a/tsconfig.json b/tsconfig.json
index 5d0dfd6..333de2e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -11,10 +11,10 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
- "target": "es6", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+ "target": "es6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"lib": [
"ES2021.String"
- ], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+ ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
@@ -27,8 +27,8 @@
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
- "module": "commonjs", /* Specify what module code is generated. */
- "rootDir": "./src", /* Specify the root folder within your source files. */
+ "module": "commonjs" /* Specify what module code is generated. */,
+ "rootDir": "./src" /* Specify the root folder within your source files. */,
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
@@ -37,7 +37,7 @@
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
- "resolveJsonModule": true, /* Enable importing .json files. */
+ "resolveJsonModule": true /* Enable importing .json files. */,
// "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
@@ -51,7 +51,7 @@
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
- "outDir": "./dist", /* Specify an output folder for all emitted files. */
+ "outDir": "./dist" /* Specify an output folder for all emitted files. */,
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
@@ -73,12 +73,12 @@
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
- "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
+ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
- "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
+ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
- "strict": true, /* Enable all strict type-checking options. */
+ "strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
@@ -100,10 +100,7 @@
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
- "skipLibCheck": true /* Skip type checking all .d.ts files. */
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
},
- "include": [
- "./**/*.ts",
- "./src/locales/*.json"
- ]
+ "include": ["./**/*.ts", "./src/locales/*.json"]
}