diff --git a/api_v1_channel_permissions.php b/api_v1_channel_permissions.php index 4373c26..a6ce976 100644 --- a/api_v1_channel_permissions.php +++ b/api_v1_channel_permissions.php @@ -16,7 +16,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { $server_id = $channel['server_id'] ?? 0; // Ensure @everyone role exists for this server - $stmt = db()->prepare("SELECT id FROM roles WHERE server_id = ? AND (name = '@everyone' OR name = 'Everyone') LIMIT 1"); + $stmt = db()->prepare("SELECT id FROM roles WHERE server_id = ? AND (LOWER(name) = '@everyone' OR LOWER(name) = 'everyone') LIMIT 1"); $stmt->execute([$server_id]); $everyone = $stmt->fetch(); if (!$everyone && $server_id) { @@ -46,18 +46,20 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { } } - if (!$has_everyone && $everyone_role_id) { + if (!$has_everyone && $everyone_role_id > 0) { $stmt = db()->prepare("SELECT name, color FROM roles WHERE id = ?"); $stmt->execute([$everyone_role_id]); $r = $stmt->fetch(); - $permissions[] = [ - 'channel_id' => (int)$channel_id, - 'role_id' => (int)$everyone_role_id, - 'allow_permissions' => 0, - 'deny_permissions' => 0, - 'role_name' => $r['name'], - 'role_color' => $r['color'] - ]; + if ($r) { + array_unshift($permissions, [ + 'channel_id' => (int)$channel_id, + 'role_id' => (int)$everyone_role_id, + 'allow_permissions' => 0, + 'deny_permissions' => 0, + 'role_name' => $r['name'], + 'role_color' => $r['color'] + ]); + } } echo json_encode(['success' => true, 'permissions' => $permissions]); @@ -70,12 +72,22 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $allow = $data['allow'] ?? 0; $deny = $data['deny'] ?? 0; - // Check if user is owner of the server - $stmt = db()->prepare("SELECT s.owner_id FROM servers s JOIN channels c ON s.id = c.server_id WHERE c.id = ?"); + // Check permissions: Owner or MANAGE_CHANNELS or ADMINISTRATOR + require_once 'includes/permissions.php'; + $stmt = db()->prepare("SELECT server_id FROM channels WHERE id = ?"); $stmt->execute([$channel_id]); + $ch = $stmt->fetch(); + $server_id = $ch['server_id'] ?? 0; + + $stmt = db()->prepare("SELECT owner_id FROM servers WHERE id = ?"); + $stmt->execute([$server_id]); $server = $stmt->fetch(); - if ($server && $server['owner_id'] == $user_id) { + $is_owner = ($server && $server['owner_id'] == $user_id); + $can_manage = Permissions::hasPermission($user_id, $server_id, Permissions::MANAGE_CHANNELS) || + Permissions::hasPermission($user_id, $server_id, Permissions::ADMINISTRATOR); + + if ($is_owner || $can_manage) { $stmt = db()->prepare(" INSERT INTO channel_permissions (channel_id, role_id, allow_permissions, deny_permissions) VALUES (?, ?, ?, ?) @@ -93,12 +105,22 @@ if ($_SERVER['REQUEST_METHOD'] === 'DELETE') { $channel_id = $data['channel_id'] ?? 0; $role_id = $data['role_id'] ?? 0; - // Check if user is owner - $stmt = db()->prepare("SELECT s.owner_id FROM servers s JOIN channels c ON s.id = c.server_id WHERE c.id = ?"); + // Check permissions + require_once 'includes/permissions.php'; + $stmt = db()->prepare("SELECT server_id FROM channels WHERE id = ?"); $stmt->execute([$channel_id]); + $ch = $stmt->fetch(); + $server_id = $ch['server_id'] ?? 0; + + $stmt = db()->prepare("SELECT owner_id FROM servers WHERE id = ?"); + $stmt->execute([$server_id]); $server = $stmt->fetch(); - if ($server && $server['owner_id'] == $user_id) { + $is_owner = ($server && $server['owner_id'] == $user_id); + $can_manage = Permissions::hasPermission($user_id, $server_id, Permissions::MANAGE_CHANNELS) || + Permissions::hasPermission($user_id, $server_id, Permissions::ADMINISTRATOR); + + if ($is_owner || $can_manage) { $stmt = db()->prepare("DELETE FROM channel_permissions WHERE channel_id = ? AND role_id = ?"); $stmt->execute([$channel_id, $role_id]); echo json_encode(['success' => true]); diff --git a/assets/js/main.js b/assets/js/main.js index b4b3d00..7c2f329 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -759,8 +759,8 @@ document.addEventListener('DOMContentLoaded', () => { channelPermissionsTabBtn?.addEventListener('click', async () => { const channelId = document.getElementById('edit-channel-id').value; currentSelectedOverrideRole = null; - channelPermissionsSettings.style.display = 'none'; - noRoleSelectedView.style.display = 'flex'; + channelPermissionsSettings.classList.add('d-none'); + noRoleSelectedView.classList.remove('d-none'); await loadChannelPermissions(channelId); await loadRolesForPermissions(channelId); }); @@ -776,37 +776,68 @@ document.addEventListener('DOMContentLoaded', () => { } async function loadRolesForPermissions(channelId) { - addPermRoleList.innerHTML = ''; - const resp = await fetch(`api_v1_roles.php?server_id=${activeServerId}`); - const data = await resp.json(); - if (data.success) { - // Filter out roles already in overrides - const existingRoleIds = channelPermissionsData.map(p => parseInt(p.role_id)); - const availableRoles = data.roles.filter(role => !existingRoleIds.includes(parseInt(role.id))); + if (!addPermRoleList) return; + addPermRoleList.innerHTML = '
  • Loading roles...
  • '; + + try { + const resp = await fetch(`api_v1_roles.php?server_id=${activeServerId}`); + const data = await resp.json(); + + if (data.success) { + addPermRoleList.innerHTML = ''; + + // Filter out roles already in overrides + const existingRoleIds = channelPermissionsData.map(p => parseInt(p.role_id)); + const availableRoles = data.roles.filter(role => !existingRoleIds.includes(parseInt(role.id))); + + if (availableRoles.length === 0) { + addPermRoleList.innerHTML = '
  • No more roles to add
  • '; + if (window.canManageServer) { + const divider = document.createElement('li'); + divider.innerHTML = ''; + addPermRoleList.appendChild(divider); + const createLink = document.createElement('li'); + createLink.innerHTML = ' Create roles in Server Settings'; + addPermRoleList.appendChild(createLink); + } + return; + } - if (availableRoles.length === 0) { - addPermRoleList.innerHTML = '
  • No more roles to add
  • '; - return; + // Add Roles section + const header = document.createElement('li'); + header.innerHTML = ''; + addPermRoleList.appendChild(header); + + availableRoles.forEach(role => { + const li = document.createElement('li'); + li.innerHTML = ` +
    + ${role.name} +
    `; + li.onclick = async (e) => { + e.preventDefault(); + const postResp = await fetch('api_v1_channel_permissions.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ channel_id: channelId, role_id: role.id, allow: 0, deny: 0 }) + }); + const postData = await postResp.json(); + if (postData.success) { + await loadChannelPermissions(channelId); + await loadRolesForPermissions(channelId); + selectOverrideRole(role.id, role.name); + } else { + alert("Error adding permission: " + (postData.error || "Unknown error")); + } + }; + addPermRoleList.appendChild(li); + }); + } else { + addPermRoleList.innerHTML = `
  • Error: ${data.error || 'Failed to load'}
  • `; } - - availableRoles.forEach(role => { - const li = document.createElement('li'); - li.innerHTML = ` -
    - ${role.name} -
    `; - li.onclick = async (e) => { - e.preventDefault(); - await fetch('api_v1_channel_permissions.php', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ channel_id: channelId, role_id: role.id, allow: 0, deny: 0 }) - }); - await loadChannelPermissions(channelId); - selectOverrideRole(role.id, role.name); - }; - addPermRoleList.appendChild(li); - }); + } catch (err) { + addPermRoleList.innerHTML = '
  • Network error
  • '; + console.error(err); } } @@ -819,11 +850,13 @@ document.addEventListener('DOMContentLoaded', () => { // Sort: @everyone always at top, then by name const sortedData = [...channelPermissionsData].sort((a, b) => { - const isAEveryone = a.role_name.toLowerCase().includes('everyone'); - const isBEveryone = b.role_name.toLowerCase().includes('everyone'); + const nameA = (a.role_name || '').toLowerCase(); + const nameB = (b.role_name || '').toLowerCase(); + const isAEveryone = nameA.includes('everyone'); + const isBEveryone = nameB.includes('everyone'); if (isAEveryone && !isBEveryone) return -1; if (!isAEveryone && isBEveryone) return 1; - return a.role_name.localeCompare(b.role_name); + return nameA.localeCompare(nameB); }); sortedData.forEach(p => { @@ -831,10 +864,10 @@ document.addEventListener('DOMContentLoaded', () => { item.className = `list-group-item list-group-item-action bg-transparent text-white border-0 mb-1 p-2 small d-flex align-items-center ${currentSelectedOverrideRole == p.role_id ? 'active' : ''}`; item.style.cursor = 'pointer'; item.innerHTML = ` -
    - ${p.role_name} +
    + ${p.role_name || 'Unknown Role'} `; - item.onclick = () => selectOverrideRole(p.role_id, p.role_name); + item.onclick = () => selectOverrideRole(p.role_id, p.role_name || 'Unknown Role'); channelPermissionsRolesList.appendChild(item); }); } @@ -847,8 +880,8 @@ document.addEventListener('DOMContentLoaded', () => { renderRoleOverridesList(channelId); selectedPermRoleName.textContent = roleName; - noRoleSelectedView.style.display = 'none'; - channelPermissionsSettings.style.display = 'block'; + noRoleSelectedView.classList.add('d-none'); + channelPermissionsSettings.classList.remove('d-none'); // Load existing permissions for this role const p = channelPermissionsData.find(perm => perm.role_id == roleId) || { allow_permissions: 0, deny_permissions: 0 }; @@ -881,8 +914,8 @@ document.addEventListener('DOMContentLoaded', () => { }); currentSelectedOverrideRole = null; - channelPermissionsSettings.style.display = 'none'; - noRoleSelectedView.style.display = 'flex'; + channelPermissionsSettings.classList.add('d-none'); + noRoleSelectedView.classList.remove('d-none'); loadChannelPermissions(channelId); }); @@ -951,6 +984,13 @@ document.addEventListener('DOMContentLoaded', () => { modal.querySelector('#edit-channel-name').value = channelName; modal.querySelector('#header-channel-name').textContent = channelName; modal.querySelector('#edit-channel-type').value = channelType; + + // Force switch to Overview tab + const overviewTabBtn = modal.querySelector('[data-bs-target="#edit-channel-general"]'); + if (overviewTabBtn) { + bootstrap.Tab.getOrCreateInstance(overviewTabBtn).show(); + } + modal.querySelector('#edit-channel-files').checked = btn.dataset.files == '1'; modal.querySelector('#edit-channel-limit').value = btn.dataset.limit || ''; modal.querySelector('#edit-channel-status').value = btn.dataset.status || ''; diff --git a/assets/pasted-20260215-214239-79c3300e.png b/assets/pasted-20260215-214239-79c3300e.png new file mode 100644 index 0000000..252efa2 Binary files /dev/null and b/assets/pasted-20260215-214239-79c3300e.png differ diff --git a/index.php b/index.php index 5f3b5ab..7d67ea3 100644 --- a/index.php +++ b/index.php @@ -1270,14 +1270,13 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
    Roles / Members + + +
    @@ -1286,7 +1285,7 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
    -