mirror of
https://github.com/arthur-pbty/LazyBot.git
synced 2026-06-03 15:07:29 +02:00
add a major part of user level
This commit is contained in:
+135
-1
@@ -4,10 +4,11 @@ loadSlashCommands();
|
||||
const db = require("./db");
|
||||
|
||||
const { Client, GatewayIntentBits, ActivityType, Events } = require("discord.js");
|
||||
const e = require('express');
|
||||
|
||||
const client = new Client({ intents: Object.values(GatewayIntentBits) });
|
||||
|
||||
client.once("clientReady", () => {
|
||||
client.once(Events.ClientReady, () => {
|
||||
console.log(`Bot connecté en tant que ${client.user.tag}`);
|
||||
client.user.setActivity("LazyBot à votre service !", { type: ActivityType.Custom });
|
||||
});
|
||||
@@ -115,6 +116,139 @@ client.on(Events.VoiceStateUpdate, (oldState, newState) => {
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
client.on(Events.MessageCreate, message => {
|
||||
if (message.author.bot) return;
|
||||
|
||||
const guildId = message.guild.id;
|
||||
|
||||
db.get(
|
||||
`SELECT
|
||||
enabled,
|
||||
level_announcements_enabled,
|
||||
level_announcements_channel_id,
|
||||
level_announcements_message,
|
||||
xp_courbe_type,
|
||||
multiplier_courbe_for_level,
|
||||
level_annoncement_every_level,
|
||||
level_max,
|
||||
role_with_without_type,
|
||||
role_with_without_xp,
|
||||
salon_with_without_type,
|
||||
salon_with_without_xp,
|
||||
gain_xp_on_message,
|
||||
gain_xp_message_lower_bound,
|
||||
gain_xp_message_upper_bound,
|
||||
cooldown_xp_message_seconds
|
||||
FROM levels_config WHERE guild_id = ?`,
|
||||
[guildId],
|
||||
(err, row) => {
|
||||
if (err || !row || !row.enabled || !row.gain_xp_on_message) return;
|
||||
if (row.role_with_without_type === "with") {
|
||||
const userRoles = message.member.roles.cache;
|
||||
const requiredRoles = JSON.parse(row.role_with_without_xp || "[]");
|
||||
if (!requiredRoles.some(roleId => userRoles.has(roleId))) {
|
||||
return; // User has an excluded role
|
||||
}
|
||||
} else if (row.role_with_without_type === "without") {
|
||||
const userRoles = message.member.roles.cache;
|
||||
const excludedRoles = JSON.parse(row.role_with_without_xp || "[]");
|
||||
if (excludedRoles.some(roleId => userRoles.has(roleId))) {
|
||||
return; // User does not have any of the required roles
|
||||
}
|
||||
} else if (row.salon_with_without_type === "with") {
|
||||
const channelId = message.channel.id;
|
||||
const requiredChannels = JSON.parse(row.salon_with_without_xp || "[]");
|
||||
if (!requiredChannels.includes(channelId)) {
|
||||
return; // Message not in a required channel
|
||||
}
|
||||
} else if (row.salon_with_without_type === "without") {
|
||||
const channelId = message.channel.id;
|
||||
const excludedChannels = JSON.parse(row.salon_with_without_xp || "[]");
|
||||
if (excludedChannels.includes(channelId)) {
|
||||
return; // Message in an excluded channel
|
||||
}
|
||||
}
|
||||
// Logic to award XP for message goes here
|
||||
const now = Date.now();
|
||||
db.get(
|
||||
`SELECT xp, level, last_xp_message_timestamp FROM user_levels WHERE guild_id = ? AND user_id = ?`,
|
||||
[guildId, message.author.id],
|
||||
(err, userRow) => {
|
||||
if (err) return;
|
||||
|
||||
const lastTimestamp = userRow ? userRow.last_xp_message_timestamp || 0 : 0;
|
||||
if (now - lastTimestamp < row.cooldown_xp_message_seconds * 1000) {
|
||||
return; // Still in cooldown
|
||||
}
|
||||
|
||||
const minXp = row.gain_xp_message_lower_bound;
|
||||
const maxXp = row.gain_xp_message_upper_bound;
|
||||
const xpToAdd = Math.floor(Math.random() * (maxXp - minXp + 1)) + minXp;
|
||||
|
||||
let newXp;
|
||||
let newLevel;
|
||||
|
||||
if (userRow) {
|
||||
newXp = userRow.xp + xpToAdd;
|
||||
newLevel = userRow.level;
|
||||
} else {
|
||||
newXp = xpToAdd;
|
||||
newLevel = 1;
|
||||
}
|
||||
|
||||
// Level up logic based on xp_courbe_type and multiplier goes here
|
||||
const firstLevelXp = 100; // Example base XP for first level ----------------------------------------
|
||||
const multiplier = row.multiplier_courbe_for_level;
|
||||
let fonction_courbe;
|
||||
|
||||
if (row.xp_courbe_type === "constante") {
|
||||
fonction_courbe = (level) => firstLevelXp * multiplier;
|
||||
} else if (row.xp_courbe_type === "linear") {
|
||||
fonction_courbe = (level) => firstLevelXp * (level) * multiplier;
|
||||
} else if (row.xp_courbe_type === "quadratic") {
|
||||
fonction_courbe = (level) => firstLevelXp * (level) * (level) * multiplier;
|
||||
} else if (row.xp_courbe_type === "exponential") {
|
||||
fonction_courbe = (level) => firstLevelXp * Math.pow(2, (level - 1)) * multiplier;
|
||||
}
|
||||
|
||||
let xpForNextLevel = fonction_courbe(newLevel);
|
||||
while (newXp >= xpForNextLevel && (row.level_max === 0 || newLevel < row.level_max)) {
|
||||
newXp -= xpForNextLevel;
|
||||
newLevel += 1;
|
||||
xpForNextLevel = fonction_courbe(newLevel);
|
||||
|
||||
// Announce level up if enabled and meets the criteria
|
||||
if (row.level_announcements_enabled && (newLevel % row.level_annoncement_every_level === 0)) {
|
||||
const channel = message.guild.channels.cache.get(row.level_announcements_channel_id);
|
||||
console.log("Channel for level announcement:", channel);
|
||||
if (channel) {
|
||||
let announcementMsg = row.level_announcements_message;
|
||||
announcementMsg = announcementMsg
|
||||
.replace("{user}", message.author.username)
|
||||
.replace("{mention}", `<@${message.author.id}>`)
|
||||
.replace("{level}", newLevel)
|
||||
.replace("{level-xp}", xpForNextLevel);
|
||||
channel.send(announcementMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db.run(
|
||||
`INSERT INTO user_levels (guild_id, user_id, xp, level, last_xp_message_timestamp)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
ON CONFLICT(guild_id, user_id) DO UPDATE SET
|
||||
xp = excluded.xp,
|
||||
level = excluded.level,
|
||||
last_xp_message_timestamp = excluded.last_xp_message_timestamp`,
|
||||
[guildId, message.author.id, newXp, newLevel, now]
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
client.login(process.env.BOT_TOKEN);
|
||||
|
||||
module.exports = client;
|
||||
|
||||
@@ -37,6 +37,38 @@ db.exec(`
|
||||
exclude_channel_ids TEXT,
|
||||
enabled INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS levels_config (
|
||||
guild_id TEXT PRIMARY KEY,
|
||||
enabled INTEGER NOT NULL,
|
||||
level_announcements_enabled INTEGER NOT NULL,
|
||||
level_announcements_channel_id TEXT,
|
||||
level_announcements_message TEXT NOT NULL,
|
||||
xp_courbe_type TEXT NOT NULL,
|
||||
multiplier_courbe_for_level INTEGER NOT NULL,
|
||||
level_annoncement_every_level INTEGER NOT NULL,
|
||||
level_max INTEGER NOT NULL,
|
||||
role_with_without_type TEXT NOT NULL,
|
||||
role_with_without_xp TEXT NOT NULL,
|
||||
salon_with_without_type TEXT NOT NULL,
|
||||
salon_with_without_xp TEXT NOT NULL,
|
||||
gain_xp_on_message INTEGER NOT NULL,
|
||||
gain_xp_message_lower_bound INTEGER NOT NULL,
|
||||
gain_xp_message_upper_bound INTEGER NOT NULL,
|
||||
cooldown_xp_message_seconds INTEGER NOT NULL,
|
||||
gain_xp_on_voice INTEGER NOT NULL,
|
||||
gain_voice_xp_lower_bound INTEGER NOT NULL,
|
||||
gain_voice_xp_upper_bound INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_levels (
|
||||
guild_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
xp INTEGER NOT NULL,
|
||||
level INTEGER NOT NULL,
|
||||
last_xp_message_timestamp INTEGER,
|
||||
PRIMARY KEY (guild_id, user_id)
|
||||
);
|
||||
`);
|
||||
|
||||
module.exports = db;
|
||||
|
||||
+135
-203
@@ -133,211 +133,143 @@
|
||||
</form>
|
||||
|
||||
|
||||
<script>
|
||||
const guildId = window.location.pathname.split("/")[2]; // récupère l'ID du serveur
|
||||
<form id="level-form">
|
||||
<label>
|
||||
<input type="checkbox" id="level-enabled" />
|
||||
Activer le système de niveaux
|
||||
</label>
|
||||
|
||||
// Afficher le nom du serveur
|
||||
fetch("/api/guilds")
|
||||
.then((res) => res.json())
|
||||
.then((guilds) => {
|
||||
const guild = guilds.find((g) => g.id === guildId);
|
||||
if (!guild) {
|
||||
document.getElementById("guild-name").textContent =
|
||||
"Serveur introuvable ou accès refusé";
|
||||
return;
|
||||
}
|
||||
document.getElementById(
|
||||
"guild-name"
|
||||
).textContent = `Dashboard : ${guild.name}`;
|
||||
});
|
||||
<label>
|
||||
<input type="checkbox" id="level-announcement-enabled" />
|
||||
Annoncer les améliorations de niveau dans un canal
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Canal d'affichage des améliorations de niveau :
|
||||
<br />
|
||||
<select id="level-announcements-channel">
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Message d'amélioration de niveau :
|
||||
<br />
|
||||
<textarea
|
||||
id="level-announcements-message"
|
||||
rows="4"
|
||||
cols="50"
|
||||
placeholder="Ex : Félicitations {user}, tu es maintenant niveau {level} ! 🎉"
|
||||
></textarea>
|
||||
</label>
|
||||
<small>
|
||||
Variables disponibles :
|
||||
<ul>
|
||||
<li><code>{user}</code> → nom de l'utilisateur</li>
|
||||
<li><code>{mention}</code> → mention de l'utilisateur</li>
|
||||
<li><code>{level}</code> → niveau atteint</li>
|
||||
<li><code>{level-xp}</code> → points d'expérience du niveau</li>
|
||||
</ul>
|
||||
</small>
|
||||
|
||||
<label>
|
||||
Courbe d'expérience des niveaux :
|
||||
<br />
|
||||
<select id="level-xp-curve-type">
|
||||
<option value="constante">Constante</option>
|
||||
<option value="linear">Linéaire</option>
|
||||
<option value="quadratic">Quadratique</option>
|
||||
<option value="exponential">Exponentielle</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Multiplicateur de points d'expérience par niveau :
|
||||
<br />
|
||||
<input type="number" id="level-xp-multiplier" min="1" value="1" />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Annonce des niveaux tout les X niveaux :
|
||||
<br />
|
||||
<input type="number" id="level-announcement-every" min="1" value="1" />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Niveau maximum (0 pour infini) :
|
||||
<br />
|
||||
<input type="number" id="level-max-level" min="0" value="0" />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Rôle avec/sans expérience :
|
||||
<br />
|
||||
<select id="level-role-with-or-without-xp-type">
|
||||
<option value="with">Avec</option>
|
||||
<option value="without">Sans</option>
|
||||
</select>
|
||||
<br />
|
||||
<select id="level-role-with-or-without-xp" multiple size="5">
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Salon avec/sans expérience :
|
||||
<br />
|
||||
<select id="level-channel-with-or-without-xp-type">
|
||||
<option value="with">Avec</option>
|
||||
<option value="without">Sans</option>
|
||||
</select>
|
||||
<br />
|
||||
<select id="level-channel-with-or-without-xp" multiple size="5">
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" id="message-xp-enabled" />
|
||||
Gagner de l'expérience en envoyant des messages
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Gain de points d'expérience par message :
|
||||
<br />
|
||||
Entre
|
||||
<input type="number" id="level-xp-per-message-min" min="1" value="15" />
|
||||
et
|
||||
<input type="number" id="level-xp-per-message-max" min="1" value="25" />
|
||||
points d'expérience
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Cooldown entre les messages pour gagner de l'XP (en secondes) :
|
||||
<br />
|
||||
<input type="number" id="level-xp-cooldown" min="0" value="2" />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" id="voice-xp-enabled" />
|
||||
Gagner de l'expérience en étant en vocal
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Gain de points d'expérience par minute en vocal :
|
||||
<br />
|
||||
Entre
|
||||
<input type="number" id="level-xp-per-voice-min" min="1" value="10" />
|
||||
et
|
||||
<input type="number" id="level-xp-per-voice-max" min="1" value="20" />
|
||||
points d'expérience
|
||||
</label>
|
||||
|
||||
<button type="submit">Sauvegarder</button>
|
||||
<div id="status-level-form"></div>
|
||||
</form>
|
||||
|
||||
|
||||
fetch(`/api/bot/get-text-channels/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(channels => {
|
||||
const selectWelcome = document.getElementById("welcome-channel");
|
||||
const selectGoodbye = document.getElementById("goodbye-channel");
|
||||
channels.forEach(channel => {
|
||||
const option = document.createElement("option");
|
||||
option.value = channel.id;
|
||||
option.textContent = `#${channel.name}`;
|
||||
selectWelcome.appendChild(option);
|
||||
selectGoodbye.appendChild(option.cloneNode(true));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
const selectExclude = document.getElementById("autorole-vocal-exclude-channel");
|
||||
selectExclude.innerHTML = ""; // reset
|
||||
|
||||
fetch(`/api/bot/get-voice-channels/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(channels => {
|
||||
channels.forEach(channel => {
|
||||
const option = document.createElement("option");
|
||||
option.value = channel.id;
|
||||
option.textContent = `#${channel.name}`;
|
||||
selectExclude.appendChild(option);
|
||||
});
|
||||
return fetch(`/api/bot/get-autorole-vocal-config/${guildId}`);
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(cfg => {
|
||||
document.getElementById("autorole-vocal-enabled").checked = !!cfg.enabled;
|
||||
document.getElementById("autorole-vocal-role").value = cfg.roleId ?? "";
|
||||
|
||||
const excluded = Array.isArray(cfg.excludeChannelIds)
|
||||
? cfg.excludeChannelIds.map(String) // sécurité
|
||||
: [];
|
||||
|
||||
Array.from(selectExclude.options).forEach(option => {
|
||||
option.selected = excluded.includes(option.value);
|
||||
});
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
|
||||
|
||||
fetch(`/api/bot/get-roles/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(roles => {
|
||||
const selectAutorole = document.getElementById("autorole-role");
|
||||
const selectAutoroleVocal = document.getElementById("autorole-vocal-role");
|
||||
roles.forEach(role => {
|
||||
const option = document.createElement("option");
|
||||
option.value = role.id;
|
||||
option.textContent = role.name;
|
||||
selectAutorole.appendChild(option);
|
||||
selectAutoroleVocal.appendChild(option.cloneNode(true));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
const welcomeForm = document.getElementById("welcome-form");
|
||||
welcomeForm.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const enabled = document.getElementById("welcome-enabled").checked;
|
||||
const channelId = document.getElementById("welcome-channel").value;
|
||||
const message = document.getElementById("welcome-message").value;
|
||||
|
||||
const res = await fetch("/api/bot/save-welcome-config", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
channelId,
|
||||
welcomeMessage: message,
|
||||
welcomeEnabled: enabled,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
document.getElementById("status-welcome-form").textContent = data.success
|
||||
? "Config de bienvenue sauvegardée ✅"
|
||||
: "Erreur ❌";
|
||||
});
|
||||
|
||||
|
||||
const goodbyeForm = document.getElementById("goodbye-form");
|
||||
goodbyeForm.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const enabled = document.getElementById("goodbye-enabled").checked;
|
||||
const channelId = document.getElementById("goodbye-channel").value;
|
||||
const message = document.getElementById("goodbye-message").value;
|
||||
|
||||
const res = await fetch("/api/bot/save-goodbye-config", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
channelId,
|
||||
goodbyeMessage: message,
|
||||
goodbyeEnabled: enabled,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
document.getElementById("status-goodbye-form").textContent = data.success
|
||||
? "Config d'au revoir sauvegardée ✅"
|
||||
: "Erreur ❌";
|
||||
});
|
||||
|
||||
|
||||
const autoroleNewUserForm = document.getElementById("autorole-newuser-form");
|
||||
autoroleNewUserForm.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const enabled = document.getElementById("autorole-enabled").checked;
|
||||
const roleId = document.getElementById("autorole-role").value;
|
||||
|
||||
const res = await fetch("/api/bot/save-autorole-newuser-config", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
roleId,
|
||||
enabled,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
document.getElementById("status-autorole-form").textContent = data.success
|
||||
? "Config d'auto-rôle pour nouveaux membres sauvegardée ✅"
|
||||
: "Erreur ❌";
|
||||
});
|
||||
|
||||
|
||||
const autoroleVocalForm = document.getElementById("autorole-vocal-form");
|
||||
autoroleVocalForm.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const enabled = document.getElementById("autorole-vocal-enabled").checked;
|
||||
const roleId = document.getElementById("autorole-vocal-role").value;
|
||||
const excludeChannelSelect = document.getElementById("autorole-vocal-exclude-channel");
|
||||
const excludeChannelId = Array.from(excludeChannelSelect.selectedOptions).map(option => option.value);
|
||||
|
||||
const res = await fetch("/api/bot/save-autorole-vocal-config", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
roleId,
|
||||
excludeChannelId,
|
||||
enabled,
|
||||
}),
|
||||
});
|
||||
const data = await res.json();
|
||||
document.getElementById("status-autorole-vocal-form").textContent = data.success
|
||||
? "Config d'auto-rôle pour membres en vocal sauvegardée ✅"
|
||||
: "Erreur ❌";
|
||||
});
|
||||
|
||||
|
||||
fetch(`/api/bot/get-welcome-config/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(cfg => {
|
||||
document.getElementById("welcome-enabled").checked = cfg.enabled;
|
||||
document.getElementById("welcome-channel").value = cfg.channelId;
|
||||
document.getElementById("welcome-message").value = cfg.message;
|
||||
});
|
||||
|
||||
|
||||
fetch(`/api/bot/get-goodbye-config/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(cfg => {
|
||||
document.getElementById("goodbye-enabled").checked = cfg.enabled;
|
||||
document.getElementById("goodbye-channel").value = cfg.channelId;
|
||||
document.getElementById("goodbye-message").value = cfg.message;
|
||||
});
|
||||
|
||||
|
||||
fetch(`/api/bot/get-autorole-newuser-config/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(cfg => {
|
||||
document.getElementById("autorole-enabled").checked = cfg.enabled;
|
||||
document.getElementById("autorole-role").value = cfg.roleId;
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
<script src="/guild/guildBase.js"></script>
|
||||
<script src="/guild/welcomeForm.js"></script>
|
||||
<script src="/guild/goodbyeForm.js"></script>
|
||||
<script src="/guild/autoroleNewUserForm.js"></script>
|
||||
<script src="/guild/autoroleVocalForm.js"></script>
|
||||
<script src="/guild/levelForm.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
const autoroleNewUserForm = document.getElementById("autorole-newuser-form");
|
||||
const autoroleEnabled = document.getElementById("autorole-enabled");
|
||||
const autoroleRole = document.getElementById("autorole-role");
|
||||
const statusAutoroleForm = document.getElementById("status-autorole-form");
|
||||
|
||||
fetch(`/api/bot/get-autorole-newuser-config/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(cfg => {
|
||||
autoroleEnabled.checked = cfg.enabled;
|
||||
autoroleRole.value = cfg.roleId;
|
||||
});
|
||||
|
||||
autoroleNewUserForm.addEventListener("submit", async e => {
|
||||
e.preventDefault();
|
||||
|
||||
const res = await fetch("/api/bot/save-autorole-newuser-config", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
enabled: autoroleEnabled.checked,
|
||||
roleId: autoroleRole.value
|
||||
})
|
||||
});
|
||||
|
||||
statusAutoroleForm.textContent = (await res.json()).success
|
||||
? "Auto-rôle sauvegardé ✅"
|
||||
: "Erreur ❌";
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
const autoroleVocalForm = document.getElementById("autorole-vocal-form");
|
||||
const autoroleVocalEnabled = document.getElementById("autorole-vocal-enabled");
|
||||
const autoroleVocalRole = document.getElementById("autorole-vocal-role");
|
||||
const excludeSelect = document.getElementById("autorole-vocal-exclude-channel");
|
||||
const statusAutoroleVocalForm = document.getElementById("status-autorole-vocal-form");
|
||||
|
||||
fetch(`/api/bot/get-voice-channels/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(channels => {
|
||||
channels.forEach(c => {
|
||||
excludeSelect.appendChild(new Option(`#${c.name}`, c.id));
|
||||
});
|
||||
return fetch(`/api/bot/get-autorole-vocal-config/${guildId}`);
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(cfg => {
|
||||
autoroleVocalEnabled.checked = cfg.enabled;
|
||||
autoroleVocalRole.value = cfg.roleId;
|
||||
Array.from(excludeSelect.options).forEach(opt => {
|
||||
opt.selected = cfg.excludeChannelIds?.includes(opt.value);
|
||||
});
|
||||
});
|
||||
|
||||
autoroleVocalForm.addEventListener("submit", async e => {
|
||||
e.preventDefault();
|
||||
|
||||
const exclude = Array.from(excludeSelect.selectedOptions).map(o => o.value);
|
||||
|
||||
const res = await fetch("/api/bot/save-autorole-vocal-config", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
enabled: autoroleVocalEnabled.checked,
|
||||
roleId: autoroleVocalRole.value,
|
||||
excludeChannelId: exclude
|
||||
})
|
||||
});
|
||||
|
||||
statusAutoroleVocalForm.textContent = (await res.json()).success
|
||||
? "Auto-rôle vocal sauvegardé ✅"
|
||||
: "Erreur ❌";
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
const goodbyeForm = document.getElementById("goodbye-form");
|
||||
const goodbyeEnabled = document.getElementById("goodbye-enabled");
|
||||
const goodbyeChannel = document.getElementById("goodbye-channel");
|
||||
const goodbyeMessage = document.getElementById("goodbye-message");
|
||||
const statusGoodbyeForm = document.getElementById("status-goodbye-form");
|
||||
|
||||
fetch(`/api/bot/get-goodbye-config/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(cfg => {
|
||||
goodbyeEnabled.checked = cfg.enabled;
|
||||
goodbyeChannel.value = cfg.channelId;
|
||||
goodbyeMessage.value = cfg.message;
|
||||
});
|
||||
|
||||
goodbyeForm.addEventListener("submit", async e => {
|
||||
e.preventDefault();
|
||||
|
||||
const res = await fetch("/api/bot/save-goodbye-config", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
goodbyeEnabled: goodbyeEnabled.checked,
|
||||
channelId: goodbyeChannel.value,
|
||||
goodbyeMessage: goodbyeMessage.value
|
||||
})
|
||||
});
|
||||
|
||||
statusGoodbyeForm.textContent = (await res.json()).success
|
||||
? "Config au revoir sauvegardée ✅"
|
||||
: "Erreur ❌";
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
window.guildId = window.location.pathname.split("/")[2];
|
||||
|
||||
// Nom du serveur
|
||||
fetch("/api/guilds")
|
||||
.then(res => res.json())
|
||||
.then(guilds => {
|
||||
const guild = guilds.find(g => g.id === guildId);
|
||||
document.getElementById("guild-name").textContent =
|
||||
guild ? `Dashboard : ${guild.name}` : "Serveur introuvable";
|
||||
});
|
||||
|
||||
// Channels texte
|
||||
fetch(`/api/bot/get-text-channels/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(channels => {
|
||||
const welcome = document.getElementById("welcome-channel");
|
||||
const goodbye = document.getElementById("goodbye-channel");
|
||||
const levelAnnouncements = document.getElementById("level-announcements-channel");
|
||||
|
||||
channels.forEach(c => {
|
||||
const opt = new Option(`#${c.name}`, c.id);
|
||||
welcome?.appendChild(opt);
|
||||
goodbye?.appendChild(opt.cloneNode(true));
|
||||
levelAnnouncements?.appendChild(opt.cloneNode(true));
|
||||
});
|
||||
});
|
||||
|
||||
// Rôles
|
||||
fetch(`/api/bot/get-roles/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(roles => {
|
||||
const newUser = document.getElementById("autorole-role");
|
||||
const vocal = document.getElementById("autorole-vocal-role");
|
||||
|
||||
roles.forEach(r => {
|
||||
const opt = new Option(r.name, r.id);
|
||||
newUser?.appendChild(opt);
|
||||
vocal?.appendChild(opt.cloneNode(true));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,119 @@
|
||||
const levelForm = document.getElementById("level-form");
|
||||
const levelEnabled = document.getElementById("level-enabled");
|
||||
const levelAnnouncementsEnabled = document.getElementById("level-announcement-enabled");
|
||||
const levelAnnouncementsChannel = document.getElementById("level-announcements-channel");
|
||||
const levelAnnouncementsMessage = document.getElementById("level-announcements-message");
|
||||
const xpCourbeType = document.getElementById("level-xp-curve-type");
|
||||
const multiplierCourbeForLevel = document.getElementById("level-xp-multiplier");
|
||||
const levelAnnouncementEveryLevel = document.getElementById("level-announcement-every");
|
||||
const levelMax = document.getElementById("level-max-level");
|
||||
const roleWithWithoutType = document.getElementById("level-role-with-or-without-xp-type");
|
||||
const roleWithWithoutXp = document.getElementById("level-role-with-or-without-xp");
|
||||
const salonWithWithoutType = document.getElementById("level-channel-with-or-without-xp-type");
|
||||
const salonWithWithoutXp = document.getElementById("level-channel-with-or-without-xp");
|
||||
const gainXpOnMessage = document.getElementById("message-xp-enabled");
|
||||
const gainXpMessageLowerBound = document.getElementById("level-xp-per-message-min");
|
||||
const gainXpMessageUpperBound = document.getElementById("level-xp-per-message-max");
|
||||
const cooldownXpMessageSeconds = document.getElementById("level-xp-cooldown");
|
||||
const gainXpOnVoice = document.getElementById("voice-xp-enabled");
|
||||
const gainVoiceXpLowerBound = document.getElementById("level-xp-per-voice-min");
|
||||
const gainVoiceXpUpperBound = document.getElementById("level-xp-per-voice-max");
|
||||
const statusLevelForm = document.getElementById("status-level-form");
|
||||
|
||||
// 1️⃣ RÔLES
|
||||
fetch(`/api/bot/get-roles/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(roles => {
|
||||
roles.forEach(r => {
|
||||
roleWithWithoutXp?.appendChild(new Option(r.name, r.id));
|
||||
});
|
||||
|
||||
// 2️⃣ SALONS TEXTE
|
||||
return fetch(`/api/bot/get-text-channels/${guildId}`);
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(textSalons => {
|
||||
textSalons.forEach(c => {
|
||||
salonWithWithoutXp?.appendChild(new Option(`#${c.name}`, c.id));
|
||||
});
|
||||
|
||||
// 3️⃣ SALONS VOCAUX
|
||||
return fetch(`/api/bot/get-voice-channels/${guildId}`);
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(voiceSalons => {
|
||||
voiceSalons.forEach(c => {
|
||||
salonWithWithoutXp?.appendChild(new Option(`🔊 ${c.name}`, c.id));
|
||||
});
|
||||
|
||||
// 4️⃣ CONFIG (APRÈS QUE TOUT EST CHARGÉ)
|
||||
return fetch(`/api/bot/get-level-config/${guildId}`);
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(cfg => {
|
||||
levelEnabled.checked = cfg.enabled;
|
||||
levelAnnouncementsEnabled.checked = cfg.levelAnnouncementsEnabled;
|
||||
levelAnnouncementsChannel.value = cfg.levelAnnouncementsChannelId;
|
||||
levelAnnouncementsMessage.value = cfg.levelAnnouncementsMessage;
|
||||
|
||||
xpCourbeType.value = cfg.xpCourbeType;
|
||||
multiplierCourbeForLevel.value = cfg.multiplierCourbeForLevel;
|
||||
levelAnnouncementEveryLevel.value = cfg.levelAnnouncementEveryLevel;
|
||||
levelMax.value = cfg.levelMax;
|
||||
|
||||
roleWithWithoutType.value = cfg.roleWithWithoutType;
|
||||
Array.from(roleWithWithoutXp.options).forEach(opt => {
|
||||
opt.selected = cfg.roleWithWithoutXp?.includes(opt.value);
|
||||
});
|
||||
|
||||
salonWithWithoutType.value = cfg.salonWithWithoutType;
|
||||
Array.from(salonWithWithoutXp.options).forEach(opt => {
|
||||
opt.selected = cfg.salonWithWithoutXp?.includes(opt.value);
|
||||
});
|
||||
|
||||
gainXpOnMessage.checked = cfg.gainXpOnMessage;
|
||||
gainXpMessageLowerBound.value = cfg.gainXpMessageLowerBound;
|
||||
gainXpMessageUpperBound.value = cfg.gainXpMessageUpperBound;
|
||||
cooldownXpMessageSeconds.value = cfg.cooldownXpMessageSeconds;
|
||||
|
||||
gainXpOnVoice.checked = cfg.gainXpOnVoice;
|
||||
gainVoiceXpLowerBound.value = cfg.gainVoiceXpLowerBound;
|
||||
gainVoiceXpUpperBound.value = cfg.gainVoiceXpUpperBound;
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
|
||||
levelForm.addEventListener("submit", async e => {
|
||||
e.preventDefault();
|
||||
|
||||
const res = await fetch("/api/bot/save-level-config", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
levelEnabled: levelEnabled.checked,
|
||||
levelAnnouncementsEnabled: levelAnnouncementsEnabled.checked,
|
||||
levelAnnouncementsChannelId: levelAnnouncementsChannel.value,
|
||||
levelAnnouncementsMessage: levelAnnouncementsMessage.value,
|
||||
xpCourbeType: xpCourbeType.value,
|
||||
multiplierCourbeForLevel: parseInt(multiplierCourbeForLevel.value, 10),
|
||||
levelAnnouncementEveryLevel: parseInt(levelAnnouncementEveryLevel.value, 10),
|
||||
levelMax: parseInt(levelMax.value, 10),
|
||||
roleWithWithoutType: roleWithWithoutType.value,
|
||||
roleWithWithoutXp: Array.from(roleWithWithoutXp.selectedOptions).map(opt => opt.value),
|
||||
salonWithWithoutType: salonWithWithoutType.value,
|
||||
salonWithWithoutXp: Array.from(salonWithWithoutXp.selectedOptions).map(opt => opt.value),
|
||||
gainXpOnMessage: gainXpOnMessage.checked,
|
||||
gainXpMessageLowerBound: parseInt(gainXpMessageLowerBound.value, 10),
|
||||
gainXpMessageUpperBound: parseInt(gainXpMessageUpperBound.value, 10),
|
||||
cooldownXpMessageSeconds: parseInt(cooldownXpMessageSeconds.value, 10),
|
||||
gainXpOnVoice: gainXpOnVoice.checked,
|
||||
gainVoiceXpLowerBound: parseInt(gainVoiceXpLowerBound.value, 10),
|
||||
gainVoiceXpUpperBound: parseInt(gainVoiceXpUpperBound.value, 10)
|
||||
})
|
||||
});
|
||||
|
||||
statusLevelForm.textContent = (await res.json()).success
|
||||
? "Config niveaux sauvegardée ✅"
|
||||
: "Erreur ❌";
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
const welcomeForm = document.getElementById("welcome-form");
|
||||
const welcomeEnabled = document.getElementById("welcome-enabled");
|
||||
const welcomeChannel = document.getElementById("welcome-channel");
|
||||
const welcomeMessage = document.getElementById("welcome-message");
|
||||
const statusWelcomeForm = document.getElementById("status-welcome-form");
|
||||
|
||||
fetch(`/api/bot/get-welcome-config/${guildId}`)
|
||||
.then(res => res.json())
|
||||
.then(cfg => {
|
||||
welcomeEnabled.checked = cfg.enabled;
|
||||
welcomeChannel.value = cfg.channelId;
|
||||
welcomeMessage.value = cfg.message;
|
||||
});
|
||||
|
||||
welcomeForm.addEventListener("submit", async e => {
|
||||
e.preventDefault();
|
||||
|
||||
const res = await fetch("/api/bot/save-welcome-config", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
welcomeEnabled: welcomeEnabled.checked,
|
||||
channelId: welcomeChannel.value,
|
||||
welcomeMessage: welcomeMessage.value
|
||||
})
|
||||
});
|
||||
|
||||
statusWelcomeForm.textContent = (await res.json()).success
|
||||
? "Config bienvenue sauvegardée ✅"
|
||||
: "Erreur ❌";
|
||||
});
|
||||
@@ -335,5 +335,215 @@ module.exports = (app, db, client) => {
|
||||
res.json(roles);
|
||||
});
|
||||
|
||||
|
||||
router.get("/bot/get-level-config/:guildId", (req, res) => {
|
||||
const { guildId } = req.params;
|
||||
|
||||
db.get(
|
||||
`SELECT
|
||||
enabled,
|
||||
level_announcements_enabled,
|
||||
level_announcements_channel_id,
|
||||
level_announcements_message,
|
||||
xp_courbe_type,
|
||||
multiplier_courbe_for_level,
|
||||
level_annoncement_every_level,
|
||||
level_max,
|
||||
role_with_without_type,
|
||||
role_with_without_xp,
|
||||
salon_with_without_type,
|
||||
salon_with_without_xp,
|
||||
gain_xp_on_message,
|
||||
gain_xp_message_lower_bound,
|
||||
gain_xp_message_upper_bound,
|
||||
cooldown_xp_message_seconds,
|
||||
gain_xp_on_voice,
|
||||
gain_voice_xp_lower_bound,
|
||||
gain_voice_xp_upper_bound
|
||||
FROM levels_config WHERE guild_id = ?`,
|
||||
[guildId],
|
||||
(err, row) => {
|
||||
if (err || !row) {
|
||||
console.error(err);
|
||||
return res.json({
|
||||
enabled: false,
|
||||
levelAnnouncementsEnabled: false,
|
||||
levelAnnouncementsChannelId: null,
|
||||
levelAnnouncementsMessage: "",
|
||||
xpCourbeType: "exponential",
|
||||
multiplierCourbeForLevel: 1,
|
||||
levelAnnouncementEveryLevel: 1,
|
||||
levelMax: 0,
|
||||
roleWithWithoutType: "with",
|
||||
roleWithWithoutXp: [],
|
||||
salonWithWithoutType: "with",
|
||||
salonWithWithoutXp: [],
|
||||
gainXpOnMessage: false,
|
||||
gainXpMessageLowerBound: 15,
|
||||
gainXpMessageUpperBound: 25,
|
||||
cooldownXpMessageSeconds: 2,
|
||||
gainXpOnVoice: false,
|
||||
gainVoiceXpLowerBound: 10,
|
||||
gainVoiceXpUpperBound: 20
|
||||
});
|
||||
}
|
||||
res.json({
|
||||
enabled: !!row.enabled,
|
||||
levelAnnouncementsEnabled: !!row.level_announcements_enabled,
|
||||
levelAnnouncementsChannelId: row.level_announcements_channel_id,
|
||||
levelAnnouncementsMessage: row.level_announcements_message,
|
||||
xpCourbeType: row.xp_courbe_type,
|
||||
multiplierCourbeForLevel: row.multiplier_courbe_for_level,
|
||||
levelAnnouncementEveryLevel: row.level_annoncement_every_level,
|
||||
levelMax: row.level_max,
|
||||
roleWithWithoutType: row.role_with_without_type,
|
||||
roleWithWithoutXp: JSON.parse(row.role_with_without_xp),
|
||||
salonWithWithoutType: row.salon_with_without_type,
|
||||
salonWithWithoutXp: JSON.parse(row.salon_with_without_xp),
|
||||
gainXpOnMessage: !!row.gain_xp_on_message,
|
||||
gainXpMessageLowerBound: row.gain_xp_message_lower_bound,
|
||||
gainXpMessageUpperBound: row.gain_xp_message_upper_bound,
|
||||
cooldownXpMessageSeconds: row.cooldown_xp_message_seconds,
|
||||
gainXpOnVoice: !!row.gain_xp_on_voice,
|
||||
gainVoiceXpLowerBound: row.gain_voice_xp_lower_bound,
|
||||
gainVoiceXpUpperBound: row.gain_voice_xp_upper_bound
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
router.post("/bot/save-level-config", express.json(), (req, res) => {
|
||||
const {
|
||||
guildId,
|
||||
levelEnabled,
|
||||
levelAnnouncementsEnabled,
|
||||
levelAnnouncementsChannelId,
|
||||
levelAnnouncementsMessage,
|
||||
xpCourbeType,
|
||||
multiplierCourbeForLevel,
|
||||
levelAnnouncementEveryLevel,
|
||||
levelMax,
|
||||
roleWithWithoutType,
|
||||
roleWithWithoutXp,
|
||||
salonWithWithoutType,
|
||||
salonWithWithoutXp,
|
||||
gainXpOnMessage,
|
||||
gainXpMessageLowerBound,
|
||||
gainXpMessageUpperBound,
|
||||
cooldownXpMessageSeconds,
|
||||
gainXpOnVoice,
|
||||
gainVoiceXpLowerBound,
|
||||
gainVoiceXpUpperBound
|
||||
} = req.body;
|
||||
|
||||
if (!req.session.guilds) {
|
||||
return res.status(401).json({ success: false });
|
||||
}
|
||||
|
||||
const isAdmin = req.session.guilds.find(
|
||||
g => g.id === guildId && (BigInt(g.permissions) & 0x8n) === 0x8n
|
||||
);
|
||||
|
||||
if (!isAdmin) {
|
||||
return res.status(401).json({ success: false });
|
||||
}
|
||||
db.run(
|
||||
`
|
||||
INSERT INTO levels_config (
|
||||
guild_id,
|
||||
enabled,
|
||||
level_announcements_enabled,
|
||||
level_announcements_channel_id,
|
||||
level_announcements_message,
|
||||
xp_courbe_type,
|
||||
multiplier_courbe_for_level,
|
||||
level_annoncement_every_level,
|
||||
level_max,
|
||||
role_with_without_type,
|
||||
role_with_without_xp,
|
||||
salon_with_without_type,
|
||||
salon_with_without_xp,
|
||||
gain_xp_on_message,
|
||||
gain_xp_message_lower_bound,
|
||||
gain_xp_message_upper_bound,
|
||||
cooldown_xp_message_seconds,
|
||||
gain_xp_on_voice,
|
||||
gain_voice_xp_lower_bound,
|
||||
gain_voice_xp_upper_bound
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(guild_id)
|
||||
DO UPDATE SET
|
||||
enabled = ?,
|
||||
level_announcements_enabled = ?,
|
||||
level_announcements_channel_id = ?,
|
||||
level_announcements_message = ?,
|
||||
xp_courbe_type = ?,
|
||||
multiplier_courbe_for_level = ?,
|
||||
level_annoncement_every_level = ?,
|
||||
level_max = ?,
|
||||
role_with_without_type = ?,
|
||||
role_with_without_xp = ?,
|
||||
salon_with_without_type = ?,
|
||||
salon_with_without_xp = ?,
|
||||
gain_xp_on_message = ?,
|
||||
gain_xp_message_lower_bound = ?,
|
||||
gain_xp_message_upper_bound = ?,
|
||||
cooldown_xp_message_seconds = ?,
|
||||
gain_xp_on_voice = ?,
|
||||
gain_voice_xp_lower_bound = ?,
|
||||
gain_voice_xp_upper_bound = ?
|
||||
`,
|
||||
[
|
||||
guildId,
|
||||
levelEnabled ? 1 : 0,
|
||||
levelAnnouncementsEnabled ? 1 : 0,
|
||||
levelAnnouncementsChannelId,
|
||||
levelAnnouncementsMessage,
|
||||
xpCourbeType,
|
||||
multiplierCourbeForLevel,
|
||||
levelAnnouncementEveryLevel,
|
||||
levelMax,
|
||||
roleWithWithoutType,
|
||||
JSON.stringify(Array.isArray(roleWithWithoutXp) ? roleWithWithoutXp : [roleWithWithoutXp]),
|
||||
salonWithWithoutType,
|
||||
JSON.stringify(Array.isArray(salonWithWithoutXp) ? salonWithWithoutXp : [salonWithWithoutXp]),
|
||||
gainXpOnMessage ? 1 : 0,
|
||||
gainXpMessageLowerBound,
|
||||
gainXpMessageUpperBound,
|
||||
cooldownXpMessageSeconds,
|
||||
gainXpOnVoice ? 1 : 0,
|
||||
gainVoiceXpLowerBound,
|
||||
gainVoiceXpUpperBound,
|
||||
levelEnabled ? 1 : 0,
|
||||
levelAnnouncementsEnabled ? 1 : 0,
|
||||
levelAnnouncementsChannelId,
|
||||
levelAnnouncementsMessage,
|
||||
xpCourbeType,
|
||||
multiplierCourbeForLevel,
|
||||
levelAnnouncementEveryLevel,
|
||||
levelMax,
|
||||
roleWithWithoutType,
|
||||
JSON.stringify(Array.isArray(roleWithWithoutXp) ? roleWithWithoutXp : [roleWithWithoutXp]),
|
||||
salonWithWithoutType,
|
||||
JSON.stringify(Array.isArray(salonWithWithoutXp) ? salonWithWithoutXp : [salonWithWithoutXp]),
|
||||
gainXpOnMessage ? 1 : 0,
|
||||
gainXpMessageLowerBound,
|
||||
gainXpMessageUpperBound,
|
||||
cooldownXpMessageSeconds,
|
||||
gainXpOnVoice ? 1 : 0,
|
||||
gainVoiceXpLowerBound,
|
||||
gainVoiceXpUpperBound
|
||||
],
|
||||
err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return res.status(500).json({ success: false });
|
||||
}
|
||||
res.json({ success: true });
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
app.use("/api", router);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user