Update Bot
This commit is contained in:
@@ -4,53 +4,85 @@
|
||||
*/
|
||||
|
||||
const chalk = require('chalk');
|
||||
const { EmbedBuilder } = require('discord.js');
|
||||
const { colors } = require('../../utils/constants');
|
||||
|
||||
module.exports = (client, db) => {
|
||||
setInterval(async () => {
|
||||
try {
|
||||
const now = Date.now();
|
||||
const twoHours = 2 * 60 * 60 * 1000;
|
||||
|
||||
// Récupérer tous les bumps de plus de 2h qui n'ont pas encore eu de rappel
|
||||
const [bumps] = await db.query(
|
||||
'SELECT * FROM bumps WHERE reminderSent = ? AND bumpTime <= ?',
|
||||
[false, now - twoHours]
|
||||
);
|
||||
|
||||
if (!bumps.length) return;
|
||||
|
||||
for (const bump of bumps) {
|
||||
try {
|
||||
const guild = client.guilds.cache.get(bump.guildId);
|
||||
if (!guild) continue;
|
||||
|
||||
const member = await guild.members.fetch(bump.userId).catch(() => null);
|
||||
if (!member) continue;
|
||||
|
||||
const [bumpChannels] = await db.query('SELECT * FROM bump_channels WHERE guildId = ?', [bump.guildId]);
|
||||
let channel = bumpChannels.length > 0 ? guild.channels.cache.get(bumpChannels[0].channelId) : guild.systemChannel;
|
||||
|
||||
if (!channel) continue;
|
||||
|
||||
const reminderEmbed = new EmbedBuilder()
|
||||
.setTitle('⏰ Rappel de Bump')
|
||||
.setDescription(`${member.toString()}, tu peux maintenant refaire un bump !`)
|
||||
.setColor(colors.info)
|
||||
.setFooter({ text: 'Utilise /bump (Disboard) pour bump le serveur • /bumptime pour vérifier' })
|
||||
.setTimestamp();
|
||||
|
||||
await channel.send({ embeds: [reminderEmbed] });
|
||||
|
||||
await db.query('UPDATE bumps SET reminderSent = ? WHERE id = ?', [true, bump.id]);
|
||||
console.log(chalk.green(`✅ Reminder de bump envoyé à ${member.user.tag} dans la guild ${guild.name}`));
|
||||
} catch (err) {
|
||||
console.error(chalk.red(`❌ Erreur reminder bump ${bump.id}:`), err);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(chalk.red('❌ Erreur vérification reminders bump:'), err);
|
||||
}
|
||||
}, 60 * 1000);
|
||||
};
|
||||
setInterval(async () => {
|
||||
try {
|
||||
const now = Date.now();
|
||||
// Récupérer les bumps qui ont besoin d'un reminder (2h après, avec une fenêtre de 1 minute)
|
||||
const twoHours = 2 * 60 * 60 * 1000;
|
||||
const oneMinute = 60 * 1000;
|
||||
|
||||
const [bumps] = await db.query(
|
||||
'SELECT * FROM bumps WHERE reminderSent = ? AND bumpTime <= ? AND bumpTime >= ?',
|
||||
[false, now - twoHours + oneMinute, now - twoHours - oneMinute]
|
||||
);
|
||||
|
||||
if (!bumps.length) return;
|
||||
|
||||
for (const bump of bumps) {
|
||||
try {
|
||||
const guild = client.guilds.cache.get(bump.guildId);
|
||||
if (!guild) {
|
||||
console.warn(chalk.yellow(`⚠️ Impossible d'envoyer le reminder de bump: le bot n'est pas dans la guild ${bump.guildId}`));
|
||||
continue;
|
||||
}
|
||||
|
||||
const member = await guild.members.fetch(bump.userId).catch(() => null);
|
||||
if (!member) {
|
||||
console.warn(chalk.yellow(`⚠️ Utilisateur ${bump.userId} introuvable dans la guild ${guild.id}`));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Trouver le canal de bump (ou utiliser le canal système)
|
||||
// On cherche dans les canaux de bump configurés, sinon on utilise le canal système
|
||||
const [bumpChannels] = await db.query(
|
||||
'SELECT * FROM bump_channels WHERE guildId = ?',
|
||||
[bump.guildId]
|
||||
);
|
||||
|
||||
let channel = null;
|
||||
if (bumpChannels.length > 0) {
|
||||
// Utiliser le premier canal de bump configuré
|
||||
channel = guild.channels.cache.get(bumpChannels[0].channelId);
|
||||
}
|
||||
|
||||
// Si pas de canal de bump configuré, utiliser le canal système
|
||||
if (!channel) {
|
||||
channel = guild.systemChannel;
|
||||
}
|
||||
|
||||
if (!channel) {
|
||||
console.warn(chalk.yellow(`⚠️ Aucun canal disponible pour envoyer le reminder de bump dans la guild ${guild.id}`));
|
||||
continue;
|
||||
}
|
||||
|
||||
const { EmbedBuilder } = require('discord.js');
|
||||
const { colors } = require('../../utils/constants');
|
||||
|
||||
const reminderEmbed = new EmbedBuilder()
|
||||
.setTitle('⏰ Rappel de Bump')
|
||||
.setDescription(`${member.toString()}, tu peux maintenant refaire un bump !`)
|
||||
.setColor(colors.info)
|
||||
.setFooter({ text: 'Utilise /bump (Disboard) pour bump le serveur • /bumptime pour vérifier' })
|
||||
.setTimestamp();
|
||||
|
||||
await channel.send({ embeds: [reminderEmbed] });
|
||||
|
||||
// Marquer le reminder comme envoyé
|
||||
await db.query(
|
||||
'UPDATE bumps SET reminderSent = ? WHERE id = ?',
|
||||
[true, bump.id]
|
||||
);
|
||||
|
||||
console.log(chalk.green(`✅ Reminder de bump envoyé à ${member.user.tag} dans la guild ${guild.name}`));
|
||||
} catch (err) {
|
||||
console.error(chalk.red(`❌ Erreur lors de l'envoi du reminder de bump ${bump.id}:`), err);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(chalk.red('❌ Erreur lors de la vérification des reminders de bump:'), err);
|
||||
}
|
||||
}, 60 * 1000); // Vérifier toutes les minutes
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST || '192.168.1.6',
|
||||
user: process.env.DB_USER || 'bot',
|
||||
password: process.env.DB_PASSWORD || 'NxKr63LJB65pHv%t7E$JqgxKRsZMw%VIHEZAjq%^O0KYKjW#cRc^ebIH@%S9kaTh*GIg^D3ai4KBjMeXEh6xwv#9afQIR2$!2UB8C3ToXjnYFmzR%$lfpshnf8g@8229',
|
||||
database: process.env.DB_NAME || 'bot',
|
||||
host: process.env.DB_HOST || '192.168.1.6',
|
||||
user: process.env.DB_USER || 'bot',
|
||||
password: process.env.DB_PASSWORD || 'NxKr63LJB65pHv%t7E$JqgxKRsZMw%VIHEZAjq%^O0KYKjW#cRc^ebIH@%S9kaTh*GIg^D3ai4KBjMeXEh6xwv#9afQIR2$!2UB8C3ToXjnYFmzR%$lfpshnf8g@8229',
|
||||
database: process.env.DB_NAME || 'bot',
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0
|
||||
@@ -13,20 +13,28 @@ const pool = mysql.createPool({
|
||||
async function initDB() {
|
||||
const conn = await pool.getConnection();
|
||||
try {
|
||||
// Tables de modération
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS bans (
|
||||
userId VARCHAR(32),
|
||||
guildId VARCHAR(32),
|
||||
userId VARCHAR(32),
|
||||
guildId VARCHAR(32),
|
||||
reason TEXT,
|
||||
modId VARCHAR(32),
|
||||
timestamp BIGINT,
|
||||
type VARCHAR(20) NOT NULL,
|
||||
unbanDate BIGINT,
|
||||
PRIMARY KEY (userId, guildId)
|
||||
)
|
||||
unbanDate BIGINT,
|
||||
PRIMARY KEY (userId, guildId)
|
||||
)
|
||||
`);
|
||||
|
||||
// Ajouter la colonne guildId si elle n'existe pas (migration)
|
||||
try {
|
||||
await conn.query('ALTER TABLE bans ADD COLUMN guildId VARCHAR(32)');
|
||||
await conn.query('ALTER TABLE bans DROP PRIMARY KEY');
|
||||
await conn.query('ALTER TABLE bans ADD PRIMARY KEY (userId, guildId)');
|
||||
} catch {
|
||||
// La colonne existe déjà, on continue
|
||||
}
|
||||
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS logs (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
@@ -34,203 +42,231 @@ async function initDB() {
|
||||
userTag VARCHAR(100),
|
||||
modId VARCHAR(32),
|
||||
modTag VARCHAR(100),
|
||||
action VARCHAR(50),
|
||||
action VARCHAR(50),
|
||||
reason TEXT,
|
||||
type ENUM('Permanent','Temporary') DEFAULT 'Permanent',
|
||||
guildId VARCHAR(32),
|
||||
guildId VARCHAR(32),
|
||||
timestamp BIGINT
|
||||
)
|
||||
`);
|
||||
|
||||
// Ajouter la colonne guildId si elle n'existe pas (migration)
|
||||
try {
|
||||
await conn.query('ALTER TABLE logs ADD COLUMN guildId VARCHAR(32)');
|
||||
} catch {
|
||||
// La colonne existe déjà, on continue
|
||||
}
|
||||
|
||||
// Agrandir la colonne action si elle est trop petite (migration)
|
||||
try {
|
||||
await conn.query('ALTER TABLE logs MODIFY COLUMN action VARCHAR(50)');
|
||||
} catch {
|
||||
// La colonne est déjà de la bonne taille ou n'existe pas, on continue
|
||||
}
|
||||
|
||||
// Table pour les mutes
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS mutes (
|
||||
userId VARCHAR(32),
|
||||
guildId VARCHAR(32),
|
||||
reason TEXT,
|
||||
modId VARCHAR(32),
|
||||
modTag VARCHAR(100),
|
||||
timestamp BIGINT,
|
||||
unmuteDate BIGINT,
|
||||
type VARCHAR(20) NOT NULL,
|
||||
PRIMARY KEY (userId, guildId)
|
||||
)
|
||||
`);
|
||||
|
||||
// Table pour les messages de ban personnalisés
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS staffbanmessages (
|
||||
userId VARCHAR(32) PRIMARY KEY,
|
||||
userTag VARCHAR(100),
|
||||
message TEXT,
|
||||
timestamp BIGINT
|
||||
)
|
||||
)
|
||||
`);
|
||||
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS mutes (
|
||||
userId VARCHAR(32),
|
||||
guildId VARCHAR(32),
|
||||
reason TEXT,
|
||||
modId VARCHAR(32),
|
||||
modTag VARCHAR(100),
|
||||
timestamp BIGINT,
|
||||
unmuteDate BIGINT,
|
||||
type VARCHAR(20) NOT NULL,
|
||||
PRIMARY KEY (userId, guildId)
|
||||
)
|
||||
`);
|
||||
// Table pour les tickets
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS tickets (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ticketId VARCHAR(20) UNIQUE NOT NULL,
|
||||
channelId VARCHAR(32) UNIQUE NOT NULL,
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
userTag VARCHAR(100),
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
type ENUM('Support', 'Plainte', 'Plainte Staff', 'Candidature', 'Problème Technique') NOT NULL,
|
||||
status ENUM('Ouvert', 'Fermé', 'En attente', 'Supprimé') DEFAULT 'Ouvert',
|
||||
createdAt BIGINT NOT NULL,
|
||||
closedAt BIGINT,
|
||||
closedBy VARCHAR(32),
|
||||
transcript TEXT,
|
||||
transcriptPath VARCHAR(255),
|
||||
INDEX idx_userId (userId),
|
||||
INDEX idx_guildId (guildId),
|
||||
INDEX idx_status (status)
|
||||
)
|
||||
`);
|
||||
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS staffbanmessages (
|
||||
userId VARCHAR(32) PRIMARY KEY,
|
||||
userTag VARCHAR(100),
|
||||
message TEXT,
|
||||
timestamp BIGINT
|
||||
)
|
||||
`);
|
||||
// Ajouter la colonne transcriptPath si elle n'existe pas (migration)
|
||||
try {
|
||||
await conn.query('ALTER TABLE tickets ADD COLUMN transcriptPath VARCHAR(255)');
|
||||
} catch {
|
||||
// La colonne existe déjà, on continue
|
||||
}
|
||||
|
||||
// Tables de tickets
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS tickets (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ticketId VARCHAR(20) UNIQUE NOT NULL,
|
||||
channelId VARCHAR(32) UNIQUE NOT NULL,
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
userTag VARCHAR(100),
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
type ENUM('Support', 'Plainte', 'Plainte Staff', 'Candidature', 'Problème Technique') NOT NULL,
|
||||
status ENUM('Ouvert', 'Fermé', 'En attente', 'Supprimé') DEFAULT 'Ouvert',
|
||||
createdAt BIGINT NOT NULL,
|
||||
closedAt BIGINT,
|
||||
closedBy VARCHAR(32),
|
||||
transcript TEXT,
|
||||
transcriptPath VARCHAR(255),
|
||||
claimedBy VARCHAR(32),
|
||||
claimedAt BIGINT,
|
||||
claimedByTag VARCHAR(100),
|
||||
INDEX idx_userId (userId),
|
||||
INDEX idx_guildId (guildId),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_claimedBy (claimedBy)
|
||||
)
|
||||
`);
|
||||
// Ajouter la colonne claimedBy si elle n'existe pas (migration)
|
||||
try {
|
||||
await conn.query('ALTER TABLE tickets ADD COLUMN claimedBy VARCHAR(32)');
|
||||
} catch {
|
||||
// La colonne existe déjà, on continue
|
||||
}
|
||||
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS ticket_messages (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ticketId VARCHAR(20) NOT NULL,
|
||||
messageId VARCHAR(32) NOT NULL,
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
userTag VARCHAR(100),
|
||||
content TEXT,
|
||||
attachments TEXT,
|
||||
timestamp BIGINT NOT NULL,
|
||||
INDEX idx_ticketId (ticketId),
|
||||
INDEX idx_messageId (messageId)
|
||||
)
|
||||
`);
|
||||
// Ajouter la colonne claimedAt si elle n'existe pas (migration)
|
||||
try {
|
||||
await conn.query('ALTER TABLE tickets ADD COLUMN claimedAt BIGINT');
|
||||
} catch {
|
||||
// La colonne existe déjà, on continue
|
||||
}
|
||||
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS candidature_responses (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ticketId VARCHAR(20) NOT NULL,
|
||||
questionNumber INT NOT NULL,
|
||||
question TEXT NOT NULL,
|
||||
response TEXT,
|
||||
timestamp BIGINT NOT NULL,
|
||||
INDEX idx_ticketId (ticketId)
|
||||
)
|
||||
`);
|
||||
// Ajouter la colonne claimedByTag si elle n'existe pas (migration)
|
||||
try {
|
||||
await conn.query('ALTER TABLE tickets ADD COLUMN claimedByTag VARCHAR(100)');
|
||||
} catch {
|
||||
// La colonne existe déjà, on continue
|
||||
}
|
||||
|
||||
// Tables XP
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS user_xp (
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
xp INT DEFAULT 0,
|
||||
level INT DEFAULT 0,
|
||||
lastMessageTime BIGINT DEFAULT 0,
|
||||
totalMessages INT DEFAULT 0,
|
||||
totalVoiceTime INT DEFAULT 0,
|
||||
lastVoiceJoin BIGINT DEFAULT 0,
|
||||
lastBumpTime BIGINT DEFAULT 0,
|
||||
PRIMARY KEY (userId, guildId),
|
||||
INDEX idx_guildId (guildId),
|
||||
INDEX idx_xp (xp),
|
||||
INDEX idx_level (level)
|
||||
)
|
||||
`);
|
||||
// Ajouter l'index pour claimedBy si elle n'existe pas (migration)
|
||||
try {
|
||||
await conn.query('CREATE INDEX idx_claimedBy ON tickets(claimedBy)');
|
||||
} catch {
|
||||
// L'index existe déjà, on continue
|
||||
}
|
||||
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS xp_excluded_channels (
|
||||
channelId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
reason VARCHAR(255),
|
||||
addedBy VARCHAR(32),
|
||||
addedAt BIGINT,
|
||||
PRIMARY KEY (channelId, guildId),
|
||||
INDEX idx_guildId (guildId)
|
||||
)
|
||||
`);
|
||||
// Table pour les messages des tickets (pour transcription)
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS ticket_messages (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ticketId VARCHAR(20) NOT NULL,
|
||||
messageId VARCHAR(32) NOT NULL,
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
userTag VARCHAR(100),
|
||||
content TEXT,
|
||||
attachments TEXT,
|
||||
timestamp BIGINT NOT NULL,
|
||||
INDEX idx_ticketId (ticketId),
|
||||
INDEX idx_messageId (messageId)
|
||||
)
|
||||
`);
|
||||
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS xp_logs (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
xpGained INT NOT NULL,
|
||||
source VARCHAR(50) NOT NULL,
|
||||
multiplier DECIMAL(3,2) DEFAULT 1.00,
|
||||
timestamp BIGINT NOT NULL,
|
||||
INDEX idx_userId (userId),
|
||||
INDEX idx_guildId (guildId),
|
||||
INDEX idx_timestamp (timestamp)
|
||||
)
|
||||
`);
|
||||
// Table pour les réponses aux questions de candidature
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS candidature_responses (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ticketId VARCHAR(20) NOT NULL,
|
||||
questionNumber INT NOT NULL,
|
||||
question TEXT NOT NULL,
|
||||
response TEXT,
|
||||
timestamp BIGINT NOT NULL,
|
||||
INDEX idx_ticketId (ticketId)
|
||||
)
|
||||
`);
|
||||
|
||||
// Tables Bump
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS bumps (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
bumpTime BIGINT NOT NULL,
|
||||
reminderSent BOOLEAN DEFAULT FALSE,
|
||||
INDEX idx_userId (userId),
|
||||
INDEX idx_guildId (guildId),
|
||||
INDEX idx_bumpTime (bumpTime)
|
||||
)
|
||||
`);
|
||||
// Table pour les niveaux/XP des utilisateurs
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS user_xp (
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
xp INT DEFAULT 0,
|
||||
level INT DEFAULT 0,
|
||||
lastMessageTime BIGINT DEFAULT 0,
|
||||
totalMessages INT DEFAULT 0,
|
||||
totalVoiceTime INT DEFAULT 0,
|
||||
lastVoiceJoin BIGINT DEFAULT 0,
|
||||
lastBumpTime BIGINT DEFAULT 0,
|
||||
PRIMARY KEY (userId, guildId),
|
||||
INDEX idx_guildId (guildId),
|
||||
INDEX idx_xp (xp),
|
||||
INDEX idx_level (level)
|
||||
)
|
||||
`);
|
||||
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS bump_channels (
|
||||
channelId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
bumpBotId VARCHAR(32),
|
||||
addedBy VARCHAR(32),
|
||||
addedAt BIGINT,
|
||||
PRIMARY KEY (channelId, guildId),
|
||||
INDEX idx_guildId (guildId)
|
||||
)
|
||||
`);
|
||||
// Table pour les salons exclus de l'XP
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS xp_excluded_channels (
|
||||
channelId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
reason VARCHAR(255),
|
||||
addedBy VARCHAR(32),
|
||||
addedAt BIGINT,
|
||||
PRIMARY KEY (channelId, guildId),
|
||||
INDEX idx_guildId (guildId)
|
||||
)
|
||||
`);
|
||||
|
||||
// Tables Profils
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS user_profiles (
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
signature TEXT,
|
||||
birthday DATE,
|
||||
color VARCHAR(7),
|
||||
gender VARCHAR(50),
|
||||
location VARCHAR(100),
|
||||
updatedAt BIGINT,
|
||||
PRIMARY KEY (userId, guildId),
|
||||
INDEX idx_guildId (guildId)
|
||||
)
|
||||
`);
|
||||
// Table pour les logs de gain d'XP (optionnel, pour debugging)
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS xp_logs (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
xpGained INT NOT NULL,
|
||||
source VARCHAR(50) NOT NULL,
|
||||
multiplier DECIMAL(3,2) DEFAULT 1.00,
|
||||
timestamp BIGINT NOT NULL,
|
||||
INDEX idx_userId (userId),
|
||||
INDEX idx_guildId (guildId),
|
||||
INDEX idx_timestamp (timestamp)
|
||||
)
|
||||
`);
|
||||
|
||||
// Migrations (pour compatibilité existante)
|
||||
// On utilise la syntaxe standard sans IF NOT EXISTS pour compatibilité maximale
|
||||
try {
|
||||
await conn.query('ALTER TABLE bans ADD COLUMN guildId VARCHAR(32)');
|
||||
await conn.query('ALTER TABLE bans DROP PRIMARY KEY');
|
||||
await conn.query('ALTER TABLE bans ADD PRIMARY KEY (userId, guildId)');
|
||||
} catch {}
|
||||
|
||||
try { await conn.query('ALTER TABLE logs ADD COLUMN guildId VARCHAR(32)'); } catch {}
|
||||
try { await conn.query('ALTER TABLE logs MODIFY COLUMN action VARCHAR(50)'); } catch {}
|
||||
try { await conn.query('ALTER TABLE tickets ADD COLUMN transcriptPath VARCHAR(255)'); } catch {}
|
||||
try { await conn.query('ALTER TABLE tickets ADD COLUMN claimedBy VARCHAR(32)'); } catch {}
|
||||
try { await conn.query('ALTER TABLE tickets ADD COLUMN claimedAt BIGINT'); } catch {}
|
||||
try { await conn.query('ALTER TABLE tickets ADD COLUMN claimedByTag VARCHAR(100)'); } catch {}
|
||||
|
||||
// Migrations Profils (Sans IF NOT EXISTS)
|
||||
try { await conn.query('ALTER TABLE user_profiles ADD COLUMN color VARCHAR(7)'); } catch {}
|
||||
try { await conn.query('ALTER TABLE user_profiles ADD COLUMN gender VARCHAR(50)'); } catch {}
|
||||
try { await conn.query('ALTER TABLE user_profiles ADD COLUMN location VARCHAR(100)'); } catch {}
|
||||
// Table pour stocker les bumps (pour reminder et XP)
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS bumps (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
bumpTime BIGINT NOT NULL,
|
||||
reminderSent BOOLEAN DEFAULT FALSE,
|
||||
INDEX idx_userId (userId),
|
||||
INDEX idx_guildId (guildId),
|
||||
INDEX idx_bumpTime (bumpTime)
|
||||
)
|
||||
`);
|
||||
|
||||
} finally {
|
||||
conn.release();
|
||||
}
|
||||
// Table pour stocker les salons de bump (configuration)
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS bump_channels (
|
||||
channelId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
bumpBotId VARCHAR(32),
|
||||
addedBy VARCHAR(32),
|
||||
addedAt BIGINT,
|
||||
PRIMARY KEY (channelId, guildId),
|
||||
INDEX idx_guildId (guildId)
|
||||
)
|
||||
`);
|
||||
|
||||
// Table pour les profils utilisateurs (signatures, etc.)
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS user_profiles (
|
||||
userId VARCHAR(32) NOT NULL,
|
||||
guildId VARCHAR(32) NOT NULL,
|
||||
signature TEXT,
|
||||
birthday DATE,
|
||||
updatedAt BIGINT,
|
||||
PRIMARY KEY (userId, guildId),
|
||||
INDEX idx_guildId (guildId)
|
||||
)
|
||||
`);
|
||||
} finally {
|
||||
conn.release();
|
||||
}
|
||||
}
|
||||
|
||||
initDB().catch(console.error);
|
||||
|
||||
module.exports = pool;
|
||||
module.exports = pool;
|
||||
|
||||
@@ -1,41 +1,43 @@
|
||||
const chalk = require('chalk');
|
||||
|
||||
module.exports = (client, db) => {
|
||||
setInterval(async () => {
|
||||
try {
|
||||
const now = Date.now();
|
||||
const [expiredBans] = await db.query(
|
||||
'SELECT * FROM bans WHERE type = ? AND unbanDate <= ?',
|
||||
['Temporary', now]
|
||||
);
|
||||
setInterval(async () => {
|
||||
try {
|
||||
const now = Date.now();
|
||||
const [expiredBans] = await db.query(
|
||||
'SELECT * FROM bans WHERE type = ? AND unbanDate <= ?',
|
||||
['Temporary', now]
|
||||
);
|
||||
|
||||
if (!expiredBans.length) return;
|
||||
if (!expiredBans.length) return;
|
||||
|
||||
for (const ban of expiredBans) {
|
||||
const guild = client.guilds.cache.get(ban.guildId);
|
||||
if (!guild) {
|
||||
console.warn(chalk.yellow(`⚠️ Impossible de débannir ${ban.userId}: le bot n'est pas dans la guild ${ban.guildId}`));
|
||||
continue;
|
||||
}
|
||||
for (const ban of expiredBans) {
|
||||
const guild = client.guilds.cache.get(ban.guildId);
|
||||
if (!guild) {
|
||||
console.warn(chalk.yellow(`⚠️ Impossible de débannir ${ban.userId}: le bot n'est pas dans la guild ${ban.guildId}`));
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
await guild.members.unban(ban.userId, 'Bannissement temporaire expiré');
|
||||
console.log(chalk.green(`✅ Auto-débanni ${ban.userId} de la guild ${guild.name} (${guild.id})`));
|
||||
} catch (err) {
|
||||
console.error(chalk.red(`❌ Échec du débannissement de ${ban.userId} de la guild ${guild.id}:`), err.message);
|
||||
}
|
||||
try {
|
||||
await guild.members.unban(ban.userId, 'Bannissement temporaire expiré');
|
||||
console.log(chalk.green(`✅ Auto-débanni ${ban.userId} de la guild ${guild.name} (${guild.id})`));
|
||||
} catch (err) {
|
||||
console.error(chalk.red(`❌ Échec du débannissement de ${ban.userId} de la guild ${guild.id}:`), err.message);
|
||||
}
|
||||
|
||||
await db.query('DELETE FROM bans WHERE userId = ? AND guildId = ?', [ban.userId, ban.guildId]);
|
||||
// Supprime uniquement le ban correspondant à cette guild
|
||||
await db.query('DELETE FROM bans WHERE userId = ? AND guildId = ?', [ban.userId, ban.guildId]);
|
||||
|
||||
await db.query(
|
||||
`INSERT INTO logs (userId, userTag, modId, modTag, action, reason, type, timestamp, guildId)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[ban.userId, null, client.user.id, client.user.tag, 'Débannissement automatique', 'Bannissement temporaire expiré', 'Temporary', Date.now(), ban.guildId]
|
||||
);
|
||||
}
|
||||
// Log automatique
|
||||
await db.query(
|
||||
`INSERT INTO logs (userId, userTag, modId, modTag, action, reason, type, timestamp, guildId)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[ban.userId, null, client.user.id, client.user.tag, 'Débannissement automatique', 'Bannissement temporaire expiré', 'Temporary', Date.now(), ban.guildId]
|
||||
);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error(chalk.red('❌ Erreur lors de l\'auto-débannissement:'), err);
|
||||
}
|
||||
}, 60_000);
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(chalk.red('❌ Erreur lors de l\'auto-débannissement:'), err);
|
||||
}
|
||||
}, 60_000);
|
||||
};
|
||||
|
||||
@@ -1,47 +1,51 @@
|
||||
const chalk = require('chalk');
|
||||
|
||||
module.exports = (client, db) => {
|
||||
setInterval(async () => {
|
||||
try {
|
||||
const now = Date.now();
|
||||
const [expiredMutes] = await db.query(
|
||||
'SELECT * FROM mutes WHERE type = ? AND unmuteDate <= ?',
|
||||
['Temporary', now]
|
||||
);
|
||||
setInterval(async () => {
|
||||
try {
|
||||
const now = Date.now();
|
||||
const [expiredMutes] = await db.query(
|
||||
'SELECT * FROM mutes WHERE type = ? AND unmuteDate <= ?',
|
||||
['Temporary', now]
|
||||
);
|
||||
|
||||
if (!expiredMutes.length) return;
|
||||
if (!expiredMutes.length) return;
|
||||
|
||||
for (const mute of expiredMutes) {
|
||||
const guild = client.guilds.cache.get(mute.guildId);
|
||||
if (!guild) {
|
||||
console.warn(chalk.yellow(`⚠️ Impossible de démuter ${mute.userId}: le bot n'est pas dans la guild ${mute.guildId}`));
|
||||
continue;
|
||||
}
|
||||
for (const mute of expiredMutes) {
|
||||
const guild = client.guilds.cache.get(mute.guildId);
|
||||
if (!guild) {
|
||||
console.warn(chalk.yellow(`⚠️ Impossible de démuter ${mute.userId}: le bot n'est pas dans la guild ${mute.guildId}`));
|
||||
continue;
|
||||
}
|
||||
|
||||
const member = await guild.members.fetch(mute.userId).catch(() => null);
|
||||
if (!member) {
|
||||
await db.query('DELETE FROM mutes WHERE userId = ? AND guildId = ?', [mute.userId, mute.guildId]);
|
||||
continue;
|
||||
}
|
||||
const member = await guild.members.fetch(mute.userId).catch(() => null);
|
||||
if (!member) {
|
||||
// L'utilisateur n'est plus sur le serveur, on supprime quand même le mute
|
||||
await db.query('DELETE FROM mutes WHERE userId = ? AND guildId = ?', [mute.userId, mute.guildId]);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
await member.timeout(null, 'Mute temporaire expiré');
|
||||
console.log(chalk.green(`✅ Auto-démuté ${mute.userId} de la guild ${guild.name} (${guild.id})`));
|
||||
} catch (err) {
|
||||
console.error(chalk.red(`❌ Échec du démute de ${mute.userId} de la guild ${guild.id}:`), err.message);
|
||||
}
|
||||
try {
|
||||
await member.timeout(null, 'Mute temporaire expiré');
|
||||
console.log(chalk.green(`✅ Auto-démuté ${mute.userId} de la guild ${guild.name} (${guild.id})`));
|
||||
} catch (err) {
|
||||
console.error(chalk.red(`❌ Échec du démute de ${mute.userId} de la guild ${guild.id}:`), err.message);
|
||||
}
|
||||
|
||||
await db.query('DELETE FROM mutes WHERE userId = ? AND guildId = ?', [mute.userId, mute.guildId]);
|
||||
// Supprime le mute de la DB
|
||||
await db.query('DELETE FROM mutes WHERE userId = ? AND guildId = ?', [mute.userId, mute.guildId]);
|
||||
|
||||
await db.query(
|
||||
`INSERT INTO logs (userId, userTag, modId, modTag, action, reason, type, timestamp, guildId)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[mute.userId, null, client.user.id, client.user.tag, 'Unmute automatique', 'Mute temporaire expiré', 'Temporary', Date.now(), mute.guildId]
|
||||
);
|
||||
}
|
||||
// Log automatique
|
||||
await db.query(
|
||||
`INSERT INTO logs (userId, userTag, modId, modTag, action, reason, type, timestamp, guildId)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[mute.userId, null, client.user.id, client.user.tag, 'Unmute automatique', 'Mute temporaire expiré', 'Temporary', Date.now(), mute.guildId]
|
||||
);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error(chalk.red('❌ Erreur lors de l\'auto-unmute:'), err);
|
||||
}
|
||||
}, 60_000);
|
||||
};
|
||||
|
||||
} catch (err) {
|
||||
console.error(chalk.red('❌ Erreur lors de l\'auto-unmute:'), err);
|
||||
}
|
||||
}, 60_000);
|
||||
};
|
||||
@@ -5,173 +5,217 @@
|
||||
const db = require('../database/db.js');
|
||||
|
||||
// Formule de calcul de l'XP nécessaire pour atteindre un niveau
|
||||
// XP total nécessaire = 5 * (level^2) + (50 * level) + 100
|
||||
// Exemples :
|
||||
// - Niveau 1 : 5 * 1^2 + 50 * 1 + 100 = 155 XP total
|
||||
// - Niveau 2 : 5 * 2^2 + 50 * 2 + 100 = 220 XP total
|
||||
// - Niveau 3 : 5 * 3^2 + 50 * 3 + 100 = 295 XP total
|
||||
function getXPForLevel(level) {
|
||||
if (level <= 0) return 0;
|
||||
return Math.floor(5 * Math.pow(level, 2) + 50 * level + 100);
|
||||
if (level <= 0) return 0;
|
||||
return Math.floor(5 * Math.pow(level, 2) + 50 * level + 100);
|
||||
}
|
||||
|
||||
// Calculer le niveau à partir de l'XP total
|
||||
function getLevelFromXP(xp) {
|
||||
if (xp < 0) return 0;
|
||||
|
||||
let level = 0;
|
||||
let requiredXP = getXPForLevel(level + 1);
|
||||
|
||||
while (xp >= requiredXP) {
|
||||
level++;
|
||||
requiredXP = getXPForLevel(level + 1);
|
||||
}
|
||||
|
||||
return level;
|
||||
if (xp < 0) return 0;
|
||||
|
||||
let level = 0;
|
||||
let requiredXP = getXPForLevel(level + 1);
|
||||
|
||||
// Trouver le niveau en vérifiant l'XP nécessaire
|
||||
while (xp >= requiredXP) {
|
||||
level++;
|
||||
requiredXP = getXPForLevel(level + 1);
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
// Calculer l'XP nécessaire pour le prochain niveau
|
||||
function getXPForNextLevel(level) {
|
||||
return getXPForLevel(level + 1);
|
||||
return getXPForLevel(level + 1);
|
||||
}
|
||||
|
||||
// Calculer l'XP progress dans le niveau actuel
|
||||
function getXPProgress(xp, level) {
|
||||
const xpForCurrentLevel = getXPForLevel(level);
|
||||
const xpForNextLevel = getXPForLevel(level + 1);
|
||||
|
||||
const xpInLevel = Math.max(0, xp - xpForCurrentLevel);
|
||||
const xpNeeded = xpForNextLevel - xpForCurrentLevel;
|
||||
|
||||
if (xpNeeded <= 0) {
|
||||
return { current: xpInLevel, needed: 100, percentage: 0 };
|
||||
}
|
||||
|
||||
const percentage = Math.max(0, Math.min(100, Math.floor((xpInLevel / xpNeeded) * 100)));
|
||||
|
||||
return { current: xpInLevel, needed: xpNeeded, percentage };
|
||||
// XP nécessaire pour atteindre le niveau actuel
|
||||
const xpForCurrentLevel = getXPForLevel(level);
|
||||
// XP nécessaire pour atteindre le prochain niveau
|
||||
const xpForNextLevel = getXPForLevel(level + 1);
|
||||
|
||||
// XP dans le niveau actuel (différence entre l'XP total et l'XP du niveau actuel)
|
||||
const xpInLevel = Math.max(0, xp - xpForCurrentLevel);
|
||||
// XP nécessaire pour passer au niveau suivant
|
||||
const xpNeeded = xpForNextLevel - xpForCurrentLevel;
|
||||
|
||||
// Éviter la division par zéro
|
||||
if (xpNeeded <= 0) {
|
||||
return {
|
||||
current: xpInLevel,
|
||||
needed: 100,
|
||||
percentage: 0
|
||||
};
|
||||
}
|
||||
|
||||
const percentage = Math.max(0, Math.min(100, Math.floor((xpInLevel / xpNeeded) * 100)));
|
||||
|
||||
return {
|
||||
current: xpInLevel,
|
||||
needed: xpNeeded,
|
||||
percentage: percentage
|
||||
};
|
||||
}
|
||||
|
||||
// Obtenir ou créer un utilisateur dans la table XP
|
||||
async function getUserXP(userId, guildId) {
|
||||
try {
|
||||
const [rows] = await db.query(
|
||||
'SELECT * FROM user_xp WHERE userId = ? AND guildId = ?',
|
||||
[userId, guildId]
|
||||
);
|
||||
|
||||
if (rows.length === 0) {
|
||||
await db.query(
|
||||
'INSERT INTO user_xp (userId, guildId, xp, level) VALUES (?, ?, 0, 0)',
|
||||
[userId, guildId]
|
||||
);
|
||||
return {
|
||||
userId, guildId, xp: 0, level: 0,
|
||||
lastMessageTime: 0, totalMessages: 0,
|
||||
totalVoiceTime: 0, lastVoiceJoin: 0, lastBumpTime: 0
|
||||
};
|
||||
}
|
||||
|
||||
return rows[0];
|
||||
} catch (err) {
|
||||
console.error('Erreur getUserXP:', err);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const [rows] = await db.query(
|
||||
'SELECT * FROM user_xp WHERE userId = ? AND guildId = ?',
|
||||
[userId, guildId]
|
||||
);
|
||||
|
||||
if (rows.length === 0) {
|
||||
// Créer l'utilisateur avec 0 XP
|
||||
await db.query(
|
||||
'INSERT INTO user_xp (userId, guildId, xp, level) VALUES (?, ?, 0, 0)',
|
||||
[userId, guildId]
|
||||
);
|
||||
return {
|
||||
userId,
|
||||
guildId,
|
||||
xp: 0,
|
||||
level: 0,
|
||||
lastMessageTime: 0,
|
||||
totalMessages: 0,
|
||||
totalVoiceTime: 0,
|
||||
lastVoiceJoin: 0,
|
||||
lastBumpTime: 0
|
||||
};
|
||||
}
|
||||
|
||||
return rows[0];
|
||||
} catch (err) {
|
||||
console.error('Erreur lors de la récupération de l\'XP:', err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Ajouter de l'XP à un utilisateur
|
||||
async function addXP(userId, guildId, xpGained, source = 'message', multiplier = 1.0) {
|
||||
try {
|
||||
const userXP = await getUserXP(userId, guildId);
|
||||
if (!userXP) return null;
|
||||
|
||||
const finalXP = Math.floor(xpGained * multiplier);
|
||||
const newXP = userXP.xp + finalXP;
|
||||
const newLevel = getLevelFromXP(newXP);
|
||||
|
||||
await db.query(
|
||||
'UPDATE user_xp SET xp = ?, level = ? WHERE userId = ? AND guildId = ?',
|
||||
[newXP, newLevel, userId, guildId]
|
||||
);
|
||||
|
||||
try {
|
||||
await db.query(
|
||||
'INSERT INTO xp_logs (userId, guildId, xpGained, source, multiplier, timestamp) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[userId, guildId, finalXP, source, multiplier, Date.now()]
|
||||
);
|
||||
} catch {}
|
||||
|
||||
return {
|
||||
oldXP: userXP.xp,
|
||||
newXP,
|
||||
oldLevel: userXP.level,
|
||||
newLevel,
|
||||
xpGained: finalXP,
|
||||
levelUp: newLevel > userXP.level
|
||||
};
|
||||
} catch (err) {
|
||||
console.error('Erreur addXP:', err);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const userXP = await getUserXP(userId, guildId);
|
||||
if (!userXP) return null;
|
||||
|
||||
const finalXP = Math.floor(xpGained * multiplier);
|
||||
const newXP = userXP.xp + finalXP;
|
||||
const newLevel = getLevelFromXP(newXP);
|
||||
|
||||
// Mettre à jour l'XP et le niveau
|
||||
await db.query(
|
||||
'UPDATE user_xp SET xp = ?, level = ? WHERE userId = ? AND guildId = ?',
|
||||
[newXP, newLevel, userId, guildId]
|
||||
);
|
||||
|
||||
// Logger le gain d'XP (optionnel, pour debugging)
|
||||
try {
|
||||
await db.query(
|
||||
'INSERT INTO xp_logs (userId, guildId, xpGained, source, multiplier, timestamp) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[userId, guildId, finalXP, source, multiplier, Date.now()]
|
||||
);
|
||||
} catch (logErr) {
|
||||
// Ignorer les erreurs de log
|
||||
}
|
||||
|
||||
return {
|
||||
oldXP: userXP.xp,
|
||||
newXP,
|
||||
oldLevel: userXP.level,
|
||||
newLevel,
|
||||
xpGained: finalXP,
|
||||
levelUp: newLevel > userXP.level
|
||||
};
|
||||
} catch (err) {
|
||||
console.error('Erreur lors de l\'ajout d\'XP:', err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Vérifier si un salon est exclus de l'XP
|
||||
async function isChannelExcluded(channelId, guildId) {
|
||||
try {
|
||||
const [rows] = await db.query(
|
||||
'SELECT * FROM xp_excluded_channels WHERE channelId = ? AND guildId = ?',
|
||||
[channelId, guildId]
|
||||
);
|
||||
return rows.length > 0;
|
||||
} catch (err) {
|
||||
console.error('Erreur isChannelExcluded:', err);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const [rows] = await db.query(
|
||||
'SELECT * FROM xp_excluded_channels WHERE channelId = ? AND guildId = ?',
|
||||
[channelId, guildId]
|
||||
);
|
||||
return rows.length > 0;
|
||||
} catch (err) {
|
||||
console.error('Erreur lors de la vérification de l\'exclusion:', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Obtenir le multiplicateur XP d'un utilisateur
|
||||
// Obtenir le multiplicateur XP d'un utilisateur (booster, vocal, etc.)
|
||||
function getXPMultiplier(member, source = 'message') {
|
||||
let multiplier = 1.0;
|
||||
if (member.premiumSince) multiplier *= 1.2;
|
||||
return multiplier;
|
||||
let multiplier = 1.0;
|
||||
|
||||
// Vérifier si l'utilisateur est booster (1.2x)
|
||||
if (member.premiumSince) {
|
||||
multiplier *= 1.2;
|
||||
}
|
||||
|
||||
// Multiplicateur vocal : 1.0x après 5 minutes de vocal (selon Issue #11)
|
||||
// Note: Cette fonction est appelée toutes les 10 minutes, donc on applique déjà le bonus
|
||||
if (source === 'voice') {
|
||||
// Le bonus vocal est déjà appliqué car on gagne de l'XP toutes les 10 minutes
|
||||
// Donc on considère qu'on a déjà passé plus de 5 minutes
|
||||
multiplier *= 1.0; // Pas de changement, mais on pourrait ajouter un bonus ici
|
||||
}
|
||||
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
// Obtenir le classement des utilisateurs par XP
|
||||
async function getLeaderboard(guildId, limit = 10) {
|
||||
try {
|
||||
const [rows] = await db.query(
|
||||
'SELECT * FROM user_xp WHERE guildId = ? ORDER BY xp DESC LIMIT ?',
|
||||
[guildId, limit]
|
||||
);
|
||||
return rows;
|
||||
} catch (err) {
|
||||
console.error('Erreur getLeaderboard:', err);
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
const [rows] = await db.query(
|
||||
'SELECT * FROM user_xp WHERE guildId = ? ORDER BY xp DESC LIMIT ?',
|
||||
[guildId, limit]
|
||||
);
|
||||
return rows;
|
||||
} catch (err) {
|
||||
console.error('Erreur lors de la récupération du classement:', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Obtenir la position d'un utilisateur dans le classement
|
||||
async function getUserRank(userId, guildId) {
|
||||
try {
|
||||
const userXP = await getUserXP(userId, guildId);
|
||||
if (!userXP) return 0;
|
||||
|
||||
const [rows] = await db.query(
|
||||
'SELECT COUNT(*) as count FROM user_xp WHERE guildId = ? AND xp > ?',
|
||||
[guildId, userXP.xp]
|
||||
);
|
||||
|
||||
return (rows[0]?.count || 0) + 1;
|
||||
} catch (err) {
|
||||
console.error('Erreur getUserRank:', err);
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
const userXP = await getUserXP(userId, guildId);
|
||||
if (!userXP) return 0;
|
||||
|
||||
const [rows] = await db.query(
|
||||
'SELECT COUNT(*) as count FROM user_xp WHERE guildId = ? AND xp > ?',
|
||||
[guildId, userXP.xp]
|
||||
);
|
||||
|
||||
return (rows[0]?.count || 0) + 1;
|
||||
} catch (err) {
|
||||
console.error('Erreur lors de la récupération du rang:', err);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getXPForLevel,
|
||||
getLevelFromXP,
|
||||
getXPForNextLevel,
|
||||
getXPProgress,
|
||||
getUserXP,
|
||||
addXP,
|
||||
isChannelExcluded,
|
||||
getXPMultiplier,
|
||||
getLeaderboard,
|
||||
getUserRank,
|
||||
};
|
||||
getXPForLevel,
|
||||
getLevelFromXP,
|
||||
getXPForNextLevel,
|
||||
getXPProgress,
|
||||
getUserXP,
|
||||
addXP,
|
||||
isChannelExcluded,
|
||||
getXPMultiplier,
|
||||
getLeaderboard,
|
||||
getUserRank,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user