diff --git a/api_v1_autoroles.php b/api_v1_autoroles.php new file mode 100644 index 0000000..bcee20f --- /dev/null +++ b/api_v1_autoroles.php @@ -0,0 +1,102 @@ +prepare("INSERT INTO channel_autoroles (channel_id, icon, title, role_id) VALUES (?, ?, ?, ?)"); + $stmt->execute([$channel_id, $icon, $title, $role_id]); + } + header('Location: index.php?server_id=' . $server_id . '&channel_id=' . $channel_id); + exit; + } + + if ($action === 'update') { + $id = $_POST['id'] ?? 0; + $channel_id = $_POST['channel_id'] ?? 0; + $server_id = $_POST['server_id'] ?? 0; + $icon = $_POST['icon'] ?? ''; + $title = $_POST['title'] ?? ''; + $role_id = $_POST['role_id'] ?? 0; + + if (Permissions::hasPermission($user_id, $server_id, Permissions::MANAGE_CHANNELS)) { + $stmt = db()->prepare("UPDATE channel_autoroles SET icon = ?, title = ?, role_id = ? WHERE id = ?"); + $stmt->execute([$icon, $title, $role_id, $id]); + } + header('Location: index.php?server_id=' . $server_id . '&channel_id=' . $channel_id); + exit; + } + + if ($action === 'delete') { + $id = $_POST['id'] ?? 0; + $channel_id = $_POST['channel_id'] ?? 0; + $server_id = $_POST['server_id'] ?? 0; + + if (Permissions::hasPermission($user_id, $server_id, Permissions::MANAGE_CHANNELS)) { + $stmt = db()->prepare("DELETE FROM channel_autoroles WHERE id = ?"); + $stmt->execute([$id]); + } + header('Location: index.php?server_id=' . $server_id . '&channel_id=' . $channel_id); + exit; + } + + if ($action === 'toggle') { + // This will be called via AJAX + $role_id = $json['role_id'] ?? 0; + + if (!$role_id) { + echo json_encode(['success' => false, 'error' => 'Invalid role']); + exit; + } + + // Find the server for this role + $stmt = db()->prepare("SELECT server_id FROM roles WHERE id = ?"); + $stmt->execute([$role_id]); + $role = $stmt->fetch(); + + if (!$role) { + echo json_encode(['success' => false, 'error' => 'Role not found']); + exit; + } + + // Check if user is member of server + $stmt = db()->prepare("SELECT 1 FROM server_members WHERE server_id = ? AND user_id = ?"); + $stmt->execute([$role['server_id'], $user_id]); + if (!$stmt->fetch()) { + echo json_encode(['success' => false, 'error' => 'Not a member of this server']); + exit; + } + + // Toggle role + $stmt = db()->prepare("SELECT 1 FROM user_roles WHERE user_id = ? AND role_id = ?"); + $stmt->execute([$user_id, $role_id]); + $has_role = $stmt->fetch(); + + if ($has_role) { + $stmt = db()->prepare("DELETE FROM user_roles WHERE user_id = ? AND role_id = ?"); + $stmt->execute([$user_id, $role_id]); + $added = false; + } else { + $stmt = db()->prepare("INSERT INTO user_roles (user_id, role_id) VALUES (?, ?)"); + $stmt->execute([$user_id, $role_id]); + $added = true; + } + + echo json_encode(['success' => true, 'added' => $added]); + exit; + } +} diff --git a/assets/js/main.js b/assets/js/main.js index 8d0118b..7d28547 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1092,9 +1092,9 @@ document.addEventListener('DOMContentLoaded', () => { const editFilesContainer = document.getElementById('edit-channel-files-container'); const clearChatBtn = document.getElementById('clear-channel-history-btn'); - if (editLimitContainer) editLimitContainer.style.display = (type === 'rules') ? 'none' : 'block'; - if (editFilesContainer) editFilesContainer.style.display = (type === 'rules') ? 'none' : 'block'; - if (clearChatBtn) clearChatBtn.style.display = (type === 'rules') ? 'none' : 'inline-block'; + if (editLimitContainer) editLimitContainer.style.display = (type === 'rules' || type === 'autorole') ? 'none' : 'block'; + if (editFilesContainer) editFilesContainer.style.display = (type === 'rules' || type === 'autorole') ? 'none' : 'block'; + if (clearChatBtn) clearChatBtn.style.display = (type === 'rules' || type === 'autorole') ? 'none' : 'inline-block'; }); // RSS Management @@ -2061,8 +2061,8 @@ document.addEventListener('DOMContentLoaded', () => { } const limitContainer = document.getElementById('add-channel-limit-container'); const filesContainer = document.getElementById('add-channel-files-container'); - if (limitContainer) limitContainer.style.display = (type === 'rules') ? 'none' : 'block'; - if (filesContainer) filesContainer.style.display = (type === 'rules') ? 'none' : 'block'; + if (limitContainer) limitContainer.style.display = (type === 'rules' || type === 'autorole') ? 'none' : 'block'; + if (filesContainer) filesContainer.style.display = (type === 'rules' || type === 'autorole') ? 'none' : 'block'; }); // User Settings - Avatar Search @@ -2277,4 +2277,80 @@ document.addEventListener('DOMContentLoaded', () => { // Initial load of roles for the server loadRoles(); + + // Autorole Toggle + document.addEventListener('click', async (e) => { + const btn = e.target.closest('.autorole-toggle-btn'); + if (!btn) return; + + const roleId = btn.dataset.roleId; + + btn.disabled = true; + + try { + const resp = await fetch('api_v1_autoroles.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ action: 'toggle', role_id: roleId }) + }); + const data = await resp.json(); + if (data.success) { + if (data.added) { + btn.classList.remove('btn-outline-secondary'); + btn.classList.add('btn-primary'); + btn.style.backgroundColor = 'var(--blurple)'; + btn.style.border = 'none'; + } else { + btn.classList.add('btn-outline-secondary'); + btn.classList.remove('btn-primary'); + btn.style.backgroundColor = '#2b2d31'; + btn.style.border = '1px solid #4e5058'; + } + } else { + alert(data.error || 'Failed to toggle role'); + } + } catch (e) { + console.error(e); + } finally { + btn.disabled = false; + } + }); + + // Edit Autorole Modal Population + document.addEventListener('click', (e) => { + const btn = e.target.closest('.edit-autorole-btn'); + if (!btn) return; + + const id = btn.dataset.id; + const icon = btn.dataset.icon; + const title = btn.dataset.title; + const roleId = btn.dataset.roleId; + + document.getElementById('edit-autorole-id').value = id; + document.getElementById('edit-autorole-icon').value = icon; + document.getElementById('edit-autorole-title').value = title; + document.getElementById('edit-autorole-role-id').value = roleId; + }); + + // Universal Emoji Picker Trigger + document.addEventListener('click', (e) => { + const btn = e.target.closest('.open-emoji-picker'); + if (!btn) return; + + const targetId = btn.dataset.target; + const targetInput = document.querySelector(targetId); + + if (typeof showEmojiPicker === 'function') { + showEmojiPicker(btn, (emoji) => { + if (targetInput) { + targetInput.value = emoji; + // Special case for role settings preview + if (targetId === '#edit-role-icon') { + const preview = document.getElementById('selected-role-emoji-preview'); + if (preview) preview.textContent = emoji; + } + } + }); + } + }); }); diff --git a/db/migrations/20260216_autorole_channels.sql b/db/migrations/20260216_autorole_channels.sql new file mode 100644 index 0000000..feee508 --- /dev/null +++ b/db/migrations/20260216_autorole_channels.sql @@ -0,0 +1,11 @@ +-- Add autorole channels support +CREATE TABLE IF NOT EXISTS channel_autoroles ( + id INT AUTO_INCREMENT PRIMARY KEY, + channel_id INT NOT NULL, + icon VARCHAR(50) NOT NULL, + title VARCHAR(255) NOT NULL, + role_id INT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (channel_id) REFERENCES channels(id) ON DELETE CASCADE, + FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE +); diff --git a/debug_reorder.log b/debug_reorder.log index 59e9ff7..68cd156 100644 --- a/debug_reorder.log +++ b/debug_reorder.log @@ -9,3 +9,6 @@ 2026-02-16 00:15:14 - Server: 1 - Orders: [{"id":"11","position":0,"category_id":null},{"id":"12","position":1,"category_id":null},{"id":"10","position":2,"category_id":null},{"id":"1","position":3,"category_id":"10"},{"id":"6","position":4,"category_id":"10"},{"id":"15","position":5,"category_id":"10"},{"id":"2","position":6,"category_id":"10"},{"id":"14","position":7,"category_id":null},{"id":"13","position":8,"category_id":null},{"id":"9","position":9,"category_id":null},{"id":"3","position":10,"category_id":null}] 2026-02-16 00:17:23 - Server: 1 - Orders: [{"id":"11","position":0,"category_id":null},{"id":"12","position":1,"category_id":null},{"id":"10","position":2,"category_id":null},{"id":"1","position":3,"category_id":"10"},{"id":"6","position":4,"category_id":"10"},{"id":"15","position":5,"category_id":"10"},{"id":"2","position":6,"category_id":"10"},{"id":"14","position":7,"category_id":null},{"id":"13","position":8,"category_id":null},{"id":"9","position":9,"category_id":null},{"id":"3","position":10,"category_id":null}] 2026-02-16 00:17:31 - Server: 1 - Orders: [{"id":"11","position":0,"category_id":null},{"id":"12","position":1,"category_id":null},{"id":"10","position":2,"category_id":null},{"id":"1","position":3,"category_id":"10"},{"id":"6","position":4,"category_id":"10"},{"id":"15","position":5,"category_id":"10"},{"id":"2","position":6,"category_id":"10"},{"id":"14","position":7,"category_id":null},{"id":"13","position":8,"category_id":null},{"id":"9","position":9,"category_id":null},{"id":"3","position":10,"category_id":null}] +2026-02-16 03:07:52 - Server: 1 - Orders: [{"id":"11","position":0,"category_id":null},{"id":"16","position":1,"category_id":null},{"id":"12","position":2,"category_id":null},{"id":"10","position":3,"category_id":null},{"id":"1","position":4,"category_id":"10"},{"id":"6","position":5,"category_id":"10"},{"id":"15","position":6,"category_id":"10"},{"id":"2","position":7,"category_id":"10"},{"id":"14","position":8,"category_id":null},{"id":"13","position":9,"category_id":null},{"id":"9","position":10,"category_id":null},{"id":"3","position":11,"category_id":null}] +2026-02-16 03:08:33 - Server: 1 - Orders: [{"id":"11","position":0,"category_id":null},{"id":"17","position":1,"category_id":null},{"id":"12","position":2,"category_id":null},{"id":"10","position":3,"category_id":null},{"id":"1","position":4,"category_id":"10"},{"id":"6","position":5,"category_id":"10"},{"id":"15","position":6,"category_id":"10"},{"id":"2","position":7,"category_id":"10"},{"id":"14","position":8,"category_id":null},{"id":"13","position":9,"category_id":null},{"id":"9","position":10,"category_id":null},{"id":"3","position":11,"category_id":null}] +2026-02-16 03:09:18 - Server: 1 - Orders: [{"id":"11","position":0,"category_id":null},{"id":"17","position":1,"category_id":null},{"id":"12","position":2,"category_id":null},{"id":"10","position":3,"category_id":null},{"id":"1","position":4,"category_id":"10"},{"id":"6","position":5,"category_id":"10"},{"id":"15","position":6,"category_id":"10"},{"id":"2","position":7,"category_id":"10"},{"id":"18","position":8,"category_id":"10"},{"id":"14","position":9,"category_id":null},{"id":"13","position":10,"category_id":null},{"id":"9","position":11,"category_id":null},{"id":"3","position":12,"category_id":null}] diff --git a/index.php b/index.php index 4dddbcf..63a38e2 100644 --- a/index.php +++ b/index.php @@ -146,6 +146,10 @@ if ($is_dm_view) { $stmt = db()->prepare("SELECT * FROM channel_rules WHERE channel_id = ? ORDER BY position ASC"); $stmt->execute([$active_channel_id]); $rules = $stmt->fetchAll(); + } elseif ($channel_type === 'autorole') { + $stmt = db()->prepare("SELECT ca.*, r.name as role_name FROM channel_autoroles ca JOIN roles r ON ca.role_id = r.id WHERE ca.channel_id = ? ORDER BY ca.id ASC"); + $stmt->execute([$active_channel_id]); + $autoroles = $stmt->fetchAll(); } elseif ($channel_type === 'forum') { $filter_status = $_GET['status'] ?? 'all'; $status_where = ""; @@ -379,6 +383,7 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; '; elseif ($c['type'] === 'rules') echo ''; + elseif ($c['type'] === 'autorole') echo ''; elseif ($c['type'] === 'forum') echo ''; elseif ($c['type'] === 'voice') echo ''; else echo ''; @@ -498,6 +503,7 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; } else { if ($active_channel['type'] === 'announcement') echo ''; elseif ($active_channel['type'] === 'rules') echo ''; + elseif ($active_channel['type'] === 'autorole') echo ''; elseif ($active_channel['type'] === 'forum') echo ''; elseif ($active_channel['type'] === 'voice') echo ''; else echo ''; @@ -649,6 +655,62 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; + +
+

🛡️

+

Cliquez sur un bouton pour vous attribuer ou vous retirer un rĂ´le.

+ +
+ prepare("SELECT 1 FROM user_roles WHERE user_id = ? AND role_id = ?"); + $stmtHasRole->execute([$current_user_id, $ar['role_id']]); + $has_role = $stmtHasRole->fetch(); + ?> +
+ + +
+ +
+ + + + + +
+
+ +
+ +
+ + +
+ +
+ +
@@ -1143,6 +1205,7 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; + @@ -1210,6 +1273,93 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
+ + + + + +