diff --git a/api_v1_accept_rules.php b/api_v1_accept_rules.php new file mode 100644 index 0000000..fd704af --- /dev/null +++ b/api_v1_accept_rules.php @@ -0,0 +1,59 @@ + false, 'error' => 'ID de canal manquant']); + exit; + } + + // Fetch channel details to get rules_role_id + $stmt = db()->prepare("SELECT * FROM channels WHERE id = ? AND type = 'rules'"); + $stmt->execute([$channel_id]); + $channel = $stmt->fetch(); + + if (!$channel) { + echo json_encode(['success' => false, 'error' => 'Canal de règles introuvable']); + exit; + } + + if (empty($channel['rules_role_id'])) { + echo json_encode(['success' => false, 'error' => 'Aucun rôle n\'est configuré pour ce canal']); + exit; + } + + $role_id = $channel['rules_role_id']; + + try { + db()->beginTransaction(); + + // 1. Record acceptance + $stmtAcc = db()->prepare("INSERT IGNORE INTO rule_acceptances (user_id, channel_id) VALUES (?, ?)"); + $stmtAcc->execute([$user_id, $channel_id]); + + // 2. Assign role + // Check if user already has this role + $stmtRoleCheck = db()->prepare("SELECT 1 FROM user_roles WHERE user_id = ? AND role_id = ?"); + $stmtRoleCheck->execute([$user_id, $role_id]); + + if (!$stmtRoleCheck->fetch()) { + $stmtRole = db()->prepare("INSERT INTO user_roles (user_id, role_id) VALUES (?, ?)"); + $stmtRole->execute([$user_id, $role_id]); + } + + db()->commit(); + echo json_encode(['success' => true]); + } catch (Exception $e) { + db()->rollBack(); + echo json_encode(['success' => false, 'error' => 'Erreur lors de l\'attribution du rôle : ' . $e->getMessage()]); + } + exit; +} + +echo json_encode(['success' => false, 'error' => 'Méthode non autorisée']); diff --git a/api_v1_channels.php b/api_v1_channels.php index 43d7054..dfb854c 100644 --- a/api_v1_channels.php +++ b/api_v1_channels.php @@ -56,6 +56,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $icon = $_POST['icon'] ?? null; if ($icon === '') $icon = null; $category_id = !empty($_POST['category_id']) ? (int)$_POST['category_id'] : null; + $rules_role_id = !empty($_POST['rules_role_id']) ? (int)$_POST['rules_role_id'] : null; // Check if user has permission to manage channels $stmt = db()->prepare("SELECT server_id FROM channels WHERE id = ?"); @@ -67,8 +68,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { // Allow spaces, accents and mixed case $name = trim($name); // Explicitly exclude position from update to prevent jumping to bottom - $stmt = db()->prepare("UPDATE channels SET name = ?, type = ?, status = ?, allow_file_sharing = ?, message_limit = ?, icon = ?, category_id = ? WHERE id = ?"); - $stmt->execute([$name, $type, $status, $allow_file_sharing, $message_limit, $icon, $category_id, $channel_id]); + $stmt = db()->prepare("UPDATE channels SET name = ?, type = ?, status = ?, allow_file_sharing = ?, message_limit = ?, icon = ?, category_id = ?, rules_role_id = ? WHERE id = ?"); + $stmt->execute([$name, $type, $status, $allow_file_sharing, $message_limit, $icon, $category_id, $rules_role_id, $channel_id]); } header('Location: index.php?server_id=' . $server_id . '&channel_id=' . $channel_id); exit; @@ -103,6 +104,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $icon = $_POST['icon'] ?? null; if ($icon === '') $icon = null; $category_id = !empty($_POST['category_id']) ? (int)$_POST['category_id'] : null; + $rules_role_id = !empty($_POST['rules_role_id']) ? (int)$_POST['rules_role_id'] : null; // Get next position $stmtPos = db()->prepare("SELECT MAX(position) as max_pos FROM channels WHERE server_id = ?"); @@ -110,8 +112,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $maxPos = $stmtPos->fetch(); $nextPos = ($maxPos['max_pos'] ?? -1) + 1; - $stmt = db()->prepare("INSERT INTO channels (server_id, name, type, allow_file_sharing, message_limit, icon, category_id, position) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); - $stmt->execute([$server_id, $name, $type, $allow_file_sharing, $message_limit, $icon, $category_id, $nextPos]); + $stmt = db()->prepare("INSERT INTO channels (server_id, name, type, allow_file_sharing, message_limit, icon, category_id, position, rules_role_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$server_id, $name, $type, $allow_file_sharing, $message_limit, $icon, $category_id, $nextPos, $rules_role_id]); $channel_id = db()->lastInsertId(); header('Location: index.php?server_id=' . $server_id . '&channel_id=' . $channel_id); diff --git a/api_v1_withdraw_rules.php b/api_v1_withdraw_rules.php new file mode 100644 index 0000000..aef376d --- /dev/null +++ b/api_v1_withdraw_rules.php @@ -0,0 +1,50 @@ + false, 'error' => 'ID de canal manquant']); + exit; + } + + // Fetch channel details to get rules_role_id + $stmt = db()->prepare("SELECT * FROM channels WHERE id = ? AND type = 'rules'"); + $stmt->execute([$channel_id]); + $channel = $stmt->fetch(); + + if (!$channel) { + echo json_encode(['success' => false, 'error' => 'Canal de règles introuvable']); + exit; + } + + $role_id = $channel['rules_role_id']; + + try { + db()->beginTransaction(); + + // 1. Remove acceptance record + $stmtAcc = db()->prepare("DELETE FROM rule_acceptances WHERE user_id = ? AND channel_id = ?"); + $stmtAcc->execute([$user_id, $channel_id]); + + // 2. Remove role if it was configured + if ($role_id) { + $stmtRole = db()->prepare("DELETE FROM user_roles WHERE user_id = ? AND role_id = ?"); + $stmtRole->execute([$user_id, $role_id]); + } + + db()->commit(); + echo json_encode(['success' => true]); + } catch (Exception $e) { + db()->rollBack(); + echo json_encode(['success' => false, 'error' => 'Erreur lors du retrait : ' . $e->getMessage()]); + } + exit; +} + +echo json_encode(['success' => false, 'error' => 'Méthode non autorisée']); diff --git a/assets/js/main.js b/assets/js/main.js index a80faf1..3f261c9 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1023,9 +1023,16 @@ document.addEventListener('DOMContentLoaded', () => { modal.querySelector('#edit-channel-limit').value = btn.dataset.limit || ''; modal.querySelector('#edit-channel-status').value = btn.dataset.status || ''; modal.querySelector('#edit-channel-icon').value = btn.dataset.icon || ''; + modal.querySelector('#edit-channel-rules-role').value = btn.dataset.rulesRole || ''; modal.querySelector('#edit-channel-category-id').value = btn.dataset.category || ''; modal.querySelector('#delete-channel-id').value = channelId; + // Toggle rules role visibility + const rulesRoleContainer = document.getElementById('edit-channel-rules-role-container'); + if (rulesRoleContainer) { + rulesRoleContainer.style.display = (channelType === 'rules') ? 'block' : 'none'; + } + // Reset delete zone document.getElementById('delete-confirm-zone').style.display = 'none'; @@ -1950,18 +1957,94 @@ document.addEventListener('DOMContentLoaded', () => { } }); + // Rules Acceptance + document.getElementById('accept-rules-btn')?.addEventListener('click', async () => { + const btn = document.getElementById('accept-rules-btn'); + btn.disabled = true; + btn.innerHTML = ' Traitement...'; + + try { + const resp = await fetch('api_v1_accept_rules.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ channel_id: window.activeChannelId }) + }); + const data = await resp.json(); + if (data.success) { + const container = document.getElementById('rules-acceptance-container'); + container.innerHTML = '
Vous avez accepté les règles.
'; + // Reload roles in members list if possible, or just reload page + setTimeout(() => location.reload(), 1500); + } else { + alert(data.error || 'Erreur lors de l\'acceptation'); + btn.disabled = false; + btn.innerHTML = ' J\'accepte les règles'; + } + } catch (e) { + console.error(e); + btn.disabled = false; + btn.innerHTML = ' J\'accepte les règles'; + } + }); + + document.getElementById('withdraw-rules-btn')?.addEventListener('click', async () => { + if (!confirm('Êtes-vous sûr de vouloir retirer votre acceptation des règles ? Vous perdrez le rôle associé.')) return; + + const btn = document.getElementById('withdraw-rules-btn'); + btn.disabled = true; + btn.innerHTML = ' Traitement...'; + + try { + const resp = await fetch('api_v1_withdraw_rules.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ channel_id: window.activeChannelId }) + }); + const data = await resp.json(); + if (data.success) { + location.reload(); + } else { + alert(data.error || 'Erreur lors du retrait'); + btn.disabled = false; + btn.innerHTML = ' Retirer mon acceptation'; + } + } catch (e) { + console.error(e); + btn.disabled = false; + btn.innerHTML = ' Retirer mon acceptation'; + } + }); + // Channel Selection Type const addChannelBtns = document.querySelectorAll('.add-channel-btn'); addChannelBtns.forEach(btn => { btn.addEventListener('click', () => { const type = btn.dataset.type; - const select = document.getElementById('channel-type-select'); + const select = document.getElementById('add-channel-type'); // Corrected ID from index.php if (select) { - select.value = type === 'voice' ? 'voice' : 'chat'; + select.value = type === 'voice' ? 'voice' : (type || 'chat'); + // Trigger change to update visibility + select.dispatchEvent(new Event('change')); } }); }); + const addChannelTypeSelect = document.getElementById('add-channel-type'); + addChannelTypeSelect?.addEventListener('change', (e) => { + const container = document.getElementById('add-channel-rules-role-container'); + if (container) { + container.style.display = (e.target.value === 'rules') ? 'block' : 'none'; + } + }); + + const editChannelTypeSelect = document.getElementById('edit-channel-type'); + editChannelTypeSelect?.addEventListener('change', (e) => { + const container = document.getElementById('edit-channel-rules-role-container'); + if (container) { + container.style.display = (e.target.value === 'rules') ? 'block' : 'none'; + } + }); + // User Settings - Avatar Search const avatarSearchBtn = document.getElementById('search-avatar-btn'); const avatarSearchQuery = document.getElementById('avatar-search-query'); diff --git a/db/migrations/20260216_rules_acceptance.sql b/db/migrations/20260216_rules_acceptance.sql new file mode 100644 index 0000000..8979a5f --- /dev/null +++ b/db/migrations/20260216_rules_acceptance.sql @@ -0,0 +1,12 @@ +-- Add rules_role_id to channels and create rule_acceptances table +ALTER TABLE channels ADD COLUMN rules_role_id INT NULL; + +CREATE TABLE IF NOT EXISTS rule_acceptances ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT NOT NULL, + channel_id INT NOT NULL, + accepted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE KEY user_channel (user_id, channel_id), + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, + FOREIGN KEY (channel_id) REFERENCES channels(id) ON DELETE CASCADE +); diff --git a/debug_reorder.log b/debug_reorder.log index b86d5af..59e9ff7 100644 --- a/debug_reorder.log +++ b/debug_reorder.log @@ -6,3 +6,6 @@ 2026-02-15 23:39:45 - 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":"2","position":5,"category_id":"10"},{"id":"9","position":6,"category_id":null},{"id":"3","position":7,"category_id":null}] 2026-02-15 23:40:11 - 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":"2","position":5,"category_id":"10"},{"id":"13","position":6,"category_id":null},{"id":"9","position":7,"category_id":null},{"id":"3","position":8,"category_id":null}] 2026-02-15 23:40:20 - 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":"2","position":5,"category_id":"10"},{"id":"14","position":6,"category_id":null},{"id":"13","position":7,"category_id":null},{"id":"9","position":8,"category_id":null},{"id":"3","position":9,"category_id":null}] +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}] diff --git a/index.php b/index.php index e87abea..5d29f85 100644 --- a/index.php +++ b/index.php @@ -201,6 +201,11 @@ if ($is_dm_view) { "); $stmt->execute([$active_server_id, $active_server_id, $active_server_id, $active_server_id]); $members = $stmt->fetchAll(); + + // Fetch all server roles + $stmt = db()->prepare("SELECT * FROM roles WHERE server_id = ? ORDER BY position DESC"); + $stmt->execute([$active_server_id]); + $server_roles = $stmt->fetchAll(); } // SEO & Env tags @@ -349,6 +354,7 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; data-limit="0" data-status="" data-icon="" + data-rules-role="" data-category=""> @@ -390,6 +396,7 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; data-limit="" data-status="" data-icon="" + data-rules-role="" data-category=""> @@ -425,6 +432,7 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; data-limit="0" data-status="" data-icon="" + data-rules-role="" data-category="" data-theme=""> @@ -608,6 +616,31 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; + + + prepare("SELECT 1 FROM rule_acceptances WHERE user_id = ? AND channel_id = ?"); + $stmtAcc->execute([$current_user_id, $active_channel_id]); + $has_accepted = $stmtAcc->fetch(); + ?> +
+ +
+ Vous avez accepté les règles. +
+
+ +
+ +

Veuillez accepter les règles pour obtenir l'accès complet.

+ + +
+
@@ -1138,6 +1171,15 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
+
@@ -1243,6 +1285,15 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
+ diff --git a/requests.log b/requests.log index fde3b26..8b37c7f 100644 --- a/requests.log +++ b/requests.log @@ -61,3 +61,36 @@ 2026-02-15 23:59:43 - GET /?fl_project=38443 - POST: [] 2026-02-16 00:02:15 - GET /index.php?server_id=1&channel_id=11 - POST: [] 2026-02-16 00:02:20 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:06:51 - GET /?fl_project=38443 - POST: [] +2026-02-16 00:11:43 - GET /?fl_project=38443 - POST: [] +2026-02-16 00:13:38 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:13:47 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:13:53 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:14:45 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:15:11 - GET /index.php?server_id=1&channel_id=15 - POST: [] +2026-02-16 00:15:42 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:15:56 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:16:00 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:16:00 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:17:19 - GET /index.php?server_id=1&channel_id=15 - POST: [] +2026-02-16 00:17:27 - GET /index.php?server_id=1&channel_id=15 - POST: [] +2026-02-16 00:17:35 - GET /index.php?server_id=1&channel_id=6 - POST: [] +2026-02-16 00:17:46 - GET /index.php?server_id=1&channel_id=15 - POST: [] +2026-02-16 00:17:58 - GET /index.php?server_id=1&channel_id=6 - POST: [] +2026-02-16 00:18:04 - GET /index.php?server_id=1&channel_id=15 - POST: [] +2026-02-16 00:18:12 - GET /index.php?server_id=1&channel_id=6 - POST: [] +2026-02-16 00:18:15 - GET /index.php?server_id=1&channel_id=1 - POST: [] +2026-02-16 00:18:17 - GET /index.php?server_id=1&channel_id=15 - POST: [] +2026-02-16 00:18:19 - GET /index.php?server_id=1&channel_id=2 - POST: [] +2026-02-16 00:18:25 - GET /index.php?server_id=1&channel_id=1 - POST: [] +2026-02-16 00:18:27 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:19:28 - GET /?fl_project=38443 - POST: [] +2026-02-16 00:23:03 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:23:08 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:23:14 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:23:19 - GET /index.php?server_id=1&channel_id=11 - POST: [] +2026-02-16 00:24:37 - GET /index.php?server_id=1&channel_id=1 - POST: [] +2026-02-16 00:24:58 - GET /index.php?server_id=1&channel_id=1 - POST: [] +2026-02-16 00:25:16 - GET /index.php?server_id=1&channel_id=6 - POST: [] +2026-02-16 00:25:18 - GET /index.php?server_id=1&channel_id=15 - POST: [] +2026-02-16 00:25:27 - GET /index.php?server_id=1&channel_id=2 - POST: []