add guildMemberAdd config

This commit is contained in:
Arthur Puechberty
2026-01-15 02:31:11 +01:00
parent 0a0c419c6b
commit 12fde58b93
9 changed files with 1571 additions and 374 deletions
+2
View File
@@ -1,4 +1,6 @@
.vscode/
*.sqlite
*.db
# Logs
logs
+22 -6
View File
@@ -1,6 +1,8 @@
const loadSlashCommands = require('./slash_commands.js');
loadSlashCommands();
const db = require("./db");
const { Client, GatewayIntentBits, ActivityType, Events } = require("discord.js");
const client = new Client({ intents: Object.values(GatewayIntentBits) });
@@ -20,12 +22,26 @@ client.on(Events.InteractionCreate, async interaction => {
});
client.on(Events.MessageCreate, message => {
if (message.author.bot) return;
const config = global.guildConfigs?.[message.guild.id];
if (config?.autoMessage) {
message.channel.send(config.autoMessage);
}
client.on(Events.GuildMemberAdd, member => {
db.get(
"SELECT enabled, channel_id, message FROM welcome_config WHERE guild_id = ?",
[member.guild.id],
(err, row) => {
if (err || !row || !row.enabled) return;
let msg = row.message;
msg = msg
.replace("{user}", member.user.username)
.replace("{mention}", `<@${member.id}>`)
.replace("{server}", member.guild.name);
const channel = member.guild.channels.cache.get(row.channel_id);
if (channel) {
channel.send(msg);
}
}
);
});
+22
View File
@@ -0,0 +1,22 @@
const sqlite3 = require("sqlite3").verbose();
const path = require("path");
const db = new sqlite3.Database(
path.join(__dirname, process.env.DB_PATH || "database.sqlite"),
err => {
if (err) console.error("Erreur DB:", err);
else console.log("DB SQLite connectée");
}
);
// Création de la table si elle n'existe pas
db.run(`
CREATE TABLE IF NOT EXISTS welcome_config (
guild_id TEXT PRIMARY KEY,
channel_id TEXT,
enabled INTEGER NOT NULL,
message TEXT NOT NULL
)
`);
module.exports = db;
+1344 -1
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -27,6 +27,7 @@
"discord.js": "^14.25.1",
"dotenv": "^17.2.3",
"express": "^5.2.1",
"express-session": "^1.18.2"
"express-session": "^1.18.2",
"sqlite3": "^5.1.7"
}
}
+107 -39
View File
@@ -1,49 +1,117 @@
<!DOCTYPE html>
<html>
<head>
<title>Dashboard du serveur</title>
</head>
<body>
<h1 id="guild-name">Chargement...</h1>
<head>
<title>Dashboard du serveur</title>
</head>
<body>
<h1 id="guild-name">Chargement...</h1>
<form id="event-form">
<label>Message automatique :</label>
<input type="text" id="auto-message" placeholder="Ex: Bonjour à tous !">
<button type="submit">Sauvegarder</button>
</form>
<form id="welcome-form">
<label>
<input type="checkbox" id="welcome-enabled" />
Activer le message de bienvenue
</label>
<div id="status"></div>
<br /><br />
<script>
const guildId = window.location.pathname.split("/")[2]; // récupère l'ID du serveur
<label>
Canal de bienvenue :
<br />
<select id="welcome-channel">
</select>
</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}`;
});
<br /><br />
// Envoyer la config du formulaire au serveur
const form = document.getElementById("event-form");
form.addEventListener("submit", async (e) => {
e.preventDefault();
const message = document.getElementById("auto-message").value;
<label>
Message :
<br />
<textarea
id="welcome-message"
rows="4"
cols="50"
placeholder="Ex : Bienvenue {user} sur {server} 🎉"
></textarea>
</label>
const res = await fetch("/api/bot/save-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ guildId, autoMessage: message })
});
<br /><br />
const data = await res.json();
document.getElementById("status").textContent = data.success ? "Config sauvegardée ✅" : "Erreur ❌";
});
</script>
</body>
<small>
Variables disponibles :
<ul>
<li><code>{user}</code> → nom de l'utilisateur</li>
<li><code>{mention}</code> → mention de l'utilisateur</li>
<li><code>{server}</code> → nom du serveur</li>
</ul>
</small>
<button type="submit">Sauvegarder</button>
</form>
<div id="status"></div>
<script>
const guildId = window.location.pathname.split("/")[2]; // récupère l'ID du serveur
// 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}`;
});
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").textContent = data.success
? "Config de bienvenue sauvegardée ✅"
: "Erreur ❌";
});
fetch(`/api/bot/get-text-channels/${guildId}`)
.then(res => res.json())
.then(channels => {
const select = document.getElementById("welcome-channel");
channels.forEach(channel => {
const option = document.createElement("option");
option.value = channel.id;
option.textContent = `#${channel.name}`;
select.appendChild(option);
});
});
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;
});
</script>
</body>
</html>
+72 -11
View File
@@ -5,6 +5,9 @@ const session = require("express-session");
const fetch = require("cross-fetch"); // fetch compatible Node
const path = require("path");
// importer la DB
const db = require("./db");
// importer le bot
const client = require("./bot");
@@ -130,25 +133,83 @@ app.get("/api/guilds", (req, res) => {
res.sendFile(path.join(__dirname, "public", "guild.html"));
});
// Exemple : sauvegarde config d'un serveur
app.post("/api/bot/save-config", express.json(), (req, res) => {
const { guildId, autoMessage } = req.body;
const userGuilds = req.session.guilds;
// API pour sauvegarder la configuration de bienvenue
app.post("/api/bot/save-welcome-config", express.json(), (req, res) => {
const { guildId, channelId, welcomeEnabled, welcomeMessage } = req.body;
// Vérifie admin + bot présent
const guildValid = userGuilds.find(
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 (!guildValid) return res.status(403).json({ error: "Accès interdit" });
// Sauvegarde dans un objet serveur côté serveur (ou DB)
if (!global.guildConfigs) global.guildConfigs = {};
global.guildConfigs[guildId] = { autoMessage };
if (!isAdmin) {
return res.status(403).json({ success: false });
}
res.json({ success: true });
db.run(
`
INSERT INTO welcome_config (guild_id, channel_id, enabled, message)
VALUES (?, ?, ?, ?)
ON CONFLICT(guild_id)
DO UPDATE SET channel_id = ?, enabled = ?, message = ?
`,
[
guildId,
channelId,
welcomeEnabled ? 1 : 0,
welcomeMessage,
channelId,
welcomeEnabled ? 1 : 0,
welcomeMessage
],
err => {
if (err) {
console.error(err);
return res.status(500).json({ success: false });
}
res.json({ success: true });
}
);
});
app.get("/api/bot/get-welcome-config/:guildId", (req, res) => {
const { guildId } = req.params;
db.get(
"SELECT enabled, channel_id, message FROM welcome_config WHERE guild_id = ?",
[guildId],
(err, row) => {
if (err || !row) {
return res.json({ enabled: false, channelId: null, message: "" });
}
res.json({
enabled: !!row.enabled,
channelId: row.channel_id,
message: row.message
});
}
);
});
app.get("/api/bot/get-text-channels/:guildId", (req, res) => {
const { guildId } = req.params;
const guild = client.guilds.cache.get(guildId);
if (!guild) {
return res.status(404).json({ error: "Serveur non trouvé" });
}
const channels = guild.channels.cache
.filter(channel => channel.isTextBased())
.map(channel => ({
id: channel.id,
name: channel.name
}));
res.json(channels);
});
res.json(validGuilds);
});
-311
View File
@@ -1,311 +0,0 @@
{
"name": "lazybot",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"discord.js": "^14.25.1"
}
},
"node_modules/@discordjs/builders": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.13.1.tgz",
"integrity": "sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/formatters": "^0.6.2",
"@discordjs/util": "^1.2.0",
"@sapphire/shapeshift": "^4.0.0",
"discord-api-types": "^0.38.33",
"fast-deep-equal": "^3.1.3",
"ts-mixer": "^6.0.4",
"tslib": "^2.6.3"
},
"engines": {
"node": ">=16.11.0"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/collection": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz",
"integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==",
"license": "Apache-2.0",
"engines": {
"node": ">=16.11.0"
}
},
"node_modules/@discordjs/formatters": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.6.2.tgz",
"integrity": "sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ==",
"license": "Apache-2.0",
"dependencies": {
"discord-api-types": "^0.38.33"
},
"engines": {
"node": ">=16.11.0"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/rest": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.6.0.tgz",
"integrity": "sha512-RDYrhmpB7mTvmCKcpj+pc5k7POKszS4E2O9TYc+U+Y4iaCP+r910QdO43qmpOja8LRr1RJ0b3U+CqVsnPqzf4w==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/collection": "^2.1.1",
"@discordjs/util": "^1.1.1",
"@sapphire/async-queue": "^1.5.3",
"@sapphire/snowflake": "^3.5.3",
"@vladfrangu/async_event_emitter": "^2.4.6",
"discord-api-types": "^0.38.16",
"magic-bytes.js": "^1.10.0",
"tslib": "^2.6.3",
"undici": "6.21.3"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/rest/node_modules/@discordjs/collection": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz",
"integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==",
"license": "Apache-2.0",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/util": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.2.0.tgz",
"integrity": "sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg==",
"license": "Apache-2.0",
"dependencies": {
"discord-api-types": "^0.38.33"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/ws": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.3.tgz",
"integrity": "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/collection": "^2.1.0",
"@discordjs/rest": "^2.5.1",
"@discordjs/util": "^1.1.0",
"@sapphire/async-queue": "^1.5.2",
"@types/ws": "^8.5.10",
"@vladfrangu/async_event_emitter": "^2.2.4",
"discord-api-types": "^0.38.1",
"tslib": "^2.6.2",
"ws": "^8.17.0"
},
"engines": {
"node": ">=16.11.0"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/ws/node_modules/@discordjs/collection": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz",
"integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==",
"license": "Apache-2.0",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@sapphire/async-queue": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz",
"integrity": "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==",
"license": "MIT",
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/@sapphire/shapeshift": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-4.0.0.tgz",
"integrity": "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"lodash": "^4.17.21"
},
"engines": {
"node": ">=v16"
}
},
"node_modules/@sapphire/snowflake": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.3.tgz",
"integrity": "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==",
"license": "MIT",
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/@types/node": {
"version": "25.0.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.8.tgz",
"integrity": "sha512-powIePYMmC3ibL0UJ2i2s0WIbq6cg6UyVFQxSCpaPxxzAaziRfimGivjdF943sSGV6RADVbk0Nvlm5P/FB44Zg==",
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"node_modules/@types/ws": {
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@vladfrangu/async_event_emitter": {
"version": "2.4.7",
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.7.tgz",
"integrity": "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==",
"license": "MIT",
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/discord-api-types": {
"version": "0.38.37",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.37.tgz",
"integrity": "sha512-Cv47jzY1jkGkh5sv0bfHYqGgKOWO1peOrGMkDFM4UmaGMOTgOW8QSexhvixa9sVOiz8MnVOBryWYyw/CEVhj7w==",
"license": "MIT",
"workspaces": [
"scripts/actions/documentation"
]
},
"node_modules/discord.js": {
"version": "14.25.1",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.25.1.tgz",
"integrity": "sha512-2l0gsPOLPs5t6GFZfQZKnL1OJNYFcuC/ETWsW4VtKVD/tg4ICa9x+jb9bkPffkMdRpRpuUaO/fKkHCBeiCKh8g==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/builders": "^1.13.0",
"@discordjs/collection": "1.5.3",
"@discordjs/formatters": "^0.6.2",
"@discordjs/rest": "^2.6.0",
"@discordjs/util": "^1.2.0",
"@discordjs/ws": "^1.2.3",
"@sapphire/snowflake": "3.5.3",
"discord-api-types": "^0.38.33",
"fast-deep-equal": "3.1.3",
"lodash.snakecase": "4.1.1",
"magic-bytes.js": "^1.10.0",
"tslib": "^2.6.3",
"undici": "6.21.3"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"license": "MIT"
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
"node_modules/lodash.snakecase": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
"integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==",
"license": "MIT"
},
"node_modules/magic-bytes.js": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.12.1.tgz",
"integrity": "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA==",
"license": "MIT"
},
"node_modules/ts-mixer": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz",
"integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==",
"license": "MIT"
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/undici": {
"version": "6.21.3",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz",
"integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==",
"license": "MIT",
"engines": {
"node": ">=18.17"
}
},
"node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"license": "MIT"
},
"node_modules/ws": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
}
}
-5
View File
@@ -1,5 +0,0 @@
{
"dependencies": {
"discord.js": "^14.25.1"
}
}