mirror of
https://github.com/arthur-pbty/LazyBot.git
synced 2026-06-03 23:36:37 +02:00
ajouter un système de messages programmés avec options de planification et interface utilisateur
This commit is contained in:
+142
@@ -410,6 +410,148 @@ client.once("clientReady", async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// ===== SCHEDULED MESSAGES SYSTEM =====
|
||||||
|
const { EmbedBuilder } = require("discord.js");
|
||||||
|
|
||||||
|
// Track last channel activity
|
||||||
|
const channelLastActivity = new Map();
|
||||||
|
|
||||||
|
// Update last activity on message
|
||||||
|
client.on("messageCreate", (message) => {
|
||||||
|
if (!message.guild || message.author.bot) return;
|
||||||
|
channelLastActivity.set(message.channel.id, Date.now());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Process scheduled messages
|
||||||
|
async function processScheduledMessages() {
|
||||||
|
try {
|
||||||
|
const messages = await db.allAsync(
|
||||||
|
"SELECT * FROM scheduled_messages WHERE enabled = 1"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Utiliser le fuseau horaire français
|
||||||
|
const now = new Date();
|
||||||
|
const parisTime = new Date(now.toLocaleString("en-US", { timeZone: "Europe/Paris" }));
|
||||||
|
const currentDay = parisTime.getDay(); // 0-6 (Sunday-Saturday)
|
||||||
|
const currentHour = parisTime.getHours().toString().padStart(2, '0');
|
||||||
|
const currentMinute = parisTime.getMinutes().toString().padStart(2, '0');
|
||||||
|
const currentTime = `${currentHour}:${currentMinute}`;
|
||||||
|
const currentTimestamp = Date.now();
|
||||||
|
|
||||||
|
for (const msg of messages) {
|
||||||
|
try {
|
||||||
|
const guild = client.guilds.cache.get(msg.guild_id);
|
||||||
|
if (!guild) continue;
|
||||||
|
|
||||||
|
const channel = guild.channels.cache.get(msg.channel_id);
|
||||||
|
if (!channel) continue;
|
||||||
|
|
||||||
|
let shouldSend = false;
|
||||||
|
|
||||||
|
if (msg.schedule_type === "weekly") {
|
||||||
|
// Check day and time
|
||||||
|
const days = JSON.parse(msg.days_of_week || "[]").map(d => parseInt(d));
|
||||||
|
const times = JSON.parse(msg.times_of_day || "[]");
|
||||||
|
|
||||||
|
if (days.includes(currentDay) && times.includes(currentTime)) {
|
||||||
|
// Check if already sent this minute
|
||||||
|
const lastSent = msg.last_sent_at || 0;
|
||||||
|
const oneMinuteAgo = currentTimestamp - 60000;
|
||||||
|
|
||||||
|
if (lastSent < oneMinuteAgo) {
|
||||||
|
shouldSend = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (msg.schedule_type === "interval") {
|
||||||
|
// Check interval
|
||||||
|
const intervalMs = msg.interval_unit === "hours"
|
||||||
|
? msg.interval_value * 60 * 60 * 1000
|
||||||
|
: msg.interval_value * 60 * 1000;
|
||||||
|
|
||||||
|
const lastSent = msg.last_sent_at || 0;
|
||||||
|
|
||||||
|
if (currentTimestamp - lastSent >= intervalMs) {
|
||||||
|
shouldSend = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldSend) continue;
|
||||||
|
|
||||||
|
// Check force_send option
|
||||||
|
if (!msg.force_send) {
|
||||||
|
const lastActivity = channelLastActivity.get(msg.channel_id) || msg.last_channel_activity || 0;
|
||||||
|
const lastSent = msg.last_sent_at || 0;
|
||||||
|
|
||||||
|
// If no activity since last send, skip
|
||||||
|
if (lastActivity <= lastSent) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete previous message if option enabled
|
||||||
|
if (msg.delete_previous && msg.last_message_id) {
|
||||||
|
try {
|
||||||
|
const oldMessage = await channel.messages.fetch(msg.last_message_id);
|
||||||
|
if (oldMessage) await oldMessage.delete();
|
||||||
|
} catch (err) {
|
||||||
|
// Message may have been deleted already
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build message content
|
||||||
|
const messageOptions = {};
|
||||||
|
|
||||||
|
if (msg.message_content && msg.message_content.trim()) {
|
||||||
|
messageOptions.content = msg.message_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.embed_enabled) {
|
||||||
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
|
if (msg.embed_title) embed.setTitle(msg.embed_title);
|
||||||
|
if (msg.embed_description) embed.setDescription(msg.embed_description);
|
||||||
|
if (msg.embed_color) {
|
||||||
|
const color = msg.embed_color.startsWith('#')
|
||||||
|
? parseInt(msg.embed_color.slice(1), 16)
|
||||||
|
: parseInt(msg.embed_color, 16);
|
||||||
|
embed.setColor(color);
|
||||||
|
}
|
||||||
|
embed.setTimestamp();
|
||||||
|
|
||||||
|
messageOptions.embeds = [embed];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send message
|
||||||
|
const sentMessage = await channel.send(messageOptions);
|
||||||
|
|
||||||
|
// Update database
|
||||||
|
db.run(
|
||||||
|
`UPDATE scheduled_messages SET
|
||||||
|
last_sent_at = ?,
|
||||||
|
last_message_id = ?,
|
||||||
|
last_channel_activity = ?
|
||||||
|
WHERE id = ?`,
|
||||||
|
[currentTimestamp, sentMessage.id, channelLastActivity.get(msg.channel_id) || currentTimestamp, msg.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`📨 Message programmé envoyé: ${msg.id} dans ${channel.name}`);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Erreur envoi message programmé ${msg.id}:`, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Erreur processScheduledMessages:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run every minute to check scheduled messages
|
||||||
|
setInterval(processScheduledMessages, 60 * 1000);
|
||||||
|
|
||||||
|
// Initial run after 10 seconds
|
||||||
|
setTimeout(processScheduledMessages, 10 * 1000);
|
||||||
|
|
||||||
|
|
||||||
client.login(process.env.BOT_TOKEN);
|
client.login(process.env.BOT_TOKEN);
|
||||||
|
|
||||||
module.exports = client;
|
module.exports = client;
|
||||||
|
|||||||
@@ -213,6 +213,29 @@ db.exec(`
|
|||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_user_activity_stats_date ON user_activity_stats(guild_id, user_id, date);
|
CREATE INDEX IF NOT EXISTS idx_user_activity_stats_date ON user_activity_stats(guild_id, user_id, date);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS scheduled_messages (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
guild_id TEXT NOT NULL,
|
||||||
|
channel_id TEXT NOT NULL,
|
||||||
|
message_content TEXT NOT NULL,
|
||||||
|
embed_enabled INTEGER NOT NULL DEFAULT 0,
|
||||||
|
embed_title TEXT,
|
||||||
|
embed_description TEXT,
|
||||||
|
embed_color TEXT DEFAULT '#5865F2',
|
||||||
|
schedule_type TEXT NOT NULL DEFAULT 'weekly',
|
||||||
|
days_of_week TEXT DEFAULT '[]',
|
||||||
|
times_of_day TEXT DEFAULT '[]',
|
||||||
|
interval_value INTEGER DEFAULT 60,
|
||||||
|
interval_unit TEXT DEFAULT 'minutes',
|
||||||
|
force_send INTEGER NOT NULL DEFAULT 1,
|
||||||
|
delete_previous INTEGER NOT NULL DEFAULT 0,
|
||||||
|
enabled INTEGER NOT NULL DEFAULT 1,
|
||||||
|
last_sent_at INTEGER,
|
||||||
|
last_message_id TEXT,
|
||||||
|
last_channel_activity INTEGER,
|
||||||
|
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
|
||||||
|
);
|
||||||
`);
|
`);
|
||||||
|
|
||||||
module.exports = db;
|
module.exports = db;
|
||||||
|
|||||||
@@ -626,3 +626,176 @@ body {
|
|||||||
gap: var(--spacing-md);
|
gap: var(--spacing-md);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== Scheduled Messages ===== */
|
||||||
|
.checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-xs);
|
||||||
|
padding: var(--spacing-xs) var(--spacing-sm);
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-item:hover {
|
||||||
|
background: var(--bg-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-item input {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group-vertical {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group-vertical .checkbox-item {
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.times-input-container {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.times-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--spacing-xs);
|
||||||
|
min-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-xs);
|
||||||
|
padding: 4px 10px;
|
||||||
|
background: var(--primary-color);
|
||||||
|
color: white;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-remove {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-remove:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
margin-top: var(--spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scheduled-message-item {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
padding: var(--spacing-md);
|
||||||
|
margin-bottom: var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scheduled-message-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scheduled-message-info strong {
|
||||||
|
color: var(--text-primary);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scheduled-message-schedule {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-active {
|
||||||
|
background: rgba(87, 242, 135, 0.2);
|
||||||
|
color: #57F287;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-inactive {
|
||||||
|
background: rgba(237, 66, 69, 0.2);
|
||||||
|
color: #ED4245;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scheduled-message-preview {
|
||||||
|
background: var(--bg-card);
|
||||||
|
padding: var(--spacing-sm);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: var(--spacing-sm);
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.embed-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 6px;
|
||||||
|
background: var(--primary-color);
|
||||||
|
color: white;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin-left: var(--spacing-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scheduled-message-options {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--spacing-xs);
|
||||||
|
margin-bottom: var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scheduled-message-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-warning {
|
||||||
|
background: #F0B232;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-warning:hover {
|
||||||
|
background: #d9a02a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,10 @@
|
|||||||
<span class="nav-item-icon">📊</span>
|
<span class="nav-item-icon">📊</span>
|
||||||
Salons de stats
|
Salons de stats
|
||||||
</a>
|
</a>
|
||||||
|
<a class="nav-item" data-section="scheduledmessages">
|
||||||
|
<span class="nav-item-icon">⏰</span>
|
||||||
|
Messages programmés
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@@ -776,6 +780,158 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- ===== SCHEDULED MESSAGES ===== -->
|
||||||
|
<section class="config-section" id="section-scheduledmessages">
|
||||||
|
<div class="config-card">
|
||||||
|
<div class="config-card-header">
|
||||||
|
<div>
|
||||||
|
<h2 class="config-card-title">⏰ Messages Programmés</h2>
|
||||||
|
<p class="config-card-subtitle">Programmez l'envoi automatique de messages dans vos salons</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="config-card-body">
|
||||||
|
|
||||||
|
<!-- Formulaire d'ajout -->
|
||||||
|
<div class="sub-section" id="scheduled-form-section">
|
||||||
|
<h4 class="sub-section-title" id="scheduled-form-title">➕ Nouveau message programmé</h4>
|
||||||
|
|
||||||
|
<input type="hidden" id="scheduled-edit-id" value="">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">📺 Salon</label>
|
||||||
|
<select class="form-select" id="scheduled-channel-select">
|
||||||
|
<option value="">-- Sélectionner un salon --</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">💬 Contenu du message</label>
|
||||||
|
<textarea class="form-textarea" id="scheduled-message-content" rows="3" placeholder="Le contenu de votre message..."></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Embed optionnel -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">
|
||||||
|
<input type="checkbox" id="scheduled-embed-enabled">
|
||||||
|
📦 Utiliser un embed
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="scheduled-embed-options" style="display: none;">
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Titre de l'embed</label>
|
||||||
|
<input type="text" class="form-input" id="scheduled-embed-title" placeholder="Titre...">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Couleur</label>
|
||||||
|
<input type="color" class="form-input" id="scheduled-embed-color" value="#5865F2" style="height: 40px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Description de l'embed</label>
|
||||||
|
<textarea class="form-textarea" id="scheduled-embed-description" rows="3" placeholder="Description..."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Type de planification -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">📅 Type de planification</label>
|
||||||
|
<select class="form-select" id="scheduled-type">
|
||||||
|
<option value="weekly">Jours et heures spécifiques</option>
|
||||||
|
<option value="interval">Intervalle régulier</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Options pour planification hebdomadaire -->
|
||||||
|
<div id="scheduled-weekly-options">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">📆 Jours de la semaine</label>
|
||||||
|
<div class="checkbox-group" id="scheduled-days">
|
||||||
|
<label class="checkbox-item"><input type="checkbox" value="1"> Lun</label>
|
||||||
|
<label class="checkbox-item"><input type="checkbox" value="2"> Mar</label>
|
||||||
|
<label class="checkbox-item"><input type="checkbox" value="3"> Mer</label>
|
||||||
|
<label class="checkbox-item"><input type="checkbox" value="4"> Jeu</label>
|
||||||
|
<label class="checkbox-item"><input type="checkbox" value="5"> Ven</label>
|
||||||
|
<label class="checkbox-item"><input type="checkbox" value="6"> Sam</label>
|
||||||
|
<label class="checkbox-item"><input type="checkbox" value="0"> Dim</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">🕐 Heures d'envoi</label>
|
||||||
|
<div class="times-input-container">
|
||||||
|
<select class="form-select" id="scheduled-hour-select" style="width: 80px;">
|
||||||
|
<option value="">HH</option>
|
||||||
|
</select>
|
||||||
|
<span style="font-size: 1.2rem; color: var(--text-primary);">:</span>
|
||||||
|
<select class="form-select" id="scheduled-minute-select" style="width: 80px;">
|
||||||
|
<option value="">MM</option>
|
||||||
|
</select>
|
||||||
|
<button type="button" class="btn btn-sm btn-secondary" id="scheduled-add-time">+ Ajouter</button>
|
||||||
|
</div>
|
||||||
|
<div class="times-list" id="scheduled-times-list"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Options pour intervalle -->
|
||||||
|
<div id="scheduled-interval-options" style="display: none;">
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Toutes les</label>
|
||||||
|
<input type="number" class="form-input" id="scheduled-interval-value" min="1" value="60">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Unité</label>
|
||||||
|
<select class="form-select" id="scheduled-interval-unit">
|
||||||
|
<option value="minutes">Minutes</option>
|
||||||
|
<option value="hours">Heures</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Options d'envoi -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">⚙️ Options d'envoi</label>
|
||||||
|
<div class="checkbox-group-vertical">
|
||||||
|
<label class="checkbox-item">
|
||||||
|
<input type="checkbox" id="scheduled-force-send" checked>
|
||||||
|
Envoyer même si le salon est inactif
|
||||||
|
</label>
|
||||||
|
<label class="checkbox-item">
|
||||||
|
<input type="checkbox" id="scheduled-delete-previous">
|
||||||
|
Supprimer le message précédent
|
||||||
|
</label>
|
||||||
|
<label class="checkbox-item">
|
||||||
|
<input type="checkbox" id="scheduled-enabled" checked>
|
||||||
|
Activer ce message programmé
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<button type="button" class="btn btn-primary" id="scheduled-save-btn">
|
||||||
|
💾 Enregistrer
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-secondary" id="scheduled-cancel-btn" style="display: none;">
|
||||||
|
❌ Annuler
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Liste des messages programmés -->
|
||||||
|
<div class="sub-section">
|
||||||
|
<h4 class="sub-section-title">📋 Messages programmés</h4>
|
||||||
|
<div id="scheduled-messages-list">
|
||||||
|
<p class="text-muted">Aucun message programmé.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
@@ -793,5 +949,6 @@
|
|||||||
<script src="/guild/privateroomForm.js"></script>
|
<script src="/guild/privateroomForm.js"></script>
|
||||||
<script src="/guild/countingForm.js"></script>
|
<script src="/guild/countingForm.js"></script>
|
||||||
<script src="/guild/statsChannelsForm.js"></script>
|
<script src="/guild/statsChannelsForm.js"></script>
|
||||||
|
<script src="/guild/scheduledMessagesForm.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -0,0 +1,412 @@
|
|||||||
|
// ===== SCHEDULED MESSAGES FORM =====
|
||||||
|
(async function () {
|
||||||
|
const channelSelect = document.getElementById("scheduled-channel-select");
|
||||||
|
const messageContent = document.getElementById("scheduled-message-content");
|
||||||
|
const embedEnabled = document.getElementById("scheduled-embed-enabled");
|
||||||
|
const embedOptions = document.getElementById("scheduled-embed-options");
|
||||||
|
const embedTitle = document.getElementById("scheduled-embed-title");
|
||||||
|
const embedDescription = document.getElementById("scheduled-embed-description");
|
||||||
|
const embedColor = document.getElementById("scheduled-embed-color");
|
||||||
|
const scheduleType = document.getElementById("scheduled-type");
|
||||||
|
const weeklyOptions = document.getElementById("scheduled-weekly-options");
|
||||||
|
const intervalOptions = document.getElementById("scheduled-interval-options");
|
||||||
|
const daysContainer = document.getElementById("scheduled-days");
|
||||||
|
const hourSelect = document.getElementById("scheduled-hour-select");
|
||||||
|
const minuteSelect = document.getElementById("scheduled-minute-select");
|
||||||
|
const addTimeBtn = document.getElementById("scheduled-add-time");
|
||||||
|
const timesList = document.getElementById("scheduled-times-list");
|
||||||
|
const intervalValue = document.getElementById("scheduled-interval-value");
|
||||||
|
const intervalUnit = document.getElementById("scheduled-interval-unit");
|
||||||
|
const forceSend = document.getElementById("scheduled-force-send");
|
||||||
|
const deletePrevious = document.getElementById("scheduled-delete-previous");
|
||||||
|
const enabledCheckbox = document.getElementById("scheduled-enabled");
|
||||||
|
const saveBtn = document.getElementById("scheduled-save-btn");
|
||||||
|
const cancelBtn = document.getElementById("scheduled-cancel-btn");
|
||||||
|
const editIdInput = document.getElementById("scheduled-edit-id");
|
||||||
|
const formTitle = document.getElementById("scheduled-form-title");
|
||||||
|
const listContainer = document.getElementById("scheduled-messages-list");
|
||||||
|
|
||||||
|
let selectedTimes = [];
|
||||||
|
|
||||||
|
// Populate hour and minute selects
|
||||||
|
function initTimeSelects() {
|
||||||
|
const now = new Date();
|
||||||
|
const currentHour = now.getHours().toString().padStart(2, "0");
|
||||||
|
const currentMinute = now.getMinutes().toString().padStart(2, "0");
|
||||||
|
|
||||||
|
// Hours 00-23
|
||||||
|
for (let h = 0; h < 24; h++) {
|
||||||
|
const opt = document.createElement("option");
|
||||||
|
opt.value = h.toString().padStart(2, "0");
|
||||||
|
opt.textContent = h.toString().padStart(2, "0");
|
||||||
|
hourSelect.appendChild(opt);
|
||||||
|
}
|
||||||
|
// Minutes 00-59
|
||||||
|
for (let m = 0; m < 60; m++) {
|
||||||
|
const opt = document.createElement("option");
|
||||||
|
opt.value = m.toString().padStart(2, "0");
|
||||||
|
opt.textContent = m.toString().padStart(2, "0");
|
||||||
|
minuteSelect.appendChild(opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default to current time
|
||||||
|
hourSelect.value = currentHour;
|
||||||
|
minuteSelect.value = currentMinute;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle embed options
|
||||||
|
embedEnabled.addEventListener("change", () => {
|
||||||
|
embedOptions.style.display = embedEnabled.checked ? "block" : "none";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Toggle schedule type options
|
||||||
|
scheduleType.addEventListener("change", () => {
|
||||||
|
if (scheduleType.value === "weekly") {
|
||||||
|
weeklyOptions.style.display = "block";
|
||||||
|
intervalOptions.style.display = "none";
|
||||||
|
} else {
|
||||||
|
weeklyOptions.style.display = "none";
|
||||||
|
intervalOptions.style.display = "block";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add time
|
||||||
|
addTimeBtn.addEventListener("click", () => {
|
||||||
|
const hour = hourSelect.value;
|
||||||
|
const minute = minuteSelect.value;
|
||||||
|
|
||||||
|
if (!hour || !minute) {
|
||||||
|
alert("Veuillez sélectionner une heure et des minutes.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = `${hour}:${minute}`;
|
||||||
|
if (selectedTimes.includes(time)) {
|
||||||
|
alert("Cette heure est déjà ajoutée.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedTimes.push(time);
|
||||||
|
selectedTimes.sort();
|
||||||
|
renderTimesList();
|
||||||
|
hourSelect.value = "";
|
||||||
|
minuteSelect.value = "";
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderTimesList() {
|
||||||
|
if (selectedTimes.length === 0) {
|
||||||
|
timesList.innerHTML = '<span class="text-muted">Aucune heure sélectionnée</span>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
timesList.innerHTML = selectedTimes.map(time => `
|
||||||
|
<span class="time-tag">
|
||||||
|
${time}
|
||||||
|
<button type="button" class="time-remove" data-time="${time}">×</button>
|
||||||
|
</span>
|
||||||
|
`).join("");
|
||||||
|
|
||||||
|
document.querySelectorAll(".time-remove").forEach(btn => {
|
||||||
|
btn.addEventListener("click", () => {
|
||||||
|
selectedTimes = selectedTimes.filter(t => t !== btn.dataset.time);
|
||||||
|
renderTimesList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load text channels
|
||||||
|
async function loadChannels() {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/bot/get-text-channels/${guildId}`);
|
||||||
|
const channels = await res.json();
|
||||||
|
channelSelect.innerHTML = '<option value="">-- Sélectionner un salon --</option>';
|
||||||
|
channels.forEach(ch => {
|
||||||
|
const opt = document.createElement("option");
|
||||||
|
opt.value = ch.id;
|
||||||
|
opt.textContent = "# " + ch.name;
|
||||||
|
channelSelect.appendChild(opt);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Erreur chargement salons:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get selected days
|
||||||
|
function getSelectedDays() {
|
||||||
|
const days = [];
|
||||||
|
daysContainer.querySelectorAll("input:checked").forEach(cb => {
|
||||||
|
days.push(parseInt(cb.value));
|
||||||
|
});
|
||||||
|
return days;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set selected days
|
||||||
|
function setSelectedDays(days) {
|
||||||
|
daysContainer.querySelectorAll("input").forEach(cb => {
|
||||||
|
cb.checked = days.includes(parseInt(cb.value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset form
|
||||||
|
function resetForm() {
|
||||||
|
editIdInput.value = "";
|
||||||
|
formTitle.textContent = "➕ Nouveau message programmé";
|
||||||
|
channelSelect.value = "";
|
||||||
|
messageContent.value = "";
|
||||||
|
embedEnabled.checked = false;
|
||||||
|
embedOptions.style.display = "none";
|
||||||
|
embedTitle.value = "";
|
||||||
|
embedDescription.value = "";
|
||||||
|
embedColor.value = "#5865F2";
|
||||||
|
scheduleType.value = "weekly";
|
||||||
|
weeklyOptions.style.display = "block";
|
||||||
|
intervalOptions.style.display = "none";
|
||||||
|
setSelectedDays([]);
|
||||||
|
selectedTimes = [];
|
||||||
|
renderTimesList();
|
||||||
|
intervalValue.value = 60;
|
||||||
|
intervalUnit.value = "minutes";
|
||||||
|
forceSend.checked = true;
|
||||||
|
deletePrevious.checked = false;
|
||||||
|
enabledCheckbox.checked = true;
|
||||||
|
saveBtn.textContent = "💾 Enregistrer";
|
||||||
|
cancelBtn.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load scheduled messages list
|
||||||
|
async function loadScheduledMessages() {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/bot/get-scheduled-messages/${guildId}`);
|
||||||
|
const messages = await res.json();
|
||||||
|
|
||||||
|
if (messages.length === 0) {
|
||||||
|
listContainer.innerHTML = '<p class="text-muted">Aucun message programmé.</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get channels for names
|
||||||
|
const channelsRes = await fetch(`/api/bot/get-text-channels/${guildId}`);
|
||||||
|
const channels = await channelsRes.json();
|
||||||
|
const channelMap = {};
|
||||||
|
channels.forEach(ch => channelMap[ch.id] = ch.name);
|
||||||
|
|
||||||
|
listContainer.innerHTML = messages.map(msg => {
|
||||||
|
const channelName = channelMap[msg.channel_id] || "Salon inconnu";
|
||||||
|
const scheduleInfo = getScheduleInfo(msg);
|
||||||
|
const statusClass = msg.enabled ? "status-active" : "status-inactive";
|
||||||
|
const statusText = msg.enabled ? "Actif" : "Inactif";
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="scheduled-message-item" data-id="${msg.id}">
|
||||||
|
<div class="scheduled-message-header">
|
||||||
|
<div class="scheduled-message-info">
|
||||||
|
<strong># ${channelName}</strong>
|
||||||
|
<span class="scheduled-message-schedule">${scheduleInfo}</span>
|
||||||
|
</div>
|
||||||
|
<span class="status-badge ${statusClass}">${statusText}</span>
|
||||||
|
</div>
|
||||||
|
<div class="scheduled-message-preview">
|
||||||
|
${msg.message_content ? escapeHtml(msg.message_content.substring(0, 100)) + (msg.message_content.length > 100 ? '...' : '') : ''}
|
||||||
|
${msg.embed_enabled ? '<span class="embed-badge">📦 Embed</span>' : ''}
|
||||||
|
</div>
|
||||||
|
<div class="scheduled-message-options">
|
||||||
|
${msg.force_send ? '<span class="option-tag">Force envoi</span>' : '<span class="option-tag">Vérifie activité</span>'}
|
||||||
|
${msg.delete_previous ? '<span class="option-tag">Supprime précédent</span>' : ''}
|
||||||
|
</div>
|
||||||
|
<div class="scheduled-message-actions">
|
||||||
|
<button class="btn btn-sm btn-secondary edit-scheduled" data-id="${msg.id}">✏️ Modifier</button>
|
||||||
|
<button class="btn btn-sm ${msg.enabled ? 'btn-warning' : 'btn-success'} toggle-scheduled" data-id="${msg.id}">
|
||||||
|
${msg.enabled ? '⏸️ Désactiver' : '▶️ Activer'}
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-danger delete-scheduled" data-id="${msg.id}">🗑️ Supprimer</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}).join("");
|
||||||
|
|
||||||
|
// Event listeners
|
||||||
|
document.querySelectorAll(".edit-scheduled").forEach(btn => {
|
||||||
|
btn.addEventListener("click", () => editMessage(messages.find(m => m.id == btn.dataset.id)));
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll(".toggle-scheduled").forEach(btn => {
|
||||||
|
btn.addEventListener("click", () => toggleMessage(btn.dataset.id));
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll(".delete-scheduled").forEach(btn => {
|
||||||
|
btn.addEventListener("click", () => deleteMessage(btn.dataset.id));
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Erreur chargement messages:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getScheduleInfo(msg) {
|
||||||
|
if (msg.schedule_type === "interval") {
|
||||||
|
return `Toutes les ${msg.interval_value} ${msg.interval_unit === 'hours' ? 'heures' : 'minutes'}`;
|
||||||
|
} else {
|
||||||
|
const days = JSON.parse(msg.days_of_week || "[]");
|
||||||
|
const times = JSON.parse(msg.times_of_day || "[]");
|
||||||
|
const dayNames = ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'];
|
||||||
|
const dayStr = days.map(d => dayNames[d]).join(', ') || 'Aucun jour';
|
||||||
|
const timeStr = times.join(', ') || 'Aucune heure';
|
||||||
|
return `${dayStr} à ${timeStr}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(text) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.textContent = text;
|
||||||
|
return div.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit message
|
||||||
|
function editMessage(msg) {
|
||||||
|
editIdInput.value = msg.id;
|
||||||
|
formTitle.textContent = "✏️ Modifier le message programmé";
|
||||||
|
channelSelect.value = msg.channel_id;
|
||||||
|
messageContent.value = msg.message_content || "";
|
||||||
|
embedEnabled.checked = !!msg.embed_enabled;
|
||||||
|
embedOptions.style.display = msg.embed_enabled ? "block" : "none";
|
||||||
|
embedTitle.value = msg.embed_title || "";
|
||||||
|
embedDescription.value = msg.embed_description || "";
|
||||||
|
embedColor.value = msg.embed_color || "#5865F2";
|
||||||
|
scheduleType.value = msg.schedule_type || "weekly";
|
||||||
|
|
||||||
|
if (msg.schedule_type === "interval") {
|
||||||
|
weeklyOptions.style.display = "none";
|
||||||
|
intervalOptions.style.display = "block";
|
||||||
|
} else {
|
||||||
|
weeklyOptions.style.display = "block";
|
||||||
|
intervalOptions.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelectedDays(JSON.parse(msg.days_of_week || "[]"));
|
||||||
|
selectedTimes = JSON.parse(msg.times_of_day || "[]");
|
||||||
|
renderTimesList();
|
||||||
|
intervalValue.value = msg.interval_value || 60;
|
||||||
|
intervalUnit.value = msg.interval_unit || "minutes";
|
||||||
|
forceSend.checked = !!msg.force_send;
|
||||||
|
deletePrevious.checked = !!msg.delete_previous;
|
||||||
|
enabledCheckbox.checked = !!msg.enabled;
|
||||||
|
saveBtn.textContent = "💾 Mettre à jour";
|
||||||
|
cancelBtn.style.display = "inline-block";
|
||||||
|
|
||||||
|
// Scroll to form
|
||||||
|
document.getElementById("scheduled-form-section").scrollIntoView({ behavior: "smooth" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle message
|
||||||
|
async function toggleMessage(id) {
|
||||||
|
try {
|
||||||
|
await fetch(`/api/bot/toggle-scheduled-message/${id}`, { method: "PATCH" });
|
||||||
|
loadScheduledMessages();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Erreur toggle:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete message
|
||||||
|
async function deleteMessage(id) {
|
||||||
|
if (!confirm("Supprimer ce message programmé ?")) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await fetch(`/api/bot/delete-scheduled-message/${id}`, { method: "DELETE" });
|
||||||
|
loadScheduledMessages();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Erreur suppression:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save button
|
||||||
|
saveBtn.addEventListener("click", async () => {
|
||||||
|
const channel = channelSelect.value;
|
||||||
|
if (!channel) {
|
||||||
|
alert("Veuillez sélectionner un salon.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = messageContent.value;
|
||||||
|
const hasEmbed = embedEnabled.checked && (embedTitle.value || embedDescription.value);
|
||||||
|
|
||||||
|
if (!content && !hasEmbed) {
|
||||||
|
alert("Veuillez entrer un message ou configurer un embed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scheduleType.value === "weekly") {
|
||||||
|
if (getSelectedDays().length === 0) {
|
||||||
|
alert("Veuillez sélectionner au moins un jour.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (selectedTimes.length === 0) {
|
||||||
|
alert("Veuillez ajouter au moins une heure.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveBtn.disabled = true;
|
||||||
|
saveBtn.textContent = "Enregistrement...";
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
guildId,
|
||||||
|
channelId: channel,
|
||||||
|
messageContent: content,
|
||||||
|
embedEnabled: embedEnabled.checked,
|
||||||
|
embedTitle: embedTitle.value,
|
||||||
|
embedDescription: embedDescription.value,
|
||||||
|
embedColor: embedColor.value,
|
||||||
|
scheduleType: scheduleType.value,
|
||||||
|
daysOfWeek: getSelectedDays(),
|
||||||
|
timesOfDay: selectedTimes,
|
||||||
|
intervalValue: parseInt(intervalValue.value) || 60,
|
||||||
|
intervalUnit: intervalUnit.value,
|
||||||
|
forceSend: forceSend.checked,
|
||||||
|
deletePrevious: deletePrevious.checked,
|
||||||
|
enabled: enabledCheckbox.checked
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const editId = editIdInput.value;
|
||||||
|
let res;
|
||||||
|
|
||||||
|
if (editId) {
|
||||||
|
res = await fetch(`/api/bot/update-scheduled-message/${editId}`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res = await fetch("/api/bot/add-scheduled-message", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await res.json();
|
||||||
|
if (result.success) {
|
||||||
|
resetForm();
|
||||||
|
loadScheduledMessages();
|
||||||
|
} else {
|
||||||
|
alert("Erreur lors de l'enregistrement.");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Erreur:", err);
|
||||||
|
alert("Erreur réseau.");
|
||||||
|
}
|
||||||
|
|
||||||
|
saveBtn.disabled = false;
|
||||||
|
saveBtn.textContent = editIdInput.value ? "💾 Mettre à jour" : "💾 Enregistrer";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cancel button
|
||||||
|
cancelBtn.addEventListener("click", resetForm);
|
||||||
|
|
||||||
|
// Init
|
||||||
|
initTimeSelects();
|
||||||
|
await loadChannels();
|
||||||
|
await loadScheduledMessages();
|
||||||
|
renderTimesList();
|
||||||
|
})();
|
||||||
@@ -92,6 +92,11 @@
|
|||||||
<h3>Stats d'Activité</h3>
|
<h3>Stats d'Activité</h3>
|
||||||
<p>Suivez l'activité de vos membres avec des graphiques détaillés : messages envoyés, temps en vocal, par semaine, mois ou année.</p>
|
<p>Suivez l'activité de vos membres avec des graphiques détaillés : messages envoyés, temps en vocal, par semaine, mois ou année.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">⏰</div>
|
||||||
|
<h3>Messages Programmés</h3>
|
||||||
|
<p>Planifiez l'envoi automatique de messages à des jours et heures précis ou à intervalles réguliers. Options avancées incluses.</p>
|
||||||
|
</div>
|
||||||
<div class="feature-card">
|
<div class="feature-card">
|
||||||
<div class="feature-icon">⚙️</div>
|
<div class="feature-icon">⚙️</div>
|
||||||
<h3>Dashboard Intuitif</h3>
|
<h3>Dashboard Intuitif</h3>
|
||||||
|
|||||||
@@ -965,5 +965,162 @@ module.exports = (app, db, client) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ===== SCHEDULED MESSAGES =====
|
||||||
|
|
||||||
|
// Récupérer tous les messages programmés d'un serveur
|
||||||
|
router.get("/bot/get-scheduled-messages/:guildId", (req, res) => {
|
||||||
|
const { guildId } = req.params;
|
||||||
|
|
||||||
|
if (!req.session.guilds) {
|
||||||
|
return res.status(401).json([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isAdmin = req.session.guilds.find(
|
||||||
|
g => g.id === guildId && (BigInt(g.permissions) & 0x8n) === 0x8n
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isAdmin) {
|
||||||
|
return res.status(403).json([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.all(
|
||||||
|
"SELECT * FROM scheduled_messages WHERE guild_id = ? ORDER BY created_at DESC",
|
||||||
|
[guildId],
|
||||||
|
(err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return res.status(500).json([]);
|
||||||
|
}
|
||||||
|
res.json(rows || []);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ajouter un message programmé
|
||||||
|
router.post("/bot/add-scheduled-message", express.json(), (req, res) => {
|
||||||
|
const {
|
||||||
|
guildId, channelId, messageContent,
|
||||||
|
embedEnabled, embedTitle, embedDescription, embedColor,
|
||||||
|
scheduleType, daysOfWeek, timesOfDay, intervalValue, intervalUnit,
|
||||||
|
forceSend, deletePrevious, enabled
|
||||||
|
} = 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(403).json({ success: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
db.run(
|
||||||
|
`INSERT INTO scheduled_messages (
|
||||||
|
guild_id, channel_id, message_content,
|
||||||
|
embed_enabled, embed_title, embed_description, embed_color,
|
||||||
|
schedule_type, days_of_week, times_of_day, interval_value, interval_unit,
|
||||||
|
force_send, delete_previous, enabled
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||||
|
[
|
||||||
|
guildId, channelId, messageContent || '',
|
||||||
|
embedEnabled ? 1 : 0, embedTitle || null, embedDescription || null, embedColor || '#5865F2',
|
||||||
|
scheduleType || 'weekly',
|
||||||
|
JSON.stringify(daysOfWeek || []),
|
||||||
|
JSON.stringify(timesOfDay || []),
|
||||||
|
intervalValue || 60, intervalUnit || 'minutes',
|
||||||
|
forceSend ? 1 : 0, deletePrevious ? 1 : 0, enabled ? 1 : 0
|
||||||
|
],
|
||||||
|
function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return res.status(500).json({ success: false });
|
||||||
|
}
|
||||||
|
res.json({ success: true, id: this.lastID });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Modifier un message programmé
|
||||||
|
router.put("/bot/update-scheduled-message/:id", express.json(), (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
const {
|
||||||
|
channelId, messageContent,
|
||||||
|
embedEnabled, embedTitle, embedDescription, embedColor,
|
||||||
|
scheduleType, daysOfWeek, timesOfDay, intervalValue, intervalUnit,
|
||||||
|
forceSend, deletePrevious, enabled
|
||||||
|
} = req.body;
|
||||||
|
|
||||||
|
if (!req.session.guilds) {
|
||||||
|
return res.status(401).json({ success: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
db.run(
|
||||||
|
`UPDATE scheduled_messages SET
|
||||||
|
channel_id = ?, message_content = ?,
|
||||||
|
embed_enabled = ?, embed_title = ?, embed_description = ?, embed_color = ?,
|
||||||
|
schedule_type = ?, days_of_week = ?, times_of_day = ?, interval_value = ?, interval_unit = ?,
|
||||||
|
force_send = ?, delete_previous = ?, enabled = ?
|
||||||
|
WHERE id = ?`,
|
||||||
|
[
|
||||||
|
channelId, messageContent || '',
|
||||||
|
embedEnabled ? 1 : 0, embedTitle || null, embedDescription || null, embedColor || '#5865F2',
|
||||||
|
scheduleType || 'weekly',
|
||||||
|
JSON.stringify(daysOfWeek || []),
|
||||||
|
JSON.stringify(timesOfDay || []),
|
||||||
|
intervalValue || 60, intervalUnit || 'minutes',
|
||||||
|
forceSend ? 1 : 0, deletePrevious ? 1 : 0, enabled ? 1 : 0,
|
||||||
|
id
|
||||||
|
],
|
||||||
|
(err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return res.status(500).json({ success: false });
|
||||||
|
}
|
||||||
|
res.json({ success: true });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Supprimer un message programmé
|
||||||
|
router.delete("/bot/delete-scheduled-message/:id", (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
|
||||||
|
if (!req.session.guilds) {
|
||||||
|
return res.status(401).json({ success: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
db.run("DELETE FROM scheduled_messages WHERE id = ?", [id], (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return res.status(500).json({ success: false });
|
||||||
|
}
|
||||||
|
res.json({ success: true });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Toggle enabled/disabled
|
||||||
|
router.patch("/bot/toggle-scheduled-message/:id", (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
|
||||||
|
if (!req.session.guilds) {
|
||||||
|
return res.status(401).json({ success: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
db.run(
|
||||||
|
"UPDATE scheduled_messages SET enabled = NOT enabled WHERE id = ?",
|
||||||
|
[id],
|
||||||
|
(err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return res.status(500).json({ success: false });
|
||||||
|
}
|
||||||
|
res.json({ success: true });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
app.use("/api", router);
|
app.use("/api", router);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user