238 lines
10 KiB
JavaScript
238 lines
10 KiB
JavaScript
const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits } = require('discord.js');
|
|
const { clashRoyaleAPI } = require('../services/clashRoyaleService');
|
|
const { UserProfileService } = require('../utils/database');
|
|
|
|
module.exports = {
|
|
data: new SlashCommandBuilder()
|
|
.setName('sync')
|
|
.setDescription('Associer votre profil Clash Royale à votre compte Discord')
|
|
.addStringOption(option =>
|
|
option
|
|
.setName('id')
|
|
.setDescription('Votre tag Clash Royale (ex: #ABC123DEF)')
|
|
.setRequired(true)
|
|
),
|
|
|
|
async execute(interaction, client) {
|
|
await interaction.deferReply({ ephemeral: true });
|
|
|
|
try {
|
|
// Vérification du rôle requis
|
|
const requiredRoleId = process.env.CLASH_ROYALE_ROLE_ID;
|
|
if (!interaction.member.roles.cache.has(requiredRoleId)) {
|
|
const errorEmbed = new EmbedBuilder()
|
|
.setColor('#FF0000')
|
|
.setTitle('❌ Accès refusé')
|
|
.setDescription('Vous devez avoir le rôle requis pour utiliser cette commande.')
|
|
.addFields([
|
|
{
|
|
name: 'Rôle requis',
|
|
value: `<@&${requiredRoleId}>`,
|
|
inline: true
|
|
}
|
|
])
|
|
.setTimestamp();
|
|
|
|
await interaction.editReply({ embeds: [errorEmbed] });
|
|
return;
|
|
}
|
|
|
|
const clashTag = interaction.options.getString('id');
|
|
const discordId = interaction.user.id;
|
|
|
|
client.logger.clash(`Tentative de synchronisation: ${interaction.user.tag} -> ${clashTag}`);
|
|
|
|
// Vérifier si l'utilisateur a déjà un profil synchronisé
|
|
const existingProfile = await UserProfileService.getByDiscordId(discordId);
|
|
|
|
// Vérifier si le tag Clash Royale est déjà utilisé par quelqu'un d'autre
|
|
const existingClashProfile = await UserProfileService.getByClashTag(clashTag);
|
|
if (existingClashProfile && existingClashProfile.discord_id !== discordId) {
|
|
const conflictEmbed = new EmbedBuilder()
|
|
.setColor('#FF6B00')
|
|
.setTitle('⚠️ Tag déjà utilisé')
|
|
.setDescription('Ce tag Clash Royale est déjà associé à un autre utilisateur Discord.')
|
|
.addFields([
|
|
{
|
|
name: 'Tag Clash Royale',
|
|
value: `\`${clashTag}\``,
|
|
inline: true
|
|
},
|
|
{
|
|
name: 'Solution',
|
|
value: 'Vérifiez que vous avez entré le bon tag ou contactez un administrateur.',
|
|
inline: false
|
|
}
|
|
])
|
|
.setTimestamp();
|
|
|
|
await interaction.editReply({ embeds: [conflictEmbed] });
|
|
return;
|
|
}
|
|
|
|
// Valider le profil Clash Royale via l'API
|
|
const validationResult = await clashRoyaleAPI.validatePlayer(clashTag);
|
|
|
|
if (!validationResult.valid) {
|
|
let errorMessage = 'Tag Clash Royale invalide ou joueur non trouvé.';
|
|
let errorTitle = '❌ Profil non trouvé';
|
|
|
|
switch (validationResult.error.type) {
|
|
case 'NOT_FOUND':
|
|
errorMessage = 'Aucun joueur trouvé avec ce tag. Vérifiez que vous avez entré le bon tag.';
|
|
break;
|
|
case 'BAD_REQUEST':
|
|
errorMessage = 'Format de tag invalide. Utilisez le format #ABC123DEF.';
|
|
break;
|
|
case 'RATE_LIMITED':
|
|
errorMessage = 'Trop de requêtes à l\'API. Réessayez dans quelques minutes.';
|
|
errorTitle = '⏳ Limite atteinte';
|
|
break;
|
|
case 'SERVICE_UNAVAILABLE':
|
|
errorMessage = 'API Clash Royale temporairement indisponible. Réessayez plus tard.';
|
|
errorTitle = '🛠️ Maintenance';
|
|
break;
|
|
}
|
|
|
|
const errorEmbed = new EmbedBuilder()
|
|
.setColor('#FF0000')
|
|
.setTitle(errorTitle)
|
|
.setDescription(errorMessage)
|
|
.addFields([
|
|
{
|
|
name: 'Tag fourni',
|
|
value: `\`${clashTag}\``,
|
|
inline: true
|
|
},
|
|
{
|
|
name: 'Aide',
|
|
value: 'Le tag se trouve dans votre profil Clash Royale, sous votre nom.',
|
|
inline: false
|
|
}
|
|
])
|
|
.setTimestamp();
|
|
|
|
await interaction.editReply({ embeds: [errorEmbed] });
|
|
return;
|
|
}
|
|
|
|
const playerData = validationResult.data;
|
|
|
|
// Créer ou mettre à jour le profil dans la base de données
|
|
const profile = await UserProfileService.createOrUpdate(discordId, playerData);
|
|
|
|
client.logger.success(`Profil synchronisé: ${playerData.name} (${playerData.tag})`);
|
|
|
|
// Déterminer si c'est une nouvelle synchronisation ou une mise à jour
|
|
const isNewSync = !existingProfile;
|
|
const actionText = isNewSync ? 'synchronisé' : 'mis à jour';
|
|
const actionEmoji = isNewSync ? '🎉' : '🔄';
|
|
|
|
// Créer l'embed de confirmation
|
|
const successEmbed = new EmbedBuilder()
|
|
.setColor('#00FF00')
|
|
.setTitle(`${actionEmoji} Profil ${actionText} avec succès !`)
|
|
.setDescription(`Votre compte Discord est maintenant associé à votre profil Clash Royale.`)
|
|
.setThumbnail(interaction.user.displayAvatarURL({ dynamic: true }))
|
|
.addFields([
|
|
{
|
|
name: '👤 Nom du joueur',
|
|
value: playerData.name,
|
|
inline: true
|
|
},
|
|
{
|
|
name: '🏷️ Tag Clash Royale',
|
|
value: `\`${playerData.tag}\``,
|
|
inline: true
|
|
},
|
|
{
|
|
name: '🏆 Trophées actuels',
|
|
value: `${playerData.trophies.toLocaleString()}`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: '🥇 Meilleur score',
|
|
value: `${playerData.bestTrophies.toLocaleString()}`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: '⭐ Niveau',
|
|
value: `${playerData.expLevel}`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: '🏰 Clan',
|
|
value: playerData.clan ?
|
|
`${playerData.clan.name}\n\`${playerData.clan.tag}\`\n*${playerData.clan.role}*` :
|
|
'Aucun clan',
|
|
inline: true
|
|
}
|
|
])
|
|
.addFields([
|
|
{
|
|
name: '✨ Fonctionnalités disponibles',
|
|
value: '• Classement automatique du serveur\n• Félicitations pour les gains de trophées\n• Statistiques personnalisées\n• Comparaisons avec les autres membres',
|
|
inline: false
|
|
}
|
|
])
|
|
.setFooter({
|
|
text: `${isNewSync ? 'Première synchronisation' : 'Profile mis à jour'} • Clash Royale Bot`,
|
|
iconURL: client.user.displayAvatarURL()
|
|
})
|
|
.setTimestamp();
|
|
|
|
await interaction.editReply({ embeds: [successEmbed] });
|
|
|
|
// Log dans le canal de logs si configuré
|
|
try {
|
|
const logChannel = client.channels.cache.get(process.env.LOGS_CHANNEL_ID);
|
|
if (logChannel) {
|
|
const logEmbed = new EmbedBuilder()
|
|
.setColor('#00BFFF')
|
|
.setTitle('📊 Nouvelle synchronisation')
|
|
.setDescription(`Un utilisateur a ${actionText} son profil Clash Royale`)
|
|
.addFields([
|
|
{
|
|
name: 'Utilisateur Discord',
|
|
value: `${interaction.user.tag} (<@${interaction.user.id}>)`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: 'Joueur Clash Royale',
|
|
value: `${playerData.name} (\`${playerData.tag}\`)`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: 'Trophées',
|
|
value: `${playerData.trophies.toLocaleString()}`,
|
|
inline: true
|
|
}
|
|
])
|
|
.setTimestamp();
|
|
|
|
await logChannel.send({ embeds: [logEmbed] });
|
|
}
|
|
} catch (error) {
|
|
client.logger.warning('Impossible d\'envoyer le log de synchronisation');
|
|
}
|
|
|
|
} catch (error) {
|
|
client.logger.error(`Erreur lors de la synchronisation: ${error.message}`);
|
|
|
|
const errorEmbed = new EmbedBuilder()
|
|
.setColor('#FF0000')
|
|
.setTitle('❌ Erreur interne')
|
|
.setDescription('Une erreur s\'est produite lors de la synchronisation. Veuillez réessayer.')
|
|
.addFields([
|
|
{
|
|
name: 'Code d\'erreur',
|
|
value: `\`${error.message}\``,
|
|
inline: false
|
|
}
|
|
])
|
|
.setTimestamp();
|
|
|
|
await interaction.editReply({ embeds: [errorEmbed] });
|
|
}
|
|
}
|
|
}; |