From c61d2186c65acbbe6f5628739fb26352eff26e7e Mon Sep 17 00:00:00 2001 From: Louis Mazin Date: Mon, 8 Dec 2025 21:53:40 +0100 Subject: [PATCH] nice --- commands/utility/link.js | 99 ++++++++++++++++++++++++++++++++++++++ commands/utility/unlink.js | 61 +++++++++++++++++++++++ database.js | 38 ++++++++++++++- 3 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 commands/utility/link.js create mode 100644 commands/utility/unlink.js diff --git a/commands/utility/link.js b/commands/utility/link.js new file mode 100644 index 0000000..53f66a5 --- /dev/null +++ b/commands/utility/link.js @@ -0,0 +1,99 @@ +const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits } = require('discord.js'); +const { getPendingPlayer, verifyLinkCode, updateUserLinkWithUsername } = require('../../database.js'); +const axios = require('axios'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('link') + .setDescription('Lier manuellement un compte Discord à un compte Palworld (Admin)') + .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) + .addStringOption(option => + option.setName('pseudo-palworld') + .setDescription('Le pseudo du joueur sur Palworld') + .setRequired(true)) + .addUserOption(option => + option.setName('discord-account') + .setDescription('Le compte Discord à lier') + .setRequired(true)), + + async execute(interaction) { + try { + await interaction.deferReply({ ephemeral: true }); + + const palworldName = interaction.options.getString('pseudo-palworld'); + const discordUser = interaction.options.getUser('discord-account'); + + // Récupérer le Steam ID depuis l'API Palworld + const response = await axios({ + method: 'get', + url: 'http://play.louismazin.ovh:8212/v1/api/players', + headers: { + 'Accept': 'application/json', + 'Authorization': `Basic ${process.env.PALWORLD_API_TOKEN}` + } + }); + + const players = response.data.players || {}; + let steamId = null; + + // Chercher le joueur par nom + for (const [id, player] of Object.entries(players)) { + if (player.name === palworldName) { + steamId = id; + break; + } + } + + if (!steamId) { + return interaction.editReply({ + content: `❌ Impossible de trouver le joueur **${palworldName}** sur le serveur.\n\n` + + `💡 Le joueur doit être connecté sur le serveur Palworld.`, + ephemeral: true + }); + } + + // Créer un code temporaire pour la liaison manuelle + const { generateLinkCode } = require('../../database.js'); + const code = await generateLinkCode(discordUser.id); + + // Effectuer la liaison immédiatement + const result = await verifyLinkCode(code, steamId, palworldName); + + if (result.success) { + await updateUserLinkWithUsername(discordUser.id, discordUser.tag); + + const embed = new EmbedBuilder() + .setColor(0x00FF00) + .setTitle('✅ Liaison manuelle réussie') + .addFields( + { name: '👤 Discord', value: `${discordUser.tag} (<@${discordUser.id}>)`, inline: false }, + { name: '🎮 Palworld', value: palworldName, inline: true }, + { name: '🆔 Steam ID', value: `\`${steamId}\``, inline: true } + ) + .setTimestamp(); + + // Envoyer un MP au joueur lié + await discordUser.send( + `✅ **Liaison effectuée par un administrateur**\n\n` + + `Votre compte Discord a été lié à votre compte Palworld:\n` + + `🎮 Nom Palworld: **${palworldName}**\n` + + `🆔 Steam ID: \`${steamId}\`` + ).catch(() => {}); + + await interaction.editReply({ embeds: [embed], ephemeral: true }); + } else { + await interaction.editReply({ + content: `❌ Erreur lors de la liaison: ${result.message}`, + ephemeral: true + }); + } + + } catch (error) { + console.error('Erreur lors de la liaison manuelle:', error); + await interaction.editReply({ + content: '❌ Une erreur est survenue lors de la liaison.', + ephemeral: true + }); + } + }, +}; diff --git a/commands/utility/unlink.js b/commands/utility/unlink.js new file mode 100644 index 0000000..3478074 --- /dev/null +++ b/commands/utility/unlink.js @@ -0,0 +1,61 @@ +const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits } = require('discord.js'); +const { getUserLink, deleteUserLink } = require('../../database.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('unlink') + .setDescription('Délier un compte Discord de son compte Palworld (Admin)') + .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) + .addUserOption(option => + option.setName('discord-account') + .setDescription('Le compte Discord à délier') + .setRequired(true)), + + async execute(interaction) { + try { + await interaction.deferReply({ ephemeral: true }); + + const discordUser = interaction.options.getUser('discord-account'); + + // Vérifier si l'utilisateur est lié + const existingLink = await getUserLink(discordUser.id); + + if (!existingLink) { + return interaction.editReply({ + content: `❌ Le compte <@${discordUser.id}> n'est pas lié à un compte Palworld.`, + ephemeral: true + }); + } + + // Supprimer la liaison + await deleteUserLink(discordUser.id); + + const embed = new EmbedBuilder() + .setColor(0xFF0000) + .setTitle('🔓 Liaison supprimée') + .setDescription(`Le compte Discord a été délié avec succès.`) + .addFields( + { name: '👤 Discord', value: `${discordUser.tag} (<@${discordUser.id}>)`, inline: false }, + { name: '🎮 Palworld (ancien)', value: existingLink.palworld_username, inline: true }, + { name: '🆔 Steam ID (ancien)', value: `\`${existingLink.steam_id}\``, inline: true } + ) + .setTimestamp(); + + // Envoyer un MP au joueur délié + await discordUser.send( + `🔓 **Liaison supprimée**\n\n` + + `Votre compte Discord a été délié de votre compte Palworld par un administrateur.\n` + + `Vous pouvez vous lier à nouveau avec \`/rygainland-link\`.` + ).catch(() => {}); + + await interaction.editReply({ embeds: [embed], ephemeral: true }); + + } catch (error) { + console.error('Erreur lors de la suppression de la liaison:', error); + await interaction.editReply({ + content: '❌ Une erreur est survenue lors de la suppression de la liaison.', + ephemeral: true + }); + } + }, +}; diff --git a/database.js b/database.js index 1b1934e..77d54a0 100644 --- a/database.js +++ b/database.js @@ -131,6 +131,38 @@ const updateUserLinkWithUsername = async (discordId, discordUsername) => { ); }; +const deleteUserLink = async (discordId) => { + const connection = getConnection(); + await connection.execute( + 'DELETE FROM user_links WHERE discord_id = ?', + [discordId] + ); +}; + +const getPendingPlayer = async (steamId) => { + const connection = getConnection(); + const [rows] = await connection.execute( + 'SELECT * FROM pending_players WHERE steam_id = ?', + [steamId] + ); + return rows.length > 0 ? rows[0] : null; +}; + +const hasActiveLinkCodes = async () => { + const connection = getConnection(); + const [rows] = await connection.execute( + 'SELECT COUNT(*) as count FROM link_codes WHERE used = FALSE AND expires_at > NOW()' + ); + return rows[0].count > 0; +}; + +const cleanExpiredCodes = async () => { + const connection = getConnection(); + await connection.execute( + 'DELETE FROM link_codes WHERE expires_at < NOW()' + ); +}; + module.exports = { initDatabase, getConnection, @@ -139,5 +171,9 @@ module.exports = { verifyLinkCode, getAllLinks, getUserLink, - updateUserLinkWithUsername + updateUserLinkWithUsername, + deleteUserLink, + getPendingPlayer, + hasActiveLinkCodes, + cleanExpiredCodes };