🚀 مُصادَق: تحديث برمجي جديد 2026-05-03 02:51
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = `<div class="text-red-400 p-8 glass-panel rounded-3xl text-center">عذراً، ليس لديك صلاحية للوصول إلى هذه الصفحة.</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await API.get('/users');
|
||||
const users = res.data;
|
||||
@@ -187,8 +196,14 @@
|
||||
html += `<div class="col-span-full text-center py-12 text-slate-500 glass-panel rounded-3xl">لا يوجد مستخدمين مسجلين.</div>`;
|
||||
} 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 += `
|
||||
<div class="glass-panel p-6 rounded-3xl flex flex-col h-full border-t-4 border-t-primary">
|
||||
<div class="flex items-center gap-4 mb-4">
|
||||
@@ -218,11 +233,20 @@
|
||||
html += `</div>`;
|
||||
contentDiv.innerHTML = html;
|
||||
} catch(err) {
|
||||
contentDiv.innerHTML = `<div class="text-red-400">خطأ في جلب المستخدمين</div>`;
|
||||
contentDiv.innerHTML = `<div class="text-red-400 p-8 glass-panel rounded-3xl">خطأ في جلب المستخدمين: ${err.error?.message_ar || err.message}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function showAddUserModal() {
|
||||
const currentRole = localStorage.getItem('user_role');
|
||||
let optionsHtml = `
|
||||
<option value="accountant">محاسب</option>
|
||||
<option value="employee">موظف</option>
|
||||
`;
|
||||
if (currentRole === 'super_admin') {
|
||||
optionsHtml += `<option value="admin">مدير نظام</option>`;
|
||||
}
|
||||
|
||||
const modals = document.getElementById('modals');
|
||||
modals.innerHTML = `
|
||||
<div class="fixed inset-0 bg-black/60 backdrop-blur-sm z-[100] flex items-center justify-center p-4 overflow-y-auto" id="user-modal">
|
||||
@@ -233,9 +257,7 @@
|
||||
<input type="email" id="usr-email" class="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-primary outline-none" placeholder="البريد الإلكتروني" required>
|
||||
<input type="password" id="usr-password" class="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-primary outline-none" placeholder="كلمة المرور" required>
|
||||
<select id="usr-role" class="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-primary outline-none" required>
|
||||
<option value="accountant">محاسب</option>
|
||||
<option value="admin">مدير</option>
|
||||
<option value="employee">موظف</option>
|
||||
${optionsHtml}
|
||||
</select>
|
||||
|
||||
<div class="flex gap-3 mt-6 pt-4 border-t border-white/10">
|
||||
@@ -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') {
|
||||
|
||||
Reference in New Issue
Block a user