mirror of
https://github.com/arthur-pbty/LazyBot.git
synced 2026-06-03 15:07:29 +02:00
ajouter une fonctionnalité d'envoi de message avec options d'embed et historique des messages
This commit is contained in:
@@ -799,3 +799,168 @@ body {
|
||||
background: #d9a02a;
|
||||
}
|
||||
|
||||
/* ===== Send Message Preview ===== */
|
||||
.message-preview {
|
||||
background: var(--bg-dark);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--spacing-md);
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.preview-content {
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.preview-embed {
|
||||
background: var(--bg-card);
|
||||
border-left: 4px solid var(--primary-color);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--spacing-md);
|
||||
position: relative;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.preview-embed-author {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xs);
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.preview-author-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.preview-embed-author a {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.preview-embed-author a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.preview-embed-title {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
font-size: 1rem;
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.preview-embed-description {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.9rem;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.preview-embed-thumbnail {
|
||||
position: absolute;
|
||||
top: var(--spacing-md);
|
||||
right: var(--spacing-md);
|
||||
max-width: 80px;
|
||||
max-height: 80px;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.preview-embed-fields {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--spacing-sm);
|
||||
margin-top: var(--spacing-md);
|
||||
}
|
||||
|
||||
.preview-embed-field {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
|
||||
.preview-embed-field.inline {
|
||||
flex: 1 1 calc(33% - var(--spacing-sm));
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.preview-field-name {
|
||||
font-weight: 600;
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.preview-field-value {
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.preview-embed-image {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
border-radius: var(--radius-sm);
|
||||
margin-top: var(--spacing-md);
|
||||
}
|
||||
|
||||
.preview-embed-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xs);
|
||||
margin-top: var(--spacing-md);
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.preview-footer-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* ===== Field Items ===== */
|
||||
.field-item {
|
||||
background: var(--bg-card);
|
||||
padding: var(--spacing-sm);
|
||||
border-radius: var(--radius-sm);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.field-item .form-row {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* ===== Send Message History ===== */
|
||||
.history-item {
|
||||
background: var(--bg-card);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--spacing-md);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.history-item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.history-channel {
|
||||
color: var(--primary-color);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.history-time {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.history-content {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.9rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@@ -66,6 +66,10 @@
|
||||
<span class="nav-item-icon">⏰</span>
|
||||
Messages programmés
|
||||
</a>
|
||||
<a class="nav-item" data-section="sendmessage">
|
||||
<span class="nav-item-icon">✉️</span>
|
||||
Envoyer un message
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -932,6 +936,132 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Section: Envoyer un message -->
|
||||
<section class="config-section" id="section-sendmessage">
|
||||
<div class="config-card">
|
||||
<div class="config-card-header">
|
||||
<div>
|
||||
<h2 class="config-card-title">✉️ Envoyer un message</h2>
|
||||
<p class="config-card-subtitle">Envoyez un message dans un salon de votre serveur</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="config-card-body">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">📺 Salon</label>
|
||||
<select class="form-select" id="sendmsg-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="sendmsg-content" rows="4" placeholder="Le contenu de votre message..."></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Embed optionnel -->
|
||||
<div class="form-group">
|
||||
<label class="form-label">
|
||||
<input type="checkbox" id="sendmsg-embed-enabled">
|
||||
📦 Ajouter un embed
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div id="sendmsg-embed-options" style="display: none;">
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Titre</label>
|
||||
<input type="text" class="form-input" id="sendmsg-embed-title" placeholder="Titre de l'embed...">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Couleur</label>
|
||||
<input type="color" class="form-input" id="sendmsg-embed-color" value="#5865F2" style="height: 40px;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Description</label>
|
||||
<textarea class="form-textarea" id="sendmsg-embed-description" rows="4" placeholder="Description de l'embed..."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">URL de l'auteur</label>
|
||||
<input type="text" class="form-input" id="sendmsg-embed-author-url" placeholder="https://...">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Nom de l'auteur</label>
|
||||
<input type="text" class="form-input" id="sendmsg-embed-author-name" placeholder="Nom...">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Icône de l'auteur (URL)</label>
|
||||
<input type="text" class="form-input" id="sendmsg-embed-author-icon" placeholder="https://...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">🖼️ Image (URL)</label>
|
||||
<input type="text" class="form-input" id="sendmsg-embed-image" placeholder="https://...">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">📎 Miniature (URL)</label>
|
||||
<input type="text" class="form-input" id="sendmsg-embed-thumbnail" placeholder="https://...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Texte du footer</label>
|
||||
<input type="text" class="form-input" id="sendmsg-embed-footer-text" placeholder="Footer...">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Icône du footer (URL)</label>
|
||||
<input type="text" class="form-input" id="sendmsg-embed-footer-icon" placeholder="https://...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">
|
||||
<input type="checkbox" id="sendmsg-embed-timestamp">
|
||||
Ajouter un timestamp (date/heure actuelle)
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Champs (Fields) -->
|
||||
<div class="form-group">
|
||||
<label class="form-label">📝 Champs (Fields)</label>
|
||||
<div id="sendmsg-fields-container"></div>
|
||||
<button type="button" class="btn btn-sm btn-secondary" id="sendmsg-add-field">+ Ajouter un champ</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Aperçu -->
|
||||
<div class="form-group">
|
||||
<label class="form-label">👁️ Aperçu</label>
|
||||
<div id="sendmsg-preview" class="message-preview">
|
||||
<p class="text-muted">L'aperçu apparaîtra ici...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="button" class="btn btn-primary" id="sendmsg-send-btn">
|
||||
📤 Envoyer le message
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Historique -->
|
||||
<div class="sub-section" style="margin-top: 2rem;">
|
||||
<h4 class="sub-section-title">📋 Derniers messages envoyés</h4>
|
||||
<div id="sendmsg-history">
|
||||
<p class="text-muted">Aucun message envoyé récemment.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -950,5 +1080,6 @@
|
||||
<script src="/guild/countingForm.js"></script>
|
||||
<script src="/guild/statsChannelsForm.js"></script>
|
||||
<script src="/guild/scheduledMessagesForm.js"></script>
|
||||
<script src="/guild/sendMessageForm.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -60,6 +60,7 @@ fetch(`/api/bot/get-text-channels/${guildId}`)
|
||||
const goodbye = document.getElementById("goodbye-channel");
|
||||
const levelAnnouncements = document.getElementById("level-announcements-channel");
|
||||
const levelChannelRestrict = document.getElementById("level-channel-with-or-without-xp");
|
||||
const sendmsgChannel = document.getElementById("sendmsg-channel-select");
|
||||
|
||||
channels.forEach(c => {
|
||||
const opt = new Option(`#${c.name}`, c.id);
|
||||
@@ -67,6 +68,7 @@ fetch(`/api/bot/get-text-channels/${guildId}`)
|
||||
goodbye?.appendChild(opt.cloneNode(true));
|
||||
levelAnnouncements?.appendChild(opt.cloneNode(true));
|
||||
levelChannelRestrict?.appendChild(opt.cloneNode(true));
|
||||
sendmsgChannel?.appendChild(opt.cloneNode(true));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
// ===== SEND MESSAGE FORM =====
|
||||
(async function () {
|
||||
const channelSelect = document.getElementById("sendmsg-channel-select");
|
||||
const messageContent = document.getElementById("sendmsg-content");
|
||||
const embedEnabled = document.getElementById("sendmsg-embed-enabled");
|
||||
const embedOptions = document.getElementById("sendmsg-embed-options");
|
||||
const embedTitle = document.getElementById("sendmsg-embed-title");
|
||||
const embedDescription = document.getElementById("sendmsg-embed-description");
|
||||
const embedColor = document.getElementById("sendmsg-embed-color");
|
||||
const embedAuthorName = document.getElementById("sendmsg-embed-author-name");
|
||||
const embedAuthorUrl = document.getElementById("sendmsg-embed-author-url");
|
||||
const embedAuthorIcon = document.getElementById("sendmsg-embed-author-icon");
|
||||
const embedImage = document.getElementById("sendmsg-embed-image");
|
||||
const embedThumbnail = document.getElementById("sendmsg-embed-thumbnail");
|
||||
const embedFooterText = document.getElementById("sendmsg-embed-footer-text");
|
||||
const embedFooterIcon = document.getElementById("sendmsg-embed-footer-icon");
|
||||
const embedTimestamp = document.getElementById("sendmsg-embed-timestamp");
|
||||
const fieldsContainer = document.getElementById("sendmsg-fields-container");
|
||||
const addFieldBtn = document.getElementById("sendmsg-add-field");
|
||||
const previewContainer = document.getElementById("sendmsg-preview");
|
||||
const sendBtn = document.getElementById("sendmsg-send-btn");
|
||||
const historyContainer = document.getElementById("sendmsg-history");
|
||||
|
||||
let fields = [];
|
||||
let sentMessages = [];
|
||||
|
||||
// Toggle embed options
|
||||
embedEnabled.addEventListener("change", () => {
|
||||
embedOptions.style.display = embedEnabled.checked ? "block" : "none";
|
||||
updatePreview();
|
||||
});
|
||||
|
||||
// Add field
|
||||
addFieldBtn.addEventListener("click", () => {
|
||||
const fieldIndex = fields.length;
|
||||
fields.push({ name: "", value: "", inline: false });
|
||||
renderFields();
|
||||
});
|
||||
|
||||
function renderFields() {
|
||||
fieldsContainer.innerHTML = "";
|
||||
fields.forEach((field, index) => {
|
||||
const fieldDiv = document.createElement("div");
|
||||
fieldDiv.className = "field-item";
|
||||
fieldDiv.innerHTML = `
|
||||
<div class="form-row" style="margin-bottom: 0.5rem;">
|
||||
<div class="form-group" style="flex: 1;">
|
||||
<input type="text" class="form-input field-name" data-index="${index}" placeholder="Nom du champ" value="${field.name}">
|
||||
</div>
|
||||
<div class="form-group" style="flex: 2;">
|
||||
<input type="text" class="form-input field-value" data-index="${index}" placeholder="Valeur" value="${field.value}">
|
||||
</div>
|
||||
<div class="form-group" style="flex: 0 0 auto; display: flex; align-items: center; gap: 0.5rem;">
|
||||
<label style="display: flex; align-items: center; gap: 0.25rem; white-space: nowrap;">
|
||||
<input type="checkbox" class="field-inline" data-index="${index}" ${field.inline ? "checked" : ""}> Inline
|
||||
</label>
|
||||
<button type="button" class="btn btn-sm btn-danger field-remove" data-index="${index}">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
fieldsContainer.appendChild(fieldDiv);
|
||||
});
|
||||
|
||||
// Event listeners for fields
|
||||
document.querySelectorAll(".field-name").forEach(input => {
|
||||
input.addEventListener("input", (e) => {
|
||||
fields[e.target.dataset.index].name = e.target.value;
|
||||
updatePreview();
|
||||
});
|
||||
});
|
||||
document.querySelectorAll(".field-value").forEach(input => {
|
||||
input.addEventListener("input", (e) => {
|
||||
fields[e.target.dataset.index].value = e.target.value;
|
||||
updatePreview();
|
||||
});
|
||||
});
|
||||
document.querySelectorAll(".field-inline").forEach(input => {
|
||||
input.addEventListener("change", (e) => {
|
||||
fields[e.target.dataset.index].inline = e.target.checked;
|
||||
updatePreview();
|
||||
});
|
||||
});
|
||||
document.querySelectorAll(".field-remove").forEach(btn => {
|
||||
btn.addEventListener("click", (e) => {
|
||||
fields.splice(e.target.dataset.index, 1);
|
||||
renderFields();
|
||||
updatePreview();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Update preview
|
||||
function updatePreview() {
|
||||
let html = "";
|
||||
|
||||
const content = messageContent.value.trim();
|
||||
if (content) {
|
||||
html += `<div class="preview-content">${escapeHtml(content)}</div>`;
|
||||
}
|
||||
|
||||
if (embedEnabled.checked) {
|
||||
const color = embedColor.value || "#5865F2";
|
||||
html += `<div class="preview-embed" style="border-left-color: ${color};">`;
|
||||
|
||||
// Author
|
||||
if (embedAuthorName.value.trim()) {
|
||||
html += `<div class="preview-embed-author">`;
|
||||
if (embedAuthorIcon.value.trim()) {
|
||||
html += `<img src="${escapeHtml(embedAuthorIcon.value)}" class="preview-author-icon" onerror="this.style.display='none'">`;
|
||||
}
|
||||
if (embedAuthorUrl.value.trim()) {
|
||||
html += `<a href="${escapeHtml(embedAuthorUrl.value)}" target="_blank">${escapeHtml(embedAuthorName.value)}</a>`;
|
||||
} else {
|
||||
html += `<span>${escapeHtml(embedAuthorName.value)}</span>`;
|
||||
}
|
||||
html += `</div>`;
|
||||
}
|
||||
|
||||
// Title
|
||||
if (embedTitle.value.trim()) {
|
||||
html += `<div class="preview-embed-title">${escapeHtml(embedTitle.value)}</div>`;
|
||||
}
|
||||
|
||||
// Description
|
||||
if (embedDescription.value.trim()) {
|
||||
html += `<div class="preview-embed-description">${escapeHtml(embedDescription.value)}</div>`;
|
||||
}
|
||||
|
||||
// Thumbnail
|
||||
if (embedThumbnail.value.trim()) {
|
||||
html += `<img src="${escapeHtml(embedThumbnail.value)}" class="preview-embed-thumbnail" onerror="this.style.display='none'">`;
|
||||
}
|
||||
|
||||
// Fields
|
||||
const validFields = fields.filter(f => f.name.trim() && f.value.trim());
|
||||
if (validFields.length > 0) {
|
||||
html += `<div class="preview-embed-fields">`;
|
||||
validFields.forEach(f => {
|
||||
html += `<div class="preview-embed-field ${f.inline ? 'inline' : ''}">
|
||||
<div class="preview-field-name">${escapeHtml(f.name)}</div>
|
||||
<div class="preview-field-value">${escapeHtml(f.value)}</div>
|
||||
</div>`;
|
||||
});
|
||||
html += `</div>`;
|
||||
}
|
||||
|
||||
// Image
|
||||
if (embedImage.value.trim()) {
|
||||
html += `<img src="${escapeHtml(embedImage.value)}" class="preview-embed-image" onerror="this.style.display='none'">`;
|
||||
}
|
||||
|
||||
// Footer
|
||||
if (embedFooterText.value.trim() || embedTimestamp.checked) {
|
||||
html += `<div class="preview-embed-footer">`;
|
||||
if (embedFooterIcon.value.trim()) {
|
||||
html += `<img src="${escapeHtml(embedFooterIcon.value)}" class="preview-footer-icon" onerror="this.style.display='none'">`;
|
||||
}
|
||||
let footerParts = [];
|
||||
if (embedFooterText.value.trim()) {
|
||||
footerParts.push(escapeHtml(embedFooterText.value));
|
||||
}
|
||||
if (embedTimestamp.checked) {
|
||||
footerParts.push(new Date().toLocaleString("fr-FR"));
|
||||
}
|
||||
html += `<span>${footerParts.join(" • ")}</span>`;
|
||||
html += `</div>`;
|
||||
}
|
||||
|
||||
html += `</div>`;
|
||||
}
|
||||
|
||||
if (!html) {
|
||||
html = `<p class="text-muted">L'aperçu apparaîtra ici...</p>`;
|
||||
}
|
||||
|
||||
previewContainer.innerHTML = html;
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement("div");
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// Add event listeners for preview updates
|
||||
[messageContent, embedTitle, embedDescription, embedAuthorName, embedAuthorUrl,
|
||||
embedAuthorIcon, embedImage, embedThumbnail, embedFooterText, embedFooterIcon].forEach(el => {
|
||||
el.addEventListener("input", updatePreview);
|
||||
});
|
||||
embedColor.addEventListener("change", updatePreview);
|
||||
embedTimestamp.addEventListener("change", updatePreview);
|
||||
|
||||
// Send message
|
||||
sendBtn.addEventListener("click", async () => {
|
||||
const channelId = channelSelect.value;
|
||||
if (!channelId) {
|
||||
alert("Veuillez sélectionner un salon.");
|
||||
return;
|
||||
}
|
||||
|
||||
const content = messageContent.value.trim();
|
||||
const hasEmbed = embedEnabled.checked;
|
||||
|
||||
if (!content && !hasEmbed) {
|
||||
alert("Veuillez entrer un message ou activer l'embed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Build embed data
|
||||
let embed = null;
|
||||
if (hasEmbed) {
|
||||
embed = {
|
||||
title: embedTitle.value.trim() || null,
|
||||
description: embedDescription.value.trim() || null,
|
||||
color: embedColor.value,
|
||||
author: null,
|
||||
thumbnail: embedThumbnail.value.trim() ? { url: embedThumbnail.value.trim() } : null,
|
||||
image: embedImage.value.trim() ? { url: embedImage.value.trim() } : null,
|
||||
footer: null,
|
||||
timestamp: embedTimestamp.checked,
|
||||
fields: fields.filter(f => f.name.trim() && f.value.trim())
|
||||
};
|
||||
|
||||
if (embedAuthorName.value.trim()) {
|
||||
embed.author = {
|
||||
name: embedAuthorName.value.trim(),
|
||||
url: embedAuthorUrl.value.trim() || null,
|
||||
icon_url: embedAuthorIcon.value.trim() || null
|
||||
};
|
||||
}
|
||||
|
||||
if (embedFooterText.value.trim()) {
|
||||
embed.footer = {
|
||||
text: embedFooterText.value.trim(),
|
||||
icon_url: embedFooterIcon.value.trim() || null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
sendBtn.disabled = true;
|
||||
sendBtn.textContent = "⏳ Envoi en cours...";
|
||||
|
||||
try {
|
||||
const res = await fetch("/api/bot/send-message", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
guildId: window.guildId,
|
||||
channelId,
|
||||
content: content || null,
|
||||
embed
|
||||
})
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (data.success) {
|
||||
// Add to history
|
||||
sentMessages.unshift({
|
||||
channelId,
|
||||
channelName: channelSelect.options[channelSelect.selectedIndex].text,
|
||||
content: content || "(Embed uniquement)",
|
||||
timestamp: new Date().toLocaleString("fr-FR")
|
||||
});
|
||||
if (sentMessages.length > 10) sentMessages.pop();
|
||||
renderHistory();
|
||||
|
||||
// Clear form
|
||||
messageContent.value = "";
|
||||
embedTitle.value = "";
|
||||
embedDescription.value = "";
|
||||
embedAuthorName.value = "";
|
||||
embedAuthorUrl.value = "";
|
||||
embedAuthorIcon.value = "";
|
||||
embedImage.value = "";
|
||||
embedThumbnail.value = "";
|
||||
embedFooterText.value = "";
|
||||
embedFooterIcon.value = "";
|
||||
embedTimestamp.checked = false;
|
||||
fields = [];
|
||||
renderFields();
|
||||
updatePreview();
|
||||
|
||||
alert("✅ Message envoyé avec succès !");
|
||||
} else {
|
||||
alert("❌ Erreur lors de l'envoi: " + (data.error || "Erreur inconnue"));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert("❌ Erreur lors de l'envoi du message.");
|
||||
}
|
||||
|
||||
sendBtn.disabled = false;
|
||||
sendBtn.textContent = "📤 Envoyer le message";
|
||||
});
|
||||
|
||||
function renderHistory() {
|
||||
if (sentMessages.length === 0) {
|
||||
historyContainer.innerHTML = `<p class="text-muted">Aucun message envoyé récemment.</p>`;
|
||||
return;
|
||||
}
|
||||
|
||||
historyContainer.innerHTML = sentMessages.map(msg => `
|
||||
<div class="history-item">
|
||||
<div class="history-item-header">
|
||||
<span class="history-channel">#${escapeHtml(msg.channelName)}</span>
|
||||
<span class="history-time">${msg.timestamp}</span>
|
||||
</div>
|
||||
<div class="history-content">${escapeHtml(msg.content.substring(0, 100))}${msg.content.length > 100 ? '...' : ''}</div>
|
||||
</div>
|
||||
`).join("");
|
||||
}
|
||||
|
||||
// Initialize
|
||||
updatePreview();
|
||||
})();
|
||||
@@ -1122,5 +1122,98 @@ module.exports = (app, db, client) => {
|
||||
);
|
||||
});
|
||||
|
||||
// Envoyer un message instantané
|
||||
router.post("/bot/send-message", express.json(), async (req, res) => {
|
||||
const { guildId, channelId, content, embed } = req.body;
|
||||
|
||||
if (!req.session.guilds) {
|
||||
return res.status(401).json({ success: false, error: "Non connecté" });
|
||||
}
|
||||
|
||||
const isAdmin = req.session.guilds.find(
|
||||
g => g.id === guildId && (BigInt(g.permissions) & 0x8n) === 0x8n
|
||||
);
|
||||
|
||||
if (!isAdmin) {
|
||||
return res.status(403).json({ success: false, error: "Permission refusée" });
|
||||
}
|
||||
|
||||
try {
|
||||
const guild = client.guilds.cache.get(guildId);
|
||||
if (!guild) {
|
||||
return res.status(404).json({ success: false, error: "Serveur non trouvé" });
|
||||
}
|
||||
|
||||
const channel = guild.channels.cache.get(channelId);
|
||||
if (!channel) {
|
||||
return res.status(404).json({ success: false, error: "Salon non trouvé" });
|
||||
}
|
||||
|
||||
// Build message options
|
||||
const messageOptions = {};
|
||||
|
||||
if (content) {
|
||||
messageOptions.content = content;
|
||||
}
|
||||
|
||||
if (embed) {
|
||||
const { EmbedBuilder } = require("discord.js");
|
||||
const embedBuilder = new EmbedBuilder();
|
||||
|
||||
if (embed.title) embedBuilder.setTitle(embed.title);
|
||||
if (embed.description) embedBuilder.setDescription(embed.description);
|
||||
if (embed.color) embedBuilder.setColor(embed.color);
|
||||
|
||||
if (embed.author && embed.author.name) {
|
||||
embedBuilder.setAuthor({
|
||||
name: embed.author.name,
|
||||
url: embed.author.url || undefined,
|
||||
iconURL: embed.author.icon_url || undefined
|
||||
});
|
||||
}
|
||||
|
||||
if (embed.thumbnail && embed.thumbnail.url) {
|
||||
embedBuilder.setThumbnail(embed.thumbnail.url);
|
||||
}
|
||||
|
||||
if (embed.image && embed.image.url) {
|
||||
embedBuilder.setImage(embed.image.url);
|
||||
}
|
||||
|
||||
if (embed.footer && embed.footer.text) {
|
||||
embedBuilder.setFooter({
|
||||
text: embed.footer.text,
|
||||
iconURL: embed.footer.icon_url || undefined
|
||||
});
|
||||
}
|
||||
|
||||
if (embed.timestamp) {
|
||||
embedBuilder.setTimestamp();
|
||||
}
|
||||
|
||||
if (embed.fields && embed.fields.length > 0) {
|
||||
embed.fields.forEach(field => {
|
||||
if (field.name && field.value) {
|
||||
embedBuilder.addFields({
|
||||
name: field.name,
|
||||
value: field.value,
|
||||
inline: field.inline || false
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
messageOptions.embeds = [embedBuilder];
|
||||
}
|
||||
|
||||
await channel.send(messageOptions);
|
||||
res.json({ success: true });
|
||||
|
||||
} catch (err) {
|
||||
console.error("Erreur envoi message:", err);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.use("/api", router);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user