mirror of
https://github.com/arthur-pbty/LazyBot.git
synced 2026-06-03 23:36:37 +02:00
add logs
This commit is contained in:
@@ -1035,3 +1035,134 @@ body {
|
||||
object-fit: cover;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ===== Logs System ===== */
|
||||
.logs-types-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.log-type-card {
|
||||
background: var(--bg-dark);
|
||||
border: 2px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--spacing-md);
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.log-type-card:hover {
|
||||
border-color: var(--primary-color);
|
||||
background: rgba(88, 101, 242, 0.05);
|
||||
}
|
||||
|
||||
.log-type-card.active {
|
||||
border-color: var(--primary-color);
|
||||
background: rgba(88, 101, 242, 0.1);
|
||||
}
|
||||
|
||||
.log-type-checkbox {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: var(--spacing-sm);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.log-type-checkbox input[type="checkbox"] {
|
||||
margin-top: 4px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
accent-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.log-type-icon {
|
||||
font-size: 1.5rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.log-type-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.log-type-name {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.log-type-desc {
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.log-type-status {
|
||||
font-size: 1rem;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.logs-channels-preview {
|
||||
background: var(--bg-dark);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--spacing-md);
|
||||
}
|
||||
|
||||
.log-channel-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
padding: var(--spacing-sm) 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.log-channel-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.log-channel-icon {
|
||||
color: var(--text-muted);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.log-channel-name {
|
||||
flex: 1;
|
||||
font-family: monospace;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.log-channel-status {
|
||||
font-size: 0.85rem;
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.log-channel-status.created {
|
||||
background: rgba(87, 242, 135, 0.15);
|
||||
color: #57F287;
|
||||
}
|
||||
|
||||
.log-channel-status.pending {
|
||||
background: rgba(240, 178, 50, 0.15);
|
||||
color: #F0B232;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
display: flex;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: var(--error-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: #c0392b;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,10 @@
|
||||
<span class="nav-item-icon">🤖</span>
|
||||
Apparence du bot
|
||||
</a>
|
||||
<a class="nav-item" data-section="logs">
|
||||
<span class="nav-item-icon">📜</span>
|
||||
Logs
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -1113,6 +1117,66 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Section: Logs -->
|
||||
<section class="config-section" id="section-logs">
|
||||
<div class="config-card">
|
||||
<div class="config-card-header">
|
||||
<div class="config-card-title">
|
||||
<span class="icon">📜</span>
|
||||
<h3>Système de Logs</h3>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="logs-enabled">
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="config-card-body">
|
||||
<p class="text-muted" style="margin-bottom: 1.5rem;">
|
||||
Activez les logs pour suivre toutes les actions sur votre serveur. Le bot créera automatiquement les salons de logs dans une catégorie dédiée.
|
||||
</p>
|
||||
|
||||
<!-- Catégorie existante ou nouvelle -->
|
||||
<div class="form-group">
|
||||
<label class="form-label">📁 Catégorie pour les logs</label>
|
||||
<select class="form-select" id="logs-category">
|
||||
<option value="">📜 Créer une nouvelle catégorie "LOGS"</option>
|
||||
</select>
|
||||
<small class="text-muted">Sélectionnez une catégorie existante ou laissez vide pour en créer une nouvelle automatiquement.</small>
|
||||
</div>
|
||||
|
||||
<!-- Types de logs -->
|
||||
<div class="form-group">
|
||||
<label class="form-label">🔧 Types de logs à activer</label>
|
||||
<p class="text-muted" style="margin-bottom: 1rem;">Sélectionnez les types de logs que vous souhaitez activer. Un salon sera créé pour chaque type activé.</p>
|
||||
|
||||
<div class="logs-types-grid" id="logs-types-container">
|
||||
<!-- Généré dynamiquement par JS -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Aperçu des salons -->
|
||||
<div class="form-group" id="logs-preview-container" style="display: none;">
|
||||
<label class="form-label">👁️ Salons de logs</label>
|
||||
<div class="logs-channels-preview" id="logs-channels-preview">
|
||||
<!-- Généré dynamiquement -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="config-card-footer">
|
||||
<div id="status-logs-form" class="status-message"></div>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-danger" id="logs-delete-btn" style="display: none;">
|
||||
🗑️ Supprimer tous les salons
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" id="logs-save-btn">
|
||||
💾 Sauvegarder
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -1133,5 +1197,6 @@
|
||||
<script src="/guild/scheduledMessagesForm.js"></script>
|
||||
<script src="/guild/sendMessageForm.js"></script>
|
||||
<script src="/guild/botAppearanceForm.js"></script>
|
||||
<script src="/guild/logsForm.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
// ===== LOGS FORM =====
|
||||
(function() {
|
||||
const logsEnabled = document.getElementById('logs-enabled');
|
||||
const logsCategory = document.getElementById('logs-category');
|
||||
const logsTypesContainer = document.getElementById('logs-types-container');
|
||||
const logsPreviewContainer = document.getElementById('logs-preview-container');
|
||||
const logsChannelsPreview = document.getElementById('logs-channels-preview');
|
||||
const logsSaveBtn = document.getElementById('logs-save-btn');
|
||||
const logsDeleteBtn = document.getElementById('logs-delete-btn');
|
||||
const statusLogsForm = document.getElementById('status-logs-form');
|
||||
|
||||
let logTypes = [];
|
||||
let currentConfig = null;
|
||||
|
||||
// Charger la config des logs
|
||||
async function loadLogsConfig() {
|
||||
try {
|
||||
const res = await fetch(`/api/bot/get-logs-config/${guildId}`);
|
||||
const data = await res.json();
|
||||
|
||||
if (data.success) {
|
||||
logTypes = data.logTypes || [];
|
||||
currentConfig = data.config || {};
|
||||
|
||||
// Remplir le select des catégories
|
||||
logsCategory.innerHTML = '<option value="">📜 Créer une nouvelle catégorie "LOGS"</option>';
|
||||
(data.categories || []).forEach(cat => {
|
||||
const option = document.createElement('option');
|
||||
option.value = cat.id;
|
||||
option.textContent = cat.name;
|
||||
if (currentConfig.category_id === cat.id) {
|
||||
option.selected = true;
|
||||
}
|
||||
logsCategory.appendChild(option);
|
||||
});
|
||||
|
||||
// Activer/désactiver le toggle
|
||||
logsEnabled.checked = !!currentConfig.enabled;
|
||||
|
||||
// Générer les checkboxes pour les types de logs
|
||||
renderLogTypes();
|
||||
|
||||
// Mettre à jour l'aperçu
|
||||
updatePreview();
|
||||
|
||||
// Afficher le bouton supprimer si des salons existent
|
||||
updateDeleteButton();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Erreur chargement config logs:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// Générer les checkboxes des types de logs
|
||||
function renderLogTypes() {
|
||||
logsTypesContainer.innerHTML = '';
|
||||
|
||||
logTypes.forEach(logType => {
|
||||
const isEnabled = currentConfig[`${logType.key}_enabled`];
|
||||
const channelId = currentConfig[`${logType.key}_channel_id`];
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.className = 'log-type-card' + (isEnabled ? ' active' : '');
|
||||
div.innerHTML = `
|
||||
<label class="log-type-checkbox">
|
||||
<input type="checkbox" name="log-type" value="${logType.key}" ${isEnabled ? 'checked' : ''}>
|
||||
<span class="log-type-icon">${logType.name.split(' ')[0]}</span>
|
||||
<div class="log-type-info">
|
||||
<div class="log-type-name">${logType.name.substring(logType.name.indexOf(' ') + 1)}</div>
|
||||
<div class="log-type-desc">${logType.description}</div>
|
||||
</div>
|
||||
${channelId ? `<span class="log-type-status">✅</span>` : ''}
|
||||
</label>
|
||||
`;
|
||||
|
||||
const checkbox = div.querySelector('input[type="checkbox"]');
|
||||
checkbox.addEventListener('change', () => {
|
||||
div.classList.toggle('active', checkbox.checked);
|
||||
updatePreview();
|
||||
});
|
||||
|
||||
logsTypesContainer.appendChild(div);
|
||||
});
|
||||
}
|
||||
|
||||
// Mettre à jour l'aperçu des salons
|
||||
function updatePreview() {
|
||||
const checkedTypes = [...document.querySelectorAll('input[name="log-type"]:checked')]
|
||||
.map(cb => cb.value);
|
||||
|
||||
if (checkedTypes.length === 0 || !logsEnabled.checked) {
|
||||
logsPreviewContainer.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
logsPreviewContainer.style.display = 'block';
|
||||
logsChannelsPreview.innerHTML = '';
|
||||
|
||||
checkedTypes.forEach(key => {
|
||||
const logType = logTypes.find(lt => lt.key === key);
|
||||
if (!logType) return;
|
||||
|
||||
const channelId = currentConfig[`${key}_channel_id`];
|
||||
const div = document.createElement('div');
|
||||
div.className = 'log-channel-item';
|
||||
div.innerHTML = `
|
||||
<span class="log-channel-icon">#</span>
|
||||
<span class="log-channel-name">${logType.channelName}</span>
|
||||
<span class="log-channel-status ${channelId ? 'created' : 'pending'}">
|
||||
${channelId ? '✅ Créé' : '⏳ Sera créé'}
|
||||
</span>
|
||||
`;
|
||||
logsChannelsPreview.appendChild(div);
|
||||
});
|
||||
}
|
||||
|
||||
// Mettre à jour le bouton supprimer
|
||||
function updateDeleteButton() {
|
||||
const hasChannels = logTypes.some(lt => currentConfig[`${lt.key}_channel_id`]);
|
||||
logsDeleteBtn.style.display = hasChannels ? 'inline-flex' : 'none';
|
||||
}
|
||||
|
||||
// Sauvegarder la config
|
||||
logsSaveBtn.addEventListener('click', async () => {
|
||||
const enabledLogs = [...document.querySelectorAll('input[name="log-type"]:checked')]
|
||||
.map(cb => cb.value);
|
||||
|
||||
logsSaveBtn.disabled = true;
|
||||
logsSaveBtn.textContent = '⏳ Sauvegarde...';
|
||||
statusLogsForm.textContent = '';
|
||||
statusLogsForm.className = 'status-message';
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/bot/save-logs-config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
enabled: logsEnabled.checked,
|
||||
categoryId: logsCategory.value || null,
|
||||
enabledLogs
|
||||
})
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (data.success) {
|
||||
statusLogsForm.textContent = '✅ Configuration sauvegardée !';
|
||||
statusLogsForm.className = 'status-message success';
|
||||
|
||||
// Mettre à jour la config locale
|
||||
if (data.categoryId) {
|
||||
currentConfig.category_id = data.categoryId;
|
||||
}
|
||||
if (data.channels) {
|
||||
for (const [key, channelId] of Object.entries(data.channels)) {
|
||||
currentConfig[`${key}_channel_id`] = channelId;
|
||||
if (enabledLogs.includes(key)) {
|
||||
currentConfig[`${key}_enabled`] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rafraîchir l'affichage
|
||||
renderLogTypes();
|
||||
updatePreview();
|
||||
updateDeleteButton();
|
||||
|
||||
// Recharger les catégories
|
||||
await loadLogsConfig();
|
||||
} else {
|
||||
statusLogsForm.textContent = '❌ ' + (data.error || 'Erreur lors de la sauvegarde');
|
||||
statusLogsForm.className = 'status-message error';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Erreur sauvegarde logs:', err);
|
||||
statusLogsForm.textContent = '❌ Erreur de connexion';
|
||||
statusLogsForm.className = 'status-message error';
|
||||
}
|
||||
|
||||
logsSaveBtn.disabled = false;
|
||||
logsSaveBtn.textContent = '💾 Sauvegarder';
|
||||
});
|
||||
|
||||
// Supprimer tous les salons
|
||||
logsDeleteBtn.addEventListener('click', async () => {
|
||||
if (!confirm('⚠️ Êtes-vous sûr de vouloir supprimer tous les salons de logs ? Cette action est irréversible.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
logsDeleteBtn.disabled = true;
|
||||
logsDeleteBtn.textContent = '⏳ Suppression...';
|
||||
statusLogsForm.textContent = '';
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/bot/delete-logs-channels', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ guildId })
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (data.success) {
|
||||
statusLogsForm.textContent = '✅ Tous les salons de logs ont été supprimés.';
|
||||
statusLogsForm.className = 'status-message success';
|
||||
|
||||
// Reset la config locale
|
||||
currentConfig = { enabled: false };
|
||||
logsEnabled.checked = false;
|
||||
|
||||
// Décocher tous les types
|
||||
document.querySelectorAll('input[name="log-type"]').forEach(cb => {
|
||||
cb.checked = false;
|
||||
cb.closest('.log-type-card')?.classList.remove('active');
|
||||
});
|
||||
|
||||
// Rafraîchir
|
||||
renderLogTypes();
|
||||
updatePreview();
|
||||
updateDeleteButton();
|
||||
} else {
|
||||
statusLogsForm.textContent = '❌ ' + (data.error || 'Erreur lors de la suppression');
|
||||
statusLogsForm.className = 'status-message error';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Erreur suppression logs:', err);
|
||||
statusLogsForm.textContent = '❌ Erreur de connexion';
|
||||
statusLogsForm.className = 'status-message error';
|
||||
}
|
||||
|
||||
logsDeleteBtn.disabled = false;
|
||||
logsDeleteBtn.textContent = '🗑️ Supprimer tous les salons';
|
||||
});
|
||||
|
||||
// Events toggle
|
||||
logsEnabled.addEventListener('change', updatePreview);
|
||||
|
||||
// Charger au démarrage
|
||||
window.addEventListener('guildLoaded', loadLogsConfig);
|
||||
if (typeof guildId !== 'undefined' && guildId) {
|
||||
loadLogsConfig();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user