Skip to content
Snippets Groups Projects
Select Git revision
  • 47af0ec945bc35bee773ac76d72b19fe23a41822
  • main default protected
  • dev
3 results

index.js

Blame
  • index.js 21.02 KiB
    // Configuration
    const config = require('./config');
    // Driver SQL
    const Sequelize = require('sequelize');
    const { Op } = require("sequelize");
    // API externe
    const express = require('express')
    const app = express()
    // Couleurs de la console
    var colors = require('colors');
    
    // API discord
    const { REST } = require('@discordjs/rest');
    const { Routes } = require('discord-api-types/v9');
    
    // Moment JS
    var moment = require('moment');
    
    // Schedule
    const schedule = require('node-schedule');
    
    ////////////////////////////////////////////////////////////////
    // MODELES DES TABLES
    ////////////////////////////////////////////////////////////////
    
    // Connexion à la base de données
    const sequelize = new Sequelize(config.get("BDD_NAME"), config.get("BDD_USER"), config.get("BDD_PASSWORD"), {
        host: config.get("BDD_HOST"),
        dialect: 'mariadb',
        logging: false,
    });
    
    // Paramètres du bot
    const botSettings = sequelize.define('discord_settings', {
        name: { type: Sequelize.STRING(128), primaryKey: true },
        value: Sequelize.STRING(512),
    }, {
        timestamps: false
    });
    
    // Entrées et sorties des membres
    const entries = sequelize.define('discord_entries', {
    	id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
    	memberId: Sequelize.BIGINT(255),
    	isJoin: Sequelize.BOOLEAN,
    	date: Sequelize.DATE,
    }, {
    	timestamps: false
    });
    
    // Paramètres des membres
    const memberSettings = sequelize.define('discord_memberSettings', {
        memberId: { type: Sequelize.BIGINT(255), primaryKey: true },
        name: { type: Sequelize.STRING(128), primaryKey: true },
        value: Sequelize.STRING(512),
    }, {
        timestamps: false
    });
    
    ////////////////////////////////////////////////////////////////
    
    const commands = [{
        name: 'ping',
        description: 'Répond avec pong!'
    },
    {
        name: 'setanniv',
        description: 'Permet de définir ta date d\'anniversaire (usage unique).',
        options: [{
            name: "date", // no uppercase as well
            description: "Date au format DD/MM/YYYY - 31/12/2001",
            type: 3,
            required: true
        }]
    },
    {
        name: 'delanniv',
        description: '[Admin] Supprime la date d\'anniversaire d\'un membre.',
        options: [{
            name: "membre", // no uppercase as well
            description: "Membre à supprimer la date d'anniversaire.",
            type: 6,
            required: true
        }]
    }];
    
    ////////////////////////////////////////////////////////////////
    // INITIALISATION DES COMMANDES ET CONNEXION À LA BASE DE DONNÉES
    ////////////////////////////////////////////////////////////////
    const rest = new REST({ version: '9' }).setToken(config.get("DISCORD_BOT_TOKEN"));
    
    (async () => {
        console.log('[' + 'INFO'.yellow + '] Connexion à la base de donnée...'.brightWhite);
        try {
            await sequelize.authenticate();
            console.log('[' + 'SUCCES'.brightGreen + '] Connexion à la base de donnée réussie.'.brightWhite);
            await initialiseDatabaseTables(); // On va initialiser les tables de la base de donnée
    
            try {
                console.log('[' + 'INFO'.yellow + '] Actualisation des commandes...'.brightWhite);
                //console.log(JSON.stringify(commands));
                await rest.put(
                    Routes.applicationGuildCommands(config.get("CLIENT_ID"), config.get("GUILD_ID")),
                    { body: commands },
                );
    
                console.log('[' + 'SUCCES'.brightGreen + '] Toutes les commandes ont été actualisées.');
            } catch (error) {
                console.error('[' + 'ERREUR'.brightRed + '] Erreur lors de l\'actualisation des commandes:'.brightWhite + error);
            }
        } catch (error) {
            console.log('[' + 'ERREUR'.brightRed + '] Erreur lors de la connexion à la base de donnée:'.brightWhite);
            console.log('[' + 'DEBUG'.yellow + '] '.brightWhite + config.get("BDD_USER") + ":" + config.get("BDD_PASSWORD") + "@" + config.get("BDD_HOST") + " db:" + config.get("BDD_NAME") + '\n');
            console.error(error);
        }
    
    })();
    
    async function initialiseDatabaseTables() {
        console.log('[' + 'INFO'.yellow + '] Initialisation des tables...'.brightWhite);
        try {
            // On synchronise les modèles de sequlize
            await botSettings.sync();
            await entries.sync();
            await memberSettings.sync();
    
            // Basiquement on regarde si l'entrée existe, puis on agit en conséquence
            let token = await botSettings.findOne({ where: { name: "token" } });
            if (token == null) {
                // INSERT si elle n'existe pas
                console.log('[' + 'INSERT'.brightMagenta + '] Insertion de token'.brightWhite);
                let token = botSettings.create({
                    name: "token",
                    value: config.get("DISCORD_BOT_TOKEN")
                });
            } else {
                // UPDATE si différente
                if (token.value != config.get("DISCORD_BOT_TOKEN")) {
                    token.update({ value: config.get("DISCORD_BOT_TOKEN") })
                        .then(updatedRecord => {
                            console.log('[' + 'UPDATE'.brightMagenta + '] Mise à jour du token dans la base de donnée'.brightWhite);
                        }).catch(err => {
                            console.log('[' + 'ERREUR'.brightRed + '] Erreur lors de la màj de token dans la base de donnée: '.brightWhite + '\n');
                            throw new Error(err);
                        });
                }
            }
    
            // Et c'est pareil à chaque fois
            let clientId = await botSettings.findOne({ where: { name: "clientId" } });
            if (clientId == null) {
                console.log('[' + 'INSERT'.brightMagenta + '] Insertion de clientId'.brightWhite);
                let clientId = botSettings.create({
                    name: "clientId",
                    value: config.get("CLIENT_ID")
                });
            } else {
                if (clientId.value != config.get("CLIENT_ID")) {
                    clientId.update({ value: config.get("CLIENT_ID") })
                        .then(updatedRecord => {
                            console.log('[' + 'UPDATE'.brightMagenta + '] Mise à jour du clientId dans la base de donnée'.brightWhite);
                        }).catch(err => {
                            console.log('[' + 'ERREUR'.brightRed + '] Erreur lors de la màj de clientId dans la base de donnée: '.brightWhite + '\n');
                            throw new Error(err);
                        });
                }
            }
    
            let guildId = await botSettings.findOne({ where: { name: "guildId" } });
            if (guildId == null) {
                console.log('[' + 'INSERT'.brightMagenta + '] Insertion de guildId'.brightWhite);
                let guildId = botSettings.create({
                    name: "guildId",
                    value: config.get("GUILD_ID")
                });
            } else {
                if (guildId.value != config.get("GUILD_ID")) {
                    guildId.update({ value: config.get("GUILD_ID") })
                        .then(updatedRecord => {
                            console.log('[' + 'UPDATE'.brightMagenta + '] Mise à jour du guildId dans la base de donnée'.brightWhite);
                        }).catch(err => {
                            console.log('[' + 'ERREUR'.brightRed + '] Erreur lors de la màj de guildId dans la base de donnée: '.brightWhite + '\n');
                            throw new Error(err);
                        });
                }
            }
    
            console.log('[' + 'SUCCES'.brightGreen + '] Tables initialisées avec succès.'.brightWhite);
        } catch (error) {
            console.error('[' + 'ERREUR'.brightRed + '] Erreur lors de l\'initialisation des tables:'.brightWhite + '\n', error);
        }
    
    }
    
    ////////////////////////////////////////////////////////////////
    
    ////////////////////////////////////////////////////////////////
    // CONSOLE
    ////////////////////////////////////////////////////////////////
    
    // Console Input/Output
    var readline = require('readline');
    
    var rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });
    
    // Ce code est a améliorer, je l'ai vulgairement recopié d'un ancien bot (lui même pas très bien conçu)
    var recursiveAsyncReadLine = function () {
        rl.question('Commande: ', function (answer) {
            //if (answer == 'exit')
            //  return rl.close();
            const args = answer.match(/(".*?"|[^"\s]+)+(?=\s*|\s*$)/g);
            const command = args.shift().toLowerCase();
    
            switch (command) {
                case "say":
                    if (!args[0] || !args[1])
                        console.log('\n' + '[' + 'ERREUR'.brightRed + "] Tu n'as pas mis d'arguments :p" + '\n' + '[' + 'INFO'.yellow + "] Usage: say <Numéro du canal> <\"Texte\">");
                    else {
                        var message = args[1].substring(1, args[1].length - 1);
                        client.channels.cache.get(args[0]).send(message);
                        console.log('\n' + '[' + 'SUCCES'.brightGreen + '] Le message a été envoyé dans le canal n°' + args[0]);
                    }
                    break;
    
                default:
                    console.log('\n' + "Commande inconnue. :p");
                    break;
            }
    
            recursiveAsyncReadLine(); //Calling this function again to ask new question
        });
    };
    
    recursiveAsyncReadLine(); //we have to actually start our recursion somehow
    
    ////////////////////////////////////////////////////////////////
    
    ////////////////////////////////////////////////////////////////
    // BOT DISCORD
    ////////////////////////////////////////////////////////////////
    // require the needed discord.js classes
    const { Client, Intents, MessageActionRow, MessageButton, WebhookClient } = require('discord.js');
    const { verify } = require('crypto');
    
    // create a new Discord client
    const client = new Client({ intents: ["GUILDS", "GUILD_MESSAGES", "DIRECT_MESSAGES", "GUILD_MEMBERS"] });
    var mcChatWebhook;
    
    client.on("ready", async function () {
        console.log('\n' + "SL-Projects Bot".brightCyan);
        console.log("");
        console.log("Bot démarré".brightGreen);
    
        var guild = client.guilds.cache.get(config.get("GUILD_ID"));
        var memberCount = guild.memberCount.toLocaleString();
        console.log('\n'+"Nous sommes "+memberCount+" membres.");
        client.user.setActivity("Regarde "+memberCount+" membres"); 
    
        checkAnniv();
    
        verifyMcChatWebhook();
    });
    
    // Actions lorsqu'un membre rejoins ou part
    client.on('guildMemberAdd', async (member) => {
    	let guild = client.guilds.cache.get(config.get("GUILD_ID"));
    	var memberCount = guild.memberCount.toLocaleString();
    
    	console.log('\n'+"Nouveau membre - "+member.user.username+" - "+memberCount+" membres");
    	member.guild.channels.cache.get(config.get("CANAL_LOG")).send("Nouveau membre - "+member.user.username+" - "+memberCount+" membres");
    	client.user.setActivity("Regarde "+memberCount+" membres");
    
    	var currentdate = new Date(); 
    	var datetime = currentdate.getFullYear() + "-"
    			+ (currentdate.getMonth()+1)	+ "-" 
    			+ currentdate.getDate() + " "	
    			+ (currentdate.getHours()+1) + ":"	
    			+ currentdate.getMinutes() + ":" 
    			+ currentdate.getSeconds();
    
    	await entries.create({
    		id: null,
    		memberId: member.user.id,
    		isJoin: 1,
    		date: datetime,
    	});
    });
    client.on('guildMemberRemove', async (member) => {
    	let guild = client.guilds.cache.get(config.get("GUILD_ID"));
    	var memberCount = guild.memberCount.toLocaleString();
    
    	console.log('\n'+"Un membre a quitté le serveur - "+member.user.username+" - "+memberCount+" membres");
    	member.guild.channels.cache.get(config.get("CANAL_LOG")).send("Un membre a quitté le serveur - "+member.user.username+" - "+memberCount+" membres");
    	client.user.setActivity("Regarde "+memberCount+" membres");
    
    	var currentdate = new Date(); 
    	var datetime = currentdate.getFullYear() + "-"
    			+ (currentdate.getMonth()+1)	+ "-" 
    			+ currentdate.getDate() + " "	
    			+ (currentdate.getHours()+1) + ":"	
    			+ currentdate.getMinutes() + ":" 
    			+ currentdate.getSeconds();
    
    	await entries.create({
    		id: null,
    		memberId: member.user.id,
    		isJoin: 0,
    		date: datetime,
    	});
    });
    
    // Commandes
    client.on('interactionCreate', async interaction => {
        if (interaction.isCommand()) {
            console.log('[' + 'COMMANDE'.brightMagenta + '] '.brightWhite + interaction.user.username.brightBlue + ' a lancé la commande '.brightWhite + interaction.commandName.yellow);
            if (interaction.commandName === 'ping') {
                await interaction.reply('Pong!');
            } else if (interaction.commandName === 'setanniv') {
                // Je check si le membre a déjà enregistré sa date d'anniversaire
                let userAnniv = await memberSettings.findOne({
                    where: {
                        memberId: interaction.user.id,
                        name: 'birthday'
                    }
                });
                // S'il ne l'a pas déjà fait
                if (userAnniv == null) {
                    // On va checker que ce qu'il a envoyé est bien une date valide
                    let memberBirthday = moment(interaction.options.getString('date'), "DD/MM/YYYY");
                    if (isNaN(memberBirthday)) {
                        console.log('\n' + '[' + 'ERREUR'.brightRed + "] Date illisible: " + interaction.options.getString('date'));
                        await interaction.reply('J\'ai du mal à lire la date que tu m\'as donné. Est-elle bien dans ce format **DD/MM/YYYY**? :thinking:');
                    } else {
                        try {
                            memberBirthday = memberBirthday.toDate();
                            console.log('[' + 'INSERT'.brightMagenta + '] '.brightWhite + interaction.user.username.brightBlue + " a renseigné sa date d'anniversaire. ".brightWhite + interaction.options.getString('date').yellow);
                            var dd = memberBirthday.getDate();
                            var mm = memberBirthday.getMonth() + 1;
    
                            var yyyy = memberBirthday.getFullYear();
                            if (dd < 10) {
                                dd = '0' + dd;
                            }
                            if (mm < 10) {
                                mm = '0' + mm;
                            }
                            let birthday = mm + '/' + dd + '/' + yyyy;
                            let insetMemberBirthday = memberSettings.create({
                                memberId: interaction.user.id,
                                name: "birthday",
                                value: birthday
                            });
                            await interaction.reply({ content: 'Je m\'en souviendrai. :thumbup:', ephemeral: true });
                            checkAnniv();
                        } catch (error) {
                            console.error('[' + 'ERREUR'.brightRed + '] Erreur lors de l\'insertion de la date d\'anniversaire: '.brightWhite + '\n', error);
                            await interaction.reply("J'ai eu un petit problème pour enregistrer ta date d'anniversaire, re-essaie plus-tard. :p");
                        }
                    }
                } else {
                    await interaction.reply('Tu ne peux pas redéfinir ta date d\'anniversaire. Demande au staff si besoin. :p');
                }
            } else if (interaction.commandName === 'delanniv') {
                // On check les perms
                if (interaction.member.roles.cache.has(config.get("ROLE_ANNIV"))) {
                    try {
                        console.log('\n' + '[' + 'DELETE'.brightMagenta + "] Suppression de la date d'anniversaire de " + interaction.options.getMember('membre'));
                        await memberSettings.destroy({
                            where: {
                                name: "birthday",
                                memberId: interaction.options.getMember('membre').id
                            }
                        });
                    } catch (error) {
                        console.error('[' + 'ERREUR'.brightRed + '] Erreur lors de la supression de la date d\'anniversaire: '.brightWhite + '\n', error);
                        await interaction.reply("J'ai eu un petit problème pour supprimer la date d'anniversaire, re-essaie plus-tard. :p");
                    }
    
                    await interaction.reply('La date d\'anniversaire de <@' + interaction.options.getMember('membre') + '> a été supprimée.');
                    checkAnniv();
                } else {
                    await interaction.reply("Tu n'as pas le droit d'exécuter cette commande.");
                }
    
            }
        }
    });
    
    
    async function checkAnniv() {
        console.log('[' + 'INFO'.yellow + '] Vérification des anniversaires.'.brightWhite);
    
        let today = new Date();
        var dd = today.getDate();
        var mm = today.getMonth() + 1;
    
        var yyyy = today.getFullYear();
        if (dd < 10) {
            dd = '0' + dd;
        }
        if (mm < 10) {
            mm = '0' + mm;
        }
        today = mm + '/' + dd;
    
        let { count, rows } = await memberSettings.findAndCountAll({
            where: {
                name: "birthday",
                value: {
                    [Op.like]: today + '%'
                }
            }
        });
    
        const guild = client.guilds.cache.get(config.get("GUILD_ID"));
        //console.log(guild);
    
        var membersWithAnnivRole = await guild.roles.cache.get(config.get("ROLE_ANNIV")).members;
        //console.log(membersWithAnnivRole);
    
        // On va vérifier que c'est bien l'anniv des membres ayant le rôle. :p
        for await (var memberWithAnnivRole of membersWithAnnivRole) {
    
            var isMemberBirthday = false;
            for await (const member of rows) {
                if (memberWithAnnivRole[0] === member.memberId.toString()) {
                    isMemberBirthday = true;
                }
            }
            if (!isMemberBirthday) {
                console.log('[' + 'INFO'.yellow + '] Suppression du rôle anniversaire pour '.brightWhite + memberWithAnnivRole[1].user.username);
                memberWithAnnivRole[1].roles.remove(config.get("ROLE_ANNIV")).catch(console.error);
            }
        }
        console.log('[' + 'SUCCES'.brightGreen + '] C\'est l\'anniversaire de ' + count + ' personne(s).');
    
        for await (var member of rows) {
            let memberFetch = await guild.members.fetch(member.memberId.toString());
            //console.log(memberFetch);
            if (memberFetch) {
                console.log(" 🎂 " + memberFetch.user.username);
                if (!memberFetch.roles.cache.has(config.get("ROLE_ANNIV"))) {
                    let annivRole = await memberFetch.guild.roles.cache.find(role => role.id === config.get("ROLE_ANNIV"));
                    if (annivRole) {
                        memberFetch.roles.add(annivRole);
                        console.log('[' + 'INFO'.yellow + '] Le rôle '.brightWhite + annivRole.name.yellow + "a été donné à " + memberFetch.user.username.brightBlue);
                        client.channels.cache.get(config.get("CANAL_GENERAL")).send("Fêtons l'anniversaire de <@" + memberFetch.id + "> ! :partying_face:").catch(console.error);
                    }
    
                }
            }
        }
    }
    
    async function verifyMcChatWebhook(){
        let mcChatWebhookId = await botSettings.findOne({ where: { name: "mcChatWebhookId" } });
        if(mcChatWebhookId != null){
            console.log("[" + 'INFO'.yellow + "] Le Webhook du serveur MC est déjà configuré.");
            let mcChatWebhookToken = await botSettings.findOne({ where: { name: "mcChatWebhookToken" } });
            if(mcChatWebhookToken){
                mcChatWebhook = new WebhookClient({ id: mcChatWebhookId.value, token: mcChatWebhookToken.value });
            }else{
                console.log("[" + 'ERREUR'.brightRed + "] Impossible de trouver le token du webhook dans la base de donnée.");
                createMcChatWebhook();
            }
        }else{
            createMcChatWebhook();
        }
    }
    
    async function createMcChatWebhook(){
        console.log("[" + 'INFO'.yellow + "] Création du Webhook du serveur MC.");
        client.channels.cache.get(config.get("CANAL_CHAT_MC")).createWebhook('Chat Serveur Minecraft', {
            avatar: 'https://sl-craft.fr/data/images/logo/short-color.png',
        })
        .then(webhook => {
            botSettings.create({
                name: "mcChatWebhookId",
                value: webhook.id
                });
            botSettings.create({
                name: "mcChatWebhookToken",
                value: webhook.token
                });
            mcChatWebhook = new WebhookClient({ id: mcChatWebhookId.value, token: mcChatWebhookToken.value });
            console.log("[" + 'INFO'.yellow + "] Le Webhook du serveur MC a été configuré avec succès.");
        })
        .catch(console.error);
    }
    
    function sendMessageFromMcChat(name, message){
        mcChatWebhook.send({
            content: message,
            username: "test"
        });
    }
    
    
    const job = schedule.scheduleJob('0 0 * * *', function(){
        console.log('[' + 'INFO'.yellow + '] Éxecution des tâches de fonds quotidiennes...'.brightWhite);
        checkAnniv();
    });
    
    
    // login to Discord with your app's token
    client.login(config.get("DISCORD_BOT_TOKEN"));
    
    ////////////////////////////////////////////////////////////////
    
    ////////////////////////////////////////////////////////////////
    // API
    ////////////////////////////////////////////////////////////////
    
    app.get('/ping', (req,res) => {
        res.send("Pong!")
    })
    app.get('/channels/:id', (req,res) => {
    	var id = req.params.id;
        res.send(client.channels.cache.get(id));
    })
    app.get('/mc/chat/:detail', (req,res) => {
        var detail = JSON.parse(decodeURI(req.params.detail));
        sendMessageFromMcChat(detail.username, detail.message);
        res.send("Envoyé!")
    })
    
    app.listen(27001, () => {
    	console.log('['+'INFO'.yellow+'] Écoute sur '.brightWhite+'node.sl-projects.com:27001'.yellow);
    });
    
    ////////////////////////////////////////////////////////////////