From 392f6dbd9ba409cf61eee0ab69ccfaed88e4f30a Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sun, 3 May 2026 02:51:50 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20=D9=85=D9=8F=D8=B5=D8=A7=D8=AF?= =?UTF-8?q?=D9=8E=D9=82:=20=D8=AA=D8=AD=D8=AF=D9=8A=D8=AB=20=D8=A8=D8=B1?= =?UTF-8?q?=D9=85=D8=AC=D9=8A=20=D8=AC=D8=AF=D9=8A=D8=AF=202026-05-03=2002?= =?UTF-8?q?:51?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Modules/Users/UsersController.php | 25 +++++++++++++++ app/Services/FileStorageService.php | 3 +- public/shell.php | 44 +++++++++++++++++++++++---- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/app/Modules/Users/UsersController.php b/app/Modules/Users/UsersController.php index ea1756a..afeb199 100644 --- a/app/Modules/Users/UsersController.php +++ b/app/Modules/Users/UsersController.php @@ -13,6 +13,12 @@ final class UsersController public function list(Request $request): void { + $currentUserRole = $request->user->role ?? 'viewer'; + if (!in_array($currentUserRole, ['super_admin', 'admin'])) { + Response::error('ليس لديك صلاحية لعرض المستخدمين', 'FORBIDDEN', 403); + return; + } + try { $tenantId = $request->tenantId; $db = Database::getInstance(); @@ -31,11 +37,30 @@ final class UsersController public function create(Request $request): void { + $currentUserRole = $request->user->role ?? 'viewer'; + if (!in_array($currentUserRole, ['super_admin', 'admin'])) { + Response::error('ليس لديك صلاحية لإضافة مستخدمين', 'FORBIDDEN', 403); + return; + } + $name = $request->input('name'); $email = $request->input('email'); $password = $request->input('password'); $role = $request->input('role', 'accountant'); + // Admin can only create accountants and employees. Only super_admin can create admins. + if ($currentUserRole === 'admin' && in_array($role, ['admin', 'super_admin'])) { + Response::error('لا تملك الصلاحية لإضافة مدراء', 'FORBIDDEN', 403); + return; + } + + // Validate valid roles + $validRoles = ['super_admin', 'admin', 'accountant', 'employee', 'viewer']; + if (!in_array($role, $validRoles)) { + Response::error('صلاحية غير صالحة', 'VALIDATION_ERROR', 422); + return; + } + if (!$name || !$email || !$password) { Response::error('Name, email, and password are required', 'VALIDATION_ERROR', 422); return; diff --git a/app/Services/FileStorageService.php b/app/Services/FileStorageService.php index 877fca7..15823a5 100644 --- a/app/Services/FileStorageService.php +++ b/app/Services/FileStorageService.php @@ -12,7 +12,8 @@ final class FileStorageService public function __construct() { - $this->storagePath = $_ENV['STORAGE_PATH'] ?? dirname(__DIR__, 2) . '/storage'; + // Use dynamic path to avoid issues if Mac .env is deployed to Linux server + $this->storagePath = dirname(__DIR__, 2) . '/storage'; } public function store(array $file, string $tenantId, string $companyId): string diff --git a/public/shell.php b/public/shell.php index 5e63903..472b321 100644 --- a/public/shell.php +++ b/public/shell.php @@ -150,6 +150,7 @@ function logout() { localStorage.removeItem('access_token'); + localStorage.removeItem('user_role'); API.accessToken = null; initApp(); } @@ -170,6 +171,14 @@ // ── Users View ─────────────────────────────────────────── async function renderUsers() { document.getElementById('page-title').textContent = 'إدارة المستخدمين'; + + // Check RBAC + const role = localStorage.getItem('user_role'); + if (role !== 'super_admin' && role !== 'admin') { + contentDiv.innerHTML = `
عذراً، ليس لديك صلاحية للوصول إلى هذه الصفحة.
`; + return; + } + try { const res = await API.get('/users'); const users = res.data; @@ -187,8 +196,14 @@ html += `
لا يوجد مستخدمين مسجلين.
`; } else { users.forEach(user => { - const roleColor = user.role === 'admin' ? 'text-primary' : (user.role === 'manager' ? 'text-blue-400' : 'text-slate-400'); - const roleLabel = user.role === 'admin' ? 'سوبر أدمن' : (user.role === 'manager' ? 'مدير' : 'محاسب'); + let roleColor = 'text-slate-400'; + let roleLabel = 'مستخدم'; + + if (user.role === 'super_admin') { roleColor = 'text-primary'; roleLabel = 'سوبر أدمن'; } + else if (user.role === 'admin') { roleColor = 'text-blue-400'; roleLabel = 'مدير النظام'; } + else if (user.role === 'accountant') { roleColor = 'text-purple-400'; roleLabel = 'محاسب'; } + else if (user.role === 'employee') { roleColor = 'text-orange-400'; roleLabel = 'موظف'; } + html += `
@@ -218,11 +233,20 @@ html += `
`; contentDiv.innerHTML = html; } catch(err) { - contentDiv.innerHTML = `
خطأ في جلب المستخدمين
`; + contentDiv.innerHTML = `
خطأ في جلب المستخدمين: ${err.error?.message_ar || err.message}
`; } } function showAddUserModal() { + const currentRole = localStorage.getItem('user_role'); + let optionsHtml = ` + + + `; + if (currentRole === 'super_admin') { + optionsHtml += ``; + } + const modals = document.getElementById('modals'); modals.innerHTML = `
@@ -233,9 +257,7 @@
@@ -301,6 +323,7 @@ const password = document.getElementById('login-password').value; const res = await API.post('/auth/login', { email, password }); localStorage.setItem('access_token', res.data.access_token); + localStorage.setItem('user_role', res.data.user.role); API.accessToken = res.data.access_token; initApp(); } catch (err) { @@ -677,6 +700,15 @@ document.getElementById('sidebar').classList.add('flex'); document.getElementById('header').classList.add('flex'); + // Hide Users menu if not admin or super_admin + const role = localStorage.getItem('user_role'); + const usersNav = document.getElementById('nav-users'); + if (role !== 'super_admin' && role !== 'admin') { + if (usersNav) usersNav.style.display = 'none'; + } else { + if (usersNav) usersNav.style.display = 'flex'; + } + // AI Chat Listener document.getElementById('ai-query').onkeydown = async (e) => { if (e.key === 'Enter') {