diff --git a/.gitignore b/.gitignore index 7b216c4..ecaabc1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules/ assets/managers/rpManager.js private-slash-commands/*.js -script.js \ No newline at end of file +script.js +assets/data/tokens.json \ No newline at end of file diff --git a/assets/data/channelTypes.json b/assets/data/channelTypes.json new file mode 100644 index 0000000..4f04e43 --- /dev/null +++ b/assets/data/channelTypes.json @@ -0,0 +1,10 @@ +{ + "GUILD_TEXT": "salon textuel", + "GUILD_NEWS": "salon des annonces", + "GUILD_VOICE": "salon vocal", + "GUILD_STAGE_VOICE": "salon des conférences", + "GUILD_PRIVATE_THREAD": "fil privé", + "GUILD_PUBLIC_THREAD": "fil public", + "GUILD_NEWS_THREAD": "fil de salon des annonces", + "GUILD_CATEGORY": "catégorie" +} \ No newline at end of file diff --git a/assets/data/commands.json b/assets/data/commands.json index c47619e..c1f2563 100644 --- a/assets/data/commands.json +++ b/assets/data/commands.json @@ -113,1114 +113,5 @@ }, "path": "./commands/.devs/test.js" } - ], - "aide": [ - { - "name": "commande", - "help": { - "name": "commande", - "aliases": [ - "cmd", - "commande-help" - ], - "description": "Affiche l'aide concernant une commande", - "permissions": [], - "private": false, - "dm": true, - "cooldown": 5 - }, - "path": "./commands/aide/cmd.js" - }, - { - "name": "help", - "help": { - "name": "help", - "description": "Commande affichant toutes les autres commandes", - "aliases": [ - "aide" - ], - "permissions": [], - "cooldown": 5, - "private": false, - "dm": true - }, - "path": "./commands/aide/help.js" - } - ], - "giveaways": [ - { - "name": "gcreate", - "help": { - "name": "gcreate", - "description": "Crée un giveaway avec un système de messages", - "aliases": [ - "giveaway-create" - ], - "permissions": [ - "manage_guild" - ], - "dm": false, - "private": false, - "cooldown": 5 - }, - "path": "./commands/giveaways/create.js" - }, - { - "name": "gend", - "help": { - "name": "gend", - "description": "Termine un giveaway", - "permissions": [ - "manage_guild" - ], - "aliases": [ - "giveaway-end" - ], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/giveaways/end.js" - }, - { - "name": "glist", - "help": { - "name": "glist", - "description": "Affiche la liste des giveaways en cours sur le serveur", - "aliases": [ - "giveaway-list" - ], - "permissions": [ - "manage_guild" - ], - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/giveaways/list.js" - }, - { - "name": "greroll", - "help": { - "name": "greroll", - "description": "Reroll un giveaway", - "aliases": [ - "giveaway-reroll" - ], - "permissions": [ - "manage_guild" - ], - "dm": false, - "private": false, - "cooldown": 5 - }, - "path": "./commands/giveaways/reroll.js" - }, - { - "name": "gstart", - "help": { - "name": "gstart", - "description": "Démarre un giveaway", - "aliases": [ - "giveaway-start" - ], - "permissions": [ - "manage_guild" - ], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/giveaways/start.js" - } - ], - "mails": [ - { - "name": "mail", - "help": { - "name": "mail", - "description": "Mail", - "private": false, - "dm": true, - "permissions": [], - "aliases": [], - "cooldown": 5 - }, - "path": "./commands/mails/mail.js" - }, - { - "name": "mail-envoi", - "help": { - "name": "mail-envoi", - "description": "Envoie un mail à un utilisateur", - "aliases": [ - "msend", - "menvoi", - "e-mail" - ], - "permissions": [], - "dm": false, - "private": false, - "cooldown": 10 - }, - "path": "./commands/mails/send.js" - } - ], - "misc": [ - { - "name": "8ball", - "help": { - "name": "8ball", - "description": "Répond à votre question (aléatoirement)", - "aliases": [], - "permissions": [], - "cooldown": 5, - "private": false, - "dm": true - }, - "path": "./commands/misc/8ball.js" - }, - { - "name": "avatar", - "help": { - "name": "avatar", - "aliases": [ - "pp", - "pdp" - ], - "permissions": [], - "description": "Affiche la photo de profil d'un utilisateur", - "cooldown": 5, - "private": false, - "dm": true - }, - "path": "./commands/misc/avatar.js" - }, - { - "name": "blague", - "help": { - "name": "blague", - "description": "Affiche une blague aléatoire", - "permissions": [], - "aliases": [ - "joke" - ], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/misc/blague.js" - }, - { - "name": "crypt", - "help": { - "name": "crypt", - "description": "Crypte un texte selon le code de vigenere", - "aliases": [ - "encrypt" - ], - "permissions": [], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/misc/crypt.js" - }, - { - "name": "customcommand", - "help": { - "name": "customcommand", - "description": "Gère les commandes personnalisées", - "private": false, - "dm": false, - "aliases": [ - "cc" - ], - "permissions": [ - "manage_guild" - ], - "cooldown": 5 - }, - "path": "./commands/misc/customcommands.js" - }, - { - "name": "decrypt", - "help": { - "name": "decrypt", - "description": "Décrypte un texte selon le code de vigenere", - "aliases": [], - "permissions": [], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/misc/decrypt.js" - }, - { - "name": "documentation", - "help": { - "name": "documentation", - "aliases": [ - "doc" - ], - "description": "Affiche la documentation du bot", - "permissions": [], - "dm": true, - "private": false, - "cooldown": 5 - }, - "path": "./commands/misc/doc.js" - }, - { - "name": "drop", - "help": { - "name": "drop", - "description": "Fait un drop dans le salon actuel", - "permissions": [ - "manage_guild" - ], - "dm": false, - "private": false, - "aliases": [] - }, - "path": "./commands/misc/drop.js" - }, - { - "name": "embed", - "help": { - "name": "embed", - "description": "Construisez un embed avec des bouttons", - "aliases": [ - "embedbuilder" - ], - "permissions": [ - "manage_channels" - ], - "private": false, - "dm": false, - "cooldown": 15 - }, - "path": "./commands/misc/embed.js" - }, - { - "name": "farsight", - "help": { - "name": "farsight", - "appear": false, - "dm": true, - "private": false, - "cooldown": 5 - }, - "path": "./commands/misc/farsight.js" - }, - { - "name": "game-number", - "help": { - "name": "game-number", - "description": "Jouez à guess the number directement sur Discord. Peut se jouer à plusieurs en ajoutant multijoueur", - "aliases": [ - "guess-the-number" - ], - "permissions": [], - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/misc/gameNumber.js" - }, - { - "name": "generatepassword", - "help": { - "name": "generatepassword", - "aliases": [ - "getpassword" - ], - "permissions": [], - "description": "Vous génère un mot de passe aléatoire plus ou moins sécurisé en fonction de vos choix", - "cooldown": 5, - "private": false, - "dm": true - }, - "path": "./commands/misc/generatePassword.js" - }, - { - "name": "google", - "help": { - "name": "google", - "description": "Effectue une recherche google", - "permissions": [], - "aliases": [ - "googlesearch" - ], - "cooldown": 5, - "private": false, - "dm": true - }, - "path": "./commands/misc/google.js" - }, - { - "name": "herobrine", - "help": { - "name": "herobrine", - "appear": false, - "dm": false, - "private": false, - "permissions": [ - "administrator" - ], - "aliases": [], - "description": ".", - "cooldown": 5 - }, - "path": "./commands/misc/herobrine.js" - }, - { - "name": "invite", - "help": { - "name": "invite", - "aliases": [ - "link" - ], - "description": "Envoie le lien d'invitation du bot", - "permissions": [], - "cooldown": 1, - "private": false, - "dm": true - }, - "path": "./commands/misc/invite.js" - }, - { - "name": "top", - "help": { - "name": "top", - "aliases": [ - "levels" - ], - "description": "Affiche le classement des niveaux sur le serveur", - "permissions": [], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/misc/levels.js" - }, - { - "name": "demineur", - "help": { - "name": "demineur", - "description": "Lance une partie de démineur sur Discord", - "aliases": [ - "minesweeper" - ], - "permissions": [], - "cooldown": 5, - "private": false, - "dm": true - }, - "path": "./commands/misc/minesweeper.js" - }, - { - "name": "morpion", - "help": { - "name": "morpion", - "description": "Joue au morpion", - "aliases": [ - "tictactoe", - "tic-tac-toe" - ], - "permissions": [], - "private": false, - "dm": false, - "cooldown": 10 - }, - "path": "./commands/misc/morpion.js" - }, - { - "name": "pile-ou-face", - "help": { - "name": "pile-ou-face", - "description": "Lance une pièce pour le pile ou face", - "aliases": [ - "pof", - "pileouface" - ], - "permissions": [], - "cooldown": 5, - "private": false, - "dm": true - }, - "path": "./commands/misc/pileOuFace.js" - }, - { - "name": "rank", - "help": { - "name": "rank", - "description": "Affiche les informations de niveaux d'un utilisateur mentionné.", - "aliases": [ - "lvl" - ], - "permissions": [], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/misc/rank.js" - }, - { - "name": "rappel", - "help": { - "name": "rappel", - "description": "Gère vos rappels", - "aliases": [ - "rmd", - "remind", - "reminders", - "rap" - ], - "permissions": [], - "dm": true, - "private": false, - "cooldown": 5 - }, - "path": "./commands/misc/remind.js" - }, - { - "name": "contact", - "help": { - "name": "contact", - "aliases": [ - "bug", - "erreur", - "report" - ], - "description": "Signale un bug à Greensky", - "permissions": [], - "dm": true, - "private": false, - "cooldown": 5 - }, - "path": "./commands/misc/report.js" - }, - { - "name": "roulette-russe", - "help": { - "name": "roulette-russe", - "description": "Joue à la roulette russe", - "aliases": [ - "russian-roulette", - "rr" - ], - "permissions": [], - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/misc/russian-roulette.js" - }, - { - "name": "suggestion", - "help": { - "name": "suggestion", - "description": "Envoie une suggestion **dans le salon actuel**", - "aliases": [ - "suggest" - ], - "permissions": [], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/misc/suggestion.js" - }, - { - "name": "super-secret-settings", - "help": { - "name": "super-secret-settings", - "appear": false, - "permissions": [], - "aliases": [ - "supersecretsettings", - "sss" - ], - "cooldown": 5, - "private": false, - "dm": true - }, - "path": "./commands/misc/supersecretsettings.js" - }, - { - "name": "support", - "help": { - "name": "support", - "description": "Affiche le lien du serveur de support.", - "aliases": [ - "support-server", - "support-server" - ], - "permissions": [], - "private": false, - "dm": true, - "cooldown": 1 - }, - "path": "./commands/misc/support.js" - }, - { - "name": "ticket", - "help": { - "name": "ticket", - "description": "Interagir avec le système de ticket. Utilisez `help` en argument pour avoir l'aide.", - "private": false, - "dm": false, - "aliases": [], - "permissions": [], - "cooldown": 5 - }, - "path": "./commands/misc/ticket.js" - } - ], - "moderation": [ - { - "name": "ban", - "help": { - "name": "ban", - "permissions": [ - "ban_members" - ], - "description": "Permet de bannir un membre", - "aliases": [], - "private": false, - "dm": false, - "cooldown": 15 - }, - "path": "./commands/moderation/ban.js" - }, - { - "name": "censure", - "help": { - "name": "censure", - "description": "Censure le pseudo d'un membre", - "aliases": [], - "permissions": [ - "manage_guild" - ], - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/moderation/censor.js" - }, - { - "name": "create-channel", - "help": { - "name": "create-channel", - "aliases": [ - "channel-create" - ], - "permissions": [ - "manage_channels" - ], - "description": "Permet de créer un salon", - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/moderation/channel-create.js" - }, - { - "name": "clear", - "help": { - "name": "clear", - "aliases": [], - "description": "Nettoie un certain nombre de messages dans un salon", - "permissions": [ - "manage_messages" - ], - "private": false, - "dm": false, - "cooldown": 10 - }, - "path": "./commands/moderation/clear.js" - }, - { - "name": "set", - "help": { - "name": "set", - "aliases": [ - "config", - "configs", - "settings", - "configssettings" - ], - "description": "Configure les différents paramètres modifiables", - "permissions": [ - "manage_guild" - ], - "private": false, - "dm": false, - "cooldown": 10 - }, - "path": "./commands/moderation/config.js" - }, - { - "name": "demote", - "help": { - "name": "demote", - "description": "Retire un ou plusieurs roles à un utilisateur. Utilisez `help` pour avoir toutes les informations.", - "aliases": [ - "downgrade", - "role-remove" - ], - "permissions": [ - "MANAGE_ROLES" - ], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/moderation/demote.js" - }, - { - "name": "edit-case", - "help": { - "name": "edit-case", - "description": "Modifie une case de modération", - "aliases": [], - "permissions": [ - "manage_guild" - ], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/moderation/edit-case.js" - }, - { - "name": "filtre-case-action", - "help": { - "name": "filtre-case-action", - "description": "Filtre les cases de modération selon votre choix.", - "private": false, - "aliases": [ - "filtre-modlogs" - ], - "permissions": [ - "manage_guild" - ], - "dm": false, - "cooldown": 5 - }, - "path": "./commands/moderation/filtre-case-action.js" - }, - { - "name": "kick", - "help": { - "name": "kick", - "description": "Expulse un membre du serveur pour une raison donnée", - "permissions": [ - "kick_members" - ], - "aliases": [ - "expulse" - ], - "private": false, - "dm": false, - "cooldown": 10 - }, - "path": "./commands/moderation/kick.js" - }, - { - "name": "lock", - "help": { - "name": "lock", - "aliases": [ - "channellock", - "lockchannel", - "lock-channel", - "channel-lock" - ], - "permissions": [ - "manage_channels" - ], - "cooldown": 5, - "private": false, - "dm": false, - "description": "Vérouille un salon pour le role everyone" - }, - "path": "./commands/moderation/lock.js" - }, - { - "name": "log", - "help": { - "name": "log", - "description": "Affiche un log de modération donné", - "aliases": [ - "log-info" - ], - "permissions": [ - "MANAGE_GUILD" - ], - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/moderation/log.js" - }, - { - "name": "massban", - "help": { - "name": "massban", - "description": "Permet de bannir plusieurs membres à la fois", - "aliases": [ - "multipleban" - ], - "permissions": [ - "ban_members" - ], - "private": false, - "dm": false, - "cooldown": 10 - }, - "path": "./commands/moderation/massBan.js" - }, - { - "name": "modlogs", - "help": { - "name": "modlogs", - "description": "Affiche les logs de modération", - "aliases": [], - "permissions": [ - "manage_guild" - ], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/moderation/modlogs.js" - }, - { - "name": "mute", - "help": { - "name": "mute", - "description": "Rend un membre du serveur muet", - "permissions": [ - "kick_members" - ], - "aliases": [], - "private": false, - "dm": false, - "cooldown": 10 - }, - "path": "./commands/moderation/mute.js" - }, - { - "name": "nuke", - "help": { - "name": "nuke", - "description": "Nettoie un salon entier", - "cooldown": 10, - "permissions": [ - "manage_channels" - ], - "private": false, - "dm": false, - "aliases": [] - }, - "path": "./commands/moderation/nuke.js" - }, - { - "name": "pin", - "help": { - "name": "pin", - "aliases": [ - "epingle", - "épingle" - ], - "permissions": [ - "manage_messages" - ], - "description": "Épingle un message. Utilisez un identifiant.", - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/moderation/pin.js" - }, - { - "name": "prefix", - "help": { - "name": "prefix", - "description": "Configure le préfixe.", - "aliases": [ - "prefixe" - ], - "permissions": [ - "manage_guild" - ], - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/moderation/prefix.js" - }, - { - "name": "purge", - "help": { - "name": "purge", - "description": "Ban tous les membres GBannis du serveur.", - "permissions": [ - "ADMINISTRATOR" - ], - "aliases": [ - "gban-purge" - ], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/moderation/purge.js" - }, - { - "name": "role", - "help": { - "name": "role", - "description": "Ajoute un rôle choisi à un utilisateur choisi", - "permissions": [ - "manage_roles" - ], - "aliases": [ - "addrole" - ], - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/moderation/role.js" - }, - { - "name": "see-warns", - "help": { - "name": "see-warns", - "aliases": [ - "infractions", - "seewarns" - ], - "description": "Montre les avertissements d'un utilisateur.", - "permissions": [ - "manage_guild" - ], - "dm": false, - "private": false, - "cooldown": 5 - }, - "path": "./commands/moderation/see-warns.js" - }, - { - "name": "slowmode", - "help": { - "name": "slowmode", - "description": "Configure le slowmode du salon", - "permissions": [ - "manage_channels" - ], - "aliases": [], - "private": false, - "dm": false, - "cooldown": 5 - }, - "path": "./commands/moderation/slowmode.js" - }, - { - "name": "snipe", - "help": { - "name": "snipe", - "description": "Affiche le dernier message supprimé dans le salon, et plus si un nombre est spécifié.", - "aliases": [], - "permissions": [ - "manage_messages" - ], - "dm": false, - "private": false, - "cooldown": 5 - }, - "path": "./commands/moderation/snipe.js" - }, - { - "name": "sondage", - "help": { - "name": "sondage", - "description": "Faites un sondage, utilisez-là de cette manière\n\n`gs sondage --choix 1 --choix 2... --choix 7` ou simplement aucun choix", - "aliases": [ - "poll" - ], - "permissions": [ - "manage_guild" - ], - "cooldown": 10, - "private": false, - "dm": false - }, - "path": "./commands/moderation/sondage.js" - }, - { - "name": "ticket-config", - "help": { - "name": "ticket-config", - "description": "Configurez un panel de ticket. Utilisez `create` pour le créer et `delete` pour le supprimer.", - "aliases": [ - "configtickets", - "config-tickets", - "tickets-config", - "ticket-panel", - "ticket-configs" - ], - "permissions": [ - "manage_guild" - ], - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/moderation/ticket-manage.js" - }, - { - "name": "unban", - "help": { - "name": "unban", - "description": "Débanni un utilisateur du serveur. Utilisez l'identifiant du membre.", - "aliases": [ - "deban" - ], - "permissions": [ - "ban_members" - ], - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/moderation/unban.js" - }, - { - "name": "unlock", - "help": { - "name": "unlock", - "description": "Dévérouille le salon pour le rôle everyone", - "permissions": [ - "manage_channels" - ], - "aliases": [], - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/moderation/unlock.js" - }, - { - "name": "unmute", - "help": { - "name": "unmute", - "description": "Démute un membre mentionné", - "aliases": [ - "demute" - ], - "permissions": [ - "manage_roles" - ], - "dm": false, - "private": false, - "cooldown": 10 - }, - "path": "./commands/moderation/unmute.js" - }, - { - "name": "unpin", - "help": { - "name": "unpin", - "aliases": [ - "desepingle", - "désepingle" - ], - "permissions": [ - "manage_messages" - ], - "description": "Désepingle un message. Utilisez un identifiant.", - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/moderation/unpin.js" - }, - { - "name": "unwarn", - "help": { - "name": "unwarn", - "aliases": [ - "dewarn" - ], - "permissions": [ - "manage_guild" - ], - "description": "Enlève un avertissement à un utilsateur", - "cooldown": 5, - "private": false, - "dm": false - }, - "path": "./commands/moderation/unwarn.js" - }, - { - "name": "warn", - "help": { - "name": "warn", - "description": "Avertit un membre", - "aliases": [ - "avertit" - ], - "permissions": [ - "manage_guild" - ], - "dm": false, - "private": false, - "cooldown": 5 - }, - "path": "./commands/moderation/warn.js" - } - ], - "rolereacts": [ - { - "name": "role-react-manage", - "help": { - "name": "role-react-manage", - "aliases": [ - "rrm", - "manage-rolesreact", - "manage-rolereact", - "rm" - ], - "description": "Configure les rôles à réactions", - "permissions": [ - "manage_guild" - ], - "dm": false, - "private": false, - "cooldown": 5 - }, - "path": "./commands/rolereacts/manage.js" - } - ], - "rpg": [ - { - "name": "adventure", - "help": { - "name": "adventure", - "aliases": [ - "aventure" - ], - "description": "Obtenez les infos sur le RPG", - "permissions": [], - "cooldown": 5, - "private": false, - "dm": true - }, - "path": "./commands/rpg/adventure.js" - } ] } \ No newline at end of file diff --git a/assets/data/configs.json b/assets/data/configs.json index e06b133..e1da856 100644 --- a/assets/data/configs.json +++ b/assets/data/configs.json @@ -120,24 +120,6 @@ "description": "Définit le message de niveau", "param": "level_message" }, - { - "name": "Système de niveaux", - "type": "boolean", - "description": "Active ou désactive le système de niveaux", - "param": "level_enable" - }, - { - "name": "Système d'interchat", - "type": "boolean", - "description": "Active ou désactive le système d'interchat", - "param": "interchat_enable" - }, - { - "name": "Salon d'interchat", - "type": "channel", - "description": "Configure le salon d'interchat", - "param": "interchat_channel" - }, { "name": "Roles d'arrivée", "type": "boolean", @@ -163,10 +145,16 @@ "param": "counting_channel" }, { - "name": "Système d'économie", + "name": "Système de tickets", "type": "boolean", - "description": "Active ou désactive le système d'économie", - "param": "economy_enable" + "description": "Active oudésactive le système de tickets", + "param": "ticket_enable" + }, + { + "name": "Salon des suggestions", + "type": "channel", + "description": "Configurer le salon des suggestions", + "param": "suggest_channel" } ] } \ No newline at end of file diff --git a/assets/data/data.json b/assets/data/data.json index 33ada91..136aa97 100644 --- a/assets/data/data.json +++ b/assets/data/data.json @@ -1,17 +1,17 @@ { - "token": "OTkxMzY1ODk4Nzc2NjI1MjA0.GVhCUd.YDI6iS1NQ75MkmmNjLVu77qvvqJ6T4FakVKn2g", "default_prefix": "+", "gs": "386479065307152384", "yz": "582211583938134028", + "swiz": "696324357940838492", "support": "https://discord.gg/Qt9Ns3uvYe", "errorChannel": "839497213113270322", "botID": "918137973202112592", "contactChannel": "827790768272834580", - "version": "1.4.2", - "beta_token": "OTE4MTM3OTczMjAyMTEyNTky.G5q2vD.tYpVroN28ovgVIPXUKR9GDVqmZexUEwneXTTLk", - "beta": false, + "version": "1.5.4", + "beta": true, "doc": "https://bit.ly/3c37f8V", "link": "https://bit.ly/3NUdTvE", + "topgg": "https://bit.ly/3pvu2hr", "error": { "id": "976874250260578404", "token": "LC8ld5MDeX1wh-DAtnhnBf9SsI8wevos2Q9N0PiqkhKWhzaT3G934trT9DqbCRQlLKkd", diff --git a/assets/data/modules.json b/assets/data/modules.json new file mode 100644 index 0000000..27954f5 --- /dev/null +++ b/assets/data/modules.json @@ -0,0 +1,37 @@ +[ + { + "name": "Économie", + "value": "economy", + "default": false + }, + { + "name": "Modération", + "value": "moderation", + "default": true + }, + { + "name": "Utilitaires", + "value": "usefull", + "default": true + }, + { + "name": "Amusement", + "value": "fun", + "default": true + }, + { + "name": "Informations", + "value": "information", + "default": true + }, + { + "name": "Divers", + "value": "misc", + "default": true + }, + { + "name": "Niveaux", + "value": "levels", + "default": false + } +] \ No newline at end of file diff --git a/assets/data/objectgw.ts.ignore b/assets/data/objectgw.ts.ignore deleted file mode 100644 index 034e645..0000000 --- a/assets/data/objectgw.ts.ignore +++ /dev/null @@ -1,10 +0,0 @@ -export class gw { - public reward: String; - public winnerCount: Number; - public endsAt: Number; - public guild_id: String; - public channel_id: String; - public message_id: String; - public hoster_id: String; - public path: String; -}; \ No newline at end of file diff --git a/assets/data/perms.json b/assets/data/perms.json index f550ee2..70ba089 100644 --- a/assets/data/perms.json +++ b/assets/data/perms.json @@ -1,2 +1,3 @@ -{"CREATE_INSTANT_INVITE":"Créer des invitations","KICK_MEMBERS": "Expulser des membres","BAN_MEMBERS": "Bannir des membres","ADMINISTRATOR": "Administrateur","MANAGE_CHANNELS": "Gérer les salons","MANAGE_GUILD": "Gérer le serveur","ADD_REACTIONS": "Ajouter des réactions","VIEW_AUDIT_LOG": "Voir les logs du serveur","PRIORITY_SPEAKER": "Voix prioritaire","STREAM": "Faire des streams","VIEW_CHANNEL": "Voir les salons","SEND_MESSAGES": "Envoyer des messages","SEND_TTS_MESSAGES": "Envoyer des TTS","MANAGE_MESSAGES": "Gérer les messages","EMBED_LINKS": "envoyer des liens","ATTACH_FILES": "Envoyer des fichiers","READ_MESSAGE_HISTORY": "Voir l'historique des messages","MENTION_EVERYONE": "Mentionner les rôles","USE_EXTERNAL_EMOJIS": "Utiliser des émojis externes","VIEW_GUILD_INSIGHTS": "Voir les paramètres du serveur","CONNECT": "Se connecter à des salons vocaux","SPEAK": "Parler en vocal","MUTE_MEMBERS": "Rendre des membres muets","DEAFEN_MEMBERS": "Déconnecter des membres","MOVE_MEMBERS": "Changer les membres de salons","USE_VAD": "je ne connais pas cette permission", - "CHANGE_NICKNAME": "Changer le pseudo","MANAGE_NICKNAMES": "Gérer les pseudos","MANAGE_ROLES": "Gérer les rôles","MANAGE_WEBHOOKS": "Gérer les webhooks","MANAGE_EMOJIS": "Gérer les émojis"} \ No newline at end of file +{"CREATE_INSTANT_INVITE":"Créer des invitations","KICK_MEMBERS": "Expulser des membres","BAN_MEMBERS": "Bannir des membres","ADMINISTRATOR": "Administrateur","MANAGE_CHANNELS": "Gérer les salons","MANAGE_GUILD": "Gérer le serveur","ADD_REACTIONS": "Ajouter des réactions","VIEW_AUDIT_LOG": "Voir les logs du serveur","PRIORITY_SPEAKER": "Voix prioritaire","STREAM": "Faire des streams","VIEW_CHANNEL": "Voir les salons","SEND_MESSAGES": "Envoyer des messages","SEND_TTS_MESSAGES": "Envoyer des TTS","MANAGE_MESSAGES": "Gérer les messages","EMBED_LINKS": "envoyer des liens","ATTACH_FILES": "Envoyer des fichiers","READ_MESSAGE_HISTORY": "Voir l'historique des messages","MENTION_EVERYONE": "Mentionner les rôles","USE_EXTERNAL_EMOJIS": "Utiliser des émojis externes","VIEW_GUILD_INSIGHTS": "Voir les paramètres du serveur","CONNECT": "Se connecter à des salons vocaux","SPEAK": "Parler en vocal","MUTE_MEMBERS": "Rendre des membres muets","DEAFEN_MEMBERS": "Déconnecter des membres","MOVE_MEMBERS": "Changer les membres de salons","USE_VAD": "Utiliser la détection de la voix", + "CHANGE_NICKNAME": "Changer le pseudo","MANAGE_NICKNAMES": "Gérer les pseudos","MANAGE_ROLES": "Gérer les rôles","MANAGE_WEBHOOKS": "Gérer les webhooks","MANAGE_EMOJIS_AND_STICKERS": "Gérer les émojis et les stickers", +"MANAGE_EVENTS": "Gérer les évènements", "MANAGE_THREADS": "Gérer les fils", "USE_APPLICATION_COMMANDS": "Utiliser les slash commandes", "SEND_MESSAGES_IN_THREADS": "Envoyer des messages dans un fil", "CREATE_PUBLIC_THREADS": "Créer des fils publiques", "CREATE_PRIVATE_THREADS": "Créer des fils privés"} \ No newline at end of file diff --git a/assets/data/splash.json b/assets/data/splash.json index 83f51a7..04b6a06 100644 --- a/assets/data/splash.json +++ b/assets/data/splash.json @@ -2,9 +2,11 @@ "{username} is you","4 815 162 342 lignes of code", "Made by Greensky", "And my webhook", "The cake was a lie", "Here's Jhonny", "May contain nuts", "Limited version", "It's here", "Indev !", "Check it out", "Yeah booooy", "Greensky bot", "There is no game", "Yaay !", "Singleplayer", "This is an easter egg !", "Bring pizza !", "Water proof", "Uninflammable", "Waw dude !", "Take frequent breaks", "Gargamel plays it", "Oui oui baguette", "Webdriver torso", "Google analyticsed", "Don't use 1234 as password !", "...", "Stay for a while, stay forever", "Stay for a while and listen", "Best treatment", "Never loose at tic tac toe", "Greensky has amazing hair !", "This text will never appear, isn't that weird?", "Also try Koya", "Also try Draftbot", "Also try Kirby", "Also try minecraft", - "Less addictive than TV", "More addictive than lemonade", "Read more books", "This is my true form", "Do a barrel roll", "Déjà vu !", "Déjà vu !", "日本ハロー!", "const bot = new GreenskyBot()", "Who put it here ?", "Can someone explain that ?", ".party()", "Put that cookie down !", "I've a suggestion !", "Yay ! Puppies for everyone", "Rule #1 : It's never my fault", + "Less addictive than TV", "More addictive than lemonade", "Read more books", "This is my true form", "Do a barrel roll", "Déjà vu !", "Déjà vu !", "日本ハロー!", "const Oracle = new GreenskyBot()", "Who put it here ?", "Can someone explain that ?", ".party()", "Put that cookie down !", "I've a suggestion !", "Yay ! Puppies for everyone", "Rule #1 : It's never my fault", "You'r going too fast", "I drunk coffeeererfezaee", "Thank you for the fish ^^", "I need more context", "Ahh !", "Don't worry, be happy !", "Water bottle", "Everybody needs somebody", "I told you months ago", "Rainbow cat ?", "a coffin can dance ?", "Click on the link", "It came from space", "Look mum, I'm a splash !", "In case it isn't obvious, foxes are not players", "Wash your hands", "Soap and water", "Support local business", "Stay at home play games", "Stay strong", "Stay safe !", "Save the world, stay at home", "Black lives matters", "Be anti-racist", "There's < { - return new MessageEmbed() + let u = user; + if (u.guild) u = u.user; + return new EmbedBuilder() .setTimestamp() - .setFooter({ text: user.username.toString(), iconURL: user.avatarURL({dynamic: true})}) + .setFooter({ text: u.username.toString(), iconURL: u.avatarURL({dynamic: true})}) } module.exports = { /** * @param {User} user - * @returns {MessageEmbed} + * @returns {EmbedBuilder} */ noUser: (user) => { - return new MessageEmbed() - .setTitle("Utilisateur introuvable") + return new EmbedBuilder() + .setTitle("🚫 Utilisateur introuvable") .setColor('DARK_RED') .setDescription(`Oops, cet utilisateur est introuvable, réessayez avec l'identifiant ou la mention.\n> Un [utilisateur](https://github.com/BotOracle/Documentation/blob/main/others/user.md) est attendu.`) }, invalidNumber: (user) => { return generateBasic(user) - .setTitle("Nombre invalide") + .setTitle("🚫 Nombre invalide") .setColor('RED') .setDescription(`Oops, on dirait que ce n'est pas un nombre correct.\n> Un [nombre](https://github.com/BotOracle/Documentation/blob/main/others/nombre.md) est attendu`) }, noReason: (user) => { return generateBasic(user) - .setTitle("Raison invalide") + .setTitle("🚫 Raison invalide") .setColor('RED') .setDescription(`Oops, vous avez oublié de saisir la raison.\n> Un [texte](https://github.com/BotOracle/Documentation/blob/main/others/texte.md) est attendu`) }, notEnoughHiger: (user, member) => { return generateBasic(user) - .setTitle("Vous n'êtes pas assez élevé") + .setTitle("🚫 Vous n'êtes pas assez élevé") .setDescription(`Oops, <@${member.id}> est supérieur ou égal à vous dans la hiérarchie des rôles.`) .setColor('DARK_RED') }, @@ -49,10 +51,11 @@ module.exports = { * @param {Discord.Guild} guild */ log: (guild) => { - let embed = new MessageEmbed() + let embed = new EmbedBuilder() .setTimestamp() if (guild.icon) embed.setFooter({ text: guild.name, iconURL: guild.iconURL({ dynamic: true })}) + else embed.setFooter({ text: guild.name }) return embed; }, /** @@ -61,30 +64,30 @@ module.exports = { */ noChannel: (user) => { return generateBasic(user) - .setTitle("Salon inexistant") + .setTitle("🚫 Salon inexistant") .setDescription(`Oops, ce salon n'existe pas, réessayez avec identifiant ou la mention.\n> Un [salon](https://github.com/BotOracle/Documentation/blob/main/others/salon.md) est attendu`) .setColor('RED') }, cancel: () => { - return new MessageEmbed() + return new EmbedBuilder() .setTitle(`:bulb: Commande annulée`) .setColor('YELLOW') }, noText: (user) => { return generateBasic(user) - .setTitle("Pas de texte") + .setTitle("🚫 Pas de texte") .setColor('RED') .setDescription(`Oops, vous avez oublié le texte, réessayez la commande en saisissant un texte.\n> Un [texte](https://github.com/BotOracle/Documentation/blob/main/others/texte.md) est attendu`) }, collectorNoMessage: (user) => { return generateBasic(user) - .setTitle("Aucune réponse") + .setTitle("🚫 Aucune réponse") .setColor('RED') .setDescription(`<@${user.id}>, je vous ai proposé un collecteur de messages mais il se trouve que vous n'y avez pas répondu.\nVeuillez réessayer.\n> Vous utilisez un [collecteur de messages](https://github.com/BotOracle/Documentation/blob/main/others/msg-collector.md)`) }, invalidTime: (user) => { return generateBasic(user) - .setTitle("Durée invalide :x:") + .setTitle("🚫 Durée invalide :x:") .setColor('RED') .setDescription(`Oops, ce n'est pas une durée valide, utilisez :\n\`s\` pour secondes\n\`m\` pour minutes\n\`h\` pour heures\n\`d\` pour jours\n\`y\` pour années.\n> [Documentation](https://github.com/BotOracle/Documentation/blob/main/others/temps.md)`) }, @@ -95,53 +98,53 @@ module.exports = { collections.errorsOnInvalidArg.set(user.id, collections.errorsOnInvalidArg.get(user.id) + 1); return generateBasic(user) - .setTitle("Arguments invalides :x:") + .setTitle("🚫 Arguments invalides :x:") .setDescription(text) .setColor('RED') }, waitForReacts: () => { - return new MessageEmbed() + return new EmbedBuilder() .setDescription(`${emojis.loading} Patientez le temps de l'ajout des réactions`) .setColor('YELLOW') }, errorSQL: (user) => { let text = "Vous ne devriez pas rencontrer ce problème, une erreur a eu lieu lors de l'interaction avec la base de données."; if (!collections.errors.has(user.id)) collections.errors.set(user.id, 0); - if (collections.errors.get(user.id) > 3) text += "\nPrévenez mon développeur si cela persiste." + if (collections.errors.get(user.id) > 3) text += `\nPrévenez mon développeur via la commande \`/contact\` ou par le [serveur de support](${data.support}) si l'erreur persiste.` collections.errors.set(user.id, collections.errors.get(user.id) + 1); return generateBasic(user) - .setTitle("Oops") + .setTitle("🚫 Oops") .setDescription(text) .setColor('#ff0000') }, guillement: (user) => { return generateBasic(user) - .setTitle("Oula !") + .setTitle("🚫 Erreur de guillemets") .setDescription(`Oops, vous ne pouvez pas saisir de \`"\` pour des raisons de sécurité.`) .setColor('#ff0000') }, noRole: (user) => { return generateBasic(user) - .setTitle("Pas de rôle") + .setTitle("🚫 Pas de rôle") .setDescription(`Vous n'avez pas précisé de [**rôle**](https://github.com/BotOracle/Documentation/blob/main/others/role.md)`) .setColor('#ff0000') }, noRoles: (user) => { return generateBasic(user) - .setTitle("Pas de rôles") + .setTitle("🚫 Pas de rôles") .setDescription(`Je n'ai pas trouvé suffisament de [**rôles**](https://github.com/BotOracle/Documentation/blob/main/others/role.md).`) .setColor('#ff0000') }, noMember: (user) => { return generateBasic(user) - .setTitle("Pas de membres") + .setTitle("🚫 Pas de membres") .setDescription(`Je n'ai pas trouvé suffisament de [**membres**](https://github.com/BotOracle/Documentation/blob/main/others/user.md).`) .setColor('#ff0000') }, noText: (user) => { return generateBasic(user) - .setTitle("Texte manquant") + .setTitle("🚫 Texte manquant") .setDescription(`Vous avez oublié de saisir un **texte**.\n> Un [texte](https://github.com/BotOracle/Documentation/blob/main/others/texte.md) est attendu`) .setColor('#ff0000') }, @@ -153,7 +156,7 @@ module.exports = { }, missingPermission: (user, perm) => { return generateBasic(user) - .setTitle("Permission manquante") + .setTitle("🚫 Permission manquante") .setDescription(`La permission \`${perm}\` est requise pour exécuter cette commande.`) .setColor('#ff0000') }, @@ -167,14 +170,118 @@ module.exports = { }, notTextChannel: (user) => { return generateBasic(user) - .setTitle("Salon invalide") + .setTitle("🚫 Salon invalide") .setDescription(`Le salon que vous avez spécifié n'est pas un salon textuel.`) .setColor('#ff0000') }, notEnoughCoins: (user) => { return generateBasic(user) - .setTitle(`Pas assez ${data.coinsSuffix}`) + .setTitle(`🚫 Pas assez ${data.coinsSuffix}`) .setDescription(`Vous n'avez pas assez ${data.coinsSuffix} pour faire ça.\n> :bulb:\n> Les ${data.coins} sont ceux comptés **qui ne sont pas dans votre banque**`) .setColor('#ff0000') + }, + loto: { + /** + * + * @param {User} user + * @param {'participate' | 'end'} type + * @returns + */ + invalidLoto: (user, type) => { + return generateBasic(user) + .setTitle("❌ Loto invalide") + .setDescription(`Il n'y a pas de loto sur le serveur.\n\n:warning:\n> Vous ne pouvez participer qu'a un loto en cours\n> Vous ne pouvez faire le tirage sur un loto terminé`) + .setColor('#ff0000') + }, + invalidNumbers: (user) => { + return generateBasic(user) + .setTitle("🚫 Nombres invalides") + .setDescription(`Les nombres que vous avez spécifié sont invalides.\n**Vérifiez que vous avez le même nombre de numéro que celui requis**.\n:warning: Vous ne pouvez pas jouer deux fois le même numéro`) + .setColor('#ff0000') + }, + alreadyParticipate: (user) => { + return generateBasic(user) + .setTitle("❌ Participation déjà enregistrée") + .setColor('#ff0000') + .setDescription(`Vous participez déjà à ce loto`) + }, + /** + * @param {User} user + * @param {Number[]} numbers + * @param {Number[]} complementaries + */ + added: (user, numbers, complementaries) => { + return generateBasic(user) + .setTitle("✅ Participation enregistrée") + .setDescription(`J'ai enregistré votre participation`) + .addFields( + { + name: "Numéro gagnants", + value: numbers.join(', '), + inline: true + }, + { + name: "Numéro complémentaires", + value: complementaries.join(', '), + inline: true + } + ) + .setColor('#00ff00') + }, + /** + * @param {{ numbers: Number[], complementaries: Number[], winners: [], user: User }} Edata + */ + end: (Edata) => { + return generateBasic(Edata.user) + .setTitle('🎉 Tirage') + .setDescription(`**Numéro gagnants :** ${Edata.numbers.join(' ')}\n**Numéro complémentaires :** ${Edata.complementaries.join(' ')} + +${Edata.winners.length == 0 ? 'Pas de gagnants' : Edata.winners.map(w => `<@${w.user_id}> : ${w.reward} ${data.coins.toLocaleString('fr-DE')}`).join('\n')}`) + .setColor('#00ee00') + .setFooter({ iconURL: undefined, text: `Les ${data.coins} ont été ajoutés au(x) gagnant(s)` }) + }, + started: (user, numbers, complementaries, reward, Rtime) => { + let time = ((parseInt(Rtime) + Date.now()) / 1000).toFixed(0); + + return generateBasic(user) + .setTitle("🎉 Loto lancé") + .setDescription(`Le loto a été lancé !\nIl prendra fin le ( )\n\nPour participer il faut **${numbers}** numéro et **${complementaries}** numéro complémentaires.\n\nRécompense :\n${reward} ${data.coins}`) + .addFields( + { + name: "Participer", + value: `Utilisez la commande \`/loto participer\` pour participer`, + inline: false + } + ) + .setColor('#ff0000') + } + }, + giveaway: { + noGw: (user, id) => { + return generateBasic(user) + .setTitle("❌ Giveaway introuvable") + .setDescription(`Le giveaway avec l'identifiant \`${id}\` est introuvable.`) + .setColor('#ff0000') + }, + alreadyEnded: (user) => { + return generateBasic(user) + .setTitle("❌ Giveaway terminé") + .setDescription(`Ce giveaway est déjà terminé`) + .setColor('#ff0000') + }, + notEnded: (user) => { + return generateBasic(user) + .setTitle("❌ Giveaway en cours") + .setDescription(`Ce giveaway n'est pas terminé`) + .setColor('#ff0000') + } + }, + /** + * @param {Guild} guild + */ + logs: (guild) => { + return new EmbedBuilder() + .setFooter({ text: guild.name, iconURL: guild.icon ? guild.iconURL({ dynamic: true }) : guild.client.user.avatarURL() }) + .setTimestamp() } } \ No newline at end of file diff --git a/assets/functions.js b/assets/functions.js index 28998a9..c933f89 100644 --- a/assets/functions.js +++ b/assets/functions.js @@ -25,7 +25,8 @@ module.exports = { perms: require('./data/perms.json'), personnages: require('./rpg/personnages.json'), configs: require('./data/data.json'), - rubis: require('./rpg/rubis.json') + rubis: require('./rpg/rubis.json'), + channelTypes: require('./data/channelTypes.json') } return package; @@ -49,22 +50,22 @@ module.exports = { let index = 0; let id = paginationName; - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .addComponents( - new Discord.MessageButton() + new Discord.ButtonBuilder() .setEmoji('◀') .setCustomId('arrière') - .setStyle('SECONDARY'), - new Discord.MessageButton() + .setStyle(Discord.ButtonStyle.Secondary), + new Discord.ButtonBuilder() .setEmoji('🔢') .setCustomId('select') - .setStyle('PRIMARY'), - new Discord.MessageButton() - .setStyle('SECONDARY') + .setStyle(Discord.ButtonStyle.Primary), + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Secondary) .setEmoji('▶') .setCustomId('avant'), - new Discord.MessageButton() - .setStyle('DANGER') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Danger) .setCustomId('close') .setEmoji('❌') ) @@ -98,7 +99,8 @@ module.exports = { }; if (interaction.customId === 'select') { - const msgCollector = channel.createMessageCollector({ filter: (m) => m.author.id == user.id , time: 120000}); + let channelCollector = (channel !== 'none' ? interaction.channel : channel); + const msgCollector = channelCollector.createMessageCollector({ filter: (m) => m.author.id == user.id , time: 120000}); var trash = new Discord.Collection(); @@ -118,9 +120,9 @@ module.exports = { }; let number = parseInt(m.content); - if (isNaN(number)) return msg.channel.send({ embeds: [ embeds.invalidNumber(user) ] }).then(x => trash.set(x.id, x)); + if (isNaN(number)) return msg.channelCollector.send({ embeds: [ embeds.invalidNumber(user) ] }).then(x => trash.set(x.id, x)); number--; - if (number < 0 || number > pages.length) return channel.send({ content: 'Cette page n\'existe pas' }).then(x => trash.set(x.id, x)); + if (number < 0 || number > pages.length) return channelCollector.send({ content: 'Cette page n\'existe pas' }).then(x => trash.set(x.id, x)); const selected = pages[number]; @@ -143,7 +145,7 @@ module.exports = { if (channel == "none") { if (interaction.replied) { - await interaction.editReply({ embeds: [ list[0] ], content: '', components: [ row ] }).catch(() => {}); + await interaction.editReply({ embeds: [ list[0] ], content: '** **', components: [ row ] }).catch((e) => {console.log(e)}); } else { await interaction.reply({ embeds: [ list[0] ], components: [ row ] }).catch(() => {}); }; @@ -177,8 +179,8 @@ module.exports = { }, getNumbersEmoji: () => { return [ - '0️⃣', '1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣' - ] + '0️⃣', '1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣', '🔟' + ]; }, /** * @returns {Number} @@ -205,19 +207,18 @@ module.exports = { addCase: (guild_id, user_id, mod_id, reason, action) => { const { client } = require('../index'); - client.db.query(`INSERT INTO mod_cases (guild_id, user_id, mod_id, action, reason) VALUES ("${guild_id}", "${user_id}", "${mod_id}", "${action}", "${reason}")`, (error, request) => { + client.db.query(`INSERT INTO mod_cases (guild_id, user_id, mod_id, action, reason) VALUES ("${guild_id?.id ?? guild_id}", "${user_id}", "${mod_id}", "${action}", "${reason}")`, (error, request) => { if (error) console.error(error); }); }, /** * * @param {Discord.Guild} guild - * @param {Discord.MessageEmbed} embed + * @param {Discord.EmbedBuilder} embed * @param {Discord.TextChannel} test */ log: (guild, embed) => { const client = guild.client; - let action = capitalize(embed.title); client.db.query(`SELECT logs_enable, logs_channel FROM configs WHERE guild_id="${guild.id}"`, (err, req) => { if (err) return console.log(err); @@ -238,6 +239,7 @@ module.exports = { * @param {Discord.GuildMember} modo * @param {Discord.GuildMember} member * @param {?Discord.CommandInteraction} interaction + * @deprecated Use `checkPerms` instead */ checkAllConditions: (guild, channel, modo, member, interaction) => { const { compareRoles } = require('./functions.js') @@ -291,6 +293,90 @@ module.exports = { }; return true; }, + /** + * @param {{ mod: Discord.GuildMember, member: Discord.GuildMember, interaction: Discord.CommandInteraction, ?checkRole: { activated: Boolean, role: Discord.Role } ?checkBotCompare: Boolean ?checkSelfUser: Boolean, ?checkOwner: Boolean, ?checkBot: Boolean, ?ownerValid: Boolean, ?all: Boolean }} data + */ + checkPerms(data) { + const send = (embed) => { + if (data.interaction.replied) { + data.interaction.editReply({ embeds: [ embed ], components: [] }).catch(() => {}); + } else { + data.interaction.reply({ embeds: [ embed ] }).catch(() => {}); + }; + }; + if (data.all == true) { + for (const x of ['checkBot', 'checkOwner', 'checkBotCompare', 'checkSelfUser']) { + data[x] = true; + }; + data.ownerValid = false; + }; + let owner = data.member.id == data.member.guild.ownerId; + + if (data.mod.id !== data.member.guild.ownerId && data.mod.roles.highest.position <= data.member.roles.highest.position) { + send(embeds.notEnoughHiger(data.mod.user, data.member)); + return false; + }; + if (data.checkRole?.activated == true) { + let role = data.checkRole.role; + if (role.position >= data.mod.guild.me.roles.highest.position) { + send(embeds.classic(data.mod.user) + .setTitle("Rôle trop haut") + .setDescription(`Le rôle <@&${role.id}> est supérieur ou égal à moi`) + .setColor('#ff0000') + ); + return false; + }; + if (role.position >= data.mod.roles.highest.position) { + send(embeds.classic(data.mod) + .setTitle("Rôle trop haut") + .setDescription(`Le rôle <@&${role.id}> est trop haut pour vous.`) + .setColor('#ff0000') + ); + return false; + }; + } + if (data.checkBotCompare == true && data.member.roles.position >= data.member.guild.me.roles.highest.position) { + send(embeds.classic(data.mod.user) + .setTitle("Pas assez élevé") + .setDescription(`Oops, il semblerait que <@${data.member.id}> soit supérieur ou égal à moi dans la hiérarchie des rôles.`) + .setColor('#ff0000') + ) + return false; + }; + if (data.checkBot == true && data.member.user.bot == true) { + send(embeds.classic(data.mod) + .setTitle("Bot") + .setDescription(`<@${data.member.id}> est un bot (je ne peux tout de même pas blâmer un coupain)`) + .setColor('#ff0000') + ); + return false; + }; + if (data.checkOwner == true && owner && (data.mod.id !== data.mod.guild.ownerId && data.ownerValid == true)) { + send(embeds.classic(data.mod) + .setTitle("Propriétaire") + .setDescription(`<@${data.member.id}> est le propriétaire du serveur, vous n'allez quand même pas tenter un coup d'état ?`) + .setColor('#ff0000') + ); + return false; + }; + if (data.checkSelfUser == true && data.member.id == data.mod.id) { + send(embeds.classic(data.mod) + .setTitle("Narcissisme") + .setDescription(`La personne que vous ciblez ( <@${data.member.id}> ) est **vous**. Je suis sûr que vous n'êtes pas narcissique à ce point !`) + .setColor('#ff0000') + ); + return false; + }; + if (!data.member.moderatable) { + send(embeds.classic(data.mod) + .setTitle("Membre non-modérable") + .setDescription(`Je ne peux pas effectuer d'actions de modération sur <@${data.member.id}>`) + .setColor('#ff0000') + ); + return false; + } + return true; + }, /** * @param {Number} number * @deprecated Use `numberToHuman` instead @@ -308,16 +394,16 @@ module.exports = { */ rpgPagination(channel, user, pages) { const texts = pages; - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .addComponents( - new Discord.MessageButton() + new Discord.ButtonBuilder() .setCustomId('past') .setEmoji('⬅') - .setStyle('SECONDARY'), - new Discord.MessageButton() + .setStyle(Discord.ButtonStyle.Secondary), + new Discord.ButtonBuilder() .setCustomId('next') .setEmoji('➡') - .setStyle('SECONDARY') + .setStyle(Discord.ButtonStyle.Secondary) ); let index = 0; @@ -364,16 +450,16 @@ module.exports = { return xdata; }, generateChoiceButton(textConfirm, textCancel) { - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .addComponents( - new Discord.MessageButton() - .setStyle('SUCCESS') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Success) .setLabel(textConfirm || 'Valider') .setCustomId('confirm'), - new Discord.MessageButton() + new Discord.ButtonBuilder() .setCustomId('cancel') .setLabel(textCancel || 'Annuler') - .setStyle('DANGER') + .setStyle(Discord.ButtonStyle.Danger) ); return row; @@ -389,8 +475,8 @@ module.exports = { }, /** * @param {Discord.Message} message - * @param {String | Discord.MessageEmbed} content - * @param {Discord.MessageActionRow} row + * @param {String | Discord.EmbedBuilder} content + * @param {Discord.ActionRowBuilder} row */ reply: async(message, content, row) => { let data = { @@ -400,7 +486,7 @@ module.exports = { if (typeof content == "string") data.content = content; else data.embeds = [ content ]; - if (row !== undefined) data.components = [ row ]; + if (row !== undefined && row.components.length > 0) data.components = [ row ]; return await message.channel.send(data).catch(() => {}); }, @@ -435,6 +521,7 @@ module.exports = { async privateSlashCommandsBuilder(client) { const commands = require('./data/slashCommands'); + if (!fs.existsSync('./private-slash-commands')) fs.mkdirSync('./private-slash-commands') const commandFiles = fs.readdirSync('./private-slash-commands'); for (const file of commandFiles) { const props = require(`../private-slash-commands/${file}`); @@ -464,7 +551,6 @@ module.exports = { command: data.commandName, date: data.time }; - if (data.isSlash == true) dataset.command = `/${data.commandName}`; data.client.db.query(`INSERT INTO cooldowns (${Object.keys(dataset).join(', ')}) VALUES (${Object.values(dataset).map(x => `"${x}"`).join(', ')})`, (err) => { if (err) console.log(err); @@ -480,5 +566,50 @@ module.exports = { return specificCooldowns.get(`${userId}.${commandName}`).date; }, getCode: (userId, commandName) => userId + '.' + commandName + }, + stickyRoles: { + /** + * @param {Discord.Guild} guild + * @param {Discord.GuildMember} member + */ + loadSpecific(guild, member) { + const sql = `SELECT role_id FROM stickyroles WHERE user_id="${member.id}" AND guild_id="${guild.id}"`; + guild.client.db.query(sql, async(err, req) => { + if (err) return console.log(err); + if (req.length == 0) return; + + for (const rId of req) { + let role = await guild.roles.fetch(rId.role_id, { cache: true }); + if (role && !member.roles.cache.has(role)) member.roles.add(role).catch(() => {}); + }; + }); + }, + /** + * @param {Discord.Client} client + */ + load(client) { + client.db.query(`SELECT user_id, guild_id FROM stickyroles`, async(err, req) => { + if (err) return console.log(err); + if (req.length == 0) return; + + let guilds = new Discord.Collection(); + await client.guilds.fetch(); + + for (const data of req) { + if (!guilds.has(data.guild_id)) { + let guild = client.guilds.cache.get(data.guild_id); + if (guild) guilds.set(guild.id, guild); + }; + + let guild = guilds.get(data.guild_id); + if (!guild) return; + + let member = (await guild.members.fetch(data.user_id)); + if (member) { + this.loadSpecific(guild, member); + }; + } + }) + } } -} \ No newline at end of file +} diff --git a/assets/images/hashtag.png b/assets/images/hashtag.png new file mode 100644 index 0000000..9b3d0ed Binary files /dev/null and b/assets/images/hashtag.png differ diff --git a/assets/managers/LotoManager.js b/assets/managers/LotoManager.js new file mode 100644 index 0000000..d52ebc0 --- /dev/null +++ b/assets/managers/LotoManager.js @@ -0,0 +1,231 @@ +class LotoManager { + constructor(client, db) { + this.client = client; + this.db = db; + this.cache = new Map(); + } + convertToObject(data) { + let x = data; + x.ended = data.ended == "1"; + ['reward', 'numbers', 'complementaries', 'endsAt'].forEach((y) => x[y] = parseInt(x[y])); + + if (typeof x.json == 'string') x.json = JSON.parse(x.json); + // x.json.forEach((userData, index) => { + // let y = userData; + // Object.keys(y).filter(x => typeof x !== "string").forEach((k) => { + // y[k] = y[k].map(yy => parseInt(yy)); + // }); + + // x.json[index] = y; + // }); + + return x; + } + convertToSql(data) { + let x = data; + x.ended = x.ended == true ? '1':'0'; + + if (typeof x.json == 'object') x.json = JSON.stringify(x.json); + + return x + } + createQuery(data, exists) { + let sql = `INSERT INTO loto (${Object.keys(data).join(', ')}) VALUES (${Object.values(data).map(x => `'${x}'`).join(', ')})`; + + if (exists == true) sql = `UPDATE loto SET ${Object.keys(data).map(x => `${x}='${data[x]}'`).join(', ')} WHERE guild_id="${data.guild_id}"`; + + return sql; + } + validLoto(guildId) { + let x = this.cache.get(guildId); + if (!x) { + return false; + }; + if (x.ended == true) { + return false; + }; + if (x.endsAt <= Date.now()) { + return false; + }; + + return true; + } + validArray(array) { + if (array.filter(x => x <= 100 && x > 0).length !== array.length) return false; + array = array.sort(); + + let valid = true; + array.forEach((x, i) => { + if (array[i + 1] == x) valid = false; + }); + if (!valid) return false; + return true; + } + /** + * @param {Number[]} array the array to tets + * @param {Number[]} compared the array that is used for compare + */ + validArrayCompare(array, compared) { + let valid = true; + array.forEach(x => { + if (compared.includes(x)) valid = false; + }); + return valid; + } + resetCache() { + this.cache = new Map(); + } + fillCache() { + this.db.query(`SELECT * FROM loto`, (err, req) => { + if (err) throw err; + + for (const data of req) { + let x = this.convertToObject(data); + + this.cache.set(x.guild_id, x); + }; + }); + } + init() { + this.fillCache(); + } + /** + * @param {{ guildId: String, userId: String, numbers: Number[], complementaries: Number[] }} data + */ + addParticipation(data) { + if (!this.validLoto(data.guildId)) return 'invalid loto'; + const loto = this.cache.get(data.guildId); + + if (loto.numbers !== data.numbers?.length) return 'invalid numbers'; + if (loto.complementaries !== data.complementaries?.length) return 'invalid numbers'; + + if (!this.validArray(data.numbers) || !this.validArray(data.complementaries)) return 'invalid arrays'; + if (!this.validArrayCompare(data.complementaries, data.numbers)) return 'invalid compared'; + + if (typeof loto.json == 'string') loto.json = JSON.parse(loto.json); + if (loto.json.find(x => x.user_id == data.userId)) return 'user already exists'; + + loto.json.push({ + user_id: data.userId, + numbers: data.numbers, + complementaries: data.complementaries + }); + this.cache.set(loto.guild_id, loto); + const sql = this.createQuery(this.convertToSql(loto), true); + this.db.query(sql, (err) => {if (err) throw err}); + + return 'added'; + } + compareArrays(first, second) { + let same = false; + + if (second.filter(x => first.includes(x)).length == second.length) same = true; + + return same; + } + /** + * @param {Number[]} first Array generated + * @param {Number[]} second Array of the user + * @returns {{matches: Number, total: Number}} total is the length of the first array + */ + compareComplementariesArrays(first, second) { + let same = second.filter(x => first.includes(x)).length; + + return { + matches: same, + total: first.length + }; + } + /** + * @param {Number[]} map + */ + random(map) { + let numbers = []; + for (let i = 1; i < 100; i++) { + numbers.push(i); + }; + + numbers = numbers.filter(x => !map.includes(x)); + let random = numbers[Math.floor(Math.random() * numbers.length)]; + + map.push(random); + return random; + } + roll(guildId) { + let loto = this.cache.get(guildId); + if (typeof loto.ended == 'string') loto = this.convertToObject(loto); + + let numbers = []; + let complementaries = []; + let all = []; + + for (let i = 0; i < loto.numbers; i++) { + numbers.push(this.random(all)); + }; + for (let i = 0; i < loto.complementaries; i++) { + complementaries.push(this.random(all)); + }; + + numbers.sort(); + complementaries.sort(); + + let winners = loto.json.filter(x => this.compareArrays(x.numbers, numbers) == true); + if (winners.length == 0) return { numbers, complementaries, winners: [] }; + + let reward = loto.reward; + if (winners.length == 1) { + let percent = this.compareComplementariesArrays(complementaries, winners[0].complementaries); + let total = numbers.length + complementaries.length; + + let winned = (reward * (percent.matches + numbers.length)) / total; + winners[0].reward = winned; + } else { + let splited = reward / winners.length; + winners.forEach((winner, index) => { + let percent = this.compareComplementariesArrays(complementaries, winner.complementaries); + let total = numbers.length + complementaries.length; + + let winned = (splited * (percent.matches + numbers.length)) / total; + winners[index].reward = winned; + }); + }; + + return { numbers, complementaries, winners }; + } + end(guildId) { + if (!this.validLoto(guildId)) return 'invalid loto'; + let loto = this.cache.get(guildId); + loto.ended = true; + + let sql = this.createQuery(this.convertToSql(loto), true); + this.db.query(sql, (err) => { + if (err) throw err; + + this.fillCache(); + }) + + return this.roll(guildId); + } + /** + * @param {{ numbers: Number, complementaries: Number, guildId: String, time: Number, reward: Number }} data + */ + start(data) { + let x = { + guild_id: data.guildId, + numbers: data?.numbers ?? 5, + complementaries: data?.complementaries ?? 2, + reward: data.reward, + endsAt: Date.now() + data.time, + json: [], + ended: false + }; + + this.db.query(this.createQuery(this.convertToSql(x), this.cache.has(data.guildId)), (err) => { + if (err) throw err; + + this.fillCache(); + }); + } +}; + +module.exports = LotoManager; \ No newline at end of file diff --git a/assets/managers/ModulesManager.js b/assets/managers/ModulesManager.js new file mode 100644 index 0000000..24639c3 --- /dev/null +++ b/assets/managers/ModulesManager.js @@ -0,0 +1,149 @@ +const Discord = require('discord.js'); +const functions = require('../functions'); +const package = functions.package(); +const mysql = require('mysql'); + +class ModulesManager { + /** + * @param {Discord.Client} client + * @param {mysql.Connection} db + */ + constructor(client, db) { + this.client = client; + this.db = db; + this.cache = new Map(); + this._params = []; + } + /** + * @returns {{ name: String, state: Boolean }[]} + */ + get params() { + return this._params; + } + formatToObject(data) { + let x = data; + Object.keys(x).filter(y => y != 'guild_id' && typeof x[y] == 'string').forEach((key) => { + x[key] = x[key] == '1'; + }); + + return x; + } + formatToSql(data) { + let x = data; + Object.keys(x).filter(y => y !== 'guild_id' && typeof x[y] == 'boolean').forEach((key) => { + x[key] = x[key] == true ? '1':'0' + }); + + return x; + } + createQuery(data) { + let x = this.formatToSql(data); + + let sql = `UPDATE modules SET ${Object.keys(x).map(y => `${y}="${x[y]}"`).join(', ')} WHERE guild_id="${x.guild_id}"`; + if (!this.cache.has(x.guild_id)) sql = `INSERT INTO modules (${Object.keys(x).join(', ')}) VALUES (${Object.values(x).map(y => `"${y}"`).join(', ')})`; + + return sql; + } + query(sql) { + this.db.query(sql, (err) => { + if (err) throw err; + this.fillCache(); + }); + } + resetCache() { + this.cache = new Map(); + } + fillCache() { + this.db.query(`SELECT * FROM modules`, (err, request) => { + if (err) throw err; + + this.resetCache(); + for (const req of request) { + let data = this.formatToObject(req); + this.cache.set(req.guild_id, data); + }; + }); + } + init() { + const modules = require(`../data/modules.json`); + + this.db.query(`DESCRIBE modules`, (err, req) => { + if (err) throw err; + + let values = req.filter(x => x.Type == 'tinyint(1)'); + let data = values.map(x => ({ name: x.Field, state: x.Default == "1" })); + + let toAdd = modules.filter(x => !data.find(y => x.value == y.name)); + let toRemove = data.filter(x => !modules.find(y => x.name == y.value)); + + toAdd.forEach((x) => { + data.push({ + name: x.value, + state: x.default + }); + }); + toRemove.forEach((x, i) => { + data.splice(i, 1); + }); + + this._params = data; + let stop = false; + if (toAdd.length > 0) { + this.db.query(`ALTER TABLE modules ADD (${toAdd.map(x => `${x.value} TINYINT(1) NOT NULL DEFAULT "${x.default == true ? '1':'0'}"`).join(', ')})`, (err) => { + if (err) throw err; + + this.fillCache(); + }); + stop = true; + }; + if (toRemove.length > 0) { + this.db.query(`ALTER TABLE modules ${toRemove.map(x => `DROP ${x.name}`).join(', ')}`, (err) => { + if (err) throw err; + + this.fillCache(); + }); + stop = true; + }; + + if (stop) return; + this.fillCache(); + }); + } + /** + * @param {String} guildId + */ + checkIfExists(guildId) { + if (!this.cache.has(guildId)) { + this.cache.set(guildId, {guild_id: guildId}); + const sql = this.createQuery({ guild_id: guildId }); + this.query(sql); + }; + } + /** + * @param {{ module: String, guildId: String }} data + */ + checkModule(data) { + if (!this.cache.has(data.guildId)) { + this.checkIfExists(data.guildId); + return this.params.find(x => x.name == data.module).state; + }; + + let x = this.cache.get(data.guildId); + x = this.formatToObject(x); + + return x[data.module] ?? require('../data/modules.json').find(x => x.value == data.module).default; + } + /** + * @param {{ module: String, guildId: String, state: Boolean }} data + */ + setModule(data) { + let x = this.cache.get(data.guildId) || { guild_id: data.guildId }; + x[data.module] = data.state; + + let sql = this.createQuery(this.formatToSql(x)); + this.query(sql); + return data.state; + } +}; + +module.exports = ModulesManager; \ No newline at end of file diff --git a/assets/managers/RolesReactManager.js b/assets/managers/RolesReactManager.js index de81716..a94e9b2 100644 --- a/assets/managers/RolesReactManager.js +++ b/assets/managers/RolesReactManager.js @@ -55,7 +55,7 @@ class RolesReactManager { * @param {{ guild: Discord.Guild, channel: Discord.BaseGuildTextChannel, content: Discord.MessageOptions }} data */ sendMessage(data) { - const components = new Discord.MessageActionRow() + const components = new Discord.ActionRowBuilder() .addComponents( new Discord.MessageSelectMenu() .setMaxValues(1) @@ -115,7 +115,7 @@ class RolesReactManager { selector.setMaxValues(1); selector.setMinValues(1); - data.message.edit({ components: [ new Discord.MessageActionRow().addComponents(selector) ] }).catch(() => {}); + data.message.edit({ components: [ new Discord.ActionRowBuilder().addComponents(selector) ] }).catch(() => {}); let { roles } = this.cache.get(data.guild.id).get(data.message.id); if (roles.length == 0) role = data.role.id; @@ -154,7 +154,7 @@ class RolesReactManager { selector.setMaxValues(1); selector.setMinValues(1); - data.message.edit({ components: [ new Discord.MessageActionRow().addComponents(selector) ] }).catch(() => {}); + data.message.edit({ components: [ new Discord.SelectMenuBuilder().addComponents(selector) ] }).catch(() => {}); let roleIndex = roles.indexOf(data.role.id); roles.splice(roleIndex, 1); diff --git a/assets/managers/assets/buttons.js b/assets/managers/assets/buttons.js new file mode 100644 index 0000000..a0a0ac8 --- /dev/null +++ b/assets/managers/assets/buttons.js @@ -0,0 +1,30 @@ +const { ButtonBuilder, ButtonStyle, ActionRowBuilder, ActionRow } = require('discord.js'); + +module.exports = { + participate: () => { + const button = new ButtonBuilder() + .setCustomId('gw-participate') + .setStyle(ButtonStyle.Success) + .setLabel("Participer") + .setEmoji('🎉') + + return button; + }, + cancelParticipation: () => { + const button = new ButtonBuilder() + .setCustomId('gw-unparticipate') + .setLabel("Annuler la participation") + .setStyle(ButtonStyle.Danger) + + return button + }, + /** + * @param {ActionRow[]} components + */ + getAsRow: (components) => { + const row = new ActionRowBuilder() + .addComponents(components) + + return row; + } +} \ No newline at end of file diff --git a/assets/managers/assets/embeds.js b/assets/managers/assets/embeds.js new file mode 100644 index 0000000..cf9f328 --- /dev/null +++ b/assets/managers/assets/embeds.js @@ -0,0 +1,108 @@ +const { EmbedBuilder } = require('discord.js'); + +module.exports = { + /** + * @param {{ reward: String, winnerCount: Number, hosterId: String, channel: TextChannel, time: Number, ?bonusRoles: String[], ?deniedRoles: String[], ?requiredRoles: String[] }} data + */ + giveaway: (data) => { + const embed = new EmbedBuilder() + .setTitle("🎉 Giveaway 🎉") + .setColor('#00ff00') + .setDescription(`**${data.reward}** +Offert par <@${data.hosterId}> +**${data.winnerCount}** gagnant${data.winnerCount > 1 ? 's':''} +Participants : ${data.participants ? data.participants.length : "0"} + +Finit `) + + if (data.bonusRoles && data.bonusRoles.length > 0) { + embed.addFields({ + name: "Rôles bonus", + value: data.bonusRoles.map((rId) => `<@&${rId}>`).join(' '), + inline: false + }); + }; + if (data.requiredRoles && data.requiredRoles.length > 0) { + embed.addFields({ + name: "Rôles requis", + value: data.requiredRoles.map((rId) => `<@&${rId}>`).join(' '), + inline: false + }); + }; + if (data.deniedRoles && data.deniedRoles.length > 0) { + embed.addFields({ + name: "Rôles interdits", + value: data.deniedRoles.map((rId) => `<@&${rId}>`).join(' '), + inline: false + }); + }; + + return embed; + }, + ended: (data, winners) => { + const embed = new EmbedBuilder() + .setTitle("🎉 Giveaway terminé 🎉") + .setColor('#ff0000') + .setDescription(`**${data.reward}** +Offert par <@${data.hoster_id}> +${winners.length > 0 ? `Gagnant${data.winnerCount > 1 ? 's': ''} : ${winners.map(x => `<@${x}>`).join(' ')}`: "Pas de gagnants"} +Participants : ${data.participants.length} + +Finit `) + + return embed; + }, + hasDeniedRoles: (deniedRoles, url) => { + let roles = deniedRoles; + if (typeof roles == 'string') roles = JSON.parse(roles); + + return new EmbedBuilder() + .setTitle("🚫 Accès refusé") + .setDescription(`L'accès à [**ce giveaway**](${url}) vous est refusé car vous avez un ou plusieurs de ces rôles :\n${roles.map(x => `<@&${x}>`).join(' ')}`) + .setColor('#ff0000') + }, + missingRequiredRoles: (requiredRoles, url) => { + let roles = requiredRoles; + if (typeof roles == 'string') roles = JSON.parse(roles); + + return new EmbedBuilder() + .setTitle("🚫 Accès refusé") + .setDescription(`L'accès à [**ce giveaway**](${url}) vous est réfusé car vous n'avez pas un ou plusieurs de ces rôles :\n${roles.map(x => `<@&${x}>`).join(' ')}`) + .setColor('#ff0000') + }, + entryAllowed: (url) => { + return new EmbedBuilder() + .setTitle("🎉 Accès autorisé") + .setColor('#00ff00') + .setDescription(`Votre participation à [**ce giveaway**](${url}) a été confirmée.\nBonne chance !`) + }, + alreadyParticipate: (url) => { + return new EmbedBuilder() + .setTitle("🚫 Déjà participé") + .setDescription(`Vous participez déjà à [**ce giveaway**](${url}).`) + .setColor('#ff0000') + }, + notParticipated: (url) => { + return new EmbedBuilder() + .setTitle("🚫 Pas de participation") + .setDescription(`Vous n'avez pas participé à [**ce giveaway**](${url})`) + .setColor('#ff0000') + }, + removeParticipation: (url) => { + return new EmbedBuilder() + .setTitle("❌ Participation annulée") + .setDescription(`Votre participation à [**ce giveaway**](${url}) a été annulée.`) + .setColor('#00ff00') + }, + winners: (winners, url) => { + if (winners.length == 0) return new EmbedBuilder() + .setTitle("Pas de gagnants") + .setDescription(`Il n'y a aucun gagnants pour [**ce giveaway**](${url}).`) + .setColor('#ff0000'); + + return new EmbedBuilder() + .setTitle("🎉 Gagnants") + .setDescription(`Le${winners.length > 1 ? 's':''} gagnant${winners.length > 1 ? 's':''} de [**ce giveaway**](${url}) ${winners.length > 1 ? 'sont':'est'} ${winners.map(x => `<@${x}>`).join(' ')}`) + .setColor('#00ff00') + } +}; \ No newline at end of file diff --git a/assets/managers/giveawayManager.js b/assets/managers/giveawayManager.js index f07ff95..9285614 100644 --- a/assets/managers/giveawayManager.js +++ b/assets/managers/giveawayManager.js @@ -1,276 +1,430 @@ -const Discord = require('discord.js'); -const functions = require('../functions.js'); -const embeds = functions.package().embeds; +const { Client, Collection, TextChannel, GuildMember, ButtonInteraction, Guild, Message } = require('discord.js'); const mysql = require('mysql'); -const moment = require('moment'); -moment.locale('fr'); +const embeds = require('./assets/embeds'); +const buttons = require('./assets/buttons'); -class GiveawayManager { +class GiveawaysManager { /** - * @param {Discord.Client} client + * @param {Client} client * @param {mysql.Connection} db */ constructor(client, db) { this.client = client; this.db = db; + this.giveaways = new Collection(); + this.ended = new Collection(); + this.timeout = new Collection(); } - generateEmbed(data, guild) { - const hoster = (guild.members.cache.get(data.hoster_id) || guild.me).user; - - const embed = embeds.classic(hoster) - .setTitle(":tada: GIVEAWAY :tada:") - .setTimestamp(new Date(parseInt(data.endsAt)).toISOString()) - .setDescription(`Appuyez sur le boutton pour participer !\n\nRécompense: \`${data.reward}\`\nOffert par: <@${data.hoster_id}>\n${data.winnerCount} gagnan${data.winnerCount > 1 ? "ts" : "t"}\nFinit le `) - .setColor(guild.me.displayHexColor) - - if (data.endsAt - Date.now() < 10000) embed.setColor('#ff0000').setTitle(":tada: **G I V E A W A Y** :tada:"); - - return embed + getUrl(data) { + return `https://discord.com/channels/${data.guild_id}/${data.channel_id}/${data.message_id}`; } /** - * @param {objectGW} data - * @param {Discord.Guild} guild + * @param {{ reward: String, winnerCount: Number, hosterId: String, channel: TextChannel, time: Number, ?bonusRoles: String[], ?deniedRoles: String[], ?requiredRoles: String[] }} data */ - generateEndedEmbed(data, guild) { - const hoster = (guild.members.cache.get(data.hoster_id) || guild.me).user; + start(data) { + if (!data.channel?.guild) return 'no guild'; + + const embed = embeds.giveaway(data); + const row = buttons.getAsRow([ buttons.participate(), buttons.cancelParticipation() ]); + + data.channel.send({ embeds: [ embed ], components: [ row ] }).then((sent) => { + let dataset = { + reward: data.reward, + hoster_id: data.hosterId, + guild_id: data.channel.guild.id, + channel_id: data.channel.id, + message_id: sent.id, + winnerCount: data.winnerCount, + winners: [], + ended: false, + participants: [], + required_roles: data.requiredRoles ?? [], + bonus_roles: data.bonusRoles ?? [], + denied_roles: data.deniedRoles ?? [], + endsAt: Date.now() + data.time + }; - const embed = embeds.classic(hoster) - .setTitle(":tada: **GIVEAWAY TERMINÉ** :tada:") - .setTimestamp(new Date(parseInt(data.endsAt)).toISOString()) - .setColor(guild.me.displayHexColor) - .setDescription(`Giveaway terminé !\n\nRécompense: \`${data.reward}\`\nOffert par <@${hoster.id}>\n${data.winnerCount} gagnan${data.winnerCount > 1 ? 'ts' : "t"}`) + let sql = this.createQuery(this.formatToSql(dataset), false); + this.giveaways.set(sent.id, this.formatToObject(dataset)); - return embed; + this.db.query(sql, (err) => { + if (err) throw err; + }); + }).catch((e) => {console.log(e)}); } - edit(data, guild) { - const channel = guild.channels.cache.get(data.channel_id); - if (!channel) return; + /** + * @param {GuildMember} member + */ + checkIfValidEntry(member, x) { + let data = this.formatToObject(x); + if (data.denied_roles && data.denied_roles?.length > 0) { + let has = false; + for (const role of data.denied_roles) { + if (member.roles.cache.has(role)) has = true; + }; - const msg = channel.messages.cache.get(data.message_id); - if (!msg) return; + if (has) { + return { + embed: embeds.hasDeniedRoles(data.denied_roles, this.getUrl(data)), + state: false + } + } + }; + if (data.required_roles && data.required_roles.length > 0) { + let has = true; + for (const role of data.required_roles) { + if (!member.roles.cache.has(role)) has = false; + }; - const embed = this.generateEmbed(data, guild); - msg.edit({ embeds: [ embed ] }).catch((e) => console.log(e)); + if (!has) { + return { + embed: embeds.missingRequiredRoles(data.required_roles, this.getUrl(data)), + state: false + }; + }; + }; + return { + embed: embeds.entryAllowed(this.getUrl(data)), + state: true + }; } /** - * @param {Discord.Guild} guild - * @param {Discord.TextChannel} - * @param {Discord.User} user - * @param {String} reward - * @param {Number} winnerCount - * @param {Number} time + * @param {{}} data + * @param {Boolean} exists */ - start(guild, channel, user, reward, winnerCount, time) { - const data = { - endsAt: time + Date.now(), - hoster_id: user.id, - reward: reward, - winnerCount: winnerCount + createQuery(data, exists) { + const arrays = ['participants', 'bonus_roles', 'denied_roles', 'required_roles', 'winners']; + + let sql = `INSERT INTO giveaways (${Object.keys(data).join(', ')}) VALUES ( ${Object.values(data).map(x => x.toString().includes('[') ? `'${x}'` : (typeof x =="string") ? `"${x.replace(/"/g, '\\"')}"`: `"${x}"`).join(', ')} )`; + + if (exists == true) { + sql = `UPDATE giveaways SET ${Object.keys(data).map((x => `${x}=${(typeof data[x] == "string" && arrays.includes(x)) ? `'${data[x].replace(/"/g, '\\"')}'` : `"${data[x]}"`}`)).join(', ')} WHERE message_id="${data.message_id}"`; }; - const row = new Discord.MessageActionRow() - .addComponents( - new Discord.MessageButton() - .setCustomId('giveaway-participate') - .setLabel('Participer') - .setEmoji('🎉') - .setStyle('SUCCESS') - ) - - const embed = this.generateEmbed(data, guild); - channel.send({ embeds: [ embed ], components: [ row ] }).then((msg) => { - this.db.query(`INSERT INTO giveaways (guild_id, channel_id, message_id, hoster_id, reward, endsAt, winnerCount, path) VALUES ("${guild.id}", "${channel.id}", "${msg.id}", "${user.id}", "${reward}", "${data.endsAt}", "${winnerCount}", "https://discord.com/channels/${guild.id}/${channel.id}/${msg.id}")`, (err, req) => { - if (err) return console.log(err) & channel.send({ embeds: [ embeds.errorSQL(user) ] }); - }); - }) + return sql; + } + formatToSql(data) { + let gw = data; + const arrays = ['participants', 'bonus_roles', 'denied_roles', 'required_roles', 'winners']; + + for (const prop of arrays) { + if (typeof gw[prop] == 'object') gw[prop] = JSON.stringify(gw[prop]); + }; + gw.ended = gw.ended == true ? '1' : "0"; + for (const string of Object.keys(gw).filter(x => typeof gw[x] == "string" && !arrays.includes(x))) { + gw[string] = gw[string].replace(/"/g, '\\"'); + }; + + return gw; + } + formatToObject(data) { + let gw = data; + + for (const prop of ['participants', 'bonus_roles', 'denied_roles', 'required_roles', 'winners']) { + if (typeof gw[prop] == 'string') gw[prop] = JSON.parse(gw[prop]); + }; + + gw.winnerCount = parseInt(gw.winnerCount); + gw.endsAt = parseInt(gw.endsAt); + gw.ended = gw.ended == "1"; + + for (const string of Object.keys(data).filter(x => typeof gw[x] == "string")) { + gw[string] = gw[string].replace(/\\"/g, '"'); + }; + + return gw; } /** - * @param {Discord.Guild} guild - * @param {objectGW} data + * @param {{ guild: Guild, channel: TextChannel, message: Message }} data */ - end(guild, data) { - const channel = guild.channels.cache.get(data.channel_id); - if (!channel) return; + async roll(gw, data) { + if (gw.participants.length == 0) return []; + let participants = []; + + for (const id of gw.participants) { + const member = await data.guild.members.fetch(id); + if (!member) return console.log('hey'); + + participants.push(id); + if (gw.bonus_roles?.length > 0) { + for (const rId of gw.bonus_roles) { + if (member.roles.cache.has(rId)) participants.push(id); + }; + }; + }; - this.db.query(`SELECT user_id FROM gw_participants WHERE message_id="${data.message_id}" AND guild_id="${guild.id}"`, (err, req) => { - if (err) return channel.send({ content: "Une erreur s'est produite lors de la récupération des participants." }) & console.log(err); + if (participants.length == 0) return []; - const users = req - this.db.query(`UPDATE giveaways SET ended="1" WHERE message_id="${data.message_id}" AND guild_id="${guild.id}"`, (e) => { - if (e) console.log(e); - }); - - if (users.length === 0) return functions.lineReply(data.message_id, channel, `Je n'ai pu trouver aucun gagnant pour ce giveaway.`); - - let winners = []; - for (let i = 0; i < data.winnerCount; i++) { - const possible = users.filter(x => !winners.includes(x)); - if (!possible.length === 0) return; - - const index = Math.floor(Math.random() * users.length); - const id = users[index].user_id; - - winners.push(id); + let winners = []; + const roll = () => { + let winner = participants[Math.floor(Math.random() * participants.length)]; + if (winner) { + participants = participants.filter(x => x !== winner); }; + return winner; + }; - let pluriel = data.winnerCount > 1; + let i = 0; + let end = false; + while (end == false) { + i++; + let winner = roll(); - this.edit(data, guild); - functions.lineReply(data.message_id, channel, `Giveaway terminé ! L${pluriel ? 'es' : 'e'} gagnan${pluriel ? 'ts sont' : "t est"} ${winners.map(u => `<@${u}>`).join(', ')} !\n${pluriel ? 'vous avez' : 'tu as'} gagné **${data.reward}**`); + if (winner) winners.push(winner); + if (participants.length == 0 || i == gw.winnerCount) end = true; + }; - }); + return winners; } /** - * @param {Discord.Guild} guild - * @param {objectGW} data + * @param {String} messageId + * @returns { "no giveaway" | "no guild" | "no channel" | "no message" | "no winner" | "not ended" | String[] } */ - reroll (guild, data) { - const channel = guild.channels.cache.get(data.channel_id); - if (!channel) return; - - this.db.query(`SELECT user_id FROM gw_participants WHERE message_id="${data.message_id}" AND guild_id="${guild.id}"`, (err, req) => { - if (err) return channel.send({ content: "Une erreur s'est produite lors de la récupération des participants." }) & console.log(err); - - const users = req - - if (users.length === 0) return functions.lineReply(data.message_id, channel, `Je n'ai pu trouver aucun gagnant pour ce giveaway.`); - - let winners = []; - for (let i = 0; i < data.winnerCount; i++) { - const possible = users.filter(x => !winners.includes(x)); - if (!possible.length === 0) return; - - const index = Math.floor(Math.random() * users.length); - const id = users[index].user_id; - - winners.push(id); - }; + async reroll(messageId) { + let gw = this.ended.get(messageId); + if (typeof gw.participants == 'string') gw = this.formatToObject(gw); + + if (!gw && this.giveaways.has(messageId)) return 'not ended'; + if (!gw) return 'no giveaway'; - let pluriel = data.winnerCount > 1; - this.edit(data, guild); - functions.lineReply(data.message_id, channel, `L${pluriel ? 'es' : 'e'} nouvea${pluriel ? 'ux' : 'u'} gagnan${pluriel ? 'ts sont' : "t est"} ${winners.map(u => `<@${u}>`).join(', ')} !\n${pluriel ? 'vous avez' : 'tu as'} gagné **${data.reward}**`); + const guild = this.client.guilds.cache.get(gw.guild_id); + if (!guild) return 'no guild'; + + const channel = guild.channels.cache.get(gw.channel_id); + if (!channel) return 'no channel'; + + const message = await channel.messages.fetch(messageId); + if (!message) return 'no message'; + + let winners = await this.roll(gw, { guild, channel, message }); + gw.winners = winners; + const embed = embeds.ended(gw, winners); + + message.edit({ embeds: [ embed ] }).catch(() => {}); + channel.send({ reply: { messageReference: message }, embeds: [ embeds.winners(winners, this.getUrl(gw)) ] }).catch(() => {}); + + let sql = this.createQuery(this.formatToSql(gw), true); + this.db.query(sql, (err) => { + if (err) throw err; }); + + this.ended.set(messageId, gw); + + return winners; } /** - * @param {Discord.TextChannel} channel - * @param {Discord.User} user + * @param {String} messageId + * @returns { "no giveaway" | "no guild" | "no channel" | "no message" | "no winner" | "already ended" | String[] } */ - list(channel, user) { - const guild = channel.guild; - - this.db.query(`SELECT * FROM giveaways WHERE guild_id="${guild.id}" AND endsAt>"${Date.now()}"`, (err, req) => { - if (err) return channel.send({ embeds: [ embeds.errorSQL(user) ] }); - - if (req.length === 0) return channel.send({ embeds: [ embeds.classic(user) - .setTitle("Pas de giveaways") - .setDescription(`Il n'y a aucun giveaway en cours sur ce serveur.`) - .setColor('#ff0000') - ] }); - - const original = require('./functions').package().embeds.classic(user) - .setTitle("Giveaways") - .setDescription(`Voici la liste des giveaways sur \`${guild.name}\`.\nIl y a actuellement **${req.length}** giveawa${req.length > 1 ? "ys" : "y"} en cours sur le serveur.`) - .setColor('ORANGE') - - if (req.length > 5) { - let now = original; - - let embeds = []; - let pile = false; - let count = 0; - - for (let i = 0; i < req.length; i++) { - const warn = req[i]; - - now.addField(`Giveaway`, `Offert par <@${warn.hoster_id}>\n> Récompense: \`${warn.reward}\`\n> Finit: ${moment(parseInt(warn.endsAt)).format('DD/MM/YYYY - hh:mm:ss')}\nDans <#${warn.channel_id}> avec ${warn.winnerCount} gagnan${warn.winnerCount > 1 ? "ts" : "t"}`, false); - - pile = false; - - count++; - if (count === 5) { - count=0; - pile = true; - embeds.push(now); - - now = null; - now = embeds.classic(user) - .setTitle("Giveaways") - .setDescription(`Voici la liste des giveaways sur \`${guild.name}\`.`) - .setColor('ORANGE') - - } - }; - - if (!pile) embeds.push(now); - - functions.pagination(user, channel, embeds, `giveaways`); - } else { - const embed = original; - - req.forEach((warn) => { - embed.addField(`Giveaway`, `Offert par <@${warn.hoster_id}>\n> Récompense: \`${warn.reward}\`\n> Finit: ${moment(parseInt(warn.endsAt)).format('DD/MM/YYYY - hh:mm:ss')}\nDans <#${warn.channel_id}> avec ${warn.winnerCount} gagnan${warn.winnerCount > 1 ? "ts" : "t"}`, false); - }); - - channel.send({ embeds: [ embed ] }); + async end(messageId) { + let gw = this.giveaways.get(messageId); + if (!gw && this.ended.has(messageId)) return 'already ended'; + if (!gw) return 'no giveaway' + + const guild = this.client.guilds.cache.get(gw.guild_id); + if (!guild) return 'no guild'; + + const channel = guild.channels.cache.get(gw.channel_id); + if (!channel) return 'no channel'; + + const message = await channel.messages.fetch(messageId); + if (!message) return 'no message'; + + if (!gw.ended == false) { + gw = this.formatToObject(gw); + }; + + let winners = await this.roll(gw, { guild, channel, message }); + const embed = embeds.ended(gw, winners); + + gw.winners = winners; + message.edit({ embeds: [ embed ], components: [] }).catch((e) => {console.log(e)}); + channel.send({ reply: { messageReference: message }, embeds: [ embeds.winners(winners, this.getUrl(gw)) ] }).catch((e) => {console.log(e)}); + gw.ended = true; + + let sql = this.createQuery(this.formatToSql(gw), true); + this.db.query(sql, (err) => { + if (err) throw err; + }); + + this.giveaways.delete(messageId); + this.ended.set(messageId, gw); + + return winners; + } + checkGw() { + this.giveaways.forEach((gw) => { + if (!this.timeout.has(gw.message_id)) { + setTimeout(() => { + this.end(gw.message_id); + this.timeout.delete(gw.message_id); + }, gw.endsAt - Date.now()); + this.timeout.set(gw.message_id, gw); } }) } - updateAll(guild) { - this.db.query(`SELECT * FROM giveaways WHERE guild_id="${guild.id}" AND ended="0"`, (err, req) => { - if(err) return console.log(err); + addParticipation(userId, data) { + let gw = data; + if (typeof gw.participants == 'string') gw.participants = JSON.parse(gw.participants); + gw.participants.push(userId); - req.forEach((x) => { - if (parseInt(x.endsAt) <= Date.now()) { - this.end(guild, x); - } else { - this.edit(x, guild); - } - }); + let sql = this.createQuery(this.formatToSql(gw), true); + + this.db.query(sql, (err) => { + if (err) throw err; }); + + this.giveaways.set(gw.message_id, gw); + return gw; } - init() { - this.client.on('interactionCreate', (interaction) => { - if (!interaction.isButton()) return; - - if (!interaction.customId === 'giveaway-participate') return; + removeParticipation(userId, data) { + let gw = data; + if (typeof gw.participants == 'string') gw.participants = JSON.parse(gw.participants); + let index = gw.participants.indexOf(userId); + gw.participants.splice(index, 1); + + let sql = this.createQuery(this.formatToSql(gw), true); + this.db.query(sql, (err) => { + if (err) throw err; + }); - this.db.query(`SELECT guild_id FROM giveaways WHERE guild_id="${interaction.guild.id}" AND channel_id="${interaction.channel.id}" AND message_id="${interaction.message.id}" AND ended="0"`, (err, req) => { - if (err) return interaction.reply({ embeds: [ embeds.errorSQL(interaction.user) ], ephemeral: true }) & console.log(err); - const data = req[0]; + this.giveaways.set(gw.message_id, gw); + return gw; + } + setOnInteraction() { + this.client.on('interactionCreate', /** @param {ButtonInteraction} interaction */ (interaction) => { + if (interaction.isButton()) { + if (interaction.customId == 'gw-participate') { + let gw = this.giveaways.get(interaction.message.id); + if (!gw) return; - if (!data) return; + if (gw.participants.includes(interaction.user.id)) return interaction.reply({ embeds: [ embeds.alreadyParticipate(this.getUrl(gw)) ], ephemeral: true }).catch(() => {}); - this.db.query(`SELECT user_id FROM gw_participants WHERE message_id="${interaction.message.id}" AND guild_id="${interaction.guild.id}" AND user_id="${interaction.user.id}"`, (error, request) => { - if (error) return interaction.reply({ embeds: [ embeds.errorSQL(interaction.user) ], ephemeral: true }) & console.log(error); + const check = this.checkIfValidEntry(interaction.member, gw); + interaction.reply({ embeds: [ check.embed ], ephemeral: true }).catch(() => {}); - if (request.length === 0) { - this.db.query(`INSERT INTO gw_participants (guild_id, channel_id, message_id, user_id) VALUES ("${interaction.guild.id}", "${interaction.channel.id}", "${interaction.message.id}", "${interaction.user.id}")`); - interaction.reply({ content: `J'ai enregistré votre participation`, ephemeral: true }); - return; - } else { - this.db.query(`DELETE FROM gw_participants WHERE guild_id="${interaction.guild.id}" AND message_id="${interaction.message.id}" AND user_id="${interaction.user.id}"`); + if (check.state == true) { + gw = this.addParticipation(interaction.user.id, gw); - interaction.reply({ content: `J'annule votre participation à ce giveaway`, ephemeral: true }); + let dataset = { + reward: gw.reward, + winnerCount: gw.winnerCount, + participants: JSON.parse(gw.participants), + winners: JSON.parse(gw.winners), + requiredRoles: JSON.parse(gw.required_roles), + deniedRoles: JSON.parse(gw.denied_roles), + bonusRoles: JSON.parse(gw.bonus_roles), + time: parseInt(gw.endsAt) - Date.now(), + hosterId: gw.hoster_id + }; + + interaction.message.edit({ embeds: [ embeds.giveaway(dataset) ] }).catch(() => {}); }; - }); - }); + }; + if (interaction.customId == 'gw-unparticipate') { + let gw = this.giveaways.get(interaction.message.id); + if (!gw) return; + + if (!gw.participants.includes(interaction.user.id)) return interaction.reply({ embeds: [ embeds.notParticipated(this.getUrl(gw)) ], ephemeral: true }).catch(() => {}); + gw = this.removeParticipation(interaction.user.id, gw); + + let dataset = { + reward: gw.reward, + winnerCount: gw.winnerCount, + participants: gw.participants, + winners: gw.winners, + requiredRoles: gw.required_roles, + bonusRoles: gw.bonus_roles, + deniedRoles: gw.denied_roles, + time: Date.now() - parseInt(gw.date), + channel: interaction.channel, + hosterId: gw.hoster_id + }; + + interaction.message.edit({ embeds: [ embeds.giveaway(this.formatToObject(dataset)) ] }).catch(() => {}); + interaction.reply({ embeds: [ embeds.removeParticipation(this.getUrl(gw)) ] }).catch(() => {}); + } + }; }); + } + /** + * @param {{ guildId: String, messageId: String }} data + * @description Search a specific giveaway in the server + * @returns {{reward: String, hoster_id: String, guild_id: String, channel_id: String, message_id: String, winnerCount: Number, winners: String[], ended: Boolean, participants: String[], required_roles: String[], bonus_roles: String[], denied_roles: String[], endsAt: Number}} + */ + fetch(data) { + let id = data.messageId; + let gId = data.guildId; + if (!id || !gId) return 'invalid data'; - setInterval(() => { - this.db.query(`SELECT * FROM giveaways WHERE ended="0"`, (err, req) => { - if (err) return console.log(err); + let gw = this.giveaways.find(x => x.guild_id == gId && x.message_id == id); + if (!gw) gw = this.ended.find(x => x.guild_id == gId && x.message_id == id); - req.forEach(/**@param {objectGW} gw */(gw) => { - const guild = this.client.guilds.cache.get(gw.guild_id); - if (!guild) return; + if (!gw) return 'giveaway not found'; + return gw; + } + /** + * @description Returns the list of all giveaways in the server + * @param {String} guildId + * @returns {{reward: String, hoster_id: String, guild_id: String, channel_id: String, message_id: String, winnerCount: Number, winners: String[], ended: Boolean, participants: String[], required_roles: String[], bonus_roles: String[], denied_roles: String[], endsAt: Number}[]} + */ + list(guildId) { + if (!guildId) return 'invalid data'; - this.updateAll(guild); - }); - }); + let giveaways = []; + const notEnded = this.giveaways.filter(x => x.guild_id === guildId).toJSON(); + const ended = this.ended.filter(x => x.guild_id === guildId).toJSON(); + + giveaways = giveaways.concat(notEnded); + giveaways = giveaways.concat(ended); + + return giveaways; + } + delete(guildId, messageId) { + if (!guildId || !messageId) return 'invalid data'; + const giveaway = this.fetch({ guildId, messageId }); + + if (!giveaway) return 'giveaway not found'; + + this.db.query(`DELETE FROM giveaways WHERE message_id="${messageId}"`, (err, req) => { + if (err) throw err; + + this.fillCache(); + }); + + return 'deleted'; + } + resetCache() { + this.giveaways = new Collection(); + this.ended = new Collection(); + } + fillCache() { + this.db.query(`SELECT * FROM giveaways`, (err, req) => { + if (err) throw err; + this.resetCache(); + + for (const RawGw of req) { + let gw = this.formatToObject(RawGw); + + if (gw.ended == true || gw.date <= Date.now()) { + this.ended.set(gw.message_id, gw); + } else { + this.giveaways.set(gw.message_id, gw); + }; + }; + }) + } + init() { + this.fillCache(); + setInterval(() => { + this.checkGw(); }, 10000); + this.setOnInteraction(); + + console.log(`Giveaways Manager is ready !`); } }; -module.exports = GiveawayManager; \ No newline at end of file +module.exports = GiveawaysManager; \ No newline at end of file diff --git a/assets/managers/mailManager.js b/assets/managers/mailsManager.js similarity index 86% rename from assets/managers/mailManager.js rename to assets/managers/mailsManager.js index 85739c4..d27dfcd 100644 --- a/assets/managers/mailManager.js +++ b/assets/managers/mailsManager.js @@ -77,24 +77,24 @@ class MailManager { }); } generateMailBoxButtons() { - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .addComponents( - new Discord.MessageButton() + new Discord.ButtonBuilder() .setLabel('Non-lus') - .setStyle('SUCCESS') + .setStyle(Discord.ButtonStyle.Success) .setCustomId('noread'), - new Discord.MessageButton() - .setStyle('SECONDARY') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Secondary) .setLabel('Lus') .setCustomId('read'), - new Discord.MessageButton() - .setStyle('PRIMARY') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Primary) .setLabel('Supprimer un mail') .setCustomId('delete') .setEmoji('🗑️') , - new Discord.MessageButton() - .setStyle('DANGER') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Danger) .setLabel('Annuler') .setCustomId('cancel') ); @@ -112,7 +112,7 @@ class MailManager { .setDescription(`Choisissez un mail`) .setColor('ORANGE') - const menu = new Discord.MessageSelectMenu() + const menu = new Discord.SelectMenuBuilder() .setCustomId('selector') .setMaxValues(1) .setMinValues(1) @@ -137,7 +137,7 @@ class MailManager { } ]); - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .addComponents( menu ) @@ -184,7 +184,7 @@ class MailManager { .setDescription(`Choisissez un mail`) .setColor('ORANGE') - const menu = new Discord.MessageSelectMenu() + const menu = new Discord.SelectMenuBuilder() .setCustomId('selector') .setMaxValues(1) .setMinValues(1) @@ -202,7 +202,7 @@ class MailManager { menu.addOptions(this.generateCancelButton()); - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .addComponents( menu ) @@ -253,16 +253,16 @@ class MailManager { menu.addOptions(this.generateCancelButton()); const confirm = (mailId, mailObject, isImportant) => { - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .addComponents( - new Discord.MessageButton() - .setStyle('SUCCESS') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Success) .setLabel('Valider') .setCustomId('confirm'), - new Discord.MessageButton() + new Discord.ButtonBuilder() .setCustomId('cancele') .setLabel('Annuler') - .setStyle('DANGER') + .setStyle(Discord.ButtonStyle.Danger) ) message.delete().catch(() => {}); message.channel.send({ components: [ row ], embeds: [ pack.embeds.classic(user) @@ -300,7 +300,7 @@ class MailManager { .setTitle("Supprimer un mail") .setDescription(`Choisissez un mail pour le supprimer`) .setColor('ORANGE') - ], components: [ new Discord.MessageActionRow().addComponents(menu) ] }).then((sent) => { + ], components: [ new Discord.ActionRowBuilder().addComponents(menu) ] }).then((sent) => { const collector = sent.createMessageComponentCollector({ filter: i => i.user.id === user.id, time: 120000, max: 1 }); collector.on('collect', /** @param {Discord.SelectMenuInteraction} interaction */(interaction) => { @@ -319,20 +319,28 @@ class MailManager { } /** * @param {Discord.User} user - * @param {Discord.TextChannel} channel + * @param {Discord.TextChannel | 'none'} channel + * @param {Discord.CommandInteraction} interaction */ - mailbox(user, channel) { + mailbox(user, channel, interaction) { + let sendFnt = async(params) => { + if (channel !== 'none') { + return await channel.send(params).catch(() => {}); + } else { + if (interaction.replied) { + await interaction.editReply(params).catch(() => {}); + } else { + await interaction.reply(params).catch(() => {}); + } + return await interaction.fetchReply(); + }; + }; this.db.query(`SELECT * FROM mails WHERE user_id="${user.id}"`, (err, mails) => { - if (err) return channel.send({ embeds: [ pack.embeds.errorSQL(user) ] }) & console.log(err); - if (mails.length === 0) return channel.send({ embeds: [ pack.embeds.classic(user) - .setTitle("Pas de mails") - .setDescription(`Vous n'avez aucun mails`) - .setColor('ORANGE') - ] }); + if (err) return sendFnt({ embeds: [ pack.embeds.errorSQL(user) ] }) & console.log(err); const row = this.generateMailBoxButtons(); - channel.send({ embeds: [ pack.embeds.classic(user) + sendFnt({ embeds: [ pack.embeds.classic(user) .setTitle("Boite mail") .setDescription(`Bienvenue dans votre boite mail`) .setColor('ORANGE') @@ -372,16 +380,11 @@ class MailManager { text = `\n\n:bulb: Vous pouvez désactiver les notifications de mail avec \`/mail-notifs disable\``; } - this.db.query(`SELECT prefix FROM prefixes WHERE guild_id="${message.guild ? message.guild.id : 'no guild'}"`, (er, re) => { - if (er) return functions.sendError(er, 'mail notif select prefix', message.author); - - let prefix = re.length > 0 ? re[0].prefix : pack.configs.default_prefix; - message.channel.send({ embeds: [ pack.embeds.classic(message.author) - .setTitle("Nouveau mail") - .setDescription(`Vous avez ${req.length} mail${req.length > 1 ? 's':''} non-lu.\n\nUtilisez la commande \`${prefix}mail\` pour le${req.length > 1 ? 's':''} consulter.${text}`) - .setColor('ORANGE') - ] }).catch(() => {}); - }) + message.channel.send({ embeds: [ pack.embeds.classic(message.author) + .setTitle("Nouveau mail") + .setDescription(`Vous avez ${req.length} mail${req.length > 1 ? 's':''} non-lu.\n\nUtilisez la commande \`/mailbox\` pour le${req.length > 1 ? 's':''} consulter.${text}`) + .setColor('ORANGE') + ] }).catch(() => {}); }; }) }); @@ -389,4 +392,4 @@ class MailManager { } }; -module.exports = MailManager \ No newline at end of file +module.exports = MailManager diff --git a/assets/managers/remindsManager.js b/assets/managers/remindsManager.js index 5a4f0ad..ffc41f7 100644 --- a/assets/managers/remindsManager.js +++ b/assets/managers/remindsManager.js @@ -54,11 +54,39 @@ class RemindsManger { }) }) } + removeInteraction(user, interaction, number) { + if (isNaN(number)) return interaction.reply({ content: pack.embeds.invalidNumber(user) }).catch(() => {}); + + this.db.query(`SELECT * FROM reminds WHERE user_id="${user.id}" AND ended="0" ORDER BY createdAt DESC`, (err, req) => { + if (err) return interaction.reply({ embeds: [ pack.embeds.errorSQL(user) ] }).catch(() => {}); + + const index = number - 1; + if (!req[index]) return interaction.reply({ content: `Vous n'avez aucun rappel de numéro \`${number}\`` }).catch(() => {}); + + const date = req[index].createdAt; + this.db.query(`DELETE FROM reminds WHERE user_id="${user.id}" AND createdAt="${date}" AND ended="0"`, (e) => { + if (e) return interaction.reply({ embeds: [ pack.embeds.errorSQL(user) ] }).catch(() => {}); + + interaction.reply({ content: `Je supprime le rappel numéro \`${number}\`` }).catch(() => {}); + }); + }); + } + /** + * @param {Discord.User} user + * @param {Discord.TextChannel | Discord.CommandInteraction} channel + */ list(user, channel) { + const fnt = (params) => { + if (channel.commandName) { + channel.reply(params).catch(() => {}); + } else { + channel.send(params).catch(() => {}); + }; + }; this.db.query(`SELECT * FROM reminds WHERE user_id="${user.id}" AND ended="0"`, (err, req) => { - if (err) return channel.send({ embeds: [ pack.embeds.errorSQL(user) ] }); + if (err) return fnt({ embeds: [ pack.embeds.errorSQL(user) ] }); - if (req.length === 0) return channel.send({ content: `Vous n'avez aucun rappel.` }); + if (req.length === 0) return fnt({ content: `Vous n'avez aucun rappel.` }); if (req.length > 5) { let now = pack.embeds.classic(user) .setTitle("Rappels") @@ -72,7 +100,7 @@ class RemindsManger { for (let i = 0; i < req.length; i++) { const warn = req[i]; - now.addField(`${i + 1})Rappel`, `\`\`\`${warn.content}\`\`\`\n> ${moment(parseInt(warn.date)).fromNow()}`, false); + now.addField(`${i + 1})Rappel`, `\`\`\`${warn.content}\`\`\`\n> `, false); pile = false; @@ -92,8 +120,12 @@ class RemindsManger { }; if (!pile) embeds.push(now); - - functions.pagination(user, channel, embeds, `rappels`); + + if (channel.commandName) { + functions.pagination(user, 'none', embeds, 'rappels', channel); + } else { + functions.pagination(user, channel, embeds, `rappels`); + }; } else { const embed = pack.embeds.classic(user) .setTitle("Rappels") @@ -102,10 +134,10 @@ class RemindsManger { req.forEach((warn) => { const id = req.indexOf(warn) + 1; - embed.addField(`${id}) Rappel`, `\`\`\`${warn.content}\`\`\`\n> ${moment(parseInt(warn.date)).fromNow()}`, false); + embed.addField(`${id}) Rappel`, `\`\`\`${warn.content}\`\`\`\n> `, false); }); - channel.send({ embeds: [ embed ] }); + fnt({ embeds: [ embed ] }); } }) } diff --git a/assets/managers/ticketsManager.js b/assets/managers/ticketsManager.js index 5445df1..e34e492 100644 --- a/assets/managers/ticketsManager.js +++ b/assets/managers/ticketsManager.js @@ -25,6 +25,7 @@ class TicketsManager { this.client = client; this.db = db; this.tickets = new Discord.Collection(); + this.configs = new Discord.Collection(); this.meanGuillement = "alt3"; } isTicket(id) { @@ -46,7 +47,7 @@ class TicketsManager { if (data.channel.type !== 'GUILD_TEXT') return 'not a text channel'; if (!this.validString(data.subject)) return 'not a valid text'; - const panel = new Discord.MessageEmbed() + const panel = new Discord.EmbedBuilder() .setTitle("Panel de ticket") .setDescription(`__Sujet du ticket :__ ${data.subject}\n__Description :__\n${data.description}\n\nRappel :\n→ Pas de spam\n→ Pas de troll\n\nAppuyez sur le bouton pour ouvrir un ticket.`) .setColor(data.guild.me.displayHexColor) @@ -54,7 +55,7 @@ class TicketsManager { if (data.image) panel.setImage(data.image); - data.channel.send({ embeds: [ panel ], components: [ new Discord.MessageActionRow().addComponents(new Discord.MessageButton({ customId: 'ticket_panel', emoji: '📥', style: 'SECONDARY' })) ] }).then((sent) => { + data.channel.send({ embeds: [ panel ], components: [ new Discord.ActionRowBuilder().addComponents(new Discord.MessageButton({ customId: 'ticket_panel', emoji: '📥', style: 'SECONDARY' })) ] }).then((sent) => { const dataset = { message_id: sent.id, guild_id: sent.guild.id, @@ -77,26 +78,36 @@ class TicketsManager { */ createTicket(data) { if (!this.validString(data.sujet)) return 'not a valid text'; - const embed = new Discord.MessageEmbed() + let { roles } = this.configs.get(data.guild.id); + if (!roles) roles = []; + + const embed = new Discord.EmbedBuilder() .setTitle("Ticket") .setDescription(`Ticket ouvert par <@${data.user.id}>.\n__Sujet :__ ${data.sujet}`) .setColor(data.guild.me.displayHexColor) if (data.image) embed.setImage(data.image); - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .addComponents( - new Discord.MessageButton() - .setStyle('SECONDARY') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Secondary) .setCustomId('ticket-close') .setEmoji('🔐'), new Discord.MessageButton() - .setStyle("DANGER") + .setStyle(Discord.ButtonStyle.Danger) .setCustomId('mention-everyone') .setLabel('mentionner everyone') ) - data.guild.channels.create(`Ticket-${functions.random(9, 0)}${functions.random(9, 0)}${functions.random(9, 0)}${functions.random(9, 0)}`, {permissionOverwrites: [{id: data.user.id, allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'ADD_REACTIONS', 'ATTACH_FILES'], deny: ['MENTION_EVERYONE', 'MUTE_MEMBERS']}, { id: data.guild.id, deny: ['VIEW_CHANNEL'] }]}).then((channel) => { + const permissions = [{id: data.user.id, allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'ADD_REACTIONS', 'ATTACH_FILES'], deny: ['MENTION_EVERYONE', 'MUTE_MEMBERS']}, { id: data.guild.id, deny: ['VIEW_CHANNEL'] }]; + if (roles.length > 0) { + for (const rId of roles) { + permissions.push({ id: rId, allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'ADD_REACTIONS', 'ATTACH_FILES'] }); + }; + }; + + data.guild.channels.create(`Ticket-${functions.random(9, 0)}${functions.random(9, 0)}${functions.random(9, 0)}${functions.random(9, 0)}`, {permissionOverwrites: permissions}).then((channel) => { channel.send({ embeds: [ embed ], components: [ row ], content: `<@${data.user.id}>, votre ticket a été crée.` }).then((sent) => { const dataset = { guild_id: data.guild.id, @@ -116,7 +127,7 @@ class TicketsManager { if (err) throw err; }); }); - }); + }).catch(() => {}); } /** * @returns {String} @@ -141,18 +152,18 @@ class TicketsManager { const menu = data.channel.messages.cache.get(ticket.message_id); if (!menu) return 'error: menu not found'; - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .addComponents( - new Discord.MessageButton() - .setStyle('SECONDARY') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Secondary) .setCustomId('ticket-reopen') .setEmoji('🔓'), - new Discord.MessageButton() - .setStyle('PRIMARY') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Primary) .setCustomId('ticket-save') .setEmoji('📜'), - new Discord.MessageButton() - .setStyle('DANGER') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Danger) .setCustomId('ticket-delete') .setEmoji('🗑') ) @@ -174,10 +185,10 @@ class TicketsManager { const menu = data.channel.messages.cache.get(ticket.message_id); if (!menu) return 'error: menu not found'; - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .addComponents( - new Discord.MessageButton() - .setStyle('SECONDARY') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Secondary) .setCustomId('ticket-close') .setEmoji('🔐') ); @@ -204,10 +215,10 @@ class TicketsManager { * @param {{ channel: Discord.GuildTextBasedChannel, menu: Discord.Message, user: Discord.User }} data */ pingEveryone(data) { - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .addComponents( - new Discord.MessageButton() - .setStyle('SECONDARY') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Secondary) .setCustomId('ticket-close') .setEmoji('🔐') ) @@ -241,22 +252,48 @@ class TicketsManager { } resetCache() { this.tickets = new Discord.Collection(); + this.configs = new Discord.Collection(); } loadCache() { this.db.query(`SELECT * FROM tickets`, (err, req) => { if (err) throw err; - this.resetCache(); + + this.db.query(`SELECT ticket_enable, ticket_roles, guild_id FROM configs`, (er, re) => { + if (er) throw er; + + this.resetCache(); + re.forEach((conf) => { + this.configs.set(conf.guild_id, { + enable: conf.ticket_enable == "1", + roles: JSON.parse(conf.ticket_roles).map(x => x.toString()) + }); + }); + req.forEach((ticket) => { + this.tickets.set(ticket.message_id, ticket); + }); - req.forEach((ticket) => { - this.tickets.set(ticket.message_id, ticket); - }); + }) }) } + checkForActivation(interaction) { + const activated = this.configs.get(interaction.guild.id).enable; + if (activated == false) { + interaction.reply({ embeds: [ pack.embeds.classic(interaction.user) + .setTitle("Système désactivé") + .setDescription(`Le système de tickets est **désactivé**.\n\nVeuillez l'activer pour utiliser les commandes de ticket.\n:bulb:\n> Utilisez la commande \`/config configurer\``) + .setColor('#ff0000') + ], ephemeral: true }).catch(() => {}); + return false; + }; + return true; + } loadInteraction() { this.client.on('interactionCreate', /** @param {Discord.ButtonInteraction} interaction */ async(interaction) => { if (interaction.isButton()) { const id = interaction.customId; if (id == 'ticket_panel') { + if (!this.checkForActivation(interaction)) return; + let { subject } = this.tickets.get(interaction.message.id); await interaction.deferUpdate(); @@ -265,20 +302,21 @@ class TicketsManager { this.createTicket(dataset); }; if (id == 'mention-everyone') { + if (!this.checkForActivation(interaction)) return; await interaction.reply({ embeds: [ pack.embeds.classic(interaction.user) .setTitle("Mention everyone") .setDescription(`Êtes-vous sûr de vouloir mentionner everyone ?`) .setColor('YELLOW') ], components: [ - new Discord.MessageActionRow() + new Discord.ActionRowBuilder() .addComponents( - new Discord.MessageButton() + new Discord.ButtonBuilder() .setLabel('Oui') - .setStyle('SUCCESS') + .setStyle(Discord.ButtonStyle.Success) .setCustomId('yes'), new Discord.MessageButton() .setLabel('Non') - .setStyle('DANGER') + .setStyle(Discord.ButtonStyle.Danger) .setCustomId('no') ) ], ephemeral: true }); @@ -296,16 +334,18 @@ class TicketsManager { }); }; if (id == 'ticket-close') { + if (!this.checkForActivation(interaction)) return; await interaction.deferUpdate(); this.closeTicket({ channel: interaction.channel }); }; if (id == 'ticket-save') { + if (!this.checkForActivation(interaction)) return; const customId = await this.saveTicket({ channel: interaction.channel }); interaction.deferReply(); setTimeout(() => { - const attachment = new Discord.MessageAttachment() + const attachment = new Discord.AttachmentBuilder() .setFile(customId) .setName(`${interaction.channel.name}-ticket-save.html`) .setDescription(`Sauvegarde du ticket`) @@ -319,11 +359,13 @@ class TicketsManager { }, 3000) }; if (id == 'ticket-reopen') { + if (!this.checkForActivation(interaction)) return; await interaction.deferUpdate(); this.reopenTicket({ channel: interaction.channel }); }; if (id == 'ticket-delete') { + if (!this.checkForActivation(interaction)) return; await interaction.deferUpdate(); this.delete({ channel: interaction.channel }); diff --git a/assets/message.js b/assets/message.js index 316862e..2838d54 100644 --- a/assets/message.js +++ b/assets/message.js @@ -25,52 +25,10 @@ module.exports = { const run = (prefix) => { - if (message.mentions.users.has(client.user.id) && !message.mentions.everyone) { - let splashes = require('./data/splash.json').filter(x => !x.includes('weird')); - - if (!functions.random(200, 0) === 132) { - const index = splashes.indexOf(x => x === 'This is an easter egg !'); - splashes.splice(index, 1); - }; - let size = require('./data/splash.json').length; - - let splash = splashes[functions.random(splashes.length, 0)].replace('{username}', message.author.username); - splash.replace('{size}', size); - - const reponse = package.embeds.classic(message.author) - .setTitle(splash) - .setDescription(`Bonjour ! Mon préfixe sur ce serveur est \`${prefix}\` !\n\nFaites \`${prefix}help\` pour obtenir de l'aide.\n\n:bulb: <@${client.user.id}> est désormais disponible en slash commands !\n> Si vous ne voyez pas mes slash commands, réinvitez moi par le lien de la commande \`${prefix}invite\`.`) - .setColor(message.guild.me.displayHexColor) - .setAuthor({ name: message.guild ? message.guild.me.nickname ? message.guild.me.nickname :'Oracle' : "Oracle", iconURL: message.author.displayAvatarURL({ dynamic: true }) }) - - if (splash === "Click on the link") { - reponse.setURL('https://www.youtube.com/watch?v=dQw4w9WgXcQ'); - }; - - functions.reply(message, reponse); - - if (message.guild) { - if (functions.random(10000, 0) === 794) { - message.guild.me.setNickname(`Oralce`); - }; - if ((message.guild.me.nickname === 'Dinnerbone' || message.guild.me.nickname === 'Grumm') && functions.random(10, 0) === 5) { - const reverse = (text) => { - let t =""; - for (let i =0;i { @@ -84,7 +42,7 @@ module.exports = { command = array.find(x => (x.name === commandName || (x.help.aliases && x.help.aliases.includes(commandName)))); }; }); - + if (!command) return; const file = require(`../${command.path}`); @@ -132,79 +90,11 @@ module.exports = { return message.channel.send({ embeds: [ package.embeds.errorSQL(message.author) ] }); }; - if (req.length === 0) { - client.db.query(`INSERT INTO cooldowns (guild_id, user_id, command, date) VALUES ("${message.guild.id}", "${message.author.id}", "${file.help.name}", "${Date.now() + file.help.cooldown * 1000}")`, (error) => { - if (error) go = false; - if (error) return message.channel.send({ embeds: [ package.embeds.errorSQL(message.author) ] }) & console.log(error); - }); - } else { - if (parseInt(req[0].date) > Date.now()) { - const moment = require('moment'); - moment.locale('fr'); - - return message.channel.send({ embeds: [ package.embeds.classic(message.author) - .setTitle('Cooldown') - .setDescription(`Oops, vous avez un cooldown sur cette commande, réessayez ${moment(req[0].date)}`) - .setColor('#ff0000') - ] }); - } else { - client.db.query(`INSERT INTO cooldowns (guild_id, user_id, command, date) VALUES ("${message.guild.id}", "${message.author.id}", "${file.name}", "${Date.now() + file.help.cooldown * 1000}")`, (error) => { - if (error) go =false & console.log(error); - if (error) return message.channel.send({ embeds: [ package.embeds.errorSQL(message.author) ] }); - }); - } - }; - if (!go) return; - suite(); - }) - + }); }; if (message.guild) { - client.db.query(`SELECT * FROM customs WHERE guild_id="${message.guild.id}" AND name="${commandName}"`, (error, request) => { - if (error) { - console.log(error); - message.channel.send({ embeds: [ package.embeds.errorSQL(message.author) ] }); - return; - } - - if (request.length === 0) return next(); - - let original = request[0].text; - - let response = original; - function replace(x, y) { - const regex = new RegExp(`{${x}}`, 'g'); - - response = response.replace(regex, y); - }; - - const corres = [ - {x: 'user.name', y: message.author.username}, - {x: 'user.tag', y: message.author.discriminator}, - {x: 'user.mention', y: `<@${message.author.id}>`}, - {x: 'user.id', y: message.author.id}, - {x: "del", y: ' '}, - {x: "args", y: args.join(' ') ? args.join(' ') : 'missingno'}, - {x: 'guild.name', y: message.guild.name}, - {x: 'guild.count', y: message.guild.members.cache.size}, - {x: 'reply', y: ' '}, - {x: 'mp', y: ' '} - ]; - corres.forEach((x) => {replace(x.x, x.y)}); - - let line = false; - - if (original.includes('{del}')) message.delete().catch(() => {}); - if (original.includes('{reply}')) line = true; - - if (original.includes('{mp}')) { - message.author.send({ content: response }).catch(() => {}); - } else { - if (line) return functions.lineReply(message.id, message.channel, response, false); - return message.channel.send({ content: response }); - } - }); + next(); } else { next(); } @@ -214,7 +104,7 @@ module.exports = { if (message.guild) { client.db.query(`SELECT prefix FROM prefixes WHERE guild_id = "${message.guild.id}"`, (err, req) => { if (err) return console.log(err); - prefix = req[0] ? req[0].prefix : require('./data/data.json').default_prefix; + prefix = req[0]?.prefix ?? require('./data/data.json').default_prefix; run(prefix); }); diff --git a/assets/morpion.js b/assets/morpion.js index cd05194..a0433e1 100644 --- a/assets/morpion.js +++ b/assets/morpion.js @@ -54,12 +54,12 @@ class Morpion { return embed; } generateButtons() { - let first = new Discord.MessageActionRow(); - let second = new Discord.MessageActionRow(); + let first = new Discord.ActionRowBuilder(); + let second = new Discord.ActionRowBuilder(); for (let i = 0;i<9;i++) { - const btn = new Discord.MessageButton() - .setStyle('SECONDARY') + const btn = new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Secondary) .setLabel(`Case ${i + 1}`) .setCustomId(i.toString()) @@ -69,8 +69,8 @@ class Morpion { }; second.addComponents( - new Discord.MessageButton() - .setStyle('DANGER') + new Discord.ButtonBuilder() + .setStyle(Discord.ButtonStyle.Danger) .setLabel('Abandonner') .setCustomId('cancel') ); diff --git a/assets/tickets.js b/assets/tickets.js deleted file mode 100644 index e5c42b4..0000000 --- a/assets/tickets.js +++ /dev/null @@ -1,228 +0,0 @@ -const Discord = require('discord.js'); -const functions = require('./functions'); -const package = functions.package(); - -/** - * @returns {Discord.Client} - */ -const Client = () => { - return require('../index.js').client; -}; - - -module.exports = { - /** - * - * @param {Discord.Guild} guild - * @param {Discord.User} user - */ - create: (guild, user, sujet) => { - guild.channels.create(`Ticket-${user.id}`, { - topic: `Ticket demandé par <@${user.id}>\n${sujet}`, - permissionOverwrites: [ - { - id: guild.roles.everyone.id, - deny: ["VIEW_CHANNEL"] - }, - { - id: user.id, - allow: ['VIEW_CHANNEL', 'ADD_REACTIONS', "SEND_MESSAGES"] - } - ] - }).then((channel) => { - const row = new Discord.MessageActionRow() - .addComponents( - new Discord.MessageButton() - .setLabel('Fermer') - .setCustomId('close-ticket') - .setStyle('SECONDARY') - ) - - channel.send({ embeds: [ package.embeds.classic(user) - .setTitle("Ticket") - .setDescription(`Ticket demandé par <@${user.id}>.\nCrée `) - .setColor('ORANGE') - ], components: [ row ] }).then((msg) => { - - const client = channel.client; - - client.db.query(`INSERT INTO tickets (guild_id, message_id, user_id, channel_id, type, subject) VALUES ("${guild.id}", "${msg.id}", "${user.id}", "${channel.id}", "ticket-message", "${sujet}")`, (err, req) => { - if (err) channel.send({ embeds: [ package.embeds.errorSQL(user) ] }) & console.log(err); - }); - - msg.channel.send({ content: `@everyone` }).catch(() => {}); - }); - }); - }, - close_ticket_panel: (guild, channel, user) => { - const row = new Discord.MessageActionRow() - .addComponents( - new Discord.MessageButton() - .setCustomId('confirm-close-ticket') - .setLabel('Confirm') - .setStyle('SUCCESS'), - new Discord.MessageButton() - .setLabel("Annuler") - .setCustomId('cancel-close-ticket') - .setStyle('DANGER') - ) - - channel.send({ embeds: [ package.embeds.classic(user) - .setTitle("Fermeture de ticket") - .setDescription(`Valider la fermeture du ticket`) - .setColor('ORANGE') - ], components: [ row ] }).then((x) => { - const client = guild.client; - client.db.query(`SELECT * FROM tickets WHERE channel_id="${channel.id}"`, (err, req) => { - if (err) channel.send({ embeds: [ package.embeds.errorSQL(user) ] }); - - let subject = "Unknown" - if (req.length) subject = req[0].subject; - - client.db.query(`INSERT INTO tickets (guild_id, message_id, user_id, channel_id, type, subject) VALUES ("${guild.id}", "${x.id}", "${user.id}", "${channel.id}", "close-ticket-panel", "${subject}")`, (e) => { - if (e) { - console.log(e); - channel.send({ embeds: [ package.embeds.errorSQL(user) ] }); - }; - }); - }); - }); - }, - /** - * - * @param {Discord.Guild} guild - * @param {Discord.TextChannel} channel - * @param {Discord.User} user - */ - close_ticket: (guild, channel, user) => { - channel.permissionOverwrites.edit(user, { - VIEW_CHANNEL: false, - SEND_MESSAGES: false, - ADD_REACTIONS: false, - READ_MESSAGE_HISTORY: false - }) - - const row = new Discord.MessageActionRow() - .addComponents( - new Discord.MessageButton() - .setLabel('Réouvrir') - .setCustomId('reopen-ticket') - .setStyle('PRIMARY'), - new Discord.MessageButton() - .setLabel('Sauvegarder') - .setStyle('SECONDARY') - .setCustomId('save-ticket'), - new Discord.MessageButton() - .setStyle('DANGER') - .setLabel('Supprimer le ticket') - .setCustomId('delete-ticket') - ) - - channel.send({ content: `Le ticket de <@${user.id}> a été fermé.`, components: [ row ] }).then((msg) => { - let content = ''; - for (let i = 0; i < 8; i++) { - let charact = user.username.charAt(i); - if (charact !== undefined) content+=charact; - }; - - channel.setName(`ticket-${content}-fermé`); - - const client = guild.client; - - client.db.query(`SELECT * FROM tickets WHERE channel_id="${channel.id}"`, (err, req) => { - if (err) channel.send({ embeds: [ package.embeds.errorSQL(user) ] }); - - let subject = "Unknown" - if (req.length) subject = req[0].subject; - - client.db.query(`INSERT INTO tickets (guild_id, message_id, user_id, channel_id, type, subject) VALUES ("${guild.id}", "${msg.id}", "${user.id}", "${channel.id}", "panel-closed-ticket", "${subject}")`, (e) => { - if (e) { - console.log(e); - channel.send({ embeds: [ package.embeds.errorSQL(user) ] }); - }; - }); - }); - }); - }, - /** - * @param {Discord.TextChannel} channel - * @param {Discord.User} user - */ - save_transcript: (channel, user) => { - const path = `./assets/transcripts/${channel.id}-${channel.guild.id}.txt`; - const fs = require('fs'); - - const writeTranscript = (toWrite) => { - fs.writeFileSync(path, toWrite); - }; - writeTranscript(""); - - let content = ` -Ticket de ${user.tag} -${channel.name}\n\n` - - channel.messages.cache.filter((x) => x.author && !x.author.bot).forEach((msg) => { - content+= `\n${msg.author.tag} : ${msg.content}`; - }); - - writeTranscript(content); - - const attachment = new Discord.MessageAttachment(path, 'transcript.txt'); - channel.send({ files: [ attachment ], content: `Voici la retranscription de la conversation.` }).catch(() => {}).then((x) => { - fs.rmSync(path); - }); - }, - /** - * @param {Discord.GuildChannel} channel - * @param {Discord.User} user User who opens the ticket - */ - reopen: (channel, user) => { - channel.permissionOverwrites.edit(user, { - VIEW_CHANNEL: true, - SEND_MESSAGES: true, - ADD_REACTIONS: true, - READ_MESSAGE_HISTORY: true - }) - - channel.setName(`ticket-${user.id}`); - channel.send({ content: `Le ticket de <@${user.id}> a été ré-ouvert.` }).catch((e) => console.log(e)); - }, - /** - * @param {Discord.TextChannel} channel Ticket - * @param {Discord.User} user - */ - delete: (channel, user) => { - const row = new Discord.MessageActionRow() - .addComponents( - new Discord.MessageButton() - .setCustomId('cancel-close-ticket-delete') - .setEmoji('❌') - .setStyle('DANGER') - ) - channel.send({ content: `Le ticket sera supprimé dans **10 secondes** si <@${user.id}> ne l'annule pas avant`, components: [ row ] }).then((msg) => { - const collector = msg.createMessageComponentCollector({ filter: (i) => i.user.id === user.id , time: 10000, max: 1}); - - collector.on('end', (collected) => { - msg.delete().catch(() => {}); - - if (collected.size != 0) return; - channel.delete().catch(() => {}); - - const client = channel.client; - client.db.query(`DELETE FROM tickets WHERE guild_id="${channel.guild.id}" AND channel_id="${channel.id}"`, (err, req) => { - if (err) console.log(err); - }); - }); - }) - }, - /** - * @returns {Boolean} - * @param {Discord.TextChannel} channel - */ - isTicket: (channel) => { - const files = reqTickets(channel.guild); - if (files.filter((x) => x.channel === channel.id && x.type === 'ticket-message').length == 0) return false; - - return true; - } -} \ No newline at end of file diff --git a/commands.json b/commands.json new file mode 100644 index 0000000..896a110 --- /dev/null +++ b/commands.json @@ -0,0 +1,2597 @@ +[ + [ + { + "name": "config", + "description": "Configure Oracle sur votre serveur", + "options": [ + { + "name": "paramètres", + "description": "Affiche les paramètres configurables", + "type": "SUB_COMMAND" + }, + { + "name": "configurer", + "description": "Configure un paramètre", + "type": "SUB_COMMAND", + "options": [ + { + "name": "paramètre", + "description": "Paramètre à configurer", + "type": "STRING", + "required": true, + "choices": [ + { + "name": "Logs", + "value": "logs_enable" + }, + { + "name": "Messages d'arrivées", + "value": "join_enable" + }, + { + "name": "Messages de départs", + "value": "leave_enable" + }, + { + "name": "Salon d'arrivée", + "value": "join_channel" + }, + { + "name": "Salon de départ", + "value": "leave_channel" + }, + { + "name": "Message d'arrivée", + "value": "join_message" + }, + { + "name": "Message de départ", + "value": "leave_message" + }, + { + "name": "Salon des logs", + "value": "logs_channel" + }, + { + "name": "Salon de niveaux", + "value": "level_channel" + }, + { + "name": "Message de niveau", + "value": "level_message" + }, + { + "name": "Roles d'arrivée", + "value": "roles_enable" + }, + { + "name": "Système de GBan", + "value": "gban_enable" + }, + { + "name": "Système de compteur", + "value": "counting_enable" + }, + { + "name": "Salon de comptage", + "value": "counting_channel" + }, + { + "name": "Système de tickets", + "value": "ticket_enable" + }, + { + "name": "Salon des suggestions", + "value": "suggest_channel" + } + ] + }, + { + "name": "état", + "description": "État binaire du paramètre (si binaire)", + "required": false, + "type": "BOOLEAN" + }, + { + "name": "texte", + "description": "Texte du paramètre (si texte)", + "required": false, + "type": "STRING" + }, + { + "name": "salon", + "description": "Salon du paramètre (si salon)", + "type": "CHANNEL", + "required": false + } + ] + } + ] + }, + { + "name": "modules", + "description": "Gère les modules", + "options": [ + { + "name": "configurer", + "description": "Configure un module", + "type": "SUB_COMMAND", + "options": [ + { + "name": "module", + "description": "Module à configurer", + "type": "STRING", + "required": true, + "choices": [ + { + "name": "Économie", + "value": "economy" + }, + { + "name": "Modération", + "value": "moderation" + }, + { + "name": "Utilitaires", + "value": "usefull" + }, + { + "name": "Amusement", + "value": "fun" + }, + { + "name": "Informations", + "value": "information" + }, + { + "name": "Divers", + "value": "misc" + }, + { + "name": "Niveaux", + "value": "levels" + } + ] + }, + { + "name": "état", + "description": "État du module", + "type": "BOOLEAN", + "required": true + } + ] + }, + { + "name": "afficher", + "description": "Affiche l'état des modules sur le serveur", + "type": "SUB_COMMAND" + } + ] + } + ], + [ + { + "name": "admin-coins", + "description": "Gère les OraCoins sur le serveur", + "options": [ + { + "name": "ajouter", + "description": "Ajoute des OraCoins à un utilisateur", + "type": "SUB_COMMAND", + "options": [ + { + "name": "utilisateur", + "description": "Utilisateur à qui ajouter des OraCoins", + "type": "USER", + "required": true + }, + { + "name": "montant", + "description": "Montant d'OraCoins à ajouter", + "type": "INTEGER", + "required": true + } + ] + }, + { + "name": "retirer", + "description": "Retire des OraCoins à un utilisateur", + "type": "SUB_COMMAND", + "options": [ + { + "name": "utilisateur", + "description": "Utilisateur à qui retirer des OraCoins", + "type": "USER", + "required": true + }, + { + "name": "montant", + "description": "Montant d'OraCoins à ajouter", + "type": "INTEGER", + "required": true + } + ] + }, + { + "name": "réinitialiser", + "description": "Réinitialiser des OraCoins", + "type": "SUB_COMMAND_GROUP", + "options": [ + { + "name": "utilisateur", + "description": "Réinitialiser des OraCoins à un utilisateur", + "type": "SUB_COMMAND", + "options": [ + { + "name": "utilisateur", + "description": "Utilisateur à qui ajouter des OraCoins", + "type": "USER", + "required": true + } + ] + }, + { + "name": "serveur", + "description": "Réinitialiser les OraCoins du serveur", + "type": "SUB_COMMAND" + } + ] + } + ] + }, + { + "name": "banque", + "description": "Utilisez votre banque", + "options": [ + { + "name": "déposer", + "description": "Déposer des OraCoins dans votre banque", + "type": "SUB_COMMAND", + "options": [ + { + "name": "montant", + "description": "Montant d'OraCoins à déposer", + "type": "INTEGER", + "required": true + } + ] + }, + { + "name": "retirer", + "description": "Retirer des OraCoins de votre banque", + "type": "SUB_COMMAND", + "options": [ + { + "name": "montant", + "description": "Montant d'OraCoins à retirer", + "type": "INTEGER", + "required": true + } + ] + } + ] + }, + { + "name": "daily", + "description": "Récupère votre récompense quotidienne" + }, + { + "name": "inventaire", + "description": "Affiche votre inventaire" + }, + { + "name": "leaderboard", + "description": "Affiche le classement des OraCoins du serveur" + }, + { + "name": "loto", + "description": "Gère un loto sur le serveur", + "options": [ + { + "name": "gérer", + "description": "Gère le loto", + "type": "SUB_COMMAND_GROUP", + "options": [ + { + "name": "démarrer", + "description": "Lance le loto sur le serveur", + "type": "SUB_COMMAND", + "options": [ + { + "name": "récompense", + "description": "Récompense en OraCoins du loto", + "type": "INTEGER", + "required": true + }, + { + "name": "gagnants", + "description": "Nombre de numéro gagnants à tirer (minimum 5)", + "type": "INTEGER", + "required": true + }, + { + "name": "complémentaires", + "description": "Nombre de numéro complémentaires à tirer (minimum 2)", + "type": "INTEGER", + "required": true + }, + { + "name": "temps", + "description": "Temps avant la fin du loto (ex: 1d)", + "type": "STRING", + "required": true + } + ] + }, + { + "name": "tirage", + "description": "Fait le tirage du loto", + "type": "SUB_COMMAND" + } + ] + }, + { + "name": "participer", + "description": "Participez au loto en cours", + "type": "SUB_COMMAND", + "options": [ + { + "name": "gagnants", + "description": "Les numéro gagnants que vous jouez (ex: 15 68 46 75 12)", + "type": "STRING", + "required": true + }, + { + "name": "complémentaires", + "description": "Les numéro complémentaires que vous jouez (ex: 94 60)", + "required": true, + "type": "STRING" + } + ] + } + ] + }, + { + "name": "pay", + "description": "Donne un montant d'OraCoins à un utilisateur", + "options": [ + { + "name": "montant", + "type": "INTEGER", + "required": true, + "description": "Montant d'argent que vous voulez donner" + }, + { + "name": "utilisateur", + "required": true, + "description": "Utilisateur à qui vous voulez donner l'argent", + "type": "USER" + } + ] + }, + { + "name": "shop", + "description": "Utilisez le système de magasin", + "options": [ + { + "name": "item", + "type": "SUB_COMMAND_GROUP", + "description": "Ajoute des items au magasin", + "options": [ + { + "name": "ajouter", + "type": "SUB_COMMAND", + "description": "Ajouter un item au magasin", + "options": [ + { + "name": "nom", + "description": "Nom de l'item", + "type": "STRING", + "required": true + }, + { + "name": "type", + "description": "Type de l'item", + "type": "STRING", + "required": true, + "choices": [ + { + "name": "Rôle", + "value": "role" + }, + { + "name": "Étiquette", + "value": "text" + } + ] + }, + { + "name": "prix", + "description": "Prix de l'item", + "type": "INTEGER", + "required": true + }, + { + "name": "quantité", + "description": "Nombre d'items que vous voulez ajouter (laissez vide pour illimité)", + "type": "INTEGER", + "required": false + }, + { + "name": "description", + "description": "Description de l'étiquette (si étiquette)", + "type": "STRING", + "required": false + }, + { + "name": "role", + "description": "Rôle (si l'item est un rôle)", + "type": "ROLE", + "required": false + } + ] + }, + { + "name": "supprimer", + "description": "Supprime un item du magasin", + "type": "SUB_COMMAND", + "options": [ + { + "name": "identifiant", + "description": "Identifiant de l'item à supprimer", + "type": "STRING", + "required": true + } + ] + } + ] + }, + { + "name": "view", + "description": "Affiche le magasin", + "type": "SUB_COMMAND" + }, + { + "name": "acheter", + "description": "Achète un item du shop", + "type": "SUB_COMMAND", + "options": [ + { + "name": "identifiant", + "type": "STRING", + "description": "Identifiant de l'item à acheter", + "required": true + } + ] + } + ] + }, + { + "name": "stats", + "description": "Affiche les statistiques économiques d'un utilisateur", + "options": [ + { + "name": "utilisateur", + "description": "Utilisateur dont vous voulez voir les statistiques", + "required": false, + "type": "USER" + } + ] + }, + { + "name": "échange", + "description": "Effectue un échange", + "options": [ + { + "name": "utilisateur", + "description": "Utilisateur avec qui vous voulez échanger", + "type": "USER", + "required": true + }, + { + "name": "item", + "type": "STRING", + "required": true, + "description": "Nom de l'item que vous voulez échanger" + }, + { + "name": "prix", + "type": "INTEGER", + "required": true, + "description": "Prix auxquel vous souhaitez échanger" + } + ] + }, + { + "name": "weekly", + "description": "Récupère votre récompense hebdomadaire" + } + ], + [ + { + "name": "8ball", + "description": "Demande quelque chose à la boule de crystal", + "options": [ + { + "name": "question", + "description": "Question à poser à la boule de crystal", + "type": "STRING", + "required": true + }, + { + "name": "discret", + "description": "Fait en sorte que seul vous voie ce message.", + "required": false, + "autocomplete": false, + "type": "BOOLEAN" + } + ] + }, + { + "name": "choix", + "description": "Fais un choix parmis les propositions", + "options": [ + { + "name": "proposition1", + "description": "Définissez la proposition 1", + "type": "STRING", + "required": true + }, + { + "name": "proposition2", + "description": "Définissez la proposition 2", + "type": "STRING", + "required": true + }, + { + "name": "proposition3", + "description": "Définissez la proposition 3", + "type": "STRING", + "required": false + }, + { + "name": "proposition4", + "description": "Définissez la proposition 4", + "type": "STRING", + "required": false + }, + { + "name": "proposition5", + "description": "Définissez la proposition 5", + "type": "STRING", + "required": false + }, + { + "name": "proposition6", + "description": "Définissez la proposition 6", + "type": "STRING", + "required": false + }, + { + "name": "proposition7", + "description": "Définissez la proposition 7", + "type": "STRING", + "required": false + }, + { + "name": "proposition8", + "description": "Définissez la proposition 8", + "type": "STRING", + "required": false + }, + { + "name": "proposition9", + "description": "Définissez la proposition 9", + "type": "STRING", + "required": false + } + ] + }, + { + "name": "demineur", + "description": "Lance une partie de démineur", + "options": [ + { + "name": "discret", + "description": "Fait en sorte que seul vous coie ce message", + "required": false, + "autocomplete": false, + "type": "BOOLEAN" + } + ] + }, + { + "name": "game", + "description": "Joue a des jeux sur Oracle", + "options": [ + { + "name": "démineur", + "description": "Joue au démineur sur Oracle", + "type": "SUB_COMMAND" + }, + { + "name": "number", + "description": "Joue à guess the number", + "type": "SUB_COMMAND_GROUP", + "options": [ + { + "name": "multijoueur", + "description": "Joue en multijoueur", + "type": "SUB_COMMAND", + "options": [ + { + "name": "max", + "description": "Nombre maximum", + "type": "INTEGER", + "required": false + }, + { + "name": "min", + "description": "Nombre minimum", + "type": "INTEGER", + "required": false + } + ] + }, + { + "name": "solo", + "description": "Joue en solo", + "type": "SUB_COMMAND", + "options": [ + { + "name": "max", + "description": "Nombre maximum", + "type": "INTEGER", + "required": false + }, + { + "name": "min", + "description": "Nombre minimum", + "type": "INTEGER", + "required": false + } + ] + } + ] + }, + { + "name": "morpion", + "description": "Joue au morpion contre Oracle", + "type": "SUB_COMMAND" + }, + { + "name": "roulette-russe", + "description": "Joue à la roulette russe", + "type": "SUB_COMMAND", + "options": [ + { + "name": "expulsion", + "description": "⚠ Si vous perdez vous serez expulsé.", + "required": false, + "type": "BOOLEAN" + } + ] + }, + { + "name": "shifumi", + "description": "Joue au shifumi contre Oracle", + "type": "SUB_COMMAND", + "options": [ + { + "name": "signe", + "type": "STRING", + "required": true, + "description": "Signe que vous jouez", + "choices": [ + { + "name": "pierre", + "value": "0", + "emoji": "✊" + }, + { + "name": "papier", + "value": "1", + "emoji": "📜" + }, + { + "name": "ciseaux", + "value": "2", + "emoji": "✂" + } + ] + } + ] + }, + { + "name": "8ball", + "description": "Pose une question au bot", + "type": "SUB_COMMAND", + "options": [ + { + "name": "question", + "description": "La question que vous voulez me poser", + "required": true, + "type": "STRING" + } + ] + }, + { + "name": "dés", + "description": "Joue au dés", + "type": "SUB_COMMAND", + "options": [ + { + "name": "nombre", + "type": "INTEGER", + "description": "Nombre de dés (maximum 64)", + "required": false + }, + { + "name": "faces", + "type": "INTEGER", + "description": "Nombre de faces sur les dés", + "required": false + } + ] + } + ] + }, + { + "name": "blague", + "description": "Affiche une blague aléatoire", + "options": [ + { + "name": "global", + "description": "Blague de type global", + "type": "SUB_COMMAND" + }, + { + "name": "dev", + "description": "Blague de type dev", + "type": "SUB_COMMAND" + }, + { + "name": "dark", + "description": "Blague de type dark", + "type": "SUB_COMMAND" + }, + { + "name": "limit", + "description": "Blague de type limit", + "type": "SUB_COMMAND" + }, + { + "name": "beauf", + "description": "Blague de type beauf", + "type": "SUB_COMMAND" + }, + { + "name": "blondes", + "description": "Blague de type blondes", + "type": "SUB_COMMAND" + } + ] + }, + { + "name": "meme", + "description": "Envoie un meme" + }, + { + "name": "mixnames", + "description": "Fait le mélange de deux pseudos", + "options": [ + { + "name": "utilisateur1", + "description": "Premier utilisateur", + "type": "USER", + "required": true + }, + { + "name": "utilisateur2", + "description": "Deuxième utilisateur", + "type": "USER", + "required": false + }, + { + "name": "texte", + "description": "Texte à la place du deuxième utilisateur", + "type": "STRING", + "required": false + } + ] + }, + { + "name": "pof", + "description": "Fait un pile ou face", + "options": [ + { + "name": "pari", + "description": "Le choix du côté de la pièce", + "type": "STRING", + "required": true, + "choices": [ + { + "name": "Pile", + "value": "pile" + }, + { + "name": "Face", + "value": "face" + } + ] + } + ] + }, + { + "name": "cryptage", + "description": "Crypte ou décrypte un texte selon votre clé", + "options": [ + { + "name": "action", + "description": "Action à effectuer sur votre texte", + "required": true, + "type": "STRING", + "choices": [ + { + "name": "Chiffrer", + "value": "code" + }, + { + "name": "Déchiffrer", + "value": "decode" + } + ] + }, + { + "name": "texte", + "type": "STRING", + "required": true, + "description": "Texte à examiner" + }, + { + "name": "clé", + "required": true, + "description": "Clé de chiffrage/déchiffrage", + "type": "STRING" + } + ] + } + ], + [ + { + "name": "avatar", + "description": "Affiche la photo de profil d'une personne", + "options": [ + { + "name": "utilisateur", + "description": "Utilisateur dont vous voulez voir la photo de profil", + "type": "USER", + "required": false, + "autocomplete": false + } + ] + }, + { + "name": "botinfo", + "description": "Affiche quelques informations sur le bot" + }, + { + "name": "channelinfo", + "description": "Affiche les informations d'un salon", + "options": [ + { + "name": "salon", + "description": "Salon dont vous voulez soutirer des informations", + "required": false, + "type": "CHANNEL" + } + ] + }, + { + "name": "roleinfo", + "description": "Affiche les informations d'un rôle", + "options": [ + { + "name": "rôle", + "description": "Rôle dont vous voulez vous informez", + "required": false, + "type": "ROLE" + } + ] + }, + { + "name": "servericon", + "description": "Affiche l'icône du serveur" + }, + { + "name": "serverinfo", + "description": "Affiche les informations du serveur" + }, + { + "name": "userinfo", + "description": "Affiche les informations d'un utilisateur", + "options": [ + { + "name": "utilisateur", + "description": "Utilisateur dont vous voulez être informé", + "type": "USER", + "required": false + } + ] + } + ], + [ + { + "name": "classement", + "description": "Affiche le classement des niveaux du serveur" + }, + { + "name": "rank", + "description": "Affiche les informations de niveau d'un utilisateur", + "options": [ + { + "name": "utilisateur", + "description": "Utilisateur concerné", + "required": false, + "autocomplete": false, + "type": "USER" + }, + { + "name": "discret", + "description": "Fait en sorte que seul vous voie ce message.", + "required": false, + "autocomplete": false, + "type": "BOOLEAN" + } + ] + } + ], + [ + { + "name": "cmdpersonnalisée", + "description": "Gère les commandes personnalisées", + "options": [ + { + "name": "créer", + "description": "Créer une commande personnalisée", + "type": "SUB_COMMAND", + "options": [ + { + "name": "nom", + "description": "Nom de la commande", + "type": "STRING", + "required": true + }, + { + "name": "réponse", + "description": "Réponse du bot", + "type": "STRING", + "required": true + } + ] + }, + { + "name": "supprimer", + "description": "Supprime une commande personnalisée", + "type": "SUB_COMMAND", + "options": [ + { + "name": "nom", + "description": "Nom de la commande", + "type": "STRING", + "required": true + } + ] + }, + { + "name": "liste", + "description": "Affiche la liste des commandes personnalisées", + "type": "SUB_COMMAND" + } + ] + }, + { + "name": "documentation", + "description": "Envoie le lien de la documentation" + }, + { + "name": "drop", + "description": "Fait un drop dans le salon", + "options": [ + { + "name": "récompense", + "description": "Récompense du drop", + "type": "STRING", + "required": true + } + ] + }, + { + "name": "generatemdp", + "description": "Génère un mot de passe aléatoire", + "options": [ + { + "type": "INTEGER", + "name": "taille", + "description": "Nombre de caractères", + "required": true + }, + { + "type": "BOOLEAN", + "name": "majuscules", + "description": "Le mot de passe doit-il inclure des majuscules ?", + "required": true + }, + { + "type": "BOOLEAN", + "name": "nombres", + "description": "Le mot de passe contient-il des nombres ?", + "required": true + }, + { + "type": "BOOLEAN", + "name": "speciaux", + "description": "Le mot de passe doit-il contenir des caractères spéciaux", + "required": true + } + ] + }, + { + "name": "giveaway", + "description": "Giveaways", + "options": [ + { + "name": "create", + "description": "Crée un giveaway", + "type": "SUB_COMMAND", + "options": [ + { + "name": "récompense", + "description": "récompense données au(x) gagnant(s)", + "required": true, + "type": "STRING", + "autocomplete": false + }, + { + "name": "temps", + "type": "STRING", + "description": "Temps du giveaway", + "autocomplete": false, + "required": true + }, + { + "name": "gagnants", + "type": "INTEGER", + "required": true, + "autocomplete": false, + "description": "Nombre de gagnants au giveaway" + }, + { + "name": "salon", + "type": "CHANNEL", + "required": false, + "autocomplete": false, + "description": "Le salon dans lequel aura lieu le giveaway" + }, + { + "name": "bonus", + "type": "STRING", + "required": false, + "description": "Identifiants des rôles bonus (séparés par un espace)" + }, + { + "name": "requis", + "type": "STRING", + "required": false, + "description": "Identifiants des rôles requis (séparés par un espace)" + }, + { + "name": "interdits", + "type": "STRING", + "required": false, + "description": "Identifiants des rôles interdits (séparés par un espace)" + } + ] + }, + { + "name": "reroll", + "description": "Reroll un giveaway", + "type": "SUB_COMMAND", + "options": [ + { + "name": "id", + "description": "identifiant du message du giveaway dans le salon", + "required": true, + "type": "STRING", + "autocomplete": false + } + ] + }, + { + "name": "end", + "description": "Met fin à un giveaway", + "type": "SUB_COMMAND", + "options": [ + { + "name": "id", + "description": "Identifiant du message du giveaway dans le salon", + "required": true, + "autocomplete": false, + "type": "STRING" + } + ] + } + ] + }, + { + "name": "google", + "description": "Fait une recherche google", + "options": [ + { + "name": "recherche", + "required": true, + "autocomplete": false, + "description": "Le texte que vous souhaitez rechercher.", + "type": "STRING" + }, + { + "name": "discret", + "description": "Fait en sorte que seul vous voie ce message", + "autocomplete": false, + "required": false, + "type": "BOOLEAN" + } + ] + }, + { + "name": "mail-notifs", + "description": "Active ou désactive les notifications de mail", + "options": [ + { + "name": "enable", + "description": "Active les notifications de mail", + "type": "SUB_COMMAND" + }, + { + "name": "disable", + "description": "Désactive les notifications de mail", + "type": "SUB_COMMAND" + } + ] + }, + { + "name": "mail", + "description": "Envoie un mail à un utilisateur", + "options": [ + { + "name": "utilisateur", + "required": true, + "type": "USER", + "description": "Utilisateur qui recevra le mail" + }, + { + "name": "objet", + "description": "Objet du mail", + "required": true, + "type": "STRING" + }, + { + "name": "contenu", + "description": "Contenu du mail", + "type": "STRING", + "required": true + } + ] + }, + { + "name": "mailbox", + "description": "Ouvre votre boite mail" + }, + { + "name": "ping", + "description": "Pong", + "options": [ + { + "name": "discret", + "description": "Fait en sorte que vous seul voyez ce message.", + "type": "BOOLEAN", + "required": false, + "autocomplete": false + } + ] + }, + { + "name": "say", + "description": "Fait dire quelque chose à Oracle", + "options": [ + { + "name": "texte", + "type": "STRING", + "required": true, + "description": "Texte à faire répéter" + } + ] + }, + { + "name": "suggestion", + "description": "Fait une suggestion dans le salon de la commande", + "options": [ + { + "name": "suggestion", + "description": "Suggestion à proposer", + "type": "STRING", + "required": true + } + ] + } + ], + [ + { + "name": "autorole", + "description": "Gère les rôles donnés automatiquement à l'arrivée sur le serveur", + "options": [ + { + "name": "ajouter", + "description": "Ajoute un rôle automatiquement donné", + "type": "SUB_COMMAND", + "options": [ + { + "name": "rôle", + "description": "Rôle à ajouter", + "type": "ROLE", + "required": true + } + ] + }, + { + "name": "retirer", + "description": "Retirer un rôle automatiquement donné", + "type": "SUB_COMMAND", + "options": [ + { + "name": "rôle", + "description": "Rôle à retirer", + "type": "ROLE", + "required": true + } + ] + }, + { + "name": "liste", + "description": "Affiche la liste des rôles automatiques", + "type": "SUB_COMMAND" + } + ] + }, + { + "name": "ban", + "description": "Banni un membre pour une raison donnée", + "options": [ + { + "name": "membre", + "required": true, + "description": "L'utilisateur que vous voulez bannir", + "autocomplete": false, + "type": "USER" + }, + { + "name": "raison", + "required": true, + "description": "Raison du bannissement", + "autocomplete": false, + "type": "STRING" + } + ] + }, + { + "name": "censure", + "description": "Censure le pseudo d'un membre", + "options": [ + { + "name": "membre", + "description": "Membre à censurer", + "type": "USER", + "required": true + }, + { + "name": "raison", + "description": "Raison de la censure", + "type": "STRING", + "required": true + } + ] + }, + { + "name": "salon", + "description": "Gère les salons", + "options": [ + { + "name": "créer", + "type": "SUB_COMMAND", + "description": "Créer un salon", + "options": [ + { + "name": "nom", + "description": "Nom du salon", + "type": "STRING", + "required": true, + "autocomplete": false + }, + { + "name": "type", + "description": "Type du salon", + "type": "STRING", + "required": true, + "autocomplete": false, + "choices": [ + { + "name": "texte", + "value": "GUILD_TEXT" + }, + { + "name": "vocal", + "value": "GUILD_VOICE" + }, + { + "name": "catégorie", + "value": "GUILD_CATEGORY" + } + ] + }, + { + "name": "catégorie", + "type": "CHANNEL", + "required": false, + "autocomplete": false, + "description": "Catégorie dans laquelle le salon sera crée" + } + ] + }, + { + "name": "supprimer", + "type": "SUB_COMMAND", + "description": "Supprimer un salon", + "options": [ + { + "name": "salon", + "description": "Le salon à supprimer", + "required": false, + "type": "CHANNEL" + } + ] + }, + { + "name": "renommer", + "type": "SUB_COMMAND", + "description": "Renommer un salon", + "options": [ + { + "name": "nom", + "description": "Nouveau nom du salon", + "required": true, + "type": "STRING" + }, + { + "name": "salon", + "description": "Salon à renommer", + "required": false, + "type": "CHANNEL" + } + ] + }, + { + "name": "déplacer", + "type": "SUB_COMMAND", + "description": "Déplacer un salon.", + "options": [ + { + "name": "places", + "description": "Nombre de places pour déplacer le salon. Rentrez un nombre négatif ou un nombre positif.", + "required": true, + "type": "NUMBER" + }, + { + "name": "salon", + "description": "Salon à déplacer", + "required": false, + "type": "CHANNEL" + } + ] + }, + { + "name": "catégoriser", + "type": "SUB_COMMAND", + "description": "Catégoriser un salon", + "options": [ + { + "name": "catégorie", + "description": "Catégorie qui pendra le salon", + "required": false, + "type": "CHANNEL" + }, + { + "name": "salon", + "description": "Salon à catégoriser", + "required": false, + "type": "CHANNEL" + } + ] + }, + { + "name": "décrire", + "type": "SUB_COMMAND", + "description": "Configure la description d'un salon", + "options": [ + { + "name": "salon", + "description": "Salon à décrire", + "type": "CHANNEL", + "required": false + }, + { + "name": "description", + "type": "STRING", + "required": false, + "description": "Description à donner au salon (laisser vide pour réinitialiser)" + } + ] + }, + { + "name": "identifier", + "description": "Affiche l'identifiant d'un salon", + "type": "SUB_COMMAND", + "options": [ + { + "name": "salon", + "description": "Salon à identifier", + "type": "CHANNEL", + "required": false + }, + { + "name": "embed", + "description": "Affiche la réponse sous forme d'embed (plus compliqué pour copier/coller)", + "required": false, + "type": "BOOLEAN" + } + ] + } + ] + }, + { + "name": "clear", + "description": "Supprime un nombre de messages dans le salon", + "options": [ + { + "name": "messages", + "description": "Nombre de messages à supprimer", + "required": true, + "type": "INTEGER" + } + ] + }, + { + "name": "demote", + "description": "Dérank un utilisateur", + "options": [ + { + "name": "highest", + "description": "Enlève le rôle le plus haut d'un utilisateur", + "type": "SUB_COMMAND", + "options": [ + { + "name": "utilisateur", + "type": "USER", + "description": "Utilisateur à dérank", + "required": true + }, + { + "name": "raison", + "type": "STRING", + "description": "raison", + "required": true + } + ] + }, + { + "name": "full", + "description": "Retire tout les rôles d'un utilisateur", + "type": "SUB_COMMAND", + "options": [ + { + "name": "utilisateur", + "type": "USER", + "description": "Utilisateur à dérank", + "required": true + }, + { + "name": "raison", + "type": "STRING", + "description": "raison", + "required": true + } + ] + } + ] + }, + { + "name": "edit-case", + "description": "Modifie un log de modération sur le serveur", + "options": [ + { + "name": "numéro", + "description": "Numéro du log", + "required": true, + "autocomplete": false, + "type": "INTEGER" + }, + { + "name": "raison", + "description": "La nouvelle raison du log", + "required": true, + "type": "STRING", + "autocomplete": false + } + ] + }, + { + "name": "filtre-case-action", + "description": "Affiche tout les logs de modération concernant une action précisée", + "options": [ + { + "name": "action", + "description": "L'action a afficher", + "required": true, + "autocomplete": false, + "type": "STRING", + "choices": [ + { + "name": "Bannissements", + "value": "ban" + }, + { + "name": "Avertissements", + "value": "avertissement" + }, + { + "name": "Réduction au silence", + "value": "mute" + }, + { + "name": "Expulsion", + "value": "kick" + }, + { + "name": "Démutage", + "value": "unmute" + }, + { + "name": "Suppression d'avertissements", + "value": "unwarn" + }, + { + "name": "Débanissement", + "value": "unban" + }, + { + "name": "Modification de pseudo", + "value": "pseudo modifié" + }, + { + "name": "Réinitialisation de pseudo", + "value": "pseudo réinitialisé" + } + ] + } + ] + }, + { + "name": "infractions", + "description": "Affiche toutes les infractions d'un utilisateur", + "options": [ + { + "name": "membre", + "description": "Membre dont vous voulez voir les infractions", + "required": false, + "type": "USER" + } + ] + }, + { + "name": "kick", + "description": "Expulse un membre du serveur", + "options": [ + { + "name": "utilisateur", + "description": "La personne à expulser du serveur", + "type": "USER", + "required": true, + "autocomplete": false + }, + { + "name": "raison", + "description": "Raison de l'expulsion", + "type": "STRING", + "required": true, + "autocomplete": false + } + ] + }, + { + "name": "logs", + "description": "Gère les logs du serveur", + "options": [ + { + "name": "afficher", + "description": "Affiche les logs du serveur", + "type": "SUB_COMMAND" + }, + { + "name": "identifier", + "description": "Affiche un log spécifique", + "type": "SUB_COMMAND", + "options": [ + { + "name": "identifiant", + "description": "Identifiant du log que vous voulez voir", + "type": "STRING", + "required": true + } + ] + } + ] + }, + { + "name": "mute", + "description": "Mute un membre du serveur", + "options": [ + { + "name": "membre", + "type": "USER", + "description": "Membre à muter", + "required": true + }, + { + "name": "raison", + "type": "STRING", + "description": "Raison du mute", + "required": true + }, + { + "name": "durée", + "type": "INTEGER", + "description": "Durée du mute", + "required": false, + "choices": [ + { + "name": "5 minutes", + "value": 300000 + }, + { + "name": "10 minutes", + "value": 600000 + }, + { + "name": "20 minutes", + "value": 1200000 + }, + { + "name": "30 minutes", + "value": 1800000 + }, + { + "name": "45 minutes", + "value": 2700000 + }, + { + "name": "1 heure", + "value": 3600000 + }, + { + "name": "2 heures", + "value": 7200000 + }, + { + "name": "6 heures", + "value": 21600000 + }, + { + "name": "1 jour", + "value": 86400000 + } + ] + } + ] + }, + { + "name": "note", + "description": "Système de notes de membres", + "options": [ + { + "name": "lire", + "description": "Lis la note d'un membre", + "type": "SUB_COMMAND", + "options": [ + { + "name": "membre", + "type": "USER", + "description": "Membre dont vous voulez lire la note", + "required": true + } + ] + }, + { + "name": "écrire", + "description": "Écrit une note pour un membre", + "type": "SUB_COMMAND", + "options": [ + { + "name": "membre", + "description": "Membre que vous voulez noter", + "required": true, + "type": "USER" + }, + { + "name": "note", + "description": "Note à mettre sur le membre", + "required": true, + "type": "STRING" + } + ] + }, + { + "name": "supprimer", + "description": "Supprime la note d'un membre", + "type": "SUB_COMMAND", + "options": [ + { + "name": "membre", + "description": "Membre dont vous voulez supprimer la note", + "type": "USER", + "required": true + } + ] + } + ] + }, + { + "name": "nuke", + "description": "Nuke un salon", + "options": [ + { + "name": "salon", + "description": "Salon à nuker", + "type": "CHANNEL", + "required": true + } + ] + }, + { + "name": "prefixe", + "description": "Configure ou modifie le préfixe de votre serveur", + "options": [ + { + "name": "view", + "description": "Affiche le préfixe du serveur", + "type": "SUB_COMMAND" + }, + { + "name": "set", + "description": "Configure le préfixe du bot sur votre serveur", + "type": "SUB_COMMAND", + "options": [ + { + "name": "nouveau_prefixe", + "description": "Nouveau préfixe du bot", + "type": "STRING", + "required": true + } + ] + } + ] + }, + { + "name": "pseudo", + "description": "Gère le pseudo d'un membre", + "options": [ + { + "name": "définir", + "description": "Définit le pseudo d'un membre", + "type": "SUB_COMMAND", + "options": [ + { + "name": "pseudo", + "description": "Pseudo à donner au membre", + "required": true, + "type": "STRING" + }, + { + "name": "membre", + "description": "Membre à renommer", + "required": false, + "type": "USER" + } + ] + }, + { + "name": "réinitialiser", + "description": "Réinitialise le pseudo d'un membre", + "type": "SUB_COMMAND", + "options": [ + { + "name": "membre", + "required": false, + "description": "Membre à renommer", + "type": "USER" + } + ] + } + ] + }, + { + "name": "role-react", + "description": "Configure les rôles à réaction", + "options": [ + { + "name": "envoyer", + "description": "Envoie le message qui aura les réactions", + "type": "SUB_COMMAND", + "options": [ + { + "name": "embed", + "type": "BOOLEAN", + "required": true, + "description": "Définit si le message est un embed" + }, + { + "name": "contenu", + "type": "STRING", + "required": true, + "description": "Définit le contenu du message" + }, + { + "name": "salon", + "description": "Salon ou sera envoyé le message", + "required": true, + "type": "CHANNEL" + }, + { + "name": "titre", + "description": "Titre de l'embed (si embed)", + "required": false, + "type": "STRING" + }, + { + "name": "couleur", + "description": "Couleur de l'embed (si embed)", + "required": false, + "type": "STRING" + }, + { + "name": "image", + "description": "URL de l'image de l'embed (si embed)", + "type": "STRING", + "required": false + } + ] + }, + { + "name": "ajouter", + "description": "Ajoute un rôle", + "type": "SUB_COMMAND", + "options": [ + { + "name": "role", + "description": "Rôle à donner", + "type": "ROLE", + "required": true + }, + { + "name": "identifiant", + "description": "Identifiant du message (celui envoyé par la commande /role-react envoyer)", + "type": "STRING", + "required": true + }, + { + "name": "salon", + "description": "Salon du message", + "required": true, + "type": "CHANNEL" + }, + { + "name": "description", + "description": "Description du rôle à réaction", + "type": "STRING", + "required": true + } + ] + }, + { + "name": "supprime", + "description": "Supprime un rôle", + "type": "SUB_COMMAND", + "options": [ + { + "name": "role", + "description": "Rôle à enlever", + "type": "ROLE", + "required": true + }, + { + "name": "identifiant", + "description": "Identifiant du message (celui envoyé par la commande /role-react envoyer)", + "type": "STRING", + "required": true + }, + { + "name": "salon", + "description": "Salon du message", + "required": true, + "type": "CHANNEL" + } + ] + } + ] + }, + { + "name": "role", + "description": "Gère les rôles", + "options": [ + { + "name": "créer", + "description": "Créer un rôle", + "type": "SUB_COMMAND", + "options": [ + { + "name": "nom", + "description": "Nom du rôle", + "required": true, + "autocomplete": false, + "type": "STRING" + } + ] + }, + { + "name": "delete", + "description": "Supprime un rôle", + "type": "SUB_COMMAND", + "options": [ + { + "name": "role", + "required": true, + "autocomplete": false, + "type": "ROLE", + "description": "Le rôle à supprimer" + } + ] + }, + { + "name": "add", + "description": "Ajoute un rôle à un membre", + "type": "SUB_COMMAND", + "options": [ + { + "name": "utilisateur", + "description": "L'utilisateur qui aura le rôle.", + "required": true, + "autocomplete": false, + "type": "USER" + }, + { + "name": "role", + "description": "Le rôle à ajouter", + "required": true, + "autocomplete": false, + "type": "ROLE" + } + ] + }, + { + "name": "remove", + "description": "Retire un rôle à un membre", + "type": "SUB_COMMAND", + "options": [ + { + "name": "utilisateur", + "description": "Utilisateur qui perdra le rôle", + "required": true, + "autocomplete": false, + "type": "USER" + }, + { + "name": "role", + "description": "Le rôle à retirer", + "required": true, + "autocomplete": false, + "type": "ROLE" + } + ] + }, + { + "name": "renommer", + "description": "Renomme un rôle", + "type": "SUB_COMMAND", + "options": [ + { + "name": "rôle", + "description": "Rôle à renommer", + "required": true, + "type": "ROLE" + }, + { + "name": "nom", + "description": "Nom du rôle", + "required": true, + "type": "STRING" + } + ] + }, + { + "name": "déplacer", + "description": "Déplace un rôle", + "type": "SUB_COMMAND", + "options": [ + { + "name": "rôle", + "description": "Rôle à déplacer", + "required": true, + "type": "ROLE" + }, + { + "name": "places", + "description": "Nombre de places pour déplacer le rôle. Rentrez un nombre négatif ou un nombre positif.", + "required": true, + "type": "INTEGER" + } + ] + }, + { + "name": "coloriser", + "description": "Colorise un rôle", + "type": "SUB_COMMAND", + "options": [ + { + "name": "rôle", + "description": "Rôle à coloriser", + "type": "ROLE", + "required": true + }, + { + "name": "couleur", + "description": "Couleur à mettre sur le rôle. Donnez la en hexadecimal (ex: #ff0000)", + "type": "STRING", + "required": true + } + ] + }, + { + "name": "identifier", + "description": "Affiche l'identifiant d'un rôle", + "type": "SUB_COMMAND", + "options": [ + { + "name": "rôle", + "description": "Rôle à identifier", + "type": "ROLE", + "required": true + }, + { + "name": "embed", + "description": "Affiche la réponse sous forme d'embed (plus compliqué pour copier/coller)", + "required": false, + "type": "BOOLEAN" + } + ] + }, + { + "name": "permissions", + "description": "Gère les permissions d'un rôle", + "type": "SUB_COMMAND_GROUP", + "options": [ + { + "name": "accorder", + "description": "Accorde une permission à un rôle", + "type": "SUB_COMMAND", + "options": [ + { + "name": "rôle", + "description": "Rôle à gérer", + "type": "ROLE", + "required": true + }, + { + "name": "permission", + "description": "Permission à accorder", + "required": true, + "type": "STRING" + } + ] + }, + { + "name": "refuser", + "description": "Refuse une permission à un rôle", + "type": "SUB_COMMAND", + "options": [ + { + "name": "rôle", + "description": "Rôle à gérer", + "required": true, + "type": "ROLE" + }, + { + "name": "permission", + "description": "Permission à refuser", + "type": "STRING", + "required": true + } + ] + }, + { + "name": "liste", + "description": "Affiche la liste des permissions accordables", + "type": "SUB_COMMAND" + } + ] + } + ] + }, + { + "name": "snipe", + "description": "Affiche le dernier message supprimé dans le salon", + "options": [ + { + "name": "numéro", + "description": "Le numéro du snipe", + "required": false, + "autocomplete": false, + "type": "INTEGER" + } + ] + }, + { + "name": "ticket-create", + "description": "Crée un ticket" + }, + { + "name": "ticket", + "description": "Interagissez avec le système de tickets", + "options": [ + { + "name": "create", + "description": "Créer un ticket", + "type": "SUB_COMMAND_GROUP", + "options": [ + { + "name": "panel", + "description": "Créer un panel de ticket", + "type": "SUB_COMMAND", + "options": [ + { + "name": "sujet", + "description": "Sujet du panel de ticket", + "type": "STRING", + "required": true + }, + { + "name": "salon", + "description": "Salon du panel de ticket", + "required": true, + "type": "CHANNEL" + }, + { + "name": "description", + "description": "Description du ticket, son objectif.", + "required": true, + "type": "STRING" + }, + { + "name": "image", + "description": "Image affichée sur l'embe du ticket", + "required": false, + "type": "STRING" + } + ] + }, + { + "name": "ticket", + "description": "Créer un ticket", + "type": "SUB_COMMAND", + "options": [ + { + "name": "sujet", + "description": "Sujet du ticket", + "required": true, + "type": "STRING" + } + ] + } + ] + }, + { + "name": "rename", + "description": "Renomme le ticket", + "type": "SUB_COMMAND", + "options": [ + { + "name": "nom", + "description": "Nouveau nom du ticket", + "required": true, + "type": "STRING" + } + ] + }, + { + "name": "save", + "description": "Sauvegarde le ticket", + "type": "SUB_COMMAND" + }, + { + "name": "add", + "description": "Ajoute un utilisateur au ticket", + "type": "SUB_COMMAND", + "options": [ + { + "name": "utilisateur", + "description": "Utilisateur à ajouter au ticket", + "type": "USER", + "required": true + } + ] + }, + { + "name": "remove", + "description": "Retire un utilisateur du ticket", + "type": "SUB_COMMAND", + "options": [ + { + "name": "utilisateur", + "description": "Utilisateur à retirer du ticket", + "required": true, + "type": "USER" + } + ] + }, + { + "name": "close", + "description": "Ferme le ticket", + "type": "SUB_COMMAND" + }, + { + "name": "delete", + "description": "Supprime le ticket", + "type": "SUB_COMMAND" + }, + { + "name": "reopen", + "description": "Réouvre le ticket", + "type": "SUB_COMMAND" + }, + { + "name": "modrole", + "description": "Gère les rôles de modérateurs de tickets", + "type": "SUB_COMMAND_GROUP", + "options": [ + { + "name": "ajouter", + "type": "SUB_COMMAND", + "description": "Ajoute un rôle de modérateur de tickets", + "options": [ + { + "name": "rôle", + "type": "ROLE", + "description": "Rôle à ajouter", + "required": true + } + ] + }, + { + "name": "retirer", + "type": "SUB_COMMAND", + "description": "Retirer un rôle de modérateur de tickets", + "options": [ + { + "name": "rôle", + "type": "ROLE", + "description": "Rôle à retirer", + "required": true + } + ] + }, + { + "name": "liste", + "description": "Affiche la liste des rôles de modérateurs de tickets", + "type": "SUB_COMMAND" + } + ] + } + ] + }, + { + "name": "unwarn", + "description": "Enlève un avertissement à un utilisateur", + "options": [ + { + "name": "membre", + "type": "USER", + "description": "Membre qui aura un avertissement en moins", + "required": true + }, + { + "name": "identifiant", + "description": "Identifiant de l'avertissement (visible avec /logs afficher)", + "type": "INTEGER", + "required": true + } + ] + }, + { + "name": "warn", + "description": "Avertit un utilisateur", + "options": [ + { + "name": "utilisateur", + "description": "L'utilisateur en question", + "required": true, + "autocomplete": false, + "type": "USER" + }, + { + "name": "raison", + "description": "Raison de l'avertissement", + "required": true, + "autocomplete": false, + "type": "STRING" + } + ] + } + ], + [ + { + "name": "commande", + "description": "Affiche les informations concernant une commande", + "options": [ + { + "name": "commande", + "description": "Nom de la commande", + "required": true, + "autocomplete": false, + "type": "STRING" + }, + { + "name": "discret", + "description": "Fait en sorte que seul vous voit la réponse.", + "required": false, + "autocomplete": false, + "type": "BOOLEAN" + } + ] + }, + { + "name": "contact", + "description": "Prend contact avec mon développeur", + "options": [ + { + "name": "bug", + "description": "Le bug à signaler", + "type": "STRING", + "required": true, + "autocomplete": false + } + ] + }, + { + "name": "csc", + "description": "Gère les slash commandes personnalisées", + "options": [ + { + "name": "créer", + "description": "Créer une slash commande personnalisée", + "type": "SUB_COMMAND", + "options": [ + { + "name": "nom", + "description": "Nom de la commande", + "type": "STRING", + "required": true + }, + { + "name": "réponse", + "description": "Réponse de la commande", + "required": true, + "type": "STRING" + }, + { + "name": "embed", + "description": "Si la réponse doit être un embed", + "required": true, + "type": "BOOLEAN" + }, + { + "name": "titre", + "description": "Titre de l'embed", + "required": false, + "type": "STRING" + }, + { + "name": "couleur", + "description": "Couleur de l'embed (optionnel)", + "required": false, + "type": "STRING" + } + ] + }, + { + "name": "supprimer", + "description": "Supprimer une slash commande personnalisée", + "type": "SUB_COMMAND", + "options": [ + { + "name": "nom", + "description": "nom de la commande", + "required": true, + "type": "STRING" + } + ] + }, + { + "name": "liste", + "description": "Liste des slash commandes personnalisées du serveur", + "type": "SUB_COMMAND" + }, + { + "name": "variables", + "description": "Variables disponibles en réponse", + "type": "SUB_COMMAND" + } + ] + }, + { + "name": "avis", + "description": "Envoie votre avis sur le bot", + "options": [ + { + "name": "avis", + "description": "Votre avis", + "type": "STRING", + "required": true, + "autocomplete": false + } + ] + }, + { + "name": "help", + "description": "Affiche la page d'aide des commandes", + "options": [ + { + "name": "discret", + "description": "Fait en sorte que vous seul voyez ce message.", + "type": "BOOLEAN", + "required": false, + "autocomplete": false + } + ] + }, + { + "name": "invite", + "description": "Envoie le lien d'invitation du bot" + }, + { + "name": "rappel", + "description": "Gère vos rappels", + "options": [ + { + "name": "ajouter", + "description": "Ajoute un rappel", + "type": "SUB_COMMAND", + "options": [ + { + "name": "temps", + "description": "Le temps avant le rappel", + "type": "STRING", + "required": true + }, + { + "name": "contenu", + "description": "Contenu du rappel", + "required": true, + "type": "STRING" + } + ] + }, + { + "name": "retirer", + "description": "Retire un rappel", + "type": "SUB_COMMAND", + "options": [ + { + "name": "numéro", + "description": "Numéro du rappel à supprimer", + "type": "NUMBER", + "required": true + } + ] + }, + { + "name": "liste", + "type": "SUB_COMMAND", + "description": "Affiche la liste de vos rappels" + } + ] + }, + { + "name": "sondage", + "description": "Fait un sondage", + "options": [ + { + "name": "question", + "type": "STRING", + "required": true, + "description": "Question du sondage" + }, + { + "name": "proposition_1", + "type": "STRING", + "description": "Proposition 1 du sondage", + "required": true + }, + { + "name": "proposition_2", + "type": "STRING", + "description": "Proposition 2 du sondage", + "required": true + }, + { + "name": "proposition_3", + "type": "STRING", + "description": "Proposition 3 du sondage", + "required": false + }, + { + "name": "proposition_4", + "type": "STRING", + "description": "Proposition 4 du sondage", + "required": false + }, + { + "name": "proposition_5", + "type": "STRING", + "description": "Proposition 5 du sondage", + "required": false + }, + { + "name": "proposition_6", + "type": "STRING", + "description": "Proposition 6 du sondage", + "required": false + }, + { + "name": "proposition_7", + "type": "STRING", + "description": "Proposition 7 du sondage", + "required": false + }, + { + "name": "proposition_8", + "type": "STRING", + "description": "Proposition 8 du sondage", + "required": false + }, + { + "name": "proposition_9", + "type": "STRING", + "description": "Proposition 9 du sondage", + "required": false + }, + { + "name": "proposition_10", + "type": "STRING", + "description": "Proposition 10 du sondage", + "required": false + } + ] + }, + { + "name": "support", + "description": "Envoie le lien du serveur de support" + } + ] +] \ No newline at end of file diff --git a/commands/.devs/eval.js b/commands/.devs/eval.js index e51711c..3304c4a 100644 --- a/commands/.devs/eval.js +++ b/commands/.devs/eval.js @@ -1,4 +1,4 @@ -const { token, gs } = require('../../assets/data/data.json') +const { gs } = require('../../assets/data/data.json') const emojis = require('../../assets/data/emojis.json') const functions = require('../../assets/functions'); @@ -12,19 +12,17 @@ const ms = require('ms'); module.exports.run = async (message, args, client, prefix) => { if (message.author.id !== gs) return - if (args.join(" ").includes(token)) return message.channel.send({content: `${emojis.gsno} Pas d'argument avec token`}); const content = args.join(' '); const result = new Promise((resolve, reject) => resolve(eval(content))); return result.then((output) => { if (typeof output !== 'string') output = require('util').inspect(output, { depth: 0 }); if (output.includes(token)) output = output.replace(token, 'T0K3N'); - return message.channel.send({ content: `\`\`\`${output}\`\`\`` }); + return message.channel?.send({ content: `\`\`\`${output}\`\`\`` }); }).catch(err => { if (err) { err = err.toString(); - if (err.includes(token)) err = err.replace(token, '`T0K3N`'); - return message.channel.send({ content: `\`\`\`${err}\`\`\`` }) + return message.channel?.send({ content: `\`\`\`${err}\`\`\`` }) } }); } diff --git a/commands/.devs/exportdb.js b/commands/.devs/exportdb.js index e90ba3a..7c4ed79 100644 --- a/commands/.devs/exportdb.js +++ b/commands/.devs/exportdb.js @@ -42,12 +42,9 @@ module.exports = { return; }; let structure = `CREATE TABLE ${table} ( -${tableData.map((x) => ` ${x.Field} ${x.Type.toUpperCase()} ${x.Null == 'NO' ? 'NOT NULL':''} ${x.Default == null ? '': `DEFAULT ${x.Default == "current_timestamp()" ? "CURRENT_TIMESTAMP" : `"${x.Default.startsWith("'") ? x.Default.substring(1, x.Default.length - 1) : x.Default}"`}`}${x.Extra.includes('auto_increment') ? " AUTO_INCREMENT":''}`).join(',\n')} +${tableData.map((x) => ` ${x.Field} ${x.Type.toUpperCase()} ${x.Null == 'NO' ? 'NOT NULL':''} ${x.Default == null ? '': `DEFAULT ${x.Default == "current_timestamp()" ? "CURRENT_TIMESTAMP" : `"${x.Default.startsWith("'") ? x.Default.substring(1, x.Default.length - 1) : x.Default}"`}`}${x.Extra.includes('auto_increment') ? " AUTO_INCREMENT":''} ${x.Key == 'PRI' ? 'PRIMARY KEY' :''}`).join(',\n')} );`; - let primaryKey = tableData.find(x => x.Key && x.Key == 'PRI'); - if (primaryKey) structure+=`\n\nALTER TABLE ${table} ADD PRIMARY KEY ( ${primaryKey.Field} );`; - sql+=structure; sql+="\n\n"; diff --git a/commands/misc/levels.js b/commands/misc/levels.js index 1be524d..8a9cd20 100644 --- a/commands/misc/levels.js +++ b/commands/misc/levels.js @@ -19,7 +19,7 @@ module.exports.help = { * @param {String} prefix */ module.exports.run = (message, args, client, prefix) => { - client.db.query(`SELECT * FROM configs WHERE guild_id="${message.guild.id}"`, (err, req) => { + client.db.query(`SELECT level_enable FROM configs WHERE guild_id="${message.guild.id}"`, (err, req) => { if (err) { console.log(err); message.channel.send({ embeds: [ package.embeds.errorSQL(message.author) ] }); diff --git a/commands/moderation/nuke.js b/commands/moderation/nuke.js index 08bfddf..21bdd03 100644 --- a/commands/moderation/nuke.js +++ b/commands/moderation/nuke.js @@ -29,7 +29,7 @@ module.exports.run = (message, args, client, prefix) => { .setStyle('DANGER') .setEmoji("❌") ) - message.channel.send({content: "Êtes-vous sûr de vouloir nettoyer " + `${message.channel.name} ? Cette action est irréversible.`, components: [ row ]}).then(async(valideMSG) => { + interaction({content: "Êtes-vous sûr de vouloir nettoyer " + `${message.channel.name} ? Cette action est irréversible.`, components: [ row ]}).then(async(valideMSG) => { const filter = (interaction) => interaction.user.id === message.author.id; diff --git a/events/channelCreate.js b/events/channelCreate.js new file mode 100644 index 0000000..65fac55 --- /dev/null +++ b/events/channelCreate.js @@ -0,0 +1,45 @@ +const Discord = require('discord.js'); +const functions = require('../assets/functions'); +const package = functions.package(); + +module.exports = { + event: 'channelCreate', + /** + * @param {Discord.NonThreadGuildBasedChannel} channel + */ + execute: (channel) => { + if (!channel.guild) return; + + channel.guild.fetchAuditLogs({ type: 'CHANNEL_CREATE' }).then((entries) => { + let log = package.embeds.log(channel.guild) + .setTitle("Salon crée") + .setColor('#00ff00') + + if (entries.entries.first().target.id == channel.id) { + const mod = entries.entries.first().executor; + log.setDescription(`Un [salon](https://discord.com/channels/${channel.guild.id}/${channel.id}) a été crée`) + .addFields( + { + name: "Modérateur", + value: `<@${mod.id}> ( ${mod.tag} \`${mod.id}\` )`, + inline: true + }, + { + name: 'Salon', + value: `<#${channel.id}> ( ${package.channelTypes[channel.type]} \`${channel.id}\` )`, + inline: true + }, + { + name: "Date", + value: ` ( )`, + inline: true + } + ) + } else { + log.setDescription(`Le salon <#${channel.id}> ( ${package.channelTypes[channel.type]} \`${channel.id}\` ) a été crée`) + }; + + functions.log(channel.guild, log); + }); + } +} \ No newline at end of file diff --git a/events/channelDelete.js b/events/channelDelete.js index c56730c..57ac54b 100644 --- a/events/channelDelete.js +++ b/events/channelDelete.js @@ -23,5 +23,37 @@ module.exports = { channel.client.db.query(`UPDATE configs SET herobrine_channel="${chan.id}" WHERE guild_id="${channel.guild.id}"`, (e) => e?console.log:null); }); }); + + channel.guild.fetchAuditLogs({ type: 'CHANNEL_DELETE' }).then((entries) => { + let log = package.embeds.log(channel.guild) + .setTitle("Salon supprimé") + .setColor('#ff0000') + + if (entries.entries.first().target.id == channel.id) { + const mod = entries.entries.first().executor; + log.setDescription(`Un salon a été supprimé`) + .addFields( + { + name: "Modérateur", + value: `<@${mod.id}> ( ${mod.tag} \`${mod.id}\` )`, + inline: true + }, + { + name: 'Salon', + value: `${channel.name} ( ${package.channelTypes[channel.type]} \`${channel.id}\` )`, + inline: true + }, + { + name: "Date", + value: ` ( )`, + inline: true + } + ) + } else { + log.setDescription(`Le salon ${channel.name} ( ${package.channelTypes[channel.type]} \`${channel.id}\` ) a été supprimé`) + }; + + functions.log(channel.guild, log); + }); } }; \ No newline at end of file diff --git a/events/endSentence.js b/events/endSentence.js index 2e20af7..b545bce 100644 --- a/events/endSentence.js +++ b/events/endSentence.js @@ -24,18 +24,18 @@ module.exports = { }); if (ctn) { - functions.lineReply(message.id, message.channel, '-' + ctn, false); + functions.reply(message.id, message.channel, '-' + ctn, false); }; }); if (message.content.toLowerCase().includes('rick roll')) { - functions.lineReply(message.id, message.channel, ``, false); + functions.reply(message.id, message.channel, ``, false); }; if (message.content.toLowerCase().includes('coffin dance')) { - functions.lineReply(message.id, message.channel, "https://tenor.com/view/dancing-coffin-coffin-dance-funeral-funny-farewell-gif-16737844", false); + functions.reply(message.id, message.channel, "https://tenor.com/view/dancing-coffin-coffin-dance-funeral-funny-farewell-gif-16737844", false); }; if (message.content.toLowerCase().includes('webdriver torso')) { - functions.lineReply(message.id, message.channel, `https://tenor.com/view/webdriver-torso-ulysses-gif-21664517`, false); + functions.reply(message.id, message.channel, `https://tenor.com/view/webdriver-torso-ulysses-gif-21664517`, false); } } }; \ No newline at end of file diff --git a/events/guildBanAdd.js b/events/guildBanAdd.js index b7e0b8f..6b0a057 100644 --- a/events/guildBanAdd.js +++ b/events/guildBanAdd.js @@ -16,7 +16,7 @@ module.exports = { }).then((logs) => { const log = logs.entries.first(); - const embed = new Discord.MessageEmbed() + const embed = new Discord.EmbedBuilder() .setTimestamp() .setFooter({ text: guild.name, iconURL: guild.iconURL({ dynamic: true }) ? guild.iconURL({ dynamic: true }) : log.target.displayAvatarURL({ dynamic: true }) }) .setTitle("Bannissement") diff --git a/events/guildCreate.js b/events/guildCreate.js index 2783191..c82dcbb 100644 --- a/events/guildCreate.js +++ b/events/guildCreate.js @@ -17,6 +17,16 @@ module.exports = { if (!web) return; web.send({ content: `J'ai été ajouté sur ${guild.name} ( ${guild.memberCount.toLocaleString('fr')} membres ) ! Je suis maintenant sur \`${guild.client.guilds.cache.size}\` serveurs` }).catch(() => {}); - }) + }); + + guild.client.db.query(`SELECT guild_id FROM configs WHERE guild_id="${guild.id}"`, (e, r) => { + if (e) functions.sendError(e, 'guild create event query fetch', guild.client.user); + + if (r.length == 0) { + guild.client.db.query(`INSERT INTO configs (guild_id) VALUES ("${guild.id}")`, (er) => { + if (er) functions.sendError(err, 'query insert at guildCreate', guild.client.user); + }); + }; + }); } } \ No newline at end of file diff --git a/events/guildMemberAdd.js b/events/guildMemberAdd.js index 86b2fb6..04bb3c5 100644 --- a/events/guildMemberAdd.js +++ b/events/guildMemberAdd.js @@ -27,12 +27,27 @@ module.exports = { }; } - client.db.query(`SELECT join_enable, join_channel, join_message, gban_enable FROM configs WHERE guild_id="${guild.id}"`, (err, req) => { + const addRoles = () => { + client.db.query(`SELECT role_id FROM roles_start WHERE guild_id="${guild.id}"`, (err, req) => { + if (err) { + functions.sendError(err, 'query fetch at roles start', member.user); + return; + }; + (async() => {await guild.roles.fetch();})(); + const roles = guild.roles.cache.filter(x => x.id !== guild.id && req.some(x => x.role_id==x.id)); + if (roles.size == 0) return; + + member.roles.add(roles).catch(() => {}); + }); + }; + client.db.query(`SELECT join_enable, join_channel, join_message, gban_enable, roles_enable FROM configs WHERE guild_id="${guild.id}"`, (err, req) => { if (err) return console.log(err); const data = req[0]; if (!data) return check(true); + if (data.roles_enable == "1") addRoles(); + if (data.join_enable == "0") return; check(data.gban_enable == '1'); diff --git a/events/guildMemberUpdate.js b/events/guildMemberUpdate.js new file mode 100644 index 0000000..8502ce1 --- /dev/null +++ b/events/guildMemberUpdate.js @@ -0,0 +1,16 @@ +const Discord = require('discord.js'); +const functions = require('../assets/functions'); +const package = functions.package(); + +module.exports = { + event: 'guildMemberUpdate', + /** + * @param {Discord.GuildMember} before + * @param {Discord.GuildMember} after + */ + execute: (before, after) => { + if (before.roles.cache.size !== after.roles.cache.size) { + functions.stickyRoles.loadSpecific(before.guild, after); + }; + } +} \ No newline at end of file diff --git a/events/interactionCreate.js b/events/interactionCreate.js index d3c8541..b0c6c33 100644 --- a/events/interactionCreate.js +++ b/events/interactionCreate.js @@ -20,7 +20,6 @@ module.exports = { .setDescription(`Je n'ai pas trouvé cette commande parmi mes commandes.\nVeuillez patienter un peu.\n\n:bulb:\n> Si l'erreur persiste, contactez [mes développeurs](${require('../assets/data/data.json').support})`) .setColor('ORANGE') ], ephemeral: true });*/ - if (cmd.guild) { const file = require(`../private-slash-commands/${interaction.guild.id}-${interaction.commandName}.js`); @@ -84,6 +83,16 @@ module.exports = { return interaction.reply({ embeds: [ package.embeds.missingPermission(interaction.user, missing.map((x) => package.perms[x]).join(', ')) ] }).catch(() => {}); } }; + if (interaction.guild && cmd.help.category !== 'configuration') { + const category = cmd.help.category; + const manager = interaction.client.ModulesManager; + + if (!manager.checkModule({ module: category, guildId: interaction.guild.id })) return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Module désactivé") + .setDescription(`Vous ne pouvez pas utiliser cette commande, car le module **${require('../assets/data/modules.json').find(x => x.value == category).name}** est désactivé sur ${interaction.guild.name}.\n\nUtilisez \`/modules configurer module: ${require('../assets/data/modules.json').find(x => x.value == category).name} état: true\` pour l'activer`) + .setColor('#ff0000') + ] }).catch(() => {}); + } const runCmd = () => { const run = new Promise((resolve) => resolve(cmd.run(interaction))); run.catch((error) => { diff --git a/events/messageCreate.js b/events/messageCreate.js index b0e3178..14ce069 100644 --- a/events/messageCreate.js +++ b/events/messageCreate.js @@ -5,7 +5,7 @@ const package = functions.package(); module.exports = { event: 'messageCreate', /** - * @param {Discord.Message} message + * @param {Discord.Message} message */ execute: (message) => { const client = message.client; @@ -14,6 +14,7 @@ module.exports = { if (message.webhookId) return; client.db.query(`SELECT * FROM configs WHERE interchat_enable="1"`, (err, req) => { + return; if (err) return console.log(err); if (req.find((x) => x.guild_id === message.guild.id)) { @@ -72,13 +73,13 @@ module.exports = { if (message.author.bot) return; - client.db.query(`SELECT level_enable, level_message, level_channel, economy_enable FROM configs WHERE guild_id="${message.guild.id}"`, (err, req) => { + client.db.query(`SELECT level_message, level_channel FROM configs WHERE guild_id="${message.guild.id}"`, (err, req) => { if (err) return console.log(err); if (req.length === 0) return; const gdata = req[0]; - if (gdata.level_enable === 0) return; + if (!message.client.ModulesManager.checkModule({ module: 'levels', guildId: message.guild.id })) return; client.db.query(`SELECT * FROM levels WHERE guild_id="${message.guild.id}" AND user_id="${message.author.id}"`, (error, request) => { if (error) return console.log(error); @@ -107,7 +108,7 @@ module.exports = { replace(/{user.level}/g, data.level); channel.send({ content: text }).catch(() => {}); - if (gdata.economy_enable == "1") { + if (message.client.ModulesManager.checkModule({ module: 'economy', guildId: message.guild.id })) { message.client.CoinsManager.addCoins({ user_id: message.author.id, guild_id: message.guild.id }, parseInt(data.level) * 100); channel.send({ embeds: [ package.embeds.classic(message.author) .setTitle("Récompense de niveau") diff --git a/events/messageCreateMention.js b/events/messageCreateMention.js new file mode 100644 index 0000000..eb97382 --- /dev/null +++ b/events/messageCreateMention.js @@ -0,0 +1,94 @@ +const { ButtonBuilder, ButtonStyle, ActionRowBuilder } = require('discord.js'); +const functions = require('../assets/functions'); +const package = functions.package(); + +module.exports = { + event: 'messageCreate', + execute: (message) => { + if (message.author.bot) return; + if (message.mentions.users.has(message.client.user.id) && !message.mentions.everyone) { + let splashes = require('../assets/data/splash.json').filter(x => !x.includes('weird')); + + if (!functions.random(200, 0) === 132) { + const index = splashes.indexOf(x => x === 'This is an easter egg !'); + splashes.splice(index, 1); + }; + let size = require('../assets/data/splash.json').length; + + let splash = splashes[functions.random(splashes.length, 0)].replace('{username}', message.author.username) + .replace('{size}', size); + + const reponse = package.embeds.classic(message.author) + .setTitle(splash) + .setDescription(`Bonjour ! Je suis fait en slash commandes, alors mon préfixe est \`/\` (comme beaucoup d'autres bots !)\n\nFaites \`/help\` pour obtenir de l'aide.\n\n:bulb: <@${message.client.user.id}> est désormais disponible en slash commands !\n> Si vous ne voyez pas mes slash commands, réinvitez moi par le lien de la commande \`/invite\`.`) + .setColor(message.guild.me.displayHexColor) + .setAuthor({ name: message.guild ? message.guild.me.nickname ? message.guild.me.nickname :'Oracle' : "Oracle", iconURL: message.author.displayAvatarURL({ dynamic: true }) }) + + if (["Click on the link", "We finally published the source code !", "Don't click"].includes('splash')) { + reponse.setURL('https://www.youtube.com/watch?v=dQw4w9WgXcQ'); + }; + + let row = new ActionRowBuilder(); + let buttons = []; + if (functions.random(10, 0) == 5) { + let support = new ButtonBuilder() + .setLabel('Serveur de support') + .setStyle(ButtonStyle.Link) + .setURL(package.configs.support) + buttons.push(support); + }; + if (functions.random(10, 0) == 5) { + let invite = new ButtonBuilder() + .setLabel('Inviter Oracle') + .setStyle(ButtonStyle.Link) + .setURL(package.configs.link) + + if (buttons.length == 0) { + buttons.push(invite) + } else { + if (functions.random(100, 0) >= 50) { + buttons.push(invite); + } else { + buttons.unshift(invite); + }; + }; + }; + if (functions.random(10, 0) == 5 && buttons.length < 2) { + let topgg = new ButtonBuilder() + .setLabel('Page top.gg') + .setStyle(ButtonStyle.Link) + .setURL(package.configs.topgg) + + if (buttons.length == 0) { + buttons.push(topgg) + } else { + if (functions.random(100, 0) >= 50) { + buttons.push(topgg); + } else { + buttons.unshift(topgg); + }; + }; + } + row.addComponents(buttons); + functions.reply(message, reponse, row); + + if (message.guild) { + if (functions.random(10000, 0) === 794) { + message.guild.me.setNickname(`Oralce`); + }; + if ((message.guild.me.nickname === 'Dinnerbone' || message.guild.me.nickname === 'Grumm') && functions.random(10, 0) === 5) { + const reverse = (text) => { + let t =""; + for (let i =0;i a été supprimé`) + .addFields( + { + name: "Message", + value: `\`${message.id}\`. Envoyé ( ) par <@${message.author.id}> ( ${message.author.tag} \`${message.author.id}\` )`, + inline: true + }, + { + name: "Salon", + value: `<#${message.channel.id}> ( ${message.channel.name} \`${message.channel.id}\` )`, + inline: true + }, + { + name: "Contenu", + value: message.content ?? message.embeds[0]?.description ?? "Pas de contenu", + inline: false + } + ); + message.guild.fetchAuditLogs({ type: 'MESSAGE_DELETE' }).then((result) => { + if (result.entries.first()?.target.id == message.id) { + const mod = result.entries.first().executor; + if (mod) { + const content = log.fields.splice(2, 1, { + name: "Modérateur", + value: `<@${mod.id}> ( ${mod.tag} \`${mod.id}\` )`, + inline: true + }); + + log.addField(content); + }; + }; + + functions.log(message.guild, log); + }) } } \ No newline at end of file diff --git a/events/messageReactionAdd.js b/events/messageReactionAdd.js deleted file mode 100644 index 6ea8271..0000000 --- a/events/messageReactionAdd.js +++ /dev/null @@ -1,32 +0,0 @@ -const Discord = require('discord.js'); -const functions = require('../assets/functions.js'); -const package = functions.package(); - -module.exports = { - event: 'messageReactionAdd', - /** - * @param {Discord.MessageReaction} reaction - * @param {Discord.User} user - */ - execute: (reaction, user) => { - if (!reaction.message || !reaction.message.guild || user.bot) return; - - const client = reaction.client; - - const message = reaction.message; - const channel = message.channel; - const guild = message.guild; - - client.db.query(`SELECT * FROM rolesreact WHERE guild_id="${guild.id}" AND channel_id="${channel.id}" AND message_id="${message.id}" AND emoji="${reaction.emoji.identifier}"`, (err, req) => { - if (err) return console.log(err); - if (req.length === 0) return; - - const data = req[0]; - const role = guild.roles.cache.get(data.role_id); - if (!role) return; - - const member = guild.members.cache.get(user.id); - member.roles.add([ role ]).catch(() => console.log); - }); - } -}; \ No newline at end of file diff --git a/events/messageReactionRemove.js b/events/messageReactionRemove.js deleted file mode 100644 index efa2c9f..0000000 --- a/events/messageReactionRemove.js +++ /dev/null @@ -1,32 +0,0 @@ -const Discord = require('discord.js'); -const functions = require('../assets/functions.js'); -const package = functions.package(); - -module.exports = { - event: 'messageReactionRemove', - /** - * @param {Discord.MessageReaction} reaction - * @param {Discord.User} user - */ - execute: (reaction, user) => { - if (!reaction.message || !reaction.message.guild || user.bot) return; - - const client = reaction.client; - - const message = reaction.message; - const channel = message.channel; - const guild = message.guild; - - client.db.query(`SELECT * FROM rolesreact WHERE guild_id="${guild.id}" AND channel_id="${channel.id}" AND message_id="${message.id}" AND emoji="${reaction.emoji.identifier}"`, (err, req) => { - if (err) return console.log(err); - if (req.length === 0) return; - - const data = req[0]; - const role = guild.roles.cache.get(data.role_id); - if (!role) return; - - const member = guild.members.cache.get(user.id); - member.roles.remove([ role ]).catch(() => console.log); - }); - } -}; \ No newline at end of file diff --git a/events/messageUpdate.js b/events/messageUpdate.js index eb43bf4..c679702 100644 --- a/events/messageUpdate.js +++ b/events/messageUpdate.js @@ -24,7 +24,7 @@ module.exports = { }, { name: "Après", - value: b.content || '\u200b', + value: a.content || '\u200b', inline: false } ) @@ -32,6 +32,6 @@ module.exports = { functions.log(a.guild, embed); }; - run(a); + // run(a); } }; \ No newline at end of file diff --git a/events/ready.js b/events/ready.js index e1fa522..7950d6f 100644 --- a/events/ready.js +++ b/events/ready.js @@ -1,8 +1,8 @@ -const { Client, MessageEmbed, Interaction } = require('discord.js'); +const { Client, EmbedBuilder, Interaction } = require('discord.js'); const { connect, beta, connectYeikzy, default_prefix } = require('../assets/data/data.json'); const commands = require('../assets/data/slashCommands'); const fs = require('fs'); -const { privateSlashCommandsBuilder, capitalize } = require('../assets/functions'); +const { privateSlashCommandsBuilder, capitalize, stickyRoles } = require('../assets/functions'); const cooldowns = require('../assets/data/collects').specificCooldowns; module.exports = { @@ -19,6 +19,8 @@ module.exports = { fs.readdirSync('./slash-commands').forEach((dir) => { fs.readdirSync(`./slash-commands/${dir}`).filter((x) => x.endsWith('.js')).forEach((fileName) => { const file = require(`../slash-commands/${dir}/${fileName}`); + + if (commands.has(file.configs.name)) throw `command ${file.configs.name} already exists`; if (file.guild) { client.application.commands.create(file.configs, file.guild).catch((e) => console.log(e)); @@ -35,19 +37,19 @@ module.exports = { }) }; const loadSpecificsCooldowns = () => { - client.db.query(`SELECT * FROM cooldowns WHERE date >= "${Date.now()}"`, (err, req) => { + client.db.query(`SELECT * FROM cooldowns WHERE date > "${Date.now()}"`, (err, req) => { if (err) throw err; for (const cd of req) { const dataset = cd; - dataset.command = `/${dataset.command}`; + dataset.command = `${dataset.command}`; cooldowns.set(`${dataset.user_id}.${dataset.command}`, dataset); } }) }; const managerBuilder = () => { - fs.readdirSync('./assets/managers').forEach((managerFileName) => { + fs.readdirSync('./assets/managers').filter(x => x.endsWith('.js')).forEach((managerFileName) => { const file = require(`../assets/managers/${managerFileName}`); const managerName = capitalize(managerFileName.split('.')[0]); @@ -61,6 +63,7 @@ module.exports = { slashCommandsBuilder(); managerBuilder(); loadSpecificsCooldowns(); + stickyRoles.load(client) const dbl = require('dblapi.js'); client.dbl = new dbl(require('../assets/data/data.json').token, { @@ -82,7 +85,7 @@ module.exports = { client.fetchWebhook(connect.id, connect.token).then((web) => { if (!web) return; - const embed = new MessageEmbed() + const embed = new EmbedBuilder() .setTitle("Reconnexion") .setDescription(`Je viens de me reconnecter`) .setColor("ORANGE") @@ -93,7 +96,7 @@ module.exports = { client.fetchWebhook(connectYeikzy.id, connectYeikzy.token).then((web) => { if (!web) return; - const embed = new MessageEmbed() + const embed = new EmbedBuilder() .setTitle("Reconnexion") .setDescription(`Je viens de me reconnecter`) .setColor("ORANGE") @@ -106,9 +109,13 @@ module.exports = { let statusIndex = 0; let status = [ {name: 'la version ' + require('../assets/data/data.json').version, type: 'WATCHING'}, - {name: `%users% utilisateurs`, type: 'WATCHING'}, + {name: `%users% utilisateurs`, type: 'LISTENING'}, {name: `%servers% serveurs`, type: 'WATCHING'}, - {name: `Le préfixe ${default_prefix}`, type: 'WATCHING'} + {name: "Passage en slash commandes !", type: 'WATCHING'}, + {name: "Mentionnez moi pour des informations", type: 'WATCHING'}, + {name: "%members% membres", type: 'WATCHING'}, + {name: 'une vidéo', type: 'STREAMING', url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'}, + {name: "ma page top.gg", type: 'WATCHING'} ]; setInterval(() => { @@ -124,6 +131,13 @@ module.exports = { statut.name = statut.name .replace('%users%', client.users.cache.size) .replace('%servers%', client.guilds.cache.size); + + if (statut.name.includes('%members%')) { + (async() => {await client.guilds.fetch()}); + let members = client.guilds.cache.map(x => x.memberCount).reduce((a, b) => a + b); + + statut.name = statut.name.replace('%members%', members); + }; client.user.setActivity(statut); }, 20000); diff --git a/index.js b/index.js index 37dd48d..7b9cbbb 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,10 @@ const Discord = require('discord.js'); const fs = require('fs'); -const { Intents } = require('discord.js'); - +const { IntentsBitField } = require('discord.js'); const client = new Discord.Client({ partials: ['MESSAGE', 'CHANNEL', 'REACTION', 'USER'], - intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES,Intents.FLAGS.GUILD_MESSAGE_REACTIONS, Intents.FLAGS.DIRECT_MESSAGES, Intents.FLAGS.GUILD_MEMBERS, Intents.FLAGS.GUILDS, Intents.FLAGS.DIRECT_MESSAGE_REACTIONS] + intents: [ IntentsBitField.Flags.Guilds, IntentsBitField.Flags.GuildMessages,IntentsBitField.Flags.GuildMessageReactions, IntentsBitField.Flags.DirectMessages, IntentsBitField.Flags.GuildMembers, IntentsBitField.Flags.DirectMessageReactions, IntentsBitField.Flags.GuildBans, IntentsBitField.Flags.GuildVoiceStates ] }); const configs = require('./assets/data/data.json'); @@ -22,7 +21,8 @@ fs.readdirSync('./events').filter(x => x.endsWith('.js')).forEach((fileName) => module.exports.client = client; var obj = {}; -fs.readdirSync('./commands').forEach((dirName) => { + +fs.readdirSync('./commands').filter(x => x.startsWith('.')).forEach((dirName) => { obj[dirName] = []; fs.readdirSync(`./commands/${dirName}`).filter((x) => x.endsWith('.js')).forEach((fileName) => { let commandFile = require(`./commands/${dirName}/${fileName}`); @@ -36,5 +36,7 @@ fs.readdirSync('./commands').forEach((dirName) => { fs.writeFileSync(`./assets/data/commands.json`, JSON.stringify(obj, '', 1)); -let token = configs.beta === true ? configs.beta_token : configs.token; +const tokens = require('./assets/data/tokens.json'); + +let token = configs.beta === true ? tokens.beta_token : tokens.token; client.login(token); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7c60cd5..30c25c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,33 +10,37 @@ "license": "ISC", "dependencies": { "@discordjs/rest": "^0.3.0", + "axios": "^0.27.2", "blagues-api": "^2.1.0", "dblapi.js": "^2.4.1", "discord-api-types": "^0.26.1", - "discord.js": "^13.6.0", + "discord.js": "^14.3.0", "fs": "^0.0.1-security", "moment": "^2.29.1", "ms": "^2.1.3", - "mysql": "^2.18.1", - "twemoji": "^14.0.2" + "mysql": "^2.18.1" } }, "node_modules/@discordjs/builders": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.11.0.tgz", - "integrity": "sha512-ZTB8yJdJKrKlq44dpWkNUrAtEJEq0gqpb7ASdv4vmq6/mZal5kOv312hQ56I/vxwMre+VIkoHquNUAfnTbiYtg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.2.0.tgz", + "integrity": "sha512-ARy4BUTMU+S0ZI6605NDqfWO+qZqV2d/xfY32z3hVSsd9IaAKJBZ1ILTZLy87oIjW8+gUpQmk9Kt0ZP9bmmd8Q==", "dependencies": { - "@sindresorhus/is": "^4.2.0", - "discord-api-types": "^0.26.0", - "ts-mixer": "^6.0.0", - "tslib": "^2.3.1", - "zod": "^3.11.6" + "@sapphire/shapeshift": "^3.5.1", + "discord-api-types": "^0.37.3", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.1", + "tslib": "^2.4.0" }, "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" + "node": ">=16.9.0" } }, + "node_modules/@discordjs/builders/node_modules/discord-api-types": { + "version": "0.37.4", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.4.tgz", + "integrity": "sha512-QgqYlUokWM++hdwvAtgVNLjmFumPBzFy+uWnnfVDiwBXKm+5jXHJPk2lx2eilkv/706UpAJPLSk/uVCY9NocjA==" + }, "node_modules/@discordjs/collection": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.4.0.tgz", @@ -64,65 +68,50 @@ } }, "node_modules/@sapphire/async-queue": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.2.0.tgz", - "integrity": "sha512-O5ND5Ljpef86X5oy8zXorQ754TMjWALcPSAgPBu4+76HLtDTrNoDyzU2uGE2G4A8Wv51u0MXHzGQ0WZ4GMtpIw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", + "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" } }, - "node_modules/@sapphire/snowflake": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.1.0.tgz", - "integrity": "sha512-K+OiqXSx4clIaXcoaghrCV56zsm3bZZ5SBpgJkgvAKegFFdETMntHviUfypjt8xVleIuDaNyQA4APOIl3BMcxg==", + "node_modules/@sapphire/shapeshift": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.5.1.tgz", + "integrity": "sha512-7JFsW5IglyOIUQI1eE0g6h06D/Far6HqpcowRScgCiLSqTf3hhkPWCWotVTtVycnDCMYIwPeaw6IEPBomKC8pA==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash.uniqwith": "^4.5.0" + }, "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" } }, - "node_modules/@sindresorhus/is": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.5.0.tgz", - "integrity": "sha512-ZzlL5VTnHZJl8wMWEaYk/13hwMNKLylTSPZRz8+0HIwfRTQMnFgUahDNRRV+rTmPADxQZYxna/nQcStNSCccKg==", + "node_modules/@sapphire/snowflake": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.2.2.tgz", + "integrity": "sha512-ula2O0kpSZtX9rKXNeQMrHwNd7E4jPDJYUXmEGTFdMRfyfMw+FPyh04oKMjAiDuOi64bYgVkOV3MjK+loImFhQ==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" + "node": ">=v14.0.0", + "npm": ">=7.0.0" } }, - "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" - }, - "node_modules/@types/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", - "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" - } + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, - "node_modules/@types/node-fetch/node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } + "node_modules/@types/node": { + "version": "18.7.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.9.tgz", + "integrity": "sha512-0N5Y1XAdcl865nDdjbO0m3T6FdmQ4ijE89/urOHLREyTXbpMWbSafx9y7XIsgWGtwUP2iYTinLyyW3FatAxBLQ==" }, "node_modules/@types/ws": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.1.tgz", - "integrity": "sha512-UxlLOfkuQnT2YSBCNq0x86SGOUxas6gAySFeDe2DcnEnA8655UIPoCDorWZCugcvKIL8IUI4oueUfJ1hhZSE2A==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", "dependencies": { "@types/node": "*" } @@ -132,6 +121,15 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, "node_modules/bignumber.js": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", @@ -196,23 +194,94 @@ } }, "node_modules/discord.js": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.6.0.tgz", - "integrity": "sha512-tXNR8zgsEPxPBvGk3AQjJ9ljIIC6/LOPjzKwpwz8Y1Q2X66Vi3ZqFgRHYwnHKC0jC0F+l4LzxlhmOJsBZDNg9g==", + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.3.0.tgz", + "integrity": "sha512-CpIwoAAuELiHSgVKRMzsCADS6ZlJwAZ9RlvcJYdEgS00aW36dSvXyBgE+S3pigkc7G+jU6BEalMUWIJFveqrBQ==", "dependencies": { - "@discordjs/builders": "^0.11.0", - "@discordjs/collection": "^0.4.0", - "@sapphire/async-queue": "^1.1.9", - "@types/node-fetch": "^2.5.12", - "@types/ws": "^8.2.2", - "discord-api-types": "^0.26.0", - "form-data": "^4.0.0", - "node-fetch": "^2.6.1", - "ws": "^8.4.0" + "@discordjs/builders": "^1.2.0", + "@discordjs/collection": "^1.1.0", + "@discordjs/rest": "^1.1.0", + "@sapphire/snowflake": "^3.2.2", + "@types/ws": "^8.5.3", + "discord-api-types": "^0.37.3", + "fast-deep-equal": "^3.1.3", + "lodash.snakecase": "^4.1.1", + "tslib": "^2.4.0", + "undici": "^5.9.1", + "ws": "^8.8.1" }, "engines": { - "node": ">=16.6.0", - "npm": ">=7.0.0" + "node": ">=16.9.0" + } + }, + "node_modules/discord.js/node_modules/@discordjs/collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.1.0.tgz", + "integrity": "sha512-PQ2Bv6pnT7aGPCKWbvvNRww5tYCGpggIQVgpuF9TdDPeR6n6vQYxezXiLVOS9z2B62Dp4c+qepQ15SgJbLYtCQ==", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/discord.js/node_modules/@discordjs/rest": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.1.0.tgz", + "integrity": "sha512-yCrthRTQeUyNThQEpCk7bvQJlwQmz6kU0tf3dcWBv2WX3Bncl41x7Wc+v5b5OsIxfNYq38PvVtWircu9jtYZug==", + "dependencies": { + "@discordjs/collection": "^1.0.1", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.2.2", + "discord-api-types": "^0.37.3", + "file-type": "^17.1.6", + "tslib": "^2.4.0", + "undici": "^5.9.1" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/discord.js/node_modules/discord-api-types": { + "version": "0.37.4", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.4.tgz", + "integrity": "sha512-QgqYlUokWM++hdwvAtgVNLjmFumPBzFy+uWnnfVDiwBXKm+5jXHJPk2lx2eilkv/706UpAJPLSk/uVCY9NocjA==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/file-type": { + "version": "17.1.6", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", + "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", + "dependencies": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0-alpha.9", + "token-types": "^5.0.0-alpha.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, "node_modules/form-data": { @@ -233,31 +302,24 @@ "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs-extra/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/inherits": { "version": "2.0.4", @@ -269,16 +331,15 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, - "node_modules/jsonfile": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-5.0.0.tgz", - "integrity": "sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==", - "dependencies": { - "universalify": "^0.1.2" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, + "node_modules/lodash.uniqwith": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", + "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==" }, "node_modules/mime-db": { "version": "1.51.0", @@ -345,6 +406,18 @@ } } }, + "node_modules/peek-readable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -364,6 +437,34 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readable-web-to-node-stream/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -385,43 +486,59 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, "node_modules/ts-mixer": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", - "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz", + "integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg==" }, "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "node_modules/twemoji": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/twemoji/-/twemoji-14.0.2.tgz", - "integrity": "sha512-BzOoXIe1QVdmsUmZ54xbEH+8AgtOKUiG53zO5vVP2iUu6h5u9lN15NcuS6te4OY96qx0H7JK9vjjl9WQbkTRuA==", - "dependencies": { - "fs-extra": "^8.0.1", - "jsonfile": "^5.0.0", - "twemoji-parser": "14.0.0", - "universalify": "^0.1.2" - } - }, - "node_modules/twemoji-parser": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/twemoji-parser/-/twemoji-parser-14.0.0.tgz", - "integrity": "sha512-9DUOTGLOWs0pFWnh1p6NF+C3CkQ96PWmEFwhOVmT3WbecRC+68AIqpsnJXygfkFcp4aXbOp8Dwbhh/HQgvoRxA==" - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/undici": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.9.1.tgz", + "integrity": "sha512-6fB3a+SNnWEm4CJbgo0/CWR8RGcOCQP68SF4X0mxtYTq2VNN8T88NYrWVBAeSX+zb7bny2dx2iYhP3XHi00omg==", "engines": { - "node": ">= 4.0.0" + "node": ">=12.18" } }, "node_modules/util-deprecate": { @@ -444,9 +561,9 @@ } }, "node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", + "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", "engines": { "node": ">=10.0.0" }, @@ -462,27 +579,26 @@ "optional": true } } - }, - "node_modules/zod": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.12.0.tgz", - "integrity": "sha512-w+mmntgEL4hDDL5NLFdN6Fq2DSzxfmlSoJqiYE1/CApO8EkOCxvJvRYEVf8Vr/lRs3i6gqoiyFM6KRcWqqdBzQ==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } } }, "dependencies": { "@discordjs/builders": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.11.0.tgz", - "integrity": "sha512-ZTB8yJdJKrKlq44dpWkNUrAtEJEq0gqpb7ASdv4vmq6/mZal5kOv312hQ56I/vxwMre+VIkoHquNUAfnTbiYtg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.2.0.tgz", + "integrity": "sha512-ARy4BUTMU+S0ZI6605NDqfWO+qZqV2d/xfY32z3hVSsd9IaAKJBZ1ILTZLy87oIjW8+gUpQmk9Kt0ZP9bmmd8Q==", "requires": { - "@sindresorhus/is": "^4.2.0", - "discord-api-types": "^0.26.0", - "ts-mixer": "^6.0.0", - "tslib": "^2.3.1", - "zod": "^3.11.6" + "@sapphire/shapeshift": "^3.5.1", + "discord-api-types": "^0.37.3", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.1", + "tslib": "^2.4.0" + }, + "dependencies": { + "discord-api-types": { + "version": "0.37.4", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.4.tgz", + "integrity": "sha512-QgqYlUokWM++hdwvAtgVNLjmFumPBzFy+uWnnfVDiwBXKm+5jXHJPk2lx2eilkv/706UpAJPLSk/uVCY9NocjA==" + } } }, "@discordjs/collection": { @@ -505,50 +621,38 @@ } }, "@sapphire/async-queue": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.2.0.tgz", - "integrity": "sha512-O5ND5Ljpef86X5oy8zXorQ754TMjWALcPSAgPBu4+76HLtDTrNoDyzU2uGE2G4A8Wv51u0MXHzGQ0WZ4GMtpIw==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", + "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==" + }, + "@sapphire/shapeshift": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.5.1.tgz", + "integrity": "sha512-7JFsW5IglyOIUQI1eE0g6h06D/Far6HqpcowRScgCiLSqTf3hhkPWCWotVTtVycnDCMYIwPeaw6IEPBomKC8pA==", + "requires": { + "fast-deep-equal": "^3.1.3", + "lodash.uniqwith": "^4.5.0" + } }, "@sapphire/snowflake": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.1.0.tgz", - "integrity": "sha512-K+OiqXSx4clIaXcoaghrCV56zsm3bZZ5SBpgJkgvAKegFFdETMntHviUfypjt8xVleIuDaNyQA4APOIl3BMcxg==" + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.2.2.tgz", + "integrity": "sha512-ula2O0kpSZtX9rKXNeQMrHwNd7E4jPDJYUXmEGTFdMRfyfMw+FPyh04oKMjAiDuOi64bYgVkOV3MjK+loImFhQ==" }, - "@sindresorhus/is": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.5.0.tgz", - "integrity": "sha512-ZzlL5VTnHZJl8wMWEaYk/13hwMNKLylTSPZRz8+0HIwfRTQMnFgUahDNRRV+rTmPADxQZYxna/nQcStNSCccKg==" + "@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, "@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" - }, - "@types/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - }, - "dependencies": { - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } + "version": "18.7.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.9.tgz", + "integrity": "sha512-0N5Y1XAdcl865nDdjbO0m3T6FdmQ4ijE89/urOHLREyTXbpMWbSafx9y7XIsgWGtwUP2iYTinLyyW3FatAxBLQ==" }, "@types/ws": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.1.tgz", - "integrity": "sha512-UxlLOfkuQnT2YSBCNq0x86SGOUxas6gAySFeDe2DcnEnA8655UIPoCDorWZCugcvKIL8IUI4oueUfJ1hhZSE2A==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", "requires": { "@types/node": "*" } @@ -558,6 +662,15 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "requires": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, "bignumber.js": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", @@ -608,21 +721,69 @@ "integrity": "sha512-T5PdMQ+Y1MEECYMV5wmyi9VEYPagEDEi4S0amgsszpWY0VB9JJ/hEvM6BgLhbdnKky4gfmZEXtEEtojN8ZKJQQ==" }, "discord.js": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.6.0.tgz", - "integrity": "sha512-tXNR8zgsEPxPBvGk3AQjJ9ljIIC6/LOPjzKwpwz8Y1Q2X66Vi3ZqFgRHYwnHKC0jC0F+l4LzxlhmOJsBZDNg9g==", + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.3.0.tgz", + "integrity": "sha512-CpIwoAAuELiHSgVKRMzsCADS6ZlJwAZ9RlvcJYdEgS00aW36dSvXyBgE+S3pigkc7G+jU6BEalMUWIJFveqrBQ==", "requires": { - "@discordjs/builders": "^0.11.0", - "@discordjs/collection": "^0.4.0", - "@sapphire/async-queue": "^1.1.9", - "@types/node-fetch": "^2.5.12", - "@types/ws": "^8.2.2", - "discord-api-types": "^0.26.0", - "form-data": "^4.0.0", - "node-fetch": "^2.6.1", - "ws": "^8.4.0" + "@discordjs/builders": "^1.2.0", + "@discordjs/collection": "^1.1.0", + "@discordjs/rest": "^1.1.0", + "@sapphire/snowflake": "^3.2.2", + "@types/ws": "^8.5.3", + "discord-api-types": "^0.37.3", + "fast-deep-equal": "^3.1.3", + "lodash.snakecase": "^4.1.1", + "tslib": "^2.4.0", + "undici": "^5.9.1", + "ws": "^8.8.1" + }, + "dependencies": { + "@discordjs/collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.1.0.tgz", + "integrity": "sha512-PQ2Bv6pnT7aGPCKWbvvNRww5tYCGpggIQVgpuF9TdDPeR6n6vQYxezXiLVOS9z2B62Dp4c+qepQ15SgJbLYtCQ==" + }, + "@discordjs/rest": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.1.0.tgz", + "integrity": "sha512-yCrthRTQeUyNThQEpCk7bvQJlwQmz6kU0tf3dcWBv2WX3Bncl41x7Wc+v5b5OsIxfNYq38PvVtWircu9jtYZug==", + "requires": { + "@discordjs/collection": "^1.0.1", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.2.2", + "discord-api-types": "^0.37.3", + "file-type": "^17.1.6", + "tslib": "^2.4.0", + "undici": "^5.9.1" + } + }, + "discord-api-types": { + "version": "0.37.4", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.4.tgz", + "integrity": "sha512-QgqYlUokWM++hdwvAtgVNLjmFumPBzFy+uWnnfVDiwBXKm+5jXHJPk2lx2eilkv/706UpAJPLSk/uVCY9NocjA==" + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "file-type": { + "version": "17.1.6", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", + "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", + "requires": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0-alpha.9", + "token-types": "^5.0.0-alpha.2" } }, + "follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" + }, "form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -638,30 +799,10 @@ "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "dependencies": { - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "requires": { - "graceful-fs": "^4.1.6" - } - } - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "inherits": { "version": "2.0.4", @@ -673,14 +814,15 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, - "jsonfile": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-5.0.0.tgz", - "integrity": "sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^0.1.2" - } + "lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, + "lodash.uniqwith": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", + "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==" }, "mime-db": { "version": "1.51.0", @@ -724,6 +866,11 @@ "whatwg-url": "^5.0.0" } }, + "peek-readable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==" + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -743,6 +890,26 @@ "util-deprecate": "~1.0.1" } }, + "readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "requires": { + "readable-stream": "^3.6.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -761,41 +928,43 @@ "safe-buffer": "~5.1.0" } }, + "strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "requires": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + } + }, + "token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "requires": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + } + }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, "ts-mixer": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", - "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz", + "integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg==" }, "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "twemoji": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/twemoji/-/twemoji-14.0.2.tgz", - "integrity": "sha512-BzOoXIe1QVdmsUmZ54xbEH+8AgtOKUiG53zO5vVP2iUu6h5u9lN15NcuS6te4OY96qx0H7JK9vjjl9WQbkTRuA==", - "requires": { - "fs-extra": "^8.0.1", - "jsonfile": "^5.0.0", - "twemoji-parser": "14.0.0", - "universalify": "^0.1.2" - } - }, - "twemoji-parser": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/twemoji-parser/-/twemoji-parser-14.0.0.tgz", - "integrity": "sha512-9DUOTGLOWs0pFWnh1p6NF+C3CkQ96PWmEFwhOVmT3WbecRC+68AIqpsnJXygfkFcp4aXbOp8Dwbhh/HQgvoRxA==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + "undici": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.9.1.tgz", + "integrity": "sha512-6fB3a+SNnWEm4CJbgo0/CWR8RGcOCQP68SF4X0mxtYTq2VNN8T88NYrWVBAeSX+zb7bny2dx2iYhP3XHi00omg==" }, "util-deprecate": { "version": "1.0.2", @@ -817,15 +986,10 @@ } }, "ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", + "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", "requires": {} - }, - "zod": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.12.0.tgz", - "integrity": "sha512-w+mmntgEL4hDDL5NLFdN6Fq2DSzxfmlSoJqiYE1/CApO8EkOCxvJvRYEVf8Vr/lRs3i6gqoiyFM6KRcWqqdBzQ==" } } } diff --git a/package.json b/package.json index ca4ddb7..1ed8e22 100644 --- a/package.json +++ b/package.json @@ -10,14 +10,14 @@ "license": "ISC", "dependencies": { "@discordjs/rest": "^0.3.0", + "axios": "^0.27.2", "blagues-api": "^2.1.0", "dblapi.js": "^2.4.1", "discord-api-types": "^0.26.1", - "discord.js": "^13.6.0", + "discord.js": "^14.3.0", "fs": "^0.0.1-security", "moment": "^2.29.1", "ms": "^2.1.3", - "mysql": "^2.18.1", - "twemoji": "^14.0.2" + "mysql": "^2.18.1" } } diff --git a/slash-commands/moderation/configs.js b/slash-commands/configuration/configs.js similarity index 80% rename from slash-commands/moderation/configs.js rename to slash-commands/configuration/configs.js index e54aec7..8e8ad65 100644 --- a/slash-commands/moderation/configs.js +++ b/slash-commands/configuration/configs.js @@ -33,7 +33,7 @@ module.exports = { choices: configs.data.map((conf) => ({name: conf.name, value: conf.param})) }, { - name: "binaire", + name: "état", description: "État binaire du paramètre (si binaire)", required: false, type: 'BOOLEAN' @@ -60,7 +60,7 @@ module.exports = { run: (interaction) => { const subcommand = interaction.options.getSubcommand(); let types = { - boolean: 'binaire', + boolean: 'état', text: 'texte', channel: 'salon' }; @@ -72,10 +72,33 @@ module.exports = { channel: 'salon' }; + let exemples = []; + for (const type of ['boolean', 'text', 'channel']) { + let selectedTypes = configs.data.filter(x => x.type == type); + let selected = selectedTypes[functions.random(selectedTypes.length, 0)]; + + if (functions.random(100, 0) >= 50) { + exemples.push(selected); + } else { + exemples.unshift(selected); + }; + }; + for (const exemple of exemples) { + let index = exemples.indexOf(exemple); + let data = { + name: docTypes[exemple.type], + value: `\`/config configurer paramètre: ${exemple.name} ${exemple.type == 'boolean' ? `binaire: ${functions.random(100, 0) >= 50 ? 'true':'false'}` : exemple.type == 'text' ? 'texte: Lorem ipsum' : `salon: #${interaction.guild.channels.cache.filter(x => ['GUILD_TEXT', 'GUILD_VOICE', 'GUILD_NEWS'].includes(x.type)).random()?.name ?? interaction.channel.name}`}\``, + inline: false + }; + + exemples[index] = data; + }; + const embed = package.embeds.classic(interaction.user) .setTitle("Paramètres") .setDescription(`Voici la liste des paramètres configurables :\n${configs.data.map((conf) => `\`${conf.name}\` : ${conf.description} (type: [${types[conf.type]}](https://github.com/BotOracle/Documentation/blob/main/others/${docTypes[conf.type]}.md))`).join('\n')}`) .setColor('ORANGE') + .addFields(exemples) interaction.reply({ embeds: [ embed ] }).catch(() => {}); }; diff --git a/slash-commands/configuration/modules.js b/slash-commands/configuration/modules.js new file mode 100644 index 0000000..aae76d9 --- /dev/null +++ b/slash-commands/configuration/modules.js @@ -0,0 +1,97 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); +const modules = require('../../assets/data/modules.json'); + +module.exports = { + help: { + cd: 5, + dev: false, + dm: false, + permissions: ['manage_guild'], + systems: [] + }, + configs: { + name: 'modules', + description: "Gère les modules", + options: [ + { + name: 'configurer', + description: "Configure un module", + type: 'SUB_COMMAND', + options: [ + { + name: "module", + description: "Module à configurer", + type: 'STRING', + required: true, + choices: modules.map(x => ({ name: x.name, value:x.value })) + }, + { + name: "état", + description: "État du module", + type: 'BOOLEAN', + required: true + } + ] + }, + { + name: "afficher", + description: "Affiche l'état des modules sur le serveur", + type: 'SUB_COMMAND' + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: (interaction) => { + const subcommand = interaction.options.getSubcommand(); + + if (subcommand == 'configurer') { + let moduleSelectioned = interaction.options.getString('module'); + let state = interaction.options.getBoolean('état'); + + interaction.client.ModulesManager.setModule({ module: moduleSelectioned, state, guildId: interaction.guild.id }); + interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Module configuré") + .setDescription(`Le module **${modules.find(x => x.value == moduleSelectioned).name}** est désormais **${state == true ? 'activé':'désactivé'}**`) + .setColor('#00ff00') + ] }).catch(() => {}); + + functions.log(interaction.guild, package.embeds.classic(interaction.user) + .setTitle("Module configuré") + .setDescription(`Un module a été configuré`) + .setColor('#00ff00') + .addFields( + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: "Module", + value: modules.find(x => x.value == moduleSelectioned).name, + inline: true + }, + { + name: "État", + value: state == true ? 'activé':'désactivé', + inline: true + } + ) + ); + }; + if (subcommand == 'afficher') { + let data = modules.map(x => ({ name: x.name, value: interaction.client.ModulesManager.checkModule({ module: x.value, guildId: interaction.guild.id }) == true ? '✅ activé':'❌ désactivé', inline: false })); + + const embed = package.embeds.classic(interaction.user) + .setTitle("Modules") + .setDescription(`Voici l'état des **${data.length} modules** du serveur`) + .addFields(data) + .setColor(interaction.guild.me.displayHexColor) + + interaction.reply({ embeds: [ embed ] }).catch(() => {}); + } + } +} \ No newline at end of file diff --git a/slash-commands/economy/adminCoins.js b/slash-commands/economy/adminCoins.js index fc2f760..96bcde8 100644 --- a/slash-commands/economy/adminCoins.js +++ b/slash-commands/economy/adminCoins.js @@ -7,7 +7,7 @@ module.exports = { dm: false, permissions: ['manage_guild'], cd: 5, - systems: [{name: "d'économie", value: 'economy_enable', state: true}], + systems: [], dev: false }, configs: { @@ -92,7 +92,7 @@ module.exports = { if (amount < 0) amount = parseInt(amount.toString().slice(1)); amount = amount.toFixed(0); if (isNaN(amount)) return interaction.reply({ embeds: [ package.embeds.invalidNumber(interaction.user) ] }).catch(() => {}); - if (!functions.checkAllConditions(interaction.guild, interaction.channel, interaction.member, member, interaction)) return; + if (!functions.checkPerms({ interaction, member, mod: interaction.member, checkBot: true, checkBotCompare: true })) return; interaction.client.CoinsManager.addCoins({ user_id: member.id, guild_id: interaction.guild.id }, amount); @@ -109,7 +109,7 @@ module.exports = { if (amount < 0) amount = parseInt(amount.toString().slice(1)); amount = amount.toFixed(0); if (isNaN(amount)) return interaction.reply({ embeds: [ package.embeds.invalidNumber(interaction.user) ] }).catch(() => {}); - if (!functions.checkAllConditions(interaction.guild, interaction.channel, interaction.member, member, interaction)) return; + if (!functions.checkPerms({ mod: interaction.member, member: member, checkBot: true, checkBotCompare: true, interaction: interaction })) return; const result = interaction.client.CoinsManager.removeCoins({ user_id: member.id, guild_id: interaction.guild.id }, amount); if (result == 'not enough coins' || result == false) return interaction.reply({ embeds: [ package.embeds.notEnoughCoins(member.user) ] }).catch(() => {}); @@ -123,15 +123,15 @@ module.exports = { if (subcommand == 'utilisateur') { let member = interaction.options.getMember('utilisateur'); - if (!functions.checkAllConditions(interaction.guild, interaction.channel, interaction.member, member, interaction)) return; + if (!functions.checkPerms({ mod: interaction.member, member: member, checkBot: true, checkBotCompare: true, checkOwner: true, interaction: interaction })) return; await interaction.reply({ embeds: [ package.embeds.classic(interaction.user) .setTitle("Confirmation") .setDescription(`Confirmez-vous que vous voulez réinitialiser les ${package.configs.coins} de <@${member.id}>`) .setColor('YELLOW') - ], components: [ new Discord.MessageActionRow().addComponents( - new Discord.MessageButton({ label: 'Oui', customId: 'y', style: 'SUCCESS' }), - new Discord.MessageButton({ label: 'Non', customId: 'n', style: 'DANGER' }) + ], components: [ new Discord.ActionRowBuilder().addComponents( + new Discord.ButtonBuilder({ label: 'Oui', customId: 'y', style: Discord.ButtonStyle.Success }), + new Discord.ButtonBuilder({ label: 'Non', customId: 'n', style: Discord.ButtonStyle.Danger }) ) ] }).catch(() => {}); const msg = await interaction.fetchReply(); @@ -152,9 +152,9 @@ module.exports = { .setTitle("Confirmation") .setDescription(`Confirmez-vous que vous voulez réinitialiser les ${package.configs.coins} de ${interaction.guild.name}`) .setColor('YELLOW') - ], components: [ new Discord.MessageActionRow().addComponents( - new Discord.MessageButton({ label: 'Oui', customId: 'y', style: 'SUCCESS' }), - new Discord.MessageButton({ label: 'Non', customId: 'n', style: 'DANGER' }) + ], components: [ new Discord.ActionRowBuilder().addComponents( + new Discord.ButtonBuilder({ label: 'Oui', customId: 'y', style: Discord.ButtonStyle.Success }), + new Discord.ButtonBuilder({ label: 'Non', customId: 'n', style: Discord.ButtonStyle.Danger }) ) ] }).catch(() => {}); const msg = await interaction.fetchReply(); diff --git a/slash-commands/economy/banque.js b/slash-commands/economy/banque.js index e76fa82..1bcd318 100644 --- a/slash-commands/economy/banque.js +++ b/slash-commands/economy/banque.js @@ -8,7 +8,7 @@ module.exports = { dm: false, dev: false, permissions: [], - systems: [{name: "d'économie", value: "economy_enable", state: true}] + systems: [], }, configs: { name: "banque", @@ -85,7 +85,7 @@ module.exports = { interaction.reply({ embeds: [ package.embeds.classic(interaction.user) .setTitle(`Argent ${value.end}`) - .setDescription(`**${amount.toLocaleString('en').replace(/,/g, ' ')} ${package.configs.coins}** ont été **${value.end}** ${value.suffix} votre compte en banque`) + .setDescription(`**${amount.toLocaleString('fr-DE')} ${package.configs.coins}** ont été **${value.end}** ${value.suffix} votre compte en banque`) .setColor(interaction.member.displayHexColor) ] }).catch(() => {}); } diff --git a/slash-commands/economy/daily.js b/slash-commands/economy/daily.js index 9944d0b..18c3b31 100644 --- a/slash-commands/economy/daily.js +++ b/slash-commands/economy/daily.js @@ -9,7 +9,7 @@ module.exports = { permissions: [], dm: false, dev: false, - systems: [{ name: "d'économie", value: "economy_enable", state: true }] + systems: [], }, configs: { name: 'daily', @@ -23,9 +23,9 @@ module.exports = { interaction.reply({ embeds: [ package.embeds.classic(interaction.user) .setTitle("Récompense quotidienne") - .setDescription(`Vous récupérez **${reward}** ${package.configs.coins} grâce à votre récompense quotidienne`) + .setDescription(`Vous récupérez **${reward.toLocaleString('fr-DE')}** ${package.configs.coins} grâce à votre récompense quotidienne`) .setColor(interaction.guild.me.displayHexColor) - ] }).catch(() => {}); + ] }).catch((e) => console.log(e)); interaction.client.CoinsManager.addCoins({ user_id: interaction.user.id, guild_id: interaction.guild.id }, reward); } diff --git a/slash-commands/economy/inventory.js b/slash-commands/economy/inventory.js index d68eab7..d5d4760 100644 --- a/slash-commands/economy/inventory.js +++ b/slash-commands/economy/inventory.js @@ -4,7 +4,7 @@ const package = functions.package(); module.exports = { help: { - systems: [{name: "d'économie", value: 'economy_enable', state: true}], + systems: [], cd: 5, dev: false, dm: false, diff --git a/slash-commands/economy/leaderboard.js b/slash-commands/economy/leaderboard.js index d503552..fa50c2e 100644 --- a/slash-commands/economy/leaderboard.js +++ b/slash-commands/economy/leaderboard.js @@ -6,7 +6,7 @@ module.exports = { help: { cd: 5, permissions: [], - systems: [{name: 'd\'économie', value: "economy_enable", state: true}], + systems: [], dm: false, dev: false }, @@ -38,7 +38,11 @@ module.exports = { let count = 0; stats.forEach((stat, i) => { - now.addField(`${i + 1}]`, `<@${stat.user}>\n${parseInt(stat.coins).toLocaleString('en').replace(/,/g, ' ')} ${package.configs.coins}`, false); + now.addFields({ + name: `${i + 1}]`, + value: `<@${stat.user}>\n${parseInt(stat.coins).toLocaleString('fr-DE')} ${package.configs.coins}`, + inline: false + }); pile = false; @@ -67,8 +71,11 @@ module.exports = { .setColor('ORANGE') stats.forEach((stat, i) => { - const x = stat.coins.toLocaleString('en'); - embed.addField(`${i + 1}]`, `<@${stat.user}>\n${x.replace(/,/g, ' ')}`, false); + const x = stat.coins.toLocaleString('fr-DE'); + embed.addFields({ + name: `${i + 1}]`, + value: `<@${stat.user}>\n${x}`, + inline: false}); }); interaction.reply({ embeds: [ embed ] }).catch(() => {}); diff --git a/slash-commands/economy/loto.js b/slash-commands/economy/loto.js new file mode 100644 index 0000000..946dd57 --- /dev/null +++ b/slash-commands/economy/loto.js @@ -0,0 +1,163 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); +const ms = require('ms'); + +module.exports = { + help: { + cd: 5, + dm: false, + dev: false, + systems: [], + permissions: [] + }, + configs: { + name: "loto", + description: "Gère un loto sur le serveur", + options: [ + { + name: 'gérer', + description: "Gère le loto", + type: "SUB_COMMAND_GROUP", + options: [ + { + name: "démarrer", + description: "Lance le loto sur le serveur", + type: 'SUB_COMMAND', + options: [ + { + name: "récompense", + description: `Récompense en ${package.configs.coins} du loto`, + type: 'INTEGER', + required: true + }, + { + name: 'gagnants', + description: "Nombre de numéro gagnants à tirer (minimum 5)", + type: 'INTEGER', + required: true + }, + { + name: "complémentaires", + description: "Nombre de numéro complémentaires à tirer (minimum 2)", + type: 'INTEGER', + required: true + }, + { + name: "temps", + description: "Temps avant la fin du loto (ex: 1d)", + type: 'STRING', + required: true + } + ] + }, + { + name: "tirage", + description: "Fait le tirage du loto", + type: 'SUB_COMMAND' + } + ] + }, + { + name: 'participer', + description: "Participez au loto en cours", + type: 'SUB_COMMAND', + options: [ + { + name: "gagnants", + description: "Les numéro gagnants que vous jouez (ex: 15 68 46 75 12)", + type: 'STRING', + required: true + }, + { + name: "complémentaires", + description: "Les numéro complémentaires que vous jouez (ex: 94 60)", + required: true, + type: 'STRING' + } + ] + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: (interaction) => { + const subcommand = interaction.options.getSubcommand(); + + if (subcommand == 'démarrer') { + if (!interaction.member.permissions.has(Discord.PermissionsBitField.Flags.ManageGuild)) return interaction.reply({ embeds: [ package.embeds.missingPermission(interaction.user, "gérer le serveur") ] }).catch(() => {}); + const reward = parseInt(interaction.options.get('récompense').value); + const numbers = parseInt(interaction.options.get('gagnants').value); + const complementaries = parseInt(interaction.options.get('complémentaires').value); + const time = ms(interaction.options.get('temps').value); + + if (!time) return interaction.reply({ embeds: [ package.embeds.invalidTime(interaction.user) ] }).catch(() => {}); + if (isNaN(reward) || isNaN(numbers) || isNaN(complementaries)) return interaction.reply({ embeds: [ package.embeds.invalidNumber(interaction.user) ] }).catch(() => {}); + + if (reward < 1 || numbers < 5 || complementaries < 2) return interaction.reply({ embeds: [ package.embeds.invalidNumber(interaction.user) ] }).catch(() => {}); + const result = interaction.client.LotoManager.start({ + numbers, + complementaries, + reward, + time, + guildId: interaction.guild.id + }); + + interaction.reply({ embeds: [ package.embeds.loto.started(interaction.user, numbers, complementaries, reward, time) ] }).catch(() => {}); + }; + if (subcommand == 'tirage') { + if (!interaction.member.permissions.has(Discord.PermissionsBitField.Flags.ManageGuild)) return interaction.reply({ embeds: [ package.embeds.missingPermission(interaction.user, "gérer le serveur") ] }).catch(() => {}); + + const result = interaction.client.LotoManager.end(interaction.guild.id); + let embed; + switch(result) { + case 'invalid loto': + embed = package.embeds.loto.invalidLoto(interaction.user, 'end'); + break; + default: + let x = result; + x.user = interaction.user; + embed = package.embeds.loto.end(x); + break; + }; + + if (typeof result == 'object' && result.length > 0) { + result.forEach((winner) => { + interaction.client.CoinsManager.addCoins({ user_id: winner.user_id, guild_id: interaction.guild.id }, winner.reward.toFixed(0)); + }); + }; + interaction.reply({ embeds: [ embed ] }).catch(() => {}); + }; + if (subcommand == 'participer') { + const numbers = interaction.options.getString('gagnants').split(' ').map(x => parseInt(x)); + const complementaries = interaction.options.getString('complémentaires').split(' ').map(x => parseInt(x)); + + const result = interaction.client.LotoManager.addParticipation({ + guildId: interaction.guild.id, + userId: interaction.user.id, + numbers, complementaries + }); + + let embed = package.embeds.loto; + switch(result) { + case 'invalid loto': + embed = embed.invalidLoto(interaction.user, 'participate'); + break; + case 'invalid numbers': + case 'invalid arrays': + case 'invalid compared': + embed = embed.invalidNumbers(interaction.user); + break; + case 'user already exists': + embed = embed.alreadyParticipate(interaction.user); + break; + case 'added': + embed = embed.added(interaction.user, numbers, complementaries); + break; + }; + + interaction.reply({ embeds: [ embed ] }).catch(() => {}); + } + } +}; \ No newline at end of file diff --git a/slash-commands/economy/pay.js b/slash-commands/economy/pay.js index f434c08..742e93c 100644 --- a/slash-commands/economy/pay.js +++ b/slash-commands/economy/pay.js @@ -4,7 +4,7 @@ const package = functions.package(); module.exports = { help: { - systems: [{name: "d'économie", value: "economy_enable", state: true}], + systems: [], cd: 5, dm: false, dev: false, @@ -42,10 +42,10 @@ module.exports = { await interaction.reply({ embeds: [ package.embeds.classic(interaction.user) .setTitle("Confirmation") - .setDescription(`Confirmez-vous que vous voulez donner **${amount.toLocaleString('en').replace(/,/g, ' ')} ${package.configs.coins}** à <@${user.id}> ?`) + .setDescription(`Confirmez-vous que vous voulez donner **${amount.toLocaleString('fr-DE')} ${package.configs.coins}** à <@${user.id}> ?`) .setColor('YELLOW') - ], components: [ new Discord.MessageActionRow() - .addComponents(new Discord.MessageButton({ label: 'Oui', style: 'SUCCESS', customId: 'y' }), new Discord.MessageButton({ label: 'Non', style: 'DANGER', customId: 'n' })) + ], components: [ new Discord.ActionRowBuilder() + .addComponents(new Discord.ButtonBuilder({ label: 'Oui', style: Discord.ButtonStyle.Success, customId: 'y' }), new Discord.ButtonBuilder({ label: 'Non', style: Discord.ButtonStyle.Danger, customId: 'n' })) ] }).catch(() => {}); const msg = await interaction.fetchReply(); @@ -58,7 +58,7 @@ module.exports = { interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) .setTitle("Transaction effectuée") - .setDescription(`Vous avez donné **${amount.toLocaleString('en').replace(/,/g, ' ')}** ${package.configs.coins} à <@${user.id}>`) + .setDescription(`Vous avez donné **${amount.toLocaleString('fr-DE')}** ${package.configs.coins} à <@${user.id}>`) .setColor(interaction.member.displayHexColor) ], components: [] }).catch(() => {}); }); diff --git a/slash-commands/economy/shop.js b/slash-commands/economy/shop.js index 74124f9..e836438 100644 --- a/slash-commands/economy/shop.js +++ b/slash-commands/economy/shop.js @@ -6,7 +6,7 @@ module.exports = { help: { cd: 5, permissions:[], - systems: [{name: "d'économie", value: 'economy_enable', state: true}], + systems: [], dm: false, dev: false }, @@ -152,7 +152,7 @@ module.exports = { interaction.reply({ embeds: [ package.embeds.classic(interaction.user) .setTitle("Item ajouté") - .setDescription(`L'item ${name} a été ajouté au magasin pour **${price.toLocaleString('en').replace(/,/g, ' ')}** ${package.configs.coins}`) + .setDescription(`L'item ${name} a été ajouté au magasin pour **${price.toLocaleString('fr-DE')}** ${package.configs.coins}`) .setColor('ORANGE') ] }).catch(() => {}); }) @@ -223,7 +223,7 @@ module.exports = { }; data.extra = JSON.parse(data.extra); - embed.addField(data.item_name, `${data.item_type == 'role' ? `<@&${data.extra.id}>` : data.extra.text}\n**Identifiant :** \`${data.id}\`\n> Prix : ${parseInt(data.price).toLocaleString('en').replace(/,/g, ' ')} ${package.configs.coins}\nEn stock : ${parseInt(data.quantity) == 0 ? "illimité" : `${data.quantity} restant(s)`}`, true); + embed.addField(data.item_name, `${data.item_type == 'role' ? `<@&${data.extra.id}>` : data.extra.text}\n**Identifiant :** \`${data.id}\`\n> Prix : ${parseInt(data.price).toLocaleString('fr-DE')} ${package.configs.coins}\nEn stock : ${parseInt(data.quantity) == 0 ? "illimité" : `${data.quantity} restant(s)`}`, true); return returned + 1; }; @@ -260,7 +260,7 @@ module.exports = { await interaction.reply({ embeds: [ package.embeds.classic(interaction.user) .setTitle("Item acheté") - .setDescription(`Vous avez acheté **${item.item_name}** pour ${item.price.toLocaleString('en').replace(/,/g, ' ')} ${package.configs.coins}`) + .setDescription(`Vous avez acheté **${item.item_name}** pour ${item.price.toLocaleString('fr-DE')} ${package.configs.coins}`) .setColor('#00ff00') ] }).catch(() => {}); @@ -283,7 +283,7 @@ module.exports = { interaction.client.CoinsManager.addCoins({ user_id: interaction.user.id, guild_id: interaction.guild.id }, item.price); interaction.editReply({ content: `<@${interaction.user.id}>`, embeds: [ package.embeds.classic(interaction.user) .setTitle("Erreur") - .setDescription(`Une erreur a eu lieu lors de l'ajout de l'item dans votre inventaire.\nL'achat vous a été remboursé, vous récupérez **${item.price.toLocaleString('en').replace(/,/g, ' ')}** ${package.configs.coins}`) + .setDescription(`Une erreur a eu lieu lors de l'ajout de l'item dans votre inventaire.\nL'achat vous a été remboursé, vous récupérez **${item.price.toLocaleString('fr-DE')}** ${package.configs.coins}`) .setColor('#ff0000') ] }).catch(() => {}); diff --git a/slash-commands/economy/stats.js b/slash-commands/economy/stats.js index 9912727..c9a59a7 100644 --- a/slash-commands/economy/stats.js +++ b/slash-commands/economy/stats.js @@ -8,7 +8,7 @@ module.exports = { dev: false, cd: 5, permissions: [], - systems: [{name: 'd\'économie', value: 'economy_enable', state: true}] + systems: [], }, configs: { name: 'stats', @@ -34,17 +34,17 @@ module.exports = { .addFields( { name: 'En poche', - value: parseInt(stats.coins).toLocaleString('en').replace(/,/g, ' ') + ' ' + package.configs.coins, + value: parseInt(stats.coins).toLocaleString('fr-DE') + ' ' + package.configs.coins, inline: true }, { name: 'Banque', - value: parseInt(stats.bank).toLocaleString('en').replace(/,/g, ' ') + ' ' + package.configs.coins, + value: parseInt(stats.bank).toLocaleString('fr-DE') + ' ' + package.configs.coins, inline: true }, { name: 'Total', - value: (parseInt(stats.coins) + parseInt(stats.bank)).toLocaleString('en').replace(/,/g, ' ') + ' ' + package.configs.coins + value: (parseInt(stats.coins) + parseInt(stats.bank)).toLocaleString('fr-DE') + ' ' + package.configs.coins } ) .setColor(interaction.guild.me.displayHexColor); diff --git a/slash-commands/economy/trade.js b/slash-commands/economy/trade.js index f8ad568..eef1829 100644 --- a/slash-commands/economy/trade.js +++ b/slash-commands/economy/trade.js @@ -6,7 +6,7 @@ module.exports = { help: { cd: 5, permissions: [], - systems: [{ name: "d'économie", value: 'economy_enable', state: true }], + systems: [], dm: false, dev: false }, @@ -63,10 +63,10 @@ module.exports = { let id = interaction.user.id; await interaction.reply({ embeds: [ package.embeds.classic(interaction.user) .setTitle("Confirmation de l'échange") - .setDescription(`Confirmez-vous que vous donnez **${itemName}** à <@${user.id}> en échange de **${price.toLocaleString('en').replace(/,/g, ' ')}** ${package.configs.coins} ?`) + .setDescription(`Confirmez-vous que vous donnez **${itemName}** à <@${user.id}> en échange de **${price.toLocaleString('fr-DE')}** ${package.configs.coins} ?`) .setColor('YELLOW') - ], components: [ new Discord.MessageActionRow() - .addComponents(new Discord.MessageButton({ label: 'Oui', style: 'SUCCESS', customId: 'y' }), new Discord.MessageButton({ label: 'Non', style: 'DANGER', customId: 'n' })) + ], components: [ new Discord.ActionRowBuilder() + .addComponents(new Discord.ButtonBuilder({ label: 'Oui', style: Discord.ButtonStyle.Success, customId: 'y' }), new Discord.ButtonBuilder({ label: 'Non', style: Discord.ButtonStyle.Danger, customId: 'n' })) ], content: `<@${id}>` }).catch(() => {}); const msg = await interaction.fetchReply(); @@ -81,7 +81,7 @@ module.exports = { id = user.id; await interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) .setTitle("Confirmation de l'échange") - .setDescription(`Confirmez-vous que vous donnez **${price.toLocaleString('en').replace(/,/g, ' ')}** ${package.configs.coins} à <@${interaction.user.id}> en échange de **${itemName}** ?`) + .setDescription(`Confirmez-vous que vous donnez **${price.toLocaleString('fr-DE')}** ${package.configs.coins} à <@${interaction.user.id}> en échange de **${itemName}** ?`) .setColor('YELLOW') ], content: `<@${id}>` }).catch(() => {}); } else { diff --git a/slash-commands/economy/weekly.js b/slash-commands/economy/weekly.js index 409223d..528cf97 100644 --- a/slash-commands/economy/weekly.js +++ b/slash-commands/economy/weekly.js @@ -9,7 +9,7 @@ module.exports = { permissions: [], dm: false, dev: false, - systems: [{ name: "d'économie", value: "economy_enable", state: true }] + systems: [], }, configs: { name: 'weekly', @@ -23,7 +23,7 @@ module.exports = { interaction.reply({ embeds: [ package.embeds.classic(interaction.user) .setTitle("Récompense quotidienne") - .setDescription(`Vous récupérez **${reward}** ${package.configs.coins} grâce à votre récompense quotidienne`) + .setDescription(`Vous récupérez **${reward.toLocaleString('fr-DE')}** ${package.configs.coins} grâce à votre récompense hebdomadaire.`) .setColor(interaction.guild.me.displayHexColor) ] }).catch(() => {}); diff --git a/slash-commands/fun/choix.js b/slash-commands/fun/choix.js index 8f82f0c..2e4f61c 100644 --- a/slash-commands/fun/choix.js +++ b/slash-commands/fun/choix.js @@ -33,14 +33,13 @@ module.exports = { */ run: (interaction) => { let props = []; - for (let i = 0; i < 9; i++) { - let name = `proposition${i + 1}`; - - if (interaction.options.get(name)) props.push(interaction.options.get(name).value); + for (let i = 0; i < 10; i++) { + props.push(interaction.options.get(`proposition${i + 1}`)?.value); }; + props = props.filter(x => ![undefined, null].includes(x)); - let choice = props[functions.random(0, props.length)]; + let choice = props[functions.random(props.length, 0)]; - interaction.reply({ content: `Mon choix est **${choice}**` }); + interaction.reply({ content: `Mon choix est **${choice}**` }).catch(() => {}); } } \ No newline at end of file diff --git a/slash-commands/fun/game.js b/slash-commands/fun/game.js index 94b8ee8..1b428ab 100644 --- a/slash-commands/fun/game.js +++ b/slash-commands/fun/game.js @@ -255,14 +255,15 @@ module.exports = { }; const filter = (m) => { + if (game == 'solo') { + if (m.author.id !== interaction.user.id) return false; + }; + if (m.content.toLowerCase() == 'haut haut bas bas gauche droite gauche droite b a') return true; let n = parseInt(m.content); if (isNaN(n)) return false; if (n < min) return false; if (n > max) return false; - if (game == 'solo') { - if (m.author.id !== interaction.user.id) return false; - }; return true; }; @@ -278,10 +279,17 @@ module.exports = { const number = functions.random(max, min); let count = 0; + let konami = {}; collector.on('collect', (message) => { count++; let num = parseInt(message.content); + if (konami[message.author.id] == true) num = number; + if (message.content.toLowerCase() == 'haut haut bas bas gauche droite gauche droite b a') { + functions.reply(message, 'KONAMI MODE ACTIVATED !'); + konami[message.author.id] = true; + return; + } if (num > number) { functions.reply(message, 'Mon nombre est plus petit'); @@ -385,7 +393,7 @@ module.exports = { const embed = package.embeds.classic(interaction.user) .setTitle("Dés") - .setDescription(`Les dés on été lancés :\n\n\`${results.map(x => `${x}`).join(' + ')}\`\n> = ${results.reduce((a, b) => a + b)}`) + .setDescription(`Les dés ont été lancés :\n\n\`${results.map(x => `${x}`).join(' + ')}\`\n> = ${results.reduce((a, b) => a + b)}`) .setColor('ORANGE') interaction.reply({ embeds: [ embed ] }).catch(() => {}); diff --git a/slash-commands/fun/joke.js b/slash-commands/fun/joke.js index 38f69ba..980542f 100644 --- a/slash-commands/fun/joke.js +++ b/slash-commands/fun/joke.js @@ -4,6 +4,14 @@ const package = functions.package(); const blagueAPI = require('blagues-api'); const blagues = new blagueAPI(package.configs['blagues-api-token']); +const values = { + global: 'général', + dev: "développeur", + dark: "noir", + limit: "limite", + beauf: 'beauf', + blondes: 'blondes' +}; module.exports = { help: { @@ -16,13 +24,21 @@ module.exports = { configs: { name: 'blague', description: "Affiche une blague aléatoire", - options: Object.keys(blagues.categories).map((x) => ({name: x.toLowerCase(), description: `Blague de type ${x.toLowerCase()}`, type: 'SUB_COMMAND'})) + options: [ + { + name: 'type', + description: "Type de la blague", + required: true, + type: 'STRING', + choices: Object.keys(values).map(x => ({ name: x, value: values[x] })) + } + ] }, /** * @param {Discord.CommandInteraction} interaction */ run: async(interaction) => { - const type = interaction.options.getSubcommand().toUpperCase(); + const type = interaction.options.getString('type'); const blague = await blagues.randomCategorized(blagues.categories[type]); const embed = package.embeds.classic(interaction.user) diff --git a/slash-commands/fun/meme.js b/slash-commands/fun/meme.js new file mode 100644 index 0000000..4ee44a4 --- /dev/null +++ b/slash-commands/fun/meme.js @@ -0,0 +1,39 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); +const axios = require('axios'); + +module.exports = { + help: { + cd: 5, + dev: false, + dm: true, + systems: [], + permissions: [] + }, + configs: { + name: 'meme', + description: "Envoie un meme" + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + await interaction.deferReply(); + + axios('https://some-random-api.ml/meme').then((res) => { + if (res.statusText !== 'OK') return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Erreur") + .setDescription(`Je n'ai pas pu récupérer de meme.\nSi ce message se réaffiche, contactez mes développeurs (\`/contact\`)`) + .setColor('#ff0000') + ] }).catch(() => {}); + + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Meme") + .setColor(interaction?.guild?.me?.displayHexColor ?? 'ORANGE') + .setDescription(res.data.caption) + .setImage(res.data.image) + ] }).catch(() => {}); + }); + } +} \ No newline at end of file diff --git a/slash-commands/fun/mixnames.js b/slash-commands/fun/mixnames.js new file mode 100644 index 0000000..0b435a8 --- /dev/null +++ b/slash-commands/fun/mixnames.js @@ -0,0 +1,52 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + dev: false, + dm: true + }, + configs: { + name: 'mixnames', + description: "Fait le mélange de deux pseudos", + options: [ + { + name: "utilisateur1", + description: "Premier utilisateur", + type: 'USER', + required: true + }, + { + name: 'utilisateur2', + description: "Deuxième utilisateur", + type: 'USER', + required: false + }, + { + name: "texte", + description: "Texte à la place du deuxième utilisateur", + type: 'STRING', + required: false + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: (interaction) => { + let first = interaction.options.getUser('utilisateur1').username; + let second = interaction.options.getUser('utilisateur2')?.username ?? interaction.options.get('texte')?.value ?? interaction.client.user.username; + + let mixed = ""; + let firstPart = first.substring(0, (first.length / 2).toFixed(0)); + let secondPart = second.substring((second.length / 2).toFixed(0)); + + interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Mix") + .setDescription(`Le mix de ${first} et de ${second} est \`${firstPart + secondPart}\``) + .setColor(interaction?.member?.displayHexColor ?? interaction?.guild?.me?.displayHexColor ?? 'ORANGE') + ] }).catch(() => {}); + } +} \ No newline at end of file diff --git a/slash-commands/fun/vigenere.js b/slash-commands/fun/vigenere.js new file mode 100644 index 0000000..ecff4ed --- /dev/null +++ b/slash-commands/fun/vigenere.js @@ -0,0 +1,62 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); +const vigenere = require('../../assets/scripts/vigenereCode'); + +new vigenere('', 't', '') + +module.exports = { + help: { + cd: 5, + dm: true, + permissions: [], + systems: [], + dev: false + }, + configs: { + name: 'cryptage', + description: "Crypte ou décrypte un texte selon votre clé", + options: [ + { + name: "action", + description: "Action à effectuer sur votre texte", + required: true, + type: 'STRING', + choices: [ + { + name: 'Chiffrer', + value: 'code' + }, + { + name: "Déchiffrer", + value: 'decode' + } + ] + }, + { + name: 'texte', + type: 'STRING', + required: true, + description: "Texte à examiner" + }, + { + name: "clé", + required: true, + description: "Clé de chiffrage/déchiffrage", + type: 'STRING' + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: (interaction) => { + let action = interaction.options.getString('action'); + let text = interaction.options.getString('texte'); + let key = interaction.options.getString('clé'); + + const result = new vigenere(text, key, action).run(); + + interaction.reply({ content: `\`\`\`${result}\`\`\``, ephemeral: true }).catch(() => {}); + } +} \ No newline at end of file diff --git a/slash-commands/misc/avatar.js b/slash-commands/information/avatar.js similarity index 84% rename from slash-commands/misc/avatar.js rename to slash-commands/information/avatar.js index 30f8ad3..fff4a7b 100644 --- a/slash-commands/misc/avatar.js +++ b/slash-commands/information/avatar.js @@ -28,6 +28,6 @@ module.exports = { run: (interaction) => { const user = interaction.options.get('utilisateur') ? interaction.options.get('utilisateur').user : interaction.user; - interaction.reply({ content: `Voici la photo de profil de **${user.username}**:\n**${user.displayAvatarURL({ dynamic: true, size: 4096 })}**` }); + interaction.reply({ content: user.displayAvatarURL({ dynamic: true, size: 4096 }) }); } } \ No newline at end of file diff --git a/slash-commands/information/botinfo.js b/slash-commands/information/botinfo.js new file mode 100644 index 0000000..cf7396d --- /dev/null +++ b/slash-commands/information/botinfo.js @@ -0,0 +1,82 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + dev: false, + dm: true + }, + configs: { + name: 'botinfo', + description: "Affiche quelques informations sur le bot" + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + await interaction.deferReply(); + await interaction.client.guilds.fetch(); + + const embed = package.embeds.classic(interaction.user) + .setThumbnail(interaction.client.user.avatarURL()) + .setTitle("Bot informations") + .setDescription(`Voici quelques informations me concernant`) + .addFields( + { + name: "Version", + value: package.configs.version, + inline: true + }, + { + name: "Serveurs", + value: interaction.client.guilds.cache.size.toLocaleString('fr-DE'), + inline: true + }, + { + name: "Utilisateurs", + value: interaction.client.guilds.cache.map(x =>x.memberCount).reduce((a, b) => a + b).toLocaleString('fr-DE'), + inline: true + }, + { + name: "\u200b", + value: '\u200b', + inline: false + }, + { + name: "Support", + value: `[invitation](${package.configs.support})`, + inline: true + }, + { + name: "Ajouter Oracle", + value: `[lien](${package.configs.link})`, + inline: true + }, + { + name: "Page top.gg", + value: `[Lien](${package.configs.topgg})`, + inline: true + }, + { + name: "Développeurs", + inline: false, + value: `[${((await interaction.client.users.fetch(package.configs.gs)).tag)}](https://github.com/Greensky-gs)\n[${((await interaction.client.users.fetch(package.configs.swiz)).tag)}](https://github.com/Swiizyy)` + } + ) + .setColor(interaction?.guild?.me?.displayHexColor ?? 'ORANGE') + + let row = new Discord.MessageActionRow() + .addComponents( + new Discord.MessageButton() + .setLabel('Code source') + .setStyle('LINK') + .setURL('https://www.youtube.com/watch?v=dQw4w9WgXcQ') + ); + + let components = []; + if (functions.random(10, 0) == 4) components.push(row); + interaction.editReply({ embeds: [ embed ], components }).catch(() => {}); + } +} \ No newline at end of file diff --git a/slash-commands/information/channelinfo.js b/slash-commands/information/channelinfo.js new file mode 100644 index 0000000..d1f3c7b --- /dev/null +++ b/slash-commands/information/channelinfo.js @@ -0,0 +1,74 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + dm: false, + dev: false + }, + configs: { + name: 'channelinfo', + description: "Affiche les informations d'un salon", + options: [ + { + name: 'salon', + description: "Salon dont vous voulez soutirer des informations", + required: false, + type: 'CHANNEL' + } + ] + }, + /** + * + * @param {Discord.CommandInteraction} interaction + */ + run: (interaction) => { + let channel = interaction.options.get('salon')?.channel ?? interaction.channel; + + let fields = [ + { + name: "Nom du salon", + value: channel.name, + inline: true + }, + { + name: "Identifiant", + value: `\`${channel.id}\``, + inline: true + }, + { + name: 'Sujet', + value: channel.topic ?? 'Pas de sujet', + inline: false + }, + { + name: "Type", + value: channel.type == 'GUILD_NEWS' ? "Annonces" : channel.type == 'GUILD_CATEGORY' ? 'catégorie' : channel.type == 'GUILD_NEWS_THREAD' ? 'Fil de salon des annonces' : channel.type == 'GUILD_PRIVATE_THREAD' ? 'Fil privé' : channel.type == 'GUILD_PUBLIC_THREAD' ? "Fil" : channel.type == 'GUILD_STAGE_VOICE' ? "Salon de conférence" : channel.type == 'GUILD_TEXT' ? "Salon textuel" : channel.type == 'GUILD_VOICE' ? 'Salon vocal' : "Inconnu", + inline: true + } + ]; + if (channel.parent) { + fields.push({ + name: "Catégorie", + value: `${channel.parent.name} ( \`${channel.parentId}\` )`, + inline: true + }); + }; + fields.push( + { + name: "Création", + value: ` ( )`, + inline: false + } + ); + + const embed = package.embeds.classic(interaction.user) + .setTitle(channel.name) + .setThumbnail('attachment://hashtag.png') + .setFields(fields) + .setColor(interaction.guild.me.displayHexColor) + interaction.reply({ embeds: [ embed ], files: [ './assets/images/hashtag.png' ] }) + } +} \ No newline at end of file diff --git a/slash-commands/information/roleinfo.js b/slash-commands/information/roleinfo.js new file mode 100644 index 0000000..fb532c6 --- /dev/null +++ b/slash-commands/information/roleinfo.js @@ -0,0 +1,81 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + permissions: [], + systems: [], + dev: false, + dm: false + }, + configs: { + name: 'roleinfo', + description: "Affiche les informations d'un rôle", + options: [ + { + name: "rôle", + description: "Rôle dont vous voulez vous informez", + required: false, + type: 'ROLE' + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + let role = interaction.options.get('rôle')?.role ?? interaction.member.roles.highest; + await interaction.deferReply(); + await interaction.guild.members.fetch(); + await interaction.guild.roles.fetch(); + + let up = interaction.guild.roles.cache.find(x => x.position == role.position + 1); + let down = interaction.guild.roles.cache.find(x => x.position == role.position - 1); + + const embed = package.embeds.classic(interaction.user) + .setTitle(role.name) + .setColor(role.hexColor) + .addFields( + { + name: 'Identifiant', + value: role.id, + inline: true + }, + { + name: "Couleur", + value: (role.hexColor.startsWith('#') ? '':"#") + role.hexColor, + inline: true + }, + { + name: "Création", + value: ` ( )`, + inline: true + }, + {name: '\u200b', value: "\u200b", inline: false}, + { + name: 'Séparé des autres membres', + value: role.hoist ? '✅':'❌', + inline: true + }, + { + name: 'Mentionnable', + value: role.mentionable ? '✅':'❌', + inline: true + }, + { + name: "Membres avec ce rôle", + value: `${role.members.size} membre${role.members.size > 1 ? 's':''} (soit ~${((role.members.size * 100) / interaction.guild.members.cache.size).toFixed(0)}% du serveur)`, + inline: true + }, + { + name: "Position", + value: (up ? `<@&${up.id}> >` : '') + `<@&${role.id}>` + (down ? down.id == interaction.guild.id ? `> @everyone`:`> <@&${down.id}>`:''), + inline: false + } + ); + + interaction.editReply({ embeds: [ embed ] }).catch(() => {}); + } +} \ No newline at end of file diff --git a/slash-commands/information/servericon.js b/slash-commands/information/servericon.js new file mode 100644 index 0000000..7befe5e --- /dev/null +++ b/slash-commands/information/servericon.js @@ -0,0 +1,29 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + dev: false, + dm: false, + permissions: [], + systems: [] + }, + configs: { + name: 'servericon', + description: "Affiche l'icône du serveur" + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: (interaction) => { + if (!interaction.guild.icon) return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Pas d'icône") + .setDescription(`${interaction.guild.name} n'a pas d'icône`) + .setColor('#ff0000') + ] }).catch(() => {}); + + interaction.reply({ content: interaction.guild.iconURL({ dynamic: true, size: 4096 }) }).catch(() => {}); + } +} \ No newline at end of file diff --git a/slash-commands/information/serverinfo.js b/slash-commands/information/serverinfo.js new file mode 100644 index 0000000..b717900 --- /dev/null +++ b/slash-commands/information/serverinfo.js @@ -0,0 +1,95 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + systems: [], + permissions: [], + dev: false, + dm: false + }, + configs: { + name: 'serverinfo', + description: "Affiche les informations du serveur" + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + const guild = interaction.guild; + await interaction.deferReply(); + await guild.members.fetch(); + await guild.roles.fetch(); + await guild.channels.fetch(); + await guild.emojis.fetch(); + + const empty = {name: '\u200b', value: '\u200b', inline: false}; + + const fields = [ + { + name: "Propriétaire", + value: `<@${guild.ownerId}> ( \`${guild.ownerId}\` )`, + inline: true + }, + { + name: "Identifiant", + value: guild.id, + inline: true + },empty, + { + name: "Membres", + value: guild.memberCount.toString(), + inline: true + }, + { + name: "Bots", + value: guild.members.cache.filter(x => x.user.bot).size + '** **', + inline: true + }, + { + name: "Humains", + value: guild.members.cache.filter(x => !x.user.bot).size + '** **', + inline: true + },empty, + { + name: "Boosts", + value: `${guild.premiumSubscriptionCount} boost${guild.premiumSubscriptionCount > 1 ? 's':''} (\`Niveau ${guild.premiumTier == 'NONE' ? 0 : guild.premiumTier == 'TIER_1' ? 1 : guild.premiumTier == 'TIER_2' ? 2 : 3}\`)`, + inline: false + }, + { + name: "Rôles", + value: `${guild.roles.cache.size}` + '** **', + inline: true + }, + { + name: "Salons", + value: `${guild.channels.cache.size}` + '** **', + inline: true + }, + { + name: "Émojis", + value: `${guild.emojis.cache.size}` + '** **', + inline: true + }, + empty, + { + name: "Création", + value: ` ( )`, + inline: false + } + ]; + + console.log(fields); + const embed = package.embeds.classic(interaction.user) + .setTitle(guild.name) + .setThumbnail(guild.iconURL({ dynamic: true }) ?? interaction.user.displayAvatarURL({ dynamic: true })) + .addFields( + fields + ) + .setColor(guild.roles.highest.hexColor) + + interaction.editReply({ embeds: [ embed ] }).catch(() => {}) + } +} \ No newline at end of file diff --git a/slash-commands/information/userinfo.js b/slash-commands/information/userinfo.js new file mode 100644 index 0000000..c831c32 --- /dev/null +++ b/slash-commands/information/userinfo.js @@ -0,0 +1,73 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + permissions: [], + systems: [], + dev: false, + dm: false + }, + configs: { + name: 'userinfo', + description: "Affiche les informations d'un utilisateur", + options: [ + { + name: 'utilisateur', + description: "Utilisateur dont vous voulez être informé", + type: 'USER', + required: false + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run:(interaction) => { + let member = interaction.options.getMember('utilisateur') ?? interaction.member; + let user = interaction.options.getUser('utilisateur') ?? interaction.user; + let roles = member.roles.cache.filter(x => x.id !== interaction.guild.id); + + const embed = package.embeds.classic(user) + .setTitle(user.tag) + .setDescription(`<@${user.id}>`) + .setThumbnail(user.displayAvatarURL({ dynamic: false, format: 'png' })) + .addFields( + { + name: 'Identifiant', + value: `\`${user.id}\``, + inline: true + }, + { + name: 'Pseudo', + value: member?.nick ?? 'Pas de pseudo', + inline: true + }, + { + name: 'Création du compte', + value: ` ( )`, + inline: false + }, + { + name: 'Date d\'arrivée', + value: ` ( )`, + inline: false + }, + { + name: `Rôle${roles.length > 0 ? 's':''}`, + value: roles.map(x => `<@&${x.id}>`).join(' '), + inline: false + }, + { + name: `Permission${member.permissions.has('ADMINISTRATOR') ? '' : member.permissions.length > 0 ? 's':''}`, + value: member.permissions.has('ADMINISTRATOR') ? 'Administrateur' : member.permissions.map(x => package.perms[x]).join(', '), + inline: false + } + ) + .setColor(member.displayHexColor) + + interaction.reply({ embeds: [ embed ] }).catch(() => {}); + } +}; \ No newline at end of file diff --git a/slash-commands/levels/levels.js b/slash-commands/levels/levels.js new file mode 100644 index 0000000..a96e6b0 --- /dev/null +++ b/slash-commands/levels/levels.js @@ -0,0 +1,92 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + dev: false, + dm: false, + systems: [], + permissions: [] + }, + configs: { + name: 'classement', + description: "Affiche le classement des niveaux du serveur" + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: (interaction) => { + interaction.client.db.query(`SELECT * FROM levels WHERE guild_id="${interaction.guild.id}"`, (error, request) => { + if (error) { + functions.sendError(error, 'query at /classement', interaction.user) + interaction.reply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + + return; + }; + + const levels = request.sort((a, b) => b.total - a.total); + + if (request.length < 5) { + const embed = package.embeds.classic(interaction.user) + .setTitle("Niveaux") + .setDescription(`Voici le top **${levels.length.toLocaleString('fr-DE')}** des niveaux du serveur.`) + .setColor('ORANGE') + + levels.forEach((lvl) => { + embed.addField({ + name: (levels.indexOf(lvl) + 1).toString(), + value: `<@${lvl.user_id}> +> Niveau **${parseInt(lvl.level).toLocaleString('fr-DE')}** +> Avec un total de **${parseInt(lvl.total).toLocaleString('fr-DE')} messages**`, + inline: false + }); + }); + + interaction.reply({ embeds: [ embed ] }).catch(() => {}); + } else { + let now = package.embeds.classic(interaction.user) + .setTitle("Niveaux") + .setDescription(`Voici le top **${levels.length.toLocaleString('fr-DE')}** des niveaux du serveur.`) + .setColor('ORANGE') + + var embeds = []; + let pile = false; + let count = 0; + + for (let i = 0; i < levels.length; i++) { + const lvl = levels[i]; + + now.addField({ + name: (levels.indexOf(lvl) + 1).toString(), + value: `<@${lvl.user_id}> +> Niveau **${parseInt(lvl.level).toLocaleString('fr-DE')}** +> Avec un total de **${parseInt(lvl.total).toLocaleString('fr-DE')} messages**`, + inline: false + }); + + pile = false; + + count++; + if (count === 5) { + count=0; + pile = true; + embeds.push(now); + + now = null; + now = package.embeds.classic(interaction.user) + .setTitle("Niveaux") + .setDescription(`Voici le top **${levels.length.toLocaleString('fr-DE')}** des niveaux du serveur.`) + .setColor('ORANGE') + + } + }; + + if (!pile) embeds.push(now); + + functions.pagination(interaction.user, 'none', embeds, 'classement', interaction); + } + }) + } +} \ No newline at end of file diff --git a/slash-commands/usefull/rank.js b/slash-commands/levels/rank.js similarity index 86% rename from slash-commands/usefull/rank.js rename to slash-commands/levels/rank.js index e685ef2..64d3ebb 100644 --- a/slash-commands/usefull/rank.js +++ b/slash-commands/levels/rank.js @@ -27,7 +27,7 @@ module.exports = { dm: false, dev: false, permissions: [], - systems: [{name: 'de niveaux', value: 'level_enable', state: true}], + systems: [], cd: 5 }, /** @@ -49,17 +49,17 @@ module.exports = { .addFields( { name: "Niveau", - value: `Niveau **${r[0].level}**`, + value: `Niveau **${r[0].level.toLocaleString('fr-DE')}**`, inline: false }, { name: "Messages", - value: `Messages totaux : ${r[0].total}`, + value: `Messages totaux : ${r[0].total.toLocaleString('fr-DE')}`, inline: false }, { name: 'Messages restants', - value: `**${parseInt(r[0].objectif) - parseInt(r[0].messages)} messages** restants avant de passer au niveau supérieur`, + value: `**${(parseInt(r[0].objectif) - parseInt(r[0].messages)).toLocaleString('fr-DE')} messages** restants avant de passer au niveau supérieur`, inline: false } ) diff --git a/slash-commands/misc/drop.js b/slash-commands/misc/drop.js index af63cd3..4014820 100644 --- a/slash-commands/misc/drop.js +++ b/slash-commands/misc/drop.js @@ -33,13 +33,13 @@ module.exports = { .setDescription(`${package.emojis.gsdrop} Drop de <@${interaction.user.id}> !\n\nSoyez le premier à appuyer sur le bouton pour gagner !\n__**Récompense :**__ ${drop}`) .setColor(interaction.guild.me.displayHexColor) - const row = new Discord.MessageActionRow() + const row = new Discord.ActionRowBuilder() .setComponents( - new Discord.MessageButton() + new Discord.ButtonBuilder() .setCustomId('claim') .setLabel('Réclamer') .setEmoji(package.emojis.gsdrop) - .setStyle('SUCCESS') + .setStyle(Discord.ButtonStyle.Success) ); await interaction.reply({ embeds: [ embed ], components: [ row ] }).catch(() => {}); diff --git a/slash-commands/usefull/giveaway.js b/slash-commands/misc/giveaway.js similarity index 56% rename from slash-commands/usefull/giveaway.js rename to slash-commands/misc/giveaway.js index b71ba79..969b49f 100644 --- a/slash-commands/usefull/giveaway.js +++ b/slash-commands/misc/giveaway.js @@ -9,11 +9,6 @@ module.exports = { name: 'giveaway', description: "Giveaways", options: [ - { - name: 'liste', - description: "Affiche la liste des giveaways", - type: 'SUB_COMMAND' - }, { name: 'create', description: "Crée un giveaway", @@ -46,7 +41,25 @@ module.exports = { required: false, autocomplete: false, description: "Le salon dans lequel aura lieu le giveaway" - } + }, + { + name: "bonus", + type: 'STRING', + required: false, + description: "Identifiants des rôles bonus (séparés par un espace)" + }, + { + name: "requis", + type: 'STRING', + required: false, + description: "Identifiants des rôles requis (séparés par un espace)" + }, + { + name: "interdits", + type: 'STRING', + required: false, + description: "Identifiants des rôles interdits (séparés par un espace)" + }, ] }, { @@ -93,50 +106,51 @@ module.exports = { const client = interaction.client; const subCommand = interaction.options.getSubcommand(); - if (subCommand === 'liste') { - client.GiveawayManager.list(interaction.channel, interaction.user); - interaction.reply({ content: "Voici la liste", ephemeral: true }); - } else if (subCommand === 'create') { + if (subCommand === 'create') { const channel = interaction.options.get('salon') ? interaction.options.get('salon').channel : interaction.channel; const ms = require('ms'); if (!ms(interaction.options.get('temps').value)) return interaction.reply({ embeds: [ package.embeds.invalidTime(interaction.user) ], ephemeral: true }); - client.GiveawayManager.start(interaction.guild, channel, interaction.user, interaction.options.get('récompense').value, interaction.options.get('gagnants').value, ms(interaction.options.get('temps').value)); + let bonus = interaction.options.getString('bonus'); + let required = interaction.options.getString('requis'); + let denied = interaction.options.getString('interdits'); + + if (bonus) bonus = bonus.split(' '); + if (required) required = required.split(' '); + if (denied) denied = denied.split(' '); + if (!bonus) bonus = []; + if (!required) required = []; + if (!denied) denied = []; + + client.GiveawayManager.start({ + reward: interaction.options.getString('récompense'), + winnerCount: interaction.options.get('gagnants').value, + hosterId: interaction.user.id, + channel: channel, + time: ms(interaction.options.get('temps').value), + bonusRoles: bonus, + requiredRoles: required, + deniedRoles: denied + }); interaction.reply({ content: `Je lance un giveaway sur <#${channel.id}>`, ephemeral: true }); } else if (subCommand === 'end') { let id = interaction.options.get('id').value; - client.db.query(`SELECT * FROM giveaways WHERE channel_id="${interaction.channel.id}" AND guild_id="${interaction.guild.id}" AND ended="0"`, (err, req) => { - if (err) return interaction.reply({ embeds: [ package.embeds.errorSQL(interaction.user) ], ephemeral: true }); - - let gw = req.find(x => x.message_id === id); - if (!gw) return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) - .setTitle("Pas de giveaway") - .setColor('#ff0000') - .setDescription(`Je ne trouve pas de giveway avec l'id \`${id}\` qui n'est pas terminé dans <#${interaction.channel.id}>`) - ], ephemeral: true }); - - client.GiveawayManager.end(interaction.guild, gw); - interaction.reply({ content: "Je met fin à ce giveaway", ephemeral: true }); - }); + const result = interaction.client.GiveawayManager.end(id); + if (result == 'already ended') return interaction.reply({ embeds: [ package.embeds.giveaway.alreadyEnded(interaction.user) ] }).catch(() => {}); + if (['no giveaway', 'no guild', 'no channel', 'no message'].includes(result)) return interaction.reply({ embeds: [ package.embeds.giveaway.noGw(interaction.user, id) ] }).catch(() => {}); + + interaction.reply({ content: "Giveaway terminé", ephemeral: true }).catch(() => {}); } else if (subCommand === 'reroll') { let id = interaction.options.get('id').value; - client.db.query(`SELECT * FROM giveaways WHERE channel_id="${interaction.channel.id}" AND guild_id="${interaction.guild.id}" AND ended="1"`, (err, req) => { - if (err) return interaction.reply({ embeds: [ package.embeds.errorSQL(interaction.user) ], ephemeral: true }); - - let gw = req.find(x => x.message_id === id); - if (!gw) return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) - .setTitle("Pas de giveaway") - .setColor('#ff0000') - .setDescription(`Je ne trouve pas de giveway avec l'id \`${id}\` qui est terminé dans <#${interaction.channel.id}>`) - ], ephemeral: true }); - - client.GiveawayManager.reroll(interaction.guild, gw); - interaction.reply({ content: "Je reroll ce giveaway", ephemeral: true }); - }); + const result = interaction.client.GiveawayManager.reroll(id); + if (result == 'not ended') return interaction.reply({ embeds: [ package.embeds.giveaway.notEnded(interaction.user) ] }).catch(() => {}); + if (['no giveaway', 'no guild', 'no channel', 'no message'].includes(result)) return interaction.reply({ embeds: [ package.embeds.giveaway.noGw(interaction.user, id) ] }).catch(() => {}); + + interaction.reply({ content: "Je reroll ce giveaway", ephemeral: true }); } } } \ No newline at end of file diff --git a/slash-commands/misc/mailbox.js b/slash-commands/misc/mailbox.js new file mode 100644 index 0000000..a1bca5d --- /dev/null +++ b/slash-commands/misc/mailbox.js @@ -0,0 +1,18 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + dm: true, + dev: false + }, + configs: { + name: "mailbox", + description: "Ouvre votre boite mail" + }, + run: (interaction) => { + interaction.client.MailsManager.mailbox(interaction.user, 'none', interaction); + } +} \ No newline at end of file diff --git a/slash-commands/misc/say.js b/slash-commands/misc/say.js new file mode 100644 index 0000000..79c9aab --- /dev/null +++ b/slash-commands/misc/say.js @@ -0,0 +1,66 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + configs: { + name: 'say', + description: "Fait dire quelque chose à Oracle", + options: [ + { + name: 'texte', + type: 'STRING', + required: true, + description: "Texte à faire répéter" + } + ] + }, + help: { + cd: 5, + dev: false, + permissions: ['manage_guild'], + systems: [], + dm: false + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + let text = interaction.options.getString('texte'); + + await interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Répétition") + .setDescription(`Je répète ce que vous avez dit`) + .setColor('YELLOW') + ], ephemeral: true }).catch(() => {}); + const msg = await (await interaction.channel.send({ content: text }).catch(() => {})).url + await interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Répétition") + .setDescription(`J'ai répété ce que vous m'avez demandé de répéter`) + .setColor('#00ff00') + ] }).catch(() => {}); + + functions.log(interaction.guild, package.embeds.classic(interaction.user) + .setTitle("Message répété") + .setDescription(`Un [**message**](${msg}) a été répété dans <#${interaction.channel.id}>`) + .addFields( + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: "Salon", + value: `<#${interaction.channel.id}> ( ${interaction.channel.name} \`${interaction.channel.id}\` )`, + inline: true + }, + { + name: "Contenu", + value: text.length < 1024 ? text : `${text.substring(0, 1021)}...`, + inline: true + } + ) + .setColor('#ff0000') + ) + } +} \ No newline at end of file diff --git a/slash-commands/misc/suggestion.js b/slash-commands/misc/suggestion.js index 1b8cecf..011b826 100644 --- a/slash-commands/misc/suggestion.js +++ b/slash-commands/misc/suggestion.js @@ -1,6 +1,7 @@ const Discord = require('discord.js'); const { gsyes, gsno } = require('../../assets/data/emojis.json'); -const { classic } = require('../../assets/embeds.js'); +const { classic, errorSQL } = require('../../assets/embeds.js'); +const functions = require('../../assets/functions'); module.exports = { configs: { @@ -26,16 +27,31 @@ module.exports = { * @param {Discord.CommandInteraction} interaction */ run: (interaction) => { - if (!interaction.guild) return interaction.reply({ content: "Cette commande n'est disponible que dans un serveur" }); + const suggest = classic(interaction.user) + .setTitle("Suggestion") + .setDescription(`Nouvelle **suggestion** de <@${interaction.user.id}> :\n> ${interaction.options.getString('suggestion')}`) + .setColor(interaction.guild.me.displayHexColor); - interaction.reply({ embeds: [ classic(interaction.user) - .setTitle("Suggestion") - .setDescription(`Nouvelle **suggestion** de <@${interaction.user.id}> :\n> ${interaction.options.getString('suggestion')}`) - .setColor(interaction.guild.me.displayHexColor) - ] }).then(() => { - interaction.fetchReply().then(async(x) => { - [ gsyes, gsno ].forEach(async(y) => await x.react(y)); - }); - }); + interaction.client.db.query(`SELECT suggest_channel FROM configs WHERE guild_id="${interaction.guild.id}"`, (err, req) => { + if (err) { + functions.sendError(err, 'query fetch at /suggestion', interaction.user); + return interaction.reply({ embeds: [ errorSQL(interaction.user) ] }).catch(() => {}); + }; + const channel = interaction.guild.channels.cache.get(req[0]?.suggest_channel); + if (!channel) return interaction.reply({ embeds: [ classic(interaction.user) + .setTitle("Non configuré") + .setDescription(`Le salon de suggestions n'est pas configuré.\nUtilisez la commande \`/config configurer\``) + .setColor('#ff0000') + ] }).catch(() => {}); + + channel.send({ embeds: [ suggest ] }).then((x) => { + interaction.reply({ embeds: [ classic(interaction.user) + .setTitle("Suggestion envoyée") + .setDescription(`J'ai envoyé votre suggestion ( <#${channel.id}> )`) + .setColor('#00ff00') + ] }).catch(() => {}); + if (x) [ gsyes, gsno ].forEach(async(y) => await x.react(y)); + }).catch(() => {}); + }) } }; \ No newline at end of file diff --git a/slash-commands/moderation/autorole.js b/slash-commands/moderation/autorole.js new file mode 100644 index 0000000..1519834 --- /dev/null +++ b/slash-commands/moderation/autorole.js @@ -0,0 +1,136 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + systems: [{name: "de rôles d'arrivée", value: "roles_enable", state: true}], + permissions: ['manage_guild', 'manage_roles'], + dev: false, + dm: false + }, + configs: { + name: "autorole", + description: "Gère les rôles donnés automatiquement à l'arrivée sur le serveur", + options: [ + { + name: "ajouter", + description: "Ajoute un rôle automatiquement donné", + type: 'SUB_COMMAND', + options: [ + { + name: "rôle", + description: "Rôle à ajouter", + type: 'ROLE', + required: true + } + ] + }, + { + name: "retirer", + description: "Retirer un rôle automatiquement donné", + type: 'SUB_COMMAND', + options: [ + { + name: "rôle", + description: "Rôle à retirer", + type: 'ROLE', + required: true + } + ] + }, + { + name: "liste", + description: "Affiche la liste des rôles automatiques", + type: "SUB_COMMAND" + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + const subcommand = interaction.options.getSubcommand(); + + await interaction.reply({ embeds: [ package.embeds.waitForDb(interaction.user) ] }).catch(() => {}); + interaction.client.db.query(`SELECT role_id FROM roles_start WHERE guild_id="${interaction.guild.id}"`, (err, req) => { + if (err) { + functions.sendError(err, 'query fetch at /autorole', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + return; + }; + + if (subcommand == 'liste') { + if (req.length == 0) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Aucun rôle automatique") + .setDescription(`Aucun rôle automatique n'a été configuré`) + .setColor('#ff0000') + ] }).catch(() => {}); + + const embed = package.embeds.classic(interaction.user) + .setTitle("Rôles automatiques") + .setDescription(`Le${req.length > 1 ? 's rôles configurés' : ' rôle configuré'} sur ${interaction.guild.name} ${req.length > 1 ? 'sont':'est'} :\n${req.map(r => `<@&${r.role_id}>`).join(' ')}`) + .setColor(interaction.member.displayHexColor) + + interaction.editReply({ embeds: [ embed ] }).catch(() => {}); + }; + if (subcommand == 'ajouter') { + let role = interaction.options.getRole('rôle'); + if (role.position >= interaction.member.roles.highest.position) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("🚫 Rôle trop haut") + .setDescription(`Ce rôle est **supérieur** ou **égal** à vous dans la hiérarchie des rôles`) + .setColor(role.hexColor) + ] }).catch(() => {}); + + if (req.find(x => x.role_id == role.id)) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle déjà configuré") + .setDescription(`Le rôle <@&${role.id}> est déjà configuré sur ${interaction.guild.name}`) + .setColor(role.hexColor) + ] }).catch(() => {}); + + interaction.client.db.query(`INSERT INTO roles_start (guild_id, role_id) VALUES ("${interaction.guild.id}", '${role.id}')`, (er) => { + if (er) { + functions.sendError(er, 'query add at /autorole ajouter', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + return; + }; + + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle configuré") + .setDescription(`Le rôle <@&${role.id}> est maintenant un rôle donné automatiquement aux nouveaux membres`) + .setColor(role.hexColor) + ] }).catch(() => {}); + }); + }; + if (subcommand == 'retirer') { + let role = interaction.options.getRole('rôle'); + if (role.position >= interaction.member.roles.highest.position) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("🚫 Rôle trop haut") + .setDescription(`Ce rôle est **supérieur** ou **égal** à vous dans la hiérarchie des rôles`) + .setColor(role.hexColor) + ] }).catch(() => {}); + + if (!req.find(x => x.role_id == role.id)) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle non configuré") + .setDescription(`Le rôle <@&${role.id}> n'est pas configuré sur ${interaction.guild.name}`) + .setColor(role.hexColor) + ] }).catch(() => {}); + + interaction.client.db.query(`DELETE FROM roles_start WHERE guild_id="${interaction.guild.id}" AND role_id="${role.id}"`, (er) => { + if (er) { + functions.sendError(er, 'query remove at /autorole retirer', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + return; + }; + + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle configuré") + .setDescription(`Le rôle <@&${role.id}> n'est maintenant plus un rôle donné automatiquement aux nouveaux membres`) + .setColor(role.hexColor) + ] }).catch(() => {}); + }); + }; + }); + } +}; \ No newline at end of file diff --git a/slash-commands/moderation/ban.js b/slash-commands/moderation/ban.js index cf9dbe4..f35b766 100644 --- a/slash-commands/moderation/ban.js +++ b/slash-commands/moderation/ban.js @@ -34,11 +34,11 @@ module.exports = { * @param {Discord.CommandInteraction} interaction */ run: (interaction) => { - const member = interaction.options.get('member').member; + const member = interaction.options.get('membre').member; const reason = interaction.options.get('raison').value; if (reason.includes('"')) return interaction.reply({ embeds: [ package.embeds.guillement(interaction.user) ] }); - if (!functions.checkAllConditions(interaction.guild, interaction.channel, interaction.member, member, interaction)) return; + if (!functions.checkPerms({ interaction, member, mod: interaction.member, checkBotCompare: true, checkOwner: true, checkSelfUser: true })) return; const banned = package.embeds.classic(interaction.user) .setTitle("Bannissement") diff --git a/slash-commands/moderation/censure.js b/slash-commands/moderation/censure.js new file mode 100644 index 0000000..34c9d62 --- /dev/null +++ b/slash-commands/moderation/censure.js @@ -0,0 +1,77 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + permissions: ['manage_nicknames'], + systems: [], + dm: false, + dev: false + }, + configs: { + name: 'censure', + description: "Censure le pseudo d'un membre", + options: [ + { + name: 'membre', + description: "Membre à censurer", + type: 'USER', + required: true + }, + { + name: 'raison', + description: "Raison de la censure", + type: 'STRING', + required: true + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: (interaction) => { + let member = interaction.options.getMember('membre'); + let reason = interaction.options.getString('raison'); + if (!functions.checkPerms({ member, interaction, mod: interaction.member, all: true })) return; + + const caracts = "0132456798#&@%*:/;,?!§^$*"; + let nickname = ""; + + const max = member?.nick?.length ?? functions.random(16, 8); + for (let i = 0; i (${interaction.user.tag})`, + inline: true + }, + { + name: "Membre", + value: `<@${member.id}> (${member.user.tag})`, + inline: true + }, + { + name: 'Raison', + value: reason, + inline: true + } + ) + + member.setNickname(nickname, reason).catch(() => {}); + + interaction.reply({ embeds: [ embed ] }).catch(() => {}); + member.send({ embeds: [embed] }).catch(() => {}); + + functions.log(interaction.guild, embed); + functions.addCase(interaction.guild.id, member.id, interaction.user.id, reason, 'censure'); + } +} \ No newline at end of file diff --git a/slash-commands/usefull/channel.js b/slash-commands/moderation/channel.js similarity index 64% rename from slash-commands/usefull/channel.js rename to slash-commands/moderation/channel.js index 4a94a43..fcdca98 100644 --- a/slash-commands/usefull/channel.js +++ b/slash-commands/moderation/channel.js @@ -118,6 +118,44 @@ module.exports = { type: 'CHANNEL' } ] + }, + { + name: "décrire", + type: 'SUB_COMMAND', + description: "Configure la description d'un salon", + options: [ + { + name: "salon", + description: "Salon à décrire", + type: 'CHANNEL', + required: false + }, + { + name: "description", + type: 'STRING', + required: false, + description: "Description à donner au salon (laisser vide pour réinitialiser)" + } + ] + }, + { + name: "identifier", + description: "Affiche l'identifiant d'un salon", + type: 'SUB_COMMAND', + options: [ + { + name: "salon", + description: "Salon à identifier", + type: 'CHANNEL', + required: false + }, + { + name: 'embed', + description: "Affiche la réponse sous forme d'embed (plus compliqué pour copier/coller)", + required: false, + type: 'BOOLEAN' + } + ] } ] }, @@ -133,6 +171,42 @@ module.exports = { */ run: (interaction) => { const subcommand = interaction.options.getSubcommand(); + + if (subcommand == 'identifier') { + let channel = interaction.options.getChannel('salon') ?? interaction.channel; + let embed = interaction.options.getBoolean('embed') ?? false; + + let id = channel.id; + let reply = {}; + if (embed == true) { + reply.embeds = [ package.embeds.classic(interaction.user) + .setTitle('Identifiant') + .setDescription(`L'identifiant ${channel.type == 'GUILD_CATEGORY' ? "de la catégorie" : "du salon"} ${channel.type == "GUILD_TEXT" ? `<#${id}>`:channel.name} est \`${id}\``) + .setColor('ORANGE') + ]; + } else { + reply.content = `\`${id}\``; + }; + + interaction.reply(reply).catch(() => {}); + }; + if (subcommand == "décrire") { + let channel = interaction.options.getChannel('salon') ?? interaction.channel; + let description = interaction.options.getString('description'); + + if (channel.type !== 'GUILD_TEXT') return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Salon invalide") + .setDescription(`Je ne peux modifier la description que d'un **salon textuel**${functions.random(10 == 2) ? ` (et aux dernières nouvelles, ${channel.name} n'en est pas un)`:''}`) + .setColor('#ff0000') + ] }).catch(() => {}); + + channel.setTopic(description ?? null).catch(() => {}); + interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Description mise à jour") + .setDescription(`La description de <#${channel.id}> a été ${description ? `mise sur \`\`\`${description}\`\`\``:'réinitialisée'}`) + .setColor(interaction.guild.me.displayHexColor) + ] }).catch(() => {}); + } if (subcommand == 'créer') { let name = interaction.options.getString('nom'); let type = interaction.options.getString('type'); @@ -161,9 +235,32 @@ module.exports = { .setTitle("Salon crée") .setDescription(`Salon crée par <@${interaction.user.id}>`) .setColor('ORANGE') - ] }); + ] }).catch(() => {}); }; - }); + + functions.log(interaction.guild, package.embeds.classic(interaction.user) + .setTitle("Salon crée") + .setDescription(`Le salon <#${channel.id}> a été crée par <@${interaction.user.id}> **(avec la commande \`/salon créer\`)**`) + .setColor('#00ff00') + .addFields( + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: "Salon", + value: `<#${channel.id}> ( ${package.channelTypes[channel.type]} \`${channel.id}\` )`, + inline: true + }, + { + name: "Date", + value: ` ( ${(Date.now() / 1000).toFixed(0)}:R> )`, + inline: true + } + ) + ); + }).catch(() => {}); }; if (subcommand == 'supprimer') { let channel = interaction.options.get('salon')?.channel || interaction.channel; @@ -172,7 +269,7 @@ module.exports = { .setTitle("Supression") .setDescription(`<#${channel.id}> sera supprimé `) .setColor('ORANGE') - ], components: [ new Discord.MessageActionRow({ components: [ new Discord.MessageButton({ label: 'Annuler', style: 'DANGER', customId: 'cancel' }) ] }) ] }).then(() => { + ], components: [ new Discord.ActionRowBuilder({ components: [ new Discord.MessageButton({ label: 'Annuler', style: 'DANGER', customId: 'cancel' }) ] }) ] }).then(() => { interaction.fetchReply().then((reply) => { const collector = reply.createMessageComponentCollector({ filter: x => x.user.id == interaction.user.id, time: 5000, max: 1 }); @@ -184,6 +281,24 @@ module.exports = { .setDescription(`Le salon ${channel.name} a été supprimé`) .setColor('ORANGE') ], components: [] }); + + functions.log(interaction.guild, package.embeds.classic(interaction.user) + .setTitle("Salon supprimé") + .setDescription(`Le salon ${channel.name} ( ${package.channelTypes[channel.type]} \`${channel.id}\` ) a été supprimé **(avec la commande \`/salon supprimer\`)**`) + .addFields( + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: 'Salon', + value: `${channel.name} ( ${package.channelTypes[channel.type]} \`${channel.id}\` )`, + inline: true + } + ) + .setColor('#ff0000') + ); } else { reply.edit({ embeds: [ package.embeds.cancel() ], components: [] }).catch(() => {}); }; diff --git a/slash-commands/moderation/clear.js b/slash-commands/moderation/clear.js new file mode 100644 index 0000000..8f9b2d0 --- /dev/null +++ b/slash-commands/moderation/clear.js @@ -0,0 +1,67 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + permissions: ['manage_messages'], + cd: 5, + dm: false, + dev: false, + systems: [] + }, + configs: { + name: 'clear', + description: "Supprime un nombre de messages dans le salon", + options: [ + { + name: 'messages', + description: "Nombre de messages à supprimer", + required: true, + type: 'INTEGER' + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + let number = parseInt(interaction.options.get('messages').value); + if (number < 1 || number > 100) return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("🚫 Nombre invalide") + .setDescription(`Merci de saisir un nombre entre **1** et **100**`) + .setColor('#ff0000') + ] }).catch(() => {}); + + await interaction.channel.bulkDelete(number).catch(() => {}); + interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("✅ Messages supprimés") + .setDescription(`**${number}** message${number > 1 ? 's ont été supprimés':' a été supprimé'}.`) + .setColor('#00ff00') + ] }).catch(() => {}); + + const logEmbed = package.embeds.classic(interaction.user) + .setTitle("Messages supprimés") + .setDescription(`**${number}** message${number > 1 ? 's ont été supprimés' : ' a été supprimé'}.`) + .addFields( + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: "Salon", + value: `<#${interaction.channel.id}> ( ${interaction.channel.name} \`${interaction.channel.id}\` )`, + inline: true + }, + { + name: "Messages", + value: `${number} message${number > 1 ? 's':''}`, + inline: true + } + ) + .setColor('#ff0000') + + functions.log(interaction.guild, logEmbed); + } +} \ No newline at end of file diff --git a/slash-commands/moderation/demote.js b/slash-commands/moderation/demote.js index 16ba1a1..93ad743 100644 --- a/slash-commands/moderation/demote.js +++ b/slash-commands/moderation/demote.js @@ -59,7 +59,7 @@ module.exports = { */ run: async(interaction) => { let member = interaction.options.getMember('utilisateur'); - if (!functions.checkAllConditions(interaction.guild, interaction.channel, interaction.member, member, interaction)) return; + if (!functions.checkPerms({ member, interaction, mod: interaction.member, checkBotCompare: true, checkSelfUser: true, checkOwner: true })) return; let select = interaction.options.getSubcommand(); await interaction.guild.roles.fetch(); diff --git a/slash-commands/moderation/edit-case.js b/slash-commands/moderation/edit-case.js index e810246..80e33d3 100644 --- a/slash-commands/moderation/edit-case.js +++ b/slash-commands/moderation/edit-case.js @@ -27,7 +27,7 @@ module.exports = { dm: false, dev: false, permissions: ['manage_guild'], - systems: [], + systems: [{name: 'de logs', value: 'logs_enable', state: true}], cd: 5 }, /** diff --git a/slash-commands/moderation/filtre-case-action.js b/slash-commands/moderation/filtre-case-action.js index 21371ca..d69a8ae 100644 --- a/slash-commands/moderation/filtre-case-action.js +++ b/slash-commands/moderation/filtre-case-action.js @@ -1,6 +1,7 @@ const Discord = require('discord.js'); const functions = require('../../assets/functions'); const package = functions.package(); +const moment = require('moment'); module.exports = { configs: { @@ -18,9 +19,13 @@ module.exports = { name: 'Bannissements', value: 'ban' }, + { + name: 'Softbannissements', + value: 'softban' + }, { name: 'Avertissements', - value: 'warn' + value: 'avertissement' }, { name: 'Réduction au silence', @@ -41,6 +46,14 @@ module.exports = { { name: 'Débanissement', value: "unban" + }, + { + name: "Modification de pseudo", + value: 'pseudo modifié' + }, + { + name: "Réinitialisation de pseudo", + value: 'pseudo réinitialisé' } ] } @@ -50,7 +63,7 @@ module.exports = { dm: false, dev: false, permissions: ['manage_guild'], - systems: [], + systems: [{name: 'de logs', value: 'logs_enable', state: true}], cd: 5 }, /** @@ -77,7 +90,7 @@ module.exports = { for (let i = 0; i < req.length; i++) { const warn = req[i]; - now.addField(action, `<@${warn.user_id}>\n> Donné par <@${warn.mod_id}>\n> Raison: \`${warn.reason}\`\n> Date: `, false); + now.addField(action, `<@${warn.user_id}>\n> Donné par <@${warn.mod_id}>\n> Raison: ${warn.reason}\n> Date: `, false); pile = false; @@ -106,7 +119,7 @@ module.exports = { .setDescription(`Voici la liste des logs de ${action}`) req.forEach((warn) => { - embed.addField(action, `<@${warn.user_id}>\n> Donné par <@${warn.mod_id}>\n> Raison: \`${warn.reason}\`\n> Date: `, false); + embed.addField(action, `<@${warn.user_id}>\n> Donné par <@${warn.mod_id}>\n> Raison: ${warn.reason}\n> Date: `, false); }); interaction.reply({ embeds: [ embed ] }); diff --git a/slash-commands/moderation/infractions.js b/slash-commands/moderation/infractions.js new file mode 100644 index 0000000..fe410d3 --- /dev/null +++ b/slash-commands/moderation/infractions.js @@ -0,0 +1,95 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); +const moment = require('moment'); + +module.exports = { + help: { + cd: 5, + permissions: ['manage_guild'], + dev: false, + dm: false + }, + configs: { + name: 'infractions', + description: "Affiche toutes les infractions d'un utilisateur", + options: [ + { + name: 'membre', + description: "Membre dont vous voulez voir les infractions", + required: false, + type: 'USER' + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + let member = interaction.options.getMember('membre') ?? interaction.member; + await interaction.reply({ embeds: [ package.embeds.waitForDb(interaction.user) ] }).catch(() => {}); + + interaction.client.db.query(`SELECT * FROM mod_cases WHERE user_id="${member.id}" AND guild_id="${interaction.guild.id}"`, (err, req) => { + if (err) { + functions.sendError(err, 'query fetch at /infractions', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + return; + }; + + if (req.length === 0) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Pas d'infractions") + .setDescription(`<@${member.id}> n'a aucune infraction sur ce serveur.`) + .setColor('GREEN') + ] }); + + if (req.length > 5) { + let now = package.embeds.classic(interaction.user) + .setTitle("Infractions") + .setDescription(`Voici la liste des infractions de <@${member.id}>.`) + .setColor('ORANGE') + + var embeds = []; + let pile = false; + let count = 0; + + for (let i = 0; i < req.length; i++) { + const warn = req[i]; + + now.addField(`Infraction`, `${warn.action}\n> Donné par <@${warn.mod_id}>\n> Raison: ${warn.reason}\n> Date: `, false); + + pile = false; + + count++; + if (count === 5) { + count=0; + pile = true; + embeds.push(now); + + now = null; + now = package.embeds.classic(interaction.user) + .setTitle("Infractions") + .setDescription(`Voici la liste des infractions de <@${member.id}>.`) + .setColor('ORANGE') + + } + }; + + if (!pile) embeds.push(now); + + functions.pagination(interaction.user, 'none', embeds, `infractions de ${member.user.tag}`, interaction); + } else { + const embed = package.embeds.classic(interaction.user) + .setTitle("Infractions") + .setColor('ORANGE') + .setDescription(`<@${member.id}> a **${req.length}** infractions`) + .setColor('ORANGE') + + req.forEach((warn) => { + embed.addField(`Infraction`, `${warn.action}\n> Donné par <@${warn.mod_id}>\n> Raison: ${warn.reason}\n> Date: `, false); + }); + + interaction.editReply({ embeds: [ embed ] }); + }; + }) + } +} \ No newline at end of file diff --git a/slash-commands/moderation/kick.js b/slash-commands/moderation/kick.js index 783ab41..47e4eeb 100644 --- a/slash-commands/moderation/kick.js +++ b/slash-commands/moderation/kick.js @@ -38,7 +38,7 @@ module.exports = { const reason = interaction.options.get('raison').value; if (reason.includes('"')) return interaction.reply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }); - if (!functions.checkAllConditions(interaction.guild, interaction, interaction.member, member, interaction)) return; + if (!functions.checkPerms({ member, interaction, mod: interaction.member, checkBotCompare: true, checkSelfUser: true, checkOwner: true })) return; const kicked = package.embeds.classic(interaction.user) .setTitle("Expulsion") @@ -48,7 +48,7 @@ module.exports = { .addFields( { name: 'Modérateur', - value: `<@${interaction.user}> ( ${interaction.user.tag} ${interaction.user.id} )`, + value: `<@${interaction.user.id}> ( ${interaction.user.tag} ${interaction.user.id} )`, inline: true }, { @@ -69,6 +69,6 @@ module.exports = { member.kick(reason).catch(() => {}); functions.log(interaction.guild, kicked); - functions.addCase(interaction.guild, member.id, interaction.user.id, reason, 'kick'); + functions.addCase(interaction.guild.id, member.id, interaction.user.id, reason, 'kick'); } } \ No newline at end of file diff --git a/slash-commands/moderation/logs.js b/slash-commands/moderation/logs.js new file mode 100644 index 0000000..c32ec02 --- /dev/null +++ b/slash-commands/moderation/logs.js @@ -0,0 +1,151 @@ +const Discord = require('discord.js'); +const moment = require('moment'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + dev: false, + dm: false, + systems: [{name: 'de logs', value: 'logs_enable', state: true}], + permissions: ['manage_guild'] + }, + configs: { + name: 'logs', + description: "Gère les logs du serveur", + options: [ + { + name: "afficher", + description: "Affiche les logs du serveur", + type: 'SUB_COMMAND' + }, + { + name: 'identifier', + description: "Affiche un log spécifique", + type: 'SUB_COMMAND', + options: [ + { + name: 'identifiant', + description: "Identifiant du log que vous voulez voir", + type: 'STRING', + required: true + } + ] + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + await interaction.reply({ embeds: [ package.embeds.waitForDb(interaction.user) ] }).catch(() => {}); + const subcommand = interaction.options.getSubcommand(); + + if (subcommand == 'afficher') { + interaction.client.db.query(`SELECT * FROM mod_cases WHERE guild_id="${interaction.guild.id}"`, (err, req) => { + if (err) { + functions.sendError(err, 'query fetch at /logs afficher', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + return; + }; + + if (req.length == 0) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("🚫 Logs de modération") + .setDescription(`Il n'y a aucun log de modération.`) + .setColor('ORANGE') + ] }).catch(() => {}); + + if (req.length > 5) { + let now = package.embeds.classic(interaction.user) + .setTitle("Logs de modération") + .setDescription(`Voici les logs de modération (**${req.length.toLocaleString('fr-DE')}** logs).`) + .setColor('ORANGE') + + var embeds = []; + let pile = false; + let count = 0; + + for (let i = 0; i < req.length; i++) { + const warn = req[i]; + + now.addField(`${warn.action}`, `<@${warn.user_id}>\n> Donné par <@${warn.mod_id}>\n> Raison: \`${warn.reason}\`\n> Date: \n*Log id: ${warn.case_id}*`, false); + + pile = false; + + count++; + if (count === 5) { + count=0; + pile = true; + embeds.push(now); + + now = null; + now = package.embeds.classic(interaction.user) + .setTitle("Logs de modération") + .setDescription(`Voici les logs de modération (**${req.length.toLocaleString('fr-DE')}** logs).`) + .setColor('ORANGE') + }; + }; + + if (!pile) embeds.push(now); + + functions.pagination(interaction.user, 'none', embeds, 'modlogs', interaction); + } else { + const embed = package.embeds.classic(interaction.user) + .setTitle("Logs de modération") + .setColor('ORANGE') + .setDescription(`voici les logs de modération.`) + + req.forEach((warn) => { + embed.addField(`${warn.action}`, `<@${warn.user_id}>\n> Donné par <@${warn.mod_id}> \n> Raison: \`${warn.reason}\`\n> Date: \n*Log id: ${warn.case_id}*`, false); + }); + + interaction.editReply({ embeds: [ embed ] }).catch(() => {}); + } + }) + }; + if (subcommand == 'identifier') { + let id = interaction.options.getString('identifiant'); + interaction.client.db.query(`SELECT * FROM mod_cases WHERE guild_id="${interaction.guild.id}" AND case_id="${id}"`, (err, req) => { + if (err) { + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + functions.sendError(err, 'query at /logs identifier', interaction.user); + return; + }; + if (req.length == 0) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("🚫 Pas de log") + .setDescription(`Le log avec \`${id}\` pour identifiant n'existe pas`) + .setColor('#ff0000') + ] }).catch(() => {}); + + const log = req[0]; + const modlog = package.embeds.classic(interaction.user) + .setTitle(log.action) + .addFields( + { + name: "Membre", + value: `<@${log.user_id}> (\`${log.user_id}\`)`, + inline: true + }, + { + name: "Modérateur", + value: `<@${log.mod_id}> (\`${log.mod_id}\`)`, + inline: true + }, + { + name: "Raison", + value: log.reason ?? "Pas de raison", + inline: true + }, + { + name: "Date", + value: ``, + inline: false + } + ) + + interaction.editReply({ embeds: [ modlog ] }).catch(() => {}); + }); + } + } +} \ No newline at end of file diff --git a/slash-commands/moderation/mute.js b/slash-commands/moderation/mute.js new file mode 100644 index 0000000..23922da --- /dev/null +++ b/slash-commands/moderation/mute.js @@ -0,0 +1,120 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +const minutes = (n) => n * 1000 * 60; + +module.exports = { + help: { + cd: 5, + dev: false, + dm: false, + systems: [], + permissions: ['manage_guild'] + }, + configs: { + name: 'mute', + description: "Mute un membre du serveur", + options: [ + { + name: "membre", + type: 'USER', + description: "Membre à muter", + required: true + }, + { + name: 'raison', + type: 'STRING', + description: "Raison du mute", + required: true + }, + { + name: 'durée', + type: 'INTEGER', + description: "Durée du mute", + required: false, + choices: [ + { + name: "5 minutes", + value: minutes(5) + }, + { + name: '10 minutes', + value: minutes(10) + }, + { + name: '20 minutes', + value: minutes(20) + }, + { + name: '30 minutes', + value: minutes(30) + }, + { + name: '45 minutes', + value: minutes(45) + }, + { + name: '1 heure', + value: minutes(60) + }, + { + name: '2 heures', + value: minutes(120) + }, + { + name: '6 heures', + value: minutes(120*3) + }, + { + name: '1 jour', + value: minutes(60*24) + } + ] + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: (interaction) => { + let member = interaction.options.getMember('membre'); + let reason = interaction.options.getString('raison'); + let time = parseInt(interaction.options.get('durée').value); + + if (!functions.checkPerms({ interaction, member, mod: interaction.member, all: true })) return; + if (reason.includes('"')) return interaction.reply({ embeds: [ package.embeds.guillement(interaction.user) ] }).catch(() => {}); + + interaction.member.timeout(time, reason); + const embed = package.embeds.classic(interaction.user) + .setTitle("Mute") + .setDescription(`<@${interaction.user.id}> a rendu <@${member.id}> muet.`) + .addFields( + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( \`${interaction.user.id}\` ${interaction.user.tag} )`, + inline: true + }, + { + name: "Membre", + value: `<@${member.id}> ( \`${member.id}\` ${member.user.tag} )`, + inline: true + }, + { + name: 'raison', + value: reason, + inline: true + }, + { + name: "Durée", + value: `<@${member.id}> sera démuté `, + inline: false + } + ) + .setColor('#ff0000') + + interaction.reply({ embeds: [ embed ] }).catch(() => {}); + functions.log(interaction.guild, embed); + functions.addCase(interaction.guild.id, member.id, interaction.user.id, reason, 'mute'); + } +} \ No newline at end of file diff --git a/slash-commands/moderation/notes.js b/slash-commands/moderation/notes.js new file mode 100644 index 0000000..63debc1 --- /dev/null +++ b/slash-commands/moderation/notes.js @@ -0,0 +1,207 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + permissions: ['manage_guild'], + systems: [], + dev: false, + dm: false + }, + configs: { + name: 'note', + description: "Système de notes de membres", + options: [ + { + name: 'lire', + description: "Lis la note d'un membre", + type: 'SUB_COMMAND', + options: [ + { + name: "membre", + type: 'USER', + description: "Membre dont vous voulez lire la note", + required: true + } + ] + }, + { + name: "écrire", + description: "Écrit une note pour un membre", + type: 'SUB_COMMAND', + options: [ + { + name: 'membre', + description: "Membre que vous voulez noter", + required: true, + type: 'USER' + }, + { + name: 'note', + description: "Note à mettre sur le membre", + required: true, + type: 'STRING' + } + ] + }, + { + name: "supprimer", + description: "Supprime la note d'un membre", + type: 'SUB_COMMAND', + options: [ + { + name: "membre", + description: "Membre dont vous voulez supprimer la note", + type: 'USER', + required: true + } + ] + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + const subcommand = interaction.options.getSubcommand(); + let member = interaction.options.getMember('membre'); + const condition = `WHERE guild_id="${interaction.guild.id}" AND user_id="${member.id}"`; + + if (!functions.checkPerms({ interaction, member, mod: interaction.member, checkOwner: true, checkBot: true, checkSelfUser: true })) return; + await interaction.reply({ embeds: [ package.embeds.waitForDb(interaction.user) ] }).catch(() => {}); + + interaction.client.db.query(`SELECT note FROM notes ${condition}`, (err, req) => { + if (err) { + functions.sendError(err, 'query fetch at /note', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + return; + }; + + if (subcommand == 'lire') { + if (req.length == 0) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Pas de notes") + .setDescription(`<@${member.id}> n'a pas de note`) + .setColor('#ff0000') + ] }).catch(() => {}); + + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Note") + .setDescription('```' + req[0].note + '```') + .setColor(member.displayHexColor) + ] }).catch(() => {}); + }; + if (subcommand == 'écrire') { + let note = interaction.options.getString('note'); + if (note.length > 255) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Note trop longue") + .setDescription(`Votre description fait **${note.length}** caractères, le maximum étant de **255**`) + .setColor('#ff0000') + ] }).catch(() => {}); + + note = note.replace('"', '\\"'); + let sql = `INSERT INTO notes (guild_id, user_id, note) VALUES ("${interaction.guild.id}", "${member.id}", "${note}")`; + if (req.length > 0) sql = `UPDATE notes SET note="${note}" ${condition}`; + + interaction.client.db.query(sql, (error) => { + if (error) { + functions.sendError(error, 'query set at /notes écrire', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + console.log(error); + return; + }; + + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Note modifiée") + .setDescription(`La note de <@${member.id}> a été modifiée en \`\`\`${note}\`\`\``) + .setColor(member.displayHexColor) + ] }).catch(() => {}); + const fields = [ + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: "Membre", + value: `<@${member.id}> ( ${member.user.tag} \`${member.id}\` )`, + inline: true + } + ]; + if (req.length > 0) { + fields.push({ + name: "Avant", + value: req[0].note, + inline: false + }, + { + name: "Après", + value: note, + inline: true + }) + } else { + fields.push({ + name: "Note", + value: note, + inline: false + }); + }; + + functions.log(interaction.guild, package.embeds.classic(interaction.user) + .setTitle("Note modifiée") + .setDescription(`Une note a été modifiée`) + .addFields(fields) + .setColor('YELLOW') + ); + }); + }; + if (subcommand == 'supprimer') { + if (req.length == 0) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Pas de notes") + .setDescription(`<@${member.id}> n'a pas de note`) + .setColor('#ff0000') + ] }).catch(() => {}); + + interaction.client.db.query(`DELETE FROM notes ${condition}`, (error) => { + if (error) { + functions.sendError(error, 'query set at /notes supprimer', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + console.log(error); + return; + }; + + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Note modifiée") + .setDescription(`La note de <@${member.id}> a été supprimée`) + .setColor(member.displayHexColor) + ] }).catch(() => {}); + const fields = [ + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: "Membre", + value: `<@${member.id}> ( ${member.user.tag} \`${member.id}\` )`, + inline: true + }, + { + name: "Note", + value: req[0].note, + inline: false + } + ]; + + functions.log(interaction.guild, package.embeds.classic(interaction.user) + .setTitle("Note supprimée") + .setDescription(`Une note a été supprimée`) + .addFields(fields) + .setColor('#ff0000') + ); + }) + }; + }); + } +}; \ No newline at end of file diff --git a/slash-commands/moderation/nuke.js b/slash-commands/moderation/nuke.js new file mode 100644 index 0000000..b388020 --- /dev/null +++ b/slash-commands/moderation/nuke.js @@ -0,0 +1,109 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + systems: [], + dev: false, + dm: false, + permissions: ['manage_channels'] + }, + configs: { + name: 'nuke', + description: "Nuke un salon", + options: [ + { + name: "salon", + description: "Salon à nuker", + type: 'CHANNEL', + required: true + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + let channel = interaction.options.getChannel('salon'); + if (channel.id == interaction.channel.id) return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Salon invalide") + .setDescription(`Je ne peux pas nuker ce salon, car c'est celui dans lequel la commande a été effectuée.`) + .setColor('#ff0000') + ] }).catch(() => {}); + + if (!['GUILD_NEWS', 'GUILD_TEXT'].includes(channel.type)) return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Salon invalide") + .setDescription(`Je ne peux nuker que des salons textuels`) + .setColor('#ff0000') + ] }).catch(() => {}); + + await interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Nuke") + .setDescription(`Le salon <#${channel.id}> sera nuké `) + .setColor('YELLOW') + ], components: [ new Discord.MessageActionRow({ components: [ new Discord.MessageButton({ label: 'Annuler', style: 'DANGER', customId: 'cancel' }) ] }) ] }).catch(() => {}); + const msg = await interaction.fetchReply(); + const collector = msg.createMessageComponentCollector({ fliter: x => x.user.id == interaction.user.id, max: 1, time: 5000 }); + + collector.on('end', async(collected) => { + if (collected.size == 1) return interaction.editReply({ embeds: [ package.embeds.cancel() ], components: [] }).catch(() => {}); + await interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Nuke") + .setDescription(`Le salon <#${channel.id}> est en cours de nettoyage ${package.emojis.loading}`) + .setColor('YELLOW') + ], components: [] }).catch(() => {}); + + const propreties = { + name: channel.name, + topic: channel.topic, + nsfw: channel.nsfw, + permissionOverwrites: channel.permissionOverwrites.cache, + type: channel.type, + rawPosition: channel.rawPosition, + position: channel.position, + calculatedPosition: channel.calculatedPosition + }; + if(channel.parent) propreties.parent = channel.parent; + + await channel.delete().catch(() => {}); + const channelN = await (interaction.guild.channels.create(channel.name, propreties).catch(() => {})); + channelN.setPosition(propreties.position); + + if (!channelN) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Erreur") + .setDescription(`Une erreur a eu lieu lors du nuke du salon`) + .setColor('#ff0000') + ], components: [] }).catch(() => {}); + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Salon nuké") + .setDescription(`Le salon <#${channelN.id}> a été nuké`) + .setColor("#00ff00") + ], components: [] }).catch(() => {}); + + channelN.send({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Nuke") + .setDescription(`Le salon a bien été réinitialisé !`) + .setColor(interaction.guild.me.displayHexColor) + ], components: [] }).catch(() => {}); + functions.log(interaction.guild, package.embeds.classic(interaction.user) + .setTitle("Nuke") + .setDescription(`Un [salon](https://discord.com/channels/${interaction.guild.id}/${channelN.id}) a été nuké`) + .addFields( + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: "Salon", + value: `<#${channelN.id}> ( ${channel.name} \`${channel.id}\` )`, + inline: true + } + ) + .setColor('#ff0000') + ) + }) + } +} \ No newline at end of file diff --git a/slash-commands/moderation/prefix.js b/slash-commands/moderation/prefix.js index 55a11c1..cac8a8a 100644 --- a/slash-commands/moderation/prefix.js +++ b/slash-commands/moderation/prefix.js @@ -38,6 +38,12 @@ module.exports = { * @param {Discord.CommandInteraction} interaction */ run: async(interaction) => { + await interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Passage en slash commande") + .setDescription(`Depuis le passage en slash commandes (depuis le pour être exact), Oracle est passé en slash commandes.\nDepuis, le préfixe n'est plus utilisable`) + .setColor('#ff0000') + ] }); + return; await interaction.reply({ embeds: [ package.embeds.waitForDb(interaction.user) ] }); interaction.client.db.query(`SELECT prefix FROM prefixes WHERE guild_id="${interaction.guild.id}"`, (err, req) => { diff --git a/slash-commands/moderation/pseudo.js b/slash-commands/moderation/pseudo.js new file mode 100644 index 0000000..dee1eaa --- /dev/null +++ b/slash-commands/moderation/pseudo.js @@ -0,0 +1,115 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + dev: false, + dm: false, + permissions: ['manage_nicknames'] + }, + configs: { + name: 'pseudo', + description: "Gère le pseudo d'un membre", + options: [ + { + name: "définir", + description: "Définit le pseudo d'un membre", + type: 'SUB_COMMAND', + options: [ + { + name: "pseudo", + description: "Pseudo à donner au membre", + required: true, + type: 'STRING' + }, + { + name: 'membre', + description: "Membre à renommer", + required: false, + type: 'USER' + } + ] + }, + { + name: "réinitialiser", + description: "Réinitialise le pseudo d'un membre", + type: 'SUB_COMMAND', + options: [ + { + name: 'membre', + required: false, + description: "Membre à renommer", + type: 'USER' + } + ] + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: (interaction) => { + const subcommand = interaction.options.getSubcommand(); + const member = interaction.options.getMember('membre') ?? interaction.member; + + let before = member.nickname ?? member.user.username; + if (!functions.checkPerms({ interaction, member, mod: interaction.member, checkBotCompare: true, checkOwner: true })) return; + let nickname = interaction.options.get('pseudo')?.value ?? null; + + member.setNickname(nickname).catch(() => {}); + + let reset = subcommand == 'réinitialiser'; + interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle(`Pseudo ${reset ? 'réinitialisé':'modifié'}`) + .setDescription(reset ? `Le pseudo de <@${member.id}> a été réinitialisé`: `Le pseudo de <@${member.id}> a été changé en ${nickname}`) + .setColor(member.displayHexColor) + ] }).catch(() => {}); + + let action = reset ? 'pseudo réinitialisé':'pseudo modifié'; + + const fields = [ + { + name: 'Modérateur', + value: `<@${interaction.user.id}> ( ${interaction.user.tag} ${interaction.user.id} )`, + inline: true + }, + { + name: 'Membre', + value: `<@${member.id}> ( ${member.user.tag} ${member.id} )`, + inline: true + } + ]; + let embed = package.embeds.classic(interaction.user) + .setTitle(functions.capitalize(action)) + .setDescription(`Le pseudo de <@${member.id}> a été réinitialisé`) + .setColor('#ff0000') + + if (!reset) { + embed.setDescription(`Le pseudo de <@${member.id}> a été modifié`) + fields.push({name: '\u200b', value: '\u200b', inline: false}) + fields.push({ + name: "Avant", + value: before, + inline: true + }, + { + name: 'Après', + value: nickname, + inline: true + }); + } else { + fields.push({ + name: 'Pseudo', + value: before, + inline: true + }); + }; + + embed.addFields(fields); + functions.log(interaction.guild, embed); + + functions.addCase(interaction.guild.id, member.id, interaction.user.id, reset ? `Ancien pseudo : ${before}` : `Ancien pseudo : ${before}\n\nNouveau pseudo : ${nickname}`, action.toLowerCase()); + } +}; \ No newline at end of file diff --git a/slash-commands/moderation/role.js b/slash-commands/moderation/role.js index 1b522c6..4b38349 100644 --- a/slash-commands/moderation/role.js +++ b/slash-commands/moderation/role.js @@ -1,6 +1,7 @@ const Discord = require('discord.js'); const functions = require('../../assets/functions'); const package = functions.package(); +const perms = Object.keys(package.perms).filter(x => x!== "USE_VAD").sort().map(x => ({ name: package.perms[x], value: x })); module.exports = { configs: { @@ -133,6 +134,75 @@ module.exports = { required: true } ] + }, + { + name: "identifier", + description: "Affiche l'identifiant d'un rôle", + type: 'SUB_COMMAND', + options: [ + { + name: "rôle", + description: "Rôle à identifier", + type: 'ROLE', + required: true + }, + { + name: 'embed', + description: "Affiche la réponse sous forme d'embed (plus compliqué pour copier/coller)", + required: false, + type: 'BOOLEAN' + } + ] + }, + { + name: 'permissions', + description: "Gère les permissions d'un rôle", + type: 'SUB_COMMAND_GROUP', + options: [ + { + name: "accorder", + description: "Accorde une permission à un rôle", + type: 'SUB_COMMAND', + options: [ + { + name: "rôle", + description: "Rôle à gérer", + type: 'ROLE', + required: true + }, + { + name: 'permission', + description: "Permission à accorder", + required: true, + type: 'STRING', + } + ] + }, + { + name: 'refuser', + description: "Refuse une permission à un rôle", + type: 'SUB_COMMAND', + options: [ + { + name: "rôle", + description: "Rôle à gérer", + required: true, + type: 'ROLE' + }, + { + name: "permission", + description: 'Permission à refuser', + type: 'STRING', + required: true + } + ] + }, + { + name: "liste", + description: "Affiche la liste des permissions accordables", + type: 'SUB_COMMAND' + } + ] } ] }, @@ -169,6 +239,75 @@ module.exports = { return true; }; + if (['accorder', 'refuser'].includes(subCommand)) { + let role = interaction.options.getRole('rôle'); + let permissionString = interaction.options.get('permission').value; + const perm = perms.find(x => x.name.toLowerCase() == permissionString.toLowerCase()); + if (!perm) return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Permission inconnue") + .setDescription(`Cette permission n'existe pas.\nUtilisez la commande \`/role permissions liste\` pour voir la liste des permissions disponibles`) + .setColor('#ff0000') + ] }).catch(() => {}); + + if (role.position >= interaction.member.roles.highest.position) return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Action impossible") + .setDescription(`Le rôle <@&${role.id}> est trop haut pour vous`) + .setColor('#ff0000') + ] }).catch(() => {}); + if (role.position >= interaction.guild.me.roles.highest.position) return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Action impossible") + .setDescription(`Le rôle <@&${role.id}> est trop haut pour moi`) + .setColor('#ff0000') + ] }).catch(() => {}); + if (!interaction.member.permissions.has(perm.value)) return interaction.reply({ embeds: [ package.embeds.missingPermission(interaction.user, perm.value) ] }).catch(() => {}); + if (!interaction.guild.me.permissions.has(perm.value)) return interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("❌ Permission manquante") + .setDescription(`Je n'ai pas la permission **${perm.name}**`) + .setColor('#ff0000') + ] }).catch(() => {}); + + let permissions = role.permissions.toArray(); + if (subCommand == 'accorder') { + if (!permissions.includes(perm.value)) permissions.push(perm.value); + } else { + if (permissions.includes(perm.value)) { + permissions.splice(permissions.indexOf(perm.value), 1); + }; + }; + + role.setPermissions(Discord.Permissions.resolve(permissions)); + + interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle(subCommand == 'accorder' ? "✅ Permission accordée":"🚫 Permission refusée") + .setColor(subCommand == 'accorder' ? '#00ff00' : '#ff0000') + .setDescription(`La permission \`${perm.name}\` a été **${subCommand == 'accorder' ? "accordée":'refusée'}** au rôle <@&${role.id}>`) + ] }).catch(() => {}); + }; + if (subCommand == 'liste') { + const embed = package.embeds.classic(interaction.user) + .setTitle("Permissions accordables") + .setDescription(`Voici la liste des permissions accordables pour un rôle :\n${perms.map(x => x.name).map(x => `\`${x}\``).join(', ')}`) + .setColor(interaction.guild.me.displayHexColor) + + interaction.reply({ embeds: [ embed ] }).catch(() => {}); + } + if (subCommand == 'identifier') { + let { id, hexColor } = interaction.options.getRole('rôle'); + let embed = interaction.options.getBoolean('embed') ?? false; + + let reply = {}; + if (embed == true) { + reply.embeds = [ package.embeds.classic(interaction.user) + .setTitle("Identifiant") + .setDescription(`L'identifiant du rôle <@&${id}> est \`${id}\``) + .setColor(hexColor) + ]; + } else { + reply.content = `\`${id}\``; + }; + + interaction.reply(reply).catch(() => {}); + } if (subCommand === 'créer') { const roleName = interaction.options.get('nom').value; diff --git a/slash-commands/moderation/softban.js b/slash-commands/moderation/softban.js new file mode 100644 index 0000000..9f40d1d --- /dev/null +++ b/slash-commands/moderation/softban.js @@ -0,0 +1,77 @@ +const { CommandInteraction } = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + dev: false, + dm: false, + permissions: ['BAN_MEMBERS'] + }, + configs: { + name: 'softban', + description: "Banni, puis débanni un membre du serveur", + options: [ + { + name: "membre", + description: "Membre à softbannir", + type: 'USER', + required: true + }, + { + name: 'raison', + description: "Raison du softban", + type: 'STRING', + required: true + } + ] + }, + /** + * @param {CommandInteraction} interaction + */ + run: async(interaction) => { + let member = interaction.options.getMember('membre'); + let raison = interaction.options.getString('raison').replace(/"/g, '\\"'); + + if (!functions.checkPerms({ interaction, member, mod: interaction.member, checkBotCompare: true, checkOwner: true, checkSelfUser: true })) return; + + await member.ban({ reason: raison }).catch(() => {}); + await interaction.guild.members.unban(member.user, raison); + + interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Softban") + .setDescription(`${member.user.tag} a été softbanni.`) + .setColor('#ff0000') + ] }).catch(() => {}); + + functions.addCase(interaction.guild.id, member.id, interaction.user.id, raison, 'softban'); + functions.log(interaction.guild, package.embeds.classic(interaction.user) + .setTitle("Softban") + .setDescription(`Un membre a été soft-banni`) + .setColor('#ff0000') + .addFields( + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: "Membre", + value: `<@${member.id}> ( ${member.user.tag} \`${member.id}\` )`, + inline: true + }, + { + name: "Raison", + value: raison.replace(/\\"/g, '"'), + inline: true + }, + { + name: 'Date', + value: ` ( )`, + inline: false + } + ) + ) + } +} \ No newline at end of file diff --git a/slash-commands/moderation/stickyroles.js b/slash-commands/moderation/stickyroles.js new file mode 100644 index 0000000..23c868b --- /dev/null +++ b/slash-commands/moderation/stickyroles.js @@ -0,0 +1,224 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + dev: false, + dm: false, + permissions: ['manage_roles', 'manage_guild'] + }, + configs: { + name: 'stickyroles', + description: "Gère les rôles collants d'un membre", + options: [ + { + name: "info", + description: "Affiche les informations sur les rôles collants", + type: 'SUB_COMMAND' + }, + { + name: 'coller', + type: 'SUB_COMMAND', + description: "Ajoute un rôle collant à un membre", + options: [ + { + name: 'rôle', + description: "Rôle collant à coller", + type: 'ROLE', + required: true + }, + { + name: 'membre', + description: "Membre qui prendra le rôle collant", + type: 'USER', + required: true + } + ] + }, + { + name: 'décoller', + type: 'SUB_COMMAND', + description: "Retire un rôle collant à un membre", + options: [ + { + name: 'rôle', + description: "Rôle collant à décoller", + type: 'ROLE', + required: true + }, + { + name: 'membre', + description: "Membre qui perdra le rôle collant", + type: 'USER', + required: true + } + ] + }, + { + name: 'liste', + type: 'SUB_COMMAND', + description: "Affiche la liste des rôles collants d'un membre", + options: [ + { + name: 'membre', + type: 'USER', + description: "Membre dont vous voulez voir les rôles collants", + required: true + } + ] + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + const subcommand = interaction.options.getSubcommand(); + if (subcommand == 'info') { + let components = []; + if (functions.random(10, 5) == 7) { + components.push(new Discord.MessageActionRow() + .setComponents( + new Discord.MessageButton({ + label: 'Serveur de support', + style: 'LINK', + url: package.configs.support + }) + ) + ); + }; + interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôles collants") + .setDescription(`Les rôles collants sont des rôles attribués à des membres, qui ne sont pas enlevables.\n\nCes rôles sont collés au membre et ne peuvent être retirés qu'avec la commande \`/stickyroles décoller\``) + .setColor(interaction.guild.me.displayHexColor) + ], components }).catch(() => {}); + return; + }; + + await interaction.reply({ embeds: [ package.embeds.waitForDb(interaction.user) ] }).catch(() => {}); + let member = interaction.options.getMember('membre'); + interaction.client.db.query(`SELECT role_id FROM stickyroles WHERE guild_id="${interaction.guild.id}" AND user_id="${member.id}"`, (err, req) => { + if (err) { + functions.sendError(err, 'query fetch at /stickyroles ' + subcommand, interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + }; + + if (subcommand == 'coller') { + let role = interaction.options.getRole('rôle'); + if (!functions.checkPerms({ mod: interaction.member, member, interaction, checkBotCompare: true, checkOwner: true, checkSelfUser: true, checkRole: { activated: true, role } })) return; + + if (req.find(x => x.role_id == role.id)) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle déjà collant") + .setDescription(`Ce rôle est déjà collant pour <@${member.id}>`) + .setColor('#ff0000') + ] }).catch(() => {}); + + if (!member.roles.cache.has(role)) member.roles.add(role).catch(() => {}); + interaction.client.db.query(`INSERT INTO stickyroles (guild_id, user_id, role_id) VALUES ("${interaction.guild.id}", "${member.id}", "${role.id}")`, (error) => { + if (error) { + functions.sendError(error, 'query insert at /stickyroles coller', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + }; + + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle collé") + .setDescription(`Le rôle <@&${role.id}> a été collé à <@${member.id}>`) + .setColor(role.hexColor) + ] }).catch(() => {}); + functions.log(interaction.guild, package.embeds.logs(interaction.guild) + .setTitle("Rôle collé") + .setDescription(`Un rôle a été collé à un membre`) + .setFields( + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: "Membre", + value: `<@${member.id}> ( ${member.user.tag} \`${member.id}\` )`, + inline: true + }, + { + name: "Rôle", + value: `<@&${role.id}> ( @${role.name} \`${role.id}\` )`, + inline: true + }, + { + name: 'Date', + value: ` ( )`, + inline: false + } + ) + .setColor(role.hexColor) + ) + }) + }; + if (subcommand == 'décoller') { + let role = interaction.options.getRole('rôle'); + if (!functions.checkPerms({ mod: interaction.member, member, interaction, checkBotCompare: true, checkOwner: true, checkSelfUser: true, checkRole: { activated: true, role } })) return; + + if (!req.find(x => x.role_id == role.id)) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle non collé") + .setDescription(`Ce rôle n'est pas collé à <@${member.id}>`) + .setColor('#ff0000') + ] }).catch(() => {}); + + if (member.roles.cache.has(role)) member.roles.remove(role).catch(() => {}); + interaction.client.db.query(`DELETE FROM stickyroles WHERE guild_id="${interaction.guild.id}" AND user_id="${member.id}" AND role_id="${role.id}"`, (error) => { + if (error) { + functions.sendError(error, 'query delete at /stickyroles décoller', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + }; + + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle décollé") + .setDescription(`Le rôle <@&${role.id}> a été décollé à <@${member.id}>`) + .setColor(role.hexColor) + ] }).catch(() => {}); + functions.log(interaction.guild, package.embeds.logs(interaction.guild) + .setTitle("Rôle collé") + .setDescription(`Un rôle a été décollé à un membre`) + .setFields( + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: "Membre", + value: `<@${member.id}> ( ${member.user.tag} \`${member.id}\` )`, + inline: true + }, + { + name: "Rôle", + value: `<@&${role.id}> ( @${role.name} \`${role.id}\` )`, + inline: true + }, + { + name: 'Date', + value: ` ( )`, + inline: false + } + ) + .setColor(role.hexColor) + ) + }) + }; + if (subcommand == 'liste') { + if (req.length == 0) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Pas de rôles collants") + .setDescription(`<@${member.id}> n'a pas de rôles collants`) + .setColor('#ff0000') + ] }).catch(() => {}); + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôles collants") + .setDescription(`Voici la liste des rôles collants de <@${member.id}> (${req.length.toLocaleString('fr-DE')})\n\n${req.map(x => `<@&${x.role_id}>`).join(' ')}`) + .setColor(member.displayHexColor) + ] }).catch(() => {}); + }; + }); + } +} \ No newline at end of file diff --git a/slash-commands/moderation/ticket.js b/slash-commands/moderation/ticket.js index 644ffe9..b1034ed 100644 --- a/slash-commands/moderation/ticket.js +++ b/slash-commands/moderation/ticket.js @@ -116,6 +116,44 @@ module.exports = { name: 'reopen', description: "Réouvre le ticket", type: 'SUB_COMMAND' + }, + { + name: 'modrole', + description: "Gère les rôles de modérateurs de tickets", + type: 'SUB_COMMAND_GROUP', + options: [ + { + name: 'ajouter', + type: 'SUB_COMMAND', + description: "Ajoute un rôle de modérateur de tickets", + options: [ + { + name: "rôle", + type: 'ROLE', + description: "Rôle à ajouter", + required: true + } + ] + }, + { + name: 'retirer', + type: 'SUB_COMMAND', + description: "Retirer un rôle de modérateur de tickets", + options: [ + { + name: "rôle", + type: 'ROLE', + description: "Rôle à retirer", + required: true + } + ] + }, + { + name: "liste", + description: "Affiche la liste des rôles de modérateurs de tickets", + type: 'SUB_COMMAND' + } + ] } ] }, @@ -123,7 +161,7 @@ module.exports = { dm: false, dev: false, permissions: [], - systems: [], + systems: [{name: "de tickets", value: "ticket_enable", state: true}], cd: 5 }, /** @@ -148,6 +186,96 @@ module.exports = { return true; }; + if (['ajouter', 'liste', 'retirer'].includes(subcommand)) { + await interaction.reply({ embeds: [ package.embeds.waitForDb(interaction.user) ] }).catch(() => {}); + interaction.client.db.query(`SELECT ticket_roles FROM configs WHERE guild_id="${interaction.guild.id}"`, (err, req) => { + if (err) { + functions.sendError(err, 'query fetch at /ticket modrole', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + return; + }; + if (req.length > 0) req[0].ticket_roles = JSON.parse(req[0].ticket_roles); + // console.log(req[0]); + + if (subcommand == 'liste') { + if (req[0].ticket_roles.length == 0) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Aucun rôle automatique") + .setDescription(`Aucun rôle de modérateur de tickets n'a été configuré`) + .setColor('#ff0000') + ] }).catch(() => {}); + + const embed = package.embeds.classic(interaction.user) + .setTitle("Rôles de modérateurs de tickets") + .setDescription(`Les rôles configurés sur ${interaction.guild.name} en tant que modérateurs de tickets ${req[0].ticket_roles.length > 1 ? 'sont':'est'} :\n${req[0].ticket_roles.map(r => `<@&${r}>`).join(' ')}`) + .setColor(interaction.member.displayHexColor) + + interaction.editReply({ embeds: [ embed ] }).catch(() => {}); + }; + if (subcommand == 'ajouter') { + let role = interaction.options.getRole('rôle'); + if (role.position >= interaction.member.roles.highest.position) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("🚫 Rôle trop haut") + .setDescription(`Ce rôle est **supérieur** ou **égal** à vous dans la hiérarchie des rôles`) + .setColor(role.hexColor) + ] }).catch(() => {}); + + if (req[0].ticket_roles.includes(role.id)) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle déjà configuré") + .setDescription(`Le rôle <@&${role.id}> est déjà configuré sur ${interaction.guild.name}`) + .setColor(role.hexColor) + ] }).catch(() => {}); + + req[0].ticket_roles.push(role.id) + + interaction.client.db.query(`UPDATE configs SET ticket_roles='${JSON.stringify(req[0].ticket_roles)}' WHERE guild_id="${interaction.guild.id}"`, (er) => { + if (er) { + functions.sendError(er, 'query add at /autorole ajouter', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + return; + }; + + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle configuré") + .setDescription(`Le rôle <@&${role.id}> est maintenant un rôle de modérateurs de tickets`) + .setColor(role.hexColor) + ] }).catch(() => {}); + interaction.client.TicketsManager.loadCache(); + }); + }; + if (subcommand == 'retirer') { + let role = interaction.options.getRole('rôle'); + if (role.position >= interaction.member.roles.highest.position) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("🚫 Rôle trop haut") + .setDescription(`Ce rôle est **supérieur** ou **égal** à vous dans la hiérarchie des rôles`) + .setColor(role.hexColor) + ] }).catch(() => {}); + + if (!req[0].ticket_roles.includes(role.id)) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle non configuré") + .setDescription(`Le rôle <@&${role.id}> n'est pas configuré sur ${interaction.guild.name}`) + .setColor(role.hexColor) + ] }).catch(() => {}); + + let index = req[0].ticket_roles.indexOf(role.id); + req[0].ticket_roles.splice(index, 1); + + interaction.client.db.query(`UPDATE configs SET ticket_roles='${JSON.stringify(req[0].ticket_roles)}' WHERE guild_id="${interaction.guild.id}"`, (er) => { + if (er) { + functions.sendError(er, 'query remove at /ticket modrole retirer', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + return; + }; + + interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Rôle configuré") + .setDescription(`Le rôle <@&${role.id}> n'est maintenant plus un rôle de modérateur de tickets`) + .setColor(role.hexColor) + ] }).catch(() => {}); + interaction.client.TicketsManager.loadCache(); + }); + }; + }); + } if (subcommand == 'ticket') { let sujet = interaction.options.getString('sujet'); tickets.createTicket({ guild: interaction.guild, user: interaction.user, sujet }); diff --git a/slash-commands/moderation/unwarn.js b/slash-commands/moderation/unwarn.js new file mode 100644 index 0000000..f7de7a5 --- /dev/null +++ b/slash-commands/moderation/unwarn.js @@ -0,0 +1,87 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + help: { + cd: 5, + permissions: ['gérer le serveur'], + systems: [], + dev: false, + dm: false + }, + configs: { + name: 'unwarn', + description: "Enlève un avertissement à un utilisateur", + options: [ + { + name: 'membre', + type: 'USER', + description: "Membre qui aura un avertissement en moins", + required: true + }, + { + name: 'identifiant', + description: 'Identifiant de l\'avertissement (visible avec /logs afficher)', + type: 'INTEGER', + required: true + } + ] + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + let member = interaction.options.getMember('membre'); + let id = interaction.options.get('identifiant').value; + + if (!functions.checkPerms({ interaction, member, mod: interaction.member, all: true })) return; + await interaction.reply({ embeds: [ package.embeds.waitForDb(interaction.user) ] }).catch(() => {}); + + interaction.client.db.query(`SELECT * FROM mod_cases WHERE id="${id}" AND action="avertissement" AND user_id="${member.id}"`, (err, req) => { + if (err) { + functions.sendError(err, 'query fetch at /unwarn', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + return; + }; + if (req.length == 0) return interaction.editReply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle('Avertissement inexistant') + .setDescription(`L'avertissement d'identifiant \`${id}\` à <@${member.id}> n'existe pas`) + .setColor('#ff0000') + ] }).catch(() => {}); + interaction.client.db.query(`DELETE FROM mod_cases WHERE id="${id}"`, (error) => { + if (error) { + functions.sendError(error, 'query delete at /unwarn', interaction.user); + interaction.editReply({ embeds: [ package.embeds.errorSQL(interaction.user) ] }).catch(() => {}); + return; + }; + + const embed = package.embeds.classic(interaction.user) + .setTitle("Suppression d'avertissement") + .setDescription(`L'avertissement d'identifiant \`${id}\` a été supprimé`) + .addFields( + { + name: "Modérateur", + value: `<@${interaction.user.id}> ( ${interaction.user.tag} \`${interaction.user.id}\` )`, + inline: true + }, + { + name: "Membre", + value: `<@${member.id}> ( ${member.user.tag} \`${member.id}\` )`, + inline: true + }, + { + name: "Raison", + value: `Raison de l'avertissement :\`\`\`${req[0]?.reason ?? 'Pas de raison'}\`\`\``, + inline: true + } + ) + .setColor('#ff0000') + + interaction.editReply({ embeds: [ embed ] }).catch(() => {}); + functions.log(interaction.guild, embed); + functions.addCase(interaction.guild.id, member.id, interaction.user.id, req[0]?.reason ?? 'pas de raison', "unwarn"); + }); + }); + } +}; \ No newline at end of file diff --git a/slash-commands/moderation/warn.js b/slash-commands/moderation/warn.js index 579f045..b92f315 100644 --- a/slash-commands/moderation/warn.js +++ b/slash-commands/moderation/warn.js @@ -37,9 +37,9 @@ module.exports = { const reason = interaction.options.get('raison').value; const member = interaction.options.get('utilisateur').member; - if (!functions.checkAllConditions(interaction.guild, interaction.channel, interaction.member, member)) return interaction.deferReply(); + if (!functions.checkPerms({ member, interaction, mod: interaction.member, checkBotCompare: true, checkSelfUser: true, checkOwner: true })) return; - functions.addCase(interaction.guild.id, member.id, interaction.user.id, reason, 'warn'); + functions.addCase(interaction.guild.id, member.id, interaction.user.id, reason, 'avertissement'); const warn = package.embeds.classic(interaction.user) .setTitle("Avertissement") .setColor('#ff0000') @@ -64,6 +64,7 @@ module.exports = { interaction.reply({ embeds: [ warn ] }); member.user.send({ embeds: [ warn ] }).catch(() => {}); + functions.log(interaction.guild, warn); } } \ No newline at end of file diff --git a/slash-commands/usefull/commande.js b/slash-commands/usefull/commande.js index ceec9b9..47de3e5 100644 --- a/slash-commands/usefull/commande.js +++ b/slash-commands/usefull/commande.js @@ -33,40 +33,35 @@ module.exports = { /** * @param {Discord.CommandInteraction} interaction */ - run: (interaction) => { - const ephemeral = interaction.options.get('discret') ? interaction.options.get('discret').value : true; + run: async(interaction) => { + const ephemeral = interaction.options.get('discret') ? interaction.options.get('discret').value : false; const commandName = interaction.options.get('commande').value; - const commandList = require('../../assets/data/commands.json'); + const commandList = require('../../assets/data/slashCommands'); - let command; - Object.keys(commandList).forEach((key) => { - const test = commandList[key].find((x) => x.help.name === commandName.toLowerCase() || (x.help.aliases && x.help.aliases.includes(commandName.toLowerCase()))); - - if (test) command = test; - }); + let command = commandList.get(commandName); if (!command || command.help.private || (command.help.appear !== undefined && command.help.appear === false)) return interaction.reply({ content: "Cette commande n'existe pas.", ephemeral: ephemeral }); const perms = package.perms; - const embed = package.embeds.classic(interaction.user) - .setTitle(`Commande ${command.name}`) - .setDescription(`**Description:** \`\`\`${command.help.description}\`\`\``) + let embed = package.embeds.classic(interaction.user) + .setTitle(`Commande ${command.configs.name}`) + .setDescription(`**Description:** \`\`\`${command.configs.description}\`\`\``) .addFields( { name: "Cooldown", - value: `${command.help.cooldown} seconde(s)`, + value: `${command.help.cd} seconde(s)`, inline: true }, { - name: "Alias", - value: command.help.aliases.length === 0 ? "Aucun alias" : command.help.aliases.map((alias) => `\`${alias}\``).join(', '), + name: "Systèmes", + value: command.help.systems?.length === 0 ? "Aucun système requis" : command.help.systems.map((system) => `Système ${system.name} : doit être **${system.state == true ? 'activé':'désactivé'}**`).join(', '), inline: true }, { name: "Permissions", - value: command.help.permissions.length === 0 ? 'Aucune permission nécéssaires' : command.help.permissions.map((perm) => '`' + perms[perm.toUpperCase()] + '`').join(', '), + value: command.help.permissions?.length === 0 ? 'Aucune permission nécéssaires' : command.help.permissions.map((perm) => '`' + perms[perm.toUpperCase()] + '`').join(', '), inline: true }, { @@ -78,15 +73,189 @@ module.exports = { name: "Exécutable en privé ?", value: command.help.dm ? "Oui" : "Non", inline: true - }, - { - name: "Documentation", - value: `[${command.name}](https://github.com/BotOracle/Documentation/blob/main/commands/${command.name})`, - inline: true } ) .setColor('ORANGE') + /** + * @param {Discord.ApplicationCommandSubCommandData[]} subCommandsList + */ + const generateSubCommandsRow = (subCommandsList) => { + return subCommandsList.map(sub => ({ label: sub.name, description: sub.description, value: sub.name })); + }; + const generateRow = () => { + let rows = []; + let groups = new Discord.MessageSelectMenu() + .setMaxValues(1) + .setMinValues(1) + .setPlaceholder('Choississez un groupe de sous-commandes') + .setCustomId('sub-commands-group') + let subCommands = new Discord.MessageSelectMenu() + .setMaxValues(1) + .setMinValues(1) + .setPlaceholder('Choisissez une sous-commande') + .setCustomId('sub-commands') + + const subs = command.configs.options.filter(x => x.type == 'SUB_COMMAND'); + const subsGroups = command.configs.options.filter(x => x.type == 'SUB_COMMAND_GROUP'); + if (subs.length > 0) subCommands.setOptions(generateSubCommandsRow(subs)); + if (subsGroups.length > 0) groups.setOptions(generateSubCommandsRow(subsGroups)); + + groups = new Discord.MessageActionRow() + .addComponents(groups); + subCommands = new Discord.MessageActionRow() + .addComponents(subCommands); + + if (subs.length > 0 && subsGroups.length > 0) rows.push(groups) & rows.push(subCommands); + else if (subs.length == 0 && subsGroups.length > 0) rows.push(groups); + else rows.push(subCommands); + + return rows; + }; + let rows = []; + + const optionsTypes = { + ROLE: 'rôle', + CHANNEL: 'salon', + STRING: "texte", + INTEGER: 'nombre', + NUMBER: 'nombre', + ATTACHMENT: 'fichier', + USER: 'utilisateur', + BOOLEAN: 'binaire' + }; + const menu = new Discord.MessageButton({ label: 'Menu', customId: 'menu', style: 'SECONDARY', emoji: '🏠' }); + if (command.configs.options?.length > 0) { + if (!['SUB_COMMAND_GROUP', 'SUB_COMMAND'].includes(command.configs.options[0].type)) { + embed.addFields( + { + name: "Options", + value: command.configs.options.map(opt => `\`${opt.name}\` (${optionsTypes[opt.type]}) : ${opt.description}${opt.required == true ? ' - **requis**':' - **optionnel**'}`).join('\n'), + inline: true + } + ); + } else { + rows = generateRow(); + rows.push(new Discord.MessageActionRow() + .addComponents(menu) + ); + }; + }; + + interaction.reply({ embeds: [ embed ], ephemeral: ephemeral, components: rows }).catch((e) => {console.log(e)}); + + if (rows.length > 0) { + const reply = await interaction.fetchReply(); + const collector = reply.createMessageComponentCollector({ time: 120000, filter: x => x.user.id == interaction.user.id }); + + collector.on('collect', /**@param {Discord.SelectMenuInteraction}int */ (int) => { + collector.resetTimer(); + int.deferUpdate(); + + if (int.customId == 'sub-commands') { + let inGroup = false; + let group; + + let subCommand = command.configs.options.find(x => (x.type == 'SUB_COMMAND' && x.name == int.values[0]) || x.options && x.options.find(y => { + if (y.type == 'SUB_COMMAND' && y.name == int.values[0]) { + inGroup = true; + group = x.name; + return true; + }; + })); + if (subCommand.type == 'SUB_COMMAND_GROUP') subCommand = subCommand.options.find(x => x.name == int.values[0]); + embed.setFields(); + embed.setDescription(`Sous commande \`/${command.configs.name} ${inGroup ? group + ' ' + subCommand.name : subCommand.name}\``); + embed.addFields( + { + name: 'Description', + value: subCommand.description, + inline: false + }, + { + name: 'Options', + value: subCommand.options?.length > 0 ? subCommand.options.map(opt => `\`${opt.name}\` (${optionsTypes[opt.type]}) : ${opt.description}${opt.required == true ? ' - **requis**':' - **optionnel**'}`).join('\n') : "Pas d'options", + inline: false + } + ); + + interaction.editReply({ embeds: [ embed ] }).catch(() => {}); + } else if (int.customId == 'sub-commands-group') { + let group = command.configs.options.find(x => x.type == 'SUB_COMMAND_GROUP' && x.name == int.values[0]); + const row = new Discord.MessageActionRow(); + + const selector = new Discord.MessageSelectMenu() + .setMaxValues(1) + .setMinValues(1) + .setPlaceholder('Choisissez une sous-commande') + .setOptions(group.options.map(x => ({ label: x.name, description: x.description, value: x.name }))) + .setCustomId('sub-commands') + row.addComponents(selector); + + embed.setFields(); + embed.setDescription(`Groupe de sous-commandes \`${command.configs.name} ${group.name}\``) + embed.addFields( + { + name: "Description", + value: group.description, + inline: true + } + ); + + interaction.editReply({ embeds: [ embed ], components: [ row, new Discord.MessageActionRow({ components: [ menu ] }) ] }).catch((e) => {console.log(e)}); + } else if (int.customId == 'menu') { + embed = package.embeds.classic(interaction.user) + .setTitle(`Commande ${command.configs.name}`) + .setDescription(`**Description:** \`\`\`${command.configs.description}\`\`\``) + .addFields( + { + name: "Cooldown", + value: `${command.help.cd} seconde(s)`, + inline: true + }, + { + name: "Systèmes", + value: command.help.systems?.length === 0 ? "Aucun système requis" : command.help.systems.map((system) => `Système ${system.name} : doit être **${system.state == true ? 'activé':'désactivé'}**`).join(', '), + inline: true + }, + { + name: "Permissions", + value: command.help.permissions?.length === 0 ? 'Aucune permission nécéssaires' : command.help.permissions.map((perm) => '`' + perms[perm.toUpperCase()] + '`').join(', '), + inline: true + }, + { + name: '\u200b', + value: "\u200b", + inline: false + }, + { + name: "Exécutable en privé ?", + value: command.help.dm ? "Oui" : "Non", + inline: true + } + ) + .setColor('ORANGE') + rows = []; + + if (command.configs.options?.length > 0) { + if (!['SUB_COMMAND_GROUP', 'SUB_COMMAND'].includes(command.configs.options[0].type)) { + embed.addFields( + { + name: "Options", + value: command.configs.options.map(opt => `\`${opt.name}\` (${optionsTypes[opt.type]}) : ${opt.description}${opt.required == true ? ' - **requis**':' - **optionnel**'}`).join('\n'), + inline: true + } + ); + } else { + rows = generateRow(); + rows.push(new Discord.MessageActionRow() + .addComponents(menu) + ); + }; + }; - interaction.reply({ embeds: [ embed ], ephemeral: ephemeral }); + interaction.editReply({ embeds: [ embed ], components: rows }).catch(() => {}); + }; + }); + } } } \ No newline at end of file diff --git a/slash-commands/usefull/contact.js b/slash-commands/usefull/contact.js index 4f62a9a..c31a923 100644 --- a/slash-commands/usefull/contact.js +++ b/slash-commands/usefull/contact.js @@ -33,7 +33,12 @@ module.exports = { .setDescription(`${interaction.user.username} ( ${interaction.user.id} ) a trouvé un bug sur Oracle :\n\`\`\`${bug}\`\`\``) .setColor('ORANGE') - interaction.client.channels.cache.get('954998495977291807').send({ embeds: [ embed ] }); - interaction.reply({ content: `J'ai signalé ce bug à mes développeurs.` }); + interaction.client.channels.cache.get('954998495977291807').send({ embeds: [ embed ] }).catch(() => {}); + const row = new Discord.MessageActionRow({ components: [ new Discord.MessageButton({ label: 'Serveur de support', style: 'LINK', url: package.configs.support }) ] }); + + interaction.reply({ embeds: [ package.embeds.classic(interaction.user) + .setTitle("Contact effectué") + .setDescription(`J'ai envoyé votre demande à mes développeurs.\nRejoingez le [serveur de support](${package.configs.support}) pour suivre la réponse à votre demande.`) + ], components: [ row ] }).catch(() => {}); } } \ No newline at end of file diff --git a/slash-commands/usefull/csc.js b/slash-commands/usefull/csc.js index 706ca5b..f78c5be 100644 --- a/slash-commands/usefull/csc.js +++ b/slash-commands/usefull/csc.js @@ -128,7 +128,7 @@ module.exports = { const fileContent = `const Discord = require('discord.js'); -const functions = require('../../assets/functions'); +const functions = require('../assets/functions'); const package = functions.package(); module.exports = { @@ -278,4 +278,4 @@ module.exports = { } } } -} \ No newline at end of file +} diff --git a/slash-commands/usefull/feedback.js b/slash-commands/usefull/feedback.js new file mode 100644 index 0000000..5aa0caf --- /dev/null +++ b/slash-commands/usefull/feedback.js @@ -0,0 +1,41 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +module.exports = { + configs: { + name: 'avis', + description: "Envoie votre avis sur le bot", + options: [ + { + name: 'avis', + description: "Votre avis", + type: 'STRING', + required: true, + autocomplete: false + } + ] + }, + help: { + dm: true, + dev: false, + permissions: [], + systems: [], + cd: 5 + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: (interaction) => { + const avis = interaction.options.get('avis').value; + const embed = package.embeds.classic(interaction.user) + .setTitle("Avis") + .setDescription(`${interaction.user.username} ( ${interaction.user.id} ) vient de donner son avis sur Oracle :\n\`\`\`${avis}\`\`\``) + .setColor('ORANGE') + + interaction.client.channels.cache.get('946079273335279676').send({ embeds: [ embed ] }).catch(() => {}); + interaction.reply({ content: `Vous avez donné votre avis sur Oracle`, ephemeral: true, components: [ new Discord.MessageActionRow() + .addComponents(new Discord.MessageButton({ label: 'Donner un avis sur top.gg', style: 'LINK', url: package.configs.topgg })) + ] }).catch(() => {}); + } +} \ No newline at end of file diff --git a/slash-commands/usefull/help.js b/slash-commands/usefull/help.js index 8d8fc6b..86f24cd 100644 --- a/slash-commands/usefull/help.js +++ b/slash-commands/usefull/help.js @@ -34,7 +34,10 @@ module.exports = { {name: 'Divers', emoji: '🎈', value: 'misc', description: "Commandes diverses"}, {name: 'Fun', emoji: '🥳', value: 'fun', description: "Commandes d'amusement"}, {name: 'Utilitaires', emoji: '⚙', description: "Commandes utiles", value: 'usefull'}, - {name: "Économie", emoji: '🪙', description: "Commandes d'économie", value: 'economy'} + {name: "Économie", emoji: '💵', description: "Commandes d'économie", value: 'economy'}, + {name: 'Information', emoji: 'ℹ️', description: "Commandes d'information", value: 'information'}, + {name: "Configuration", emoji: '🔨', description: "Commandes de configuration d'Oracle", value: 'configuration'}, + {name: "Niveaux", emoji: '🆙', description: "Commandes de niveaux", value: 'levels'} ]; correspondance.push({value: 'close', name: "Fermer", emoji: '❌', description: "Ferme le menu"}); diff --git a/slash-commands/usefull/remind.js b/slash-commands/usefull/remind.js index b935459..43e7d0b 100644 --- a/slash-commands/usefull/remind.js +++ b/slash-commands/usefull/remind.js @@ -58,8 +58,6 @@ module.exports = { * @param {Discord.CommandInteraction} interaction */ run: (interaction) => { - return interaction.reply({ embeds: [ new Discord.MessageEmbed({ title: 'Commande en développement', color: 'YELLOW' }) ] }).catch(() => {}); - const sub = interaction.options.getSubcommand(); const manager = interaction.client.RemindsManager; @@ -69,6 +67,14 @@ module.exports = { const remind = interaction.options.get('contenu').value; manager.createInteraction(interaction.user, interaction, ms(time), remind); + }; + if (sub == 'liste') { + manager.list(interaction.user, interaction); + }; + if (sub == 'retirer') { + let value = parseInt(interaction.options.get('numéro').value); + + manager.removeInteraction(interaction.user, interaction, value); } } } \ No newline at end of file diff --git a/slash-commands/usefull/sondage.js b/slash-commands/usefull/sondage.js new file mode 100644 index 0000000..5531be2 --- /dev/null +++ b/slash-commands/usefull/sondage.js @@ -0,0 +1,55 @@ +const Discord = require('discord.js'); +const functions = require('../../assets/functions'); +const package = functions.package(); + +let options = [{name: 'question', type: 'STRING', required: true, description: "Question du sondage"}]; +for (let i = 0; i < 10; i++) { + options.push({ + name: `proposition_${i + 1}`, + type: 'STRING', + description: `Proposition ${i + 1} du sondage`, + required: i < 2 + }); +}; + +module.exports = { + help: { + cd: 5, + dev: false, + dm: false, + systems: [], + permissions: ['manage_guild'] + }, + configs: { + name: 'sondage', + description: "Fait un sondage", + options + }, + /** + * @param {Discord.CommandInteraction} interaction + */ + run: async(interaction) => { + let props = []; + for (let i = 0; i < 10; i++) { + props.push(interaction.options.get(`proposition_${i + 1}`)?.value); + }; + props = props.filter(x => ![undefined, null].includes(x)); + + const emojis = functions.getNumbersEmoji(); + emojis.splice(0, 1); + emojis.splice(props.length, functions.getNumbersEmoji().length - props.length); + + const embed = package.embeds.classic(interaction.user) + .setTitle("Sondage") + .setDescription(`**${interaction.options.getString('question')}**\n\n${props.map((x, i) => `${emojis[i]} ${x}`).join('\n')}`) + .setColor(('YELLOW')) + + await interaction.reply({ embeds: [ embed ] }).catch(() => {}); + const msg = await interaction.fetchReply(); + if (!msg) return; + + for (const emoji of emojis) { + await msg.react(emoji).catch(() => {}); + }; + } +} \ No newline at end of file