465 lines
24 KiB
PHP
465 lines
24 KiB
PHP
<?php
|
|
// ACTION HANDLING FIRST
|
|
require_once __DIR__ . '/db/config.php';
|
|
require_once __DIR__ . '/includes/lang.php';
|
|
|
|
if (!isset($_SESSION['user_id'])) {
|
|
header('Location: login.php');
|
|
exit;
|
|
}
|
|
|
|
// Permission check for users.php
|
|
if (!has_permission('view', 'users.php')) {
|
|
header('Location: admin.php');
|
|
exit;
|
|
}
|
|
|
|
$manageable_pages = [
|
|
'admin.php' => 'dashboard',
|
|
'pos.php' => 'pos',
|
|
'orders.php' => 'orders',
|
|
'lab.php' => 'lab',
|
|
'customers.php' => 'customers',
|
|
'customer_statement.php' => 'customer_statement',
|
|
'reports.php' => 'reports',
|
|
'items.php' => 'items',
|
|
'branches.php' => 'branches',
|
|
'users.php' => 'users',
|
|
'profile.php' => 'user_profile',
|
|
'company_profile.php' => 'company_profile',
|
|
'order_details.php' => 'order_details',
|
|
'receipt.php' => 'receipt',
|
|
'ratings.php' => 'ratings'
|
|
];
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|
if ($_POST['action'] === 'add_user' && has_permission('add', 'users.php')) {
|
|
$username = $_POST['username'];
|
|
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
|
|
$full_name_en = $_POST['full_name_en'];
|
|
$full_name_ar = $_POST['full_name_ar'];
|
|
$role = $_POST['role'];
|
|
$branch_ids = $_POST['branch_ids'] ?? [];
|
|
$company_id = 1; // Default for now
|
|
|
|
$primary_branch_id = !empty($branch_ids) ? $branch_ids[0] : null;
|
|
|
|
$stmt = db()->prepare("INSERT INTO users (username, password_hash, full_name_en, full_name_ar, role, branch_id, company_id) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
|
$stmt->execute([$username, $password, $full_name_en, $full_name_ar, $role, $primary_branch_id, $company_id]);
|
|
$new_user_id = db()->lastInsertId();
|
|
|
|
// Sync branches
|
|
foreach ($branch_ids as $bid) {
|
|
$stmt = db()->prepare("INSERT INTO user_branches (user_id, branch_id) VALUES (?, ?)");
|
|
$stmt->execute([$new_user_id, $bid]);
|
|
}
|
|
|
|
// Seed default permissions based on role for the new user
|
|
$default_pages = [
|
|
'super_admin' => array_keys($manageable_pages),
|
|
'branch_manager' => ['admin.php', 'pos.php', 'orders.php', 'lab.php', 'customers.php', 'customer_statement.php', 'reports.php', 'items.php', 'branches.php', 'profile.php', 'order_details.php', 'receipt.php'],
|
|
'cashier' => ['admin.php', 'pos.php', 'orders.php', 'lab.php', 'customers.php', 'customer_statement.php', 'profile.php', 'order_details.php', 'receipt.php'],
|
|
'limited_viewer' => ['admin.php', 'profile.php']
|
|
];
|
|
|
|
$pages = $default_pages[$role] ?? [];
|
|
foreach ($pages as $p) {
|
|
$can_add_edit_del = ($role !== 'limited_viewer' ? 1 : 0);
|
|
$stmt = db()->prepare("INSERT INTO user_permissions (user_id, page, can_view, can_add, can_edit, can_delete) VALUES (?, ?, 1, ?, ?, ?)");
|
|
$stmt->execute([$new_user_id, $p, $can_add_edit_del, $can_add_edit_del, $can_add_edit_del]);
|
|
}
|
|
|
|
header('Location: users.php');
|
|
exit;
|
|
}
|
|
|
|
if ($_POST['action'] === 'edit_user' && has_permission('edit', 'users.php')) {
|
|
$id = $_POST['id'];
|
|
$username = $_POST['username'];
|
|
$full_name_en = $_POST['full_name_en'];
|
|
$full_name_ar = $_POST['full_name_ar'];
|
|
$role = $_POST['role'];
|
|
$branch_ids = $_POST['branch_ids'] ?? [];
|
|
|
|
$primary_branch_id = !empty($branch_ids) ? $branch_ids[0] : null;
|
|
|
|
if (!empty($_POST['password'])) {
|
|
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
|
|
$stmt = db()->prepare("UPDATE users SET username = ?, password_hash = ?, full_name_en = ?, full_name_ar = ?, role = ?, branch_id = ? WHERE id = ?");
|
|
$stmt->execute([$username, $password, $full_name_en, $full_name_ar, $role, $primary_branch_id, $id]);
|
|
} else {
|
|
$stmt = db()->prepare("UPDATE users SET username = ?, full_name_en = ?, full_name_ar = ?, role = ?, branch_id = ? WHERE id = ?");
|
|
$stmt->execute([$username, $full_name_en, $full_name_ar, $role, $primary_branch_id, $id]);
|
|
}
|
|
|
|
// Sync branches
|
|
$stmt = db()->prepare("DELETE FROM user_branches WHERE user_id = ?");
|
|
$stmt->execute([$id]);
|
|
foreach ($branch_ids as $bid) {
|
|
$stmt = db()->prepare("INSERT INTO user_branches (user_id, branch_id) VALUES (?, ?)");
|
|
$stmt->execute([$id, $bid]);
|
|
}
|
|
|
|
header('Location: users.php?msg=user_updated');
|
|
exit;
|
|
}
|
|
|
|
if ($_POST['action'] === 'delete_user' && has_permission('delete', 'users.php')) {
|
|
$id = $_POST['id'];
|
|
// Prevent self-deletion
|
|
if ($id == $_SESSION['user_id']) {
|
|
header('Location: users.php?error=cannot_delete_self');
|
|
exit;
|
|
}
|
|
$stmt = db()->prepare("DELETE FROM users WHERE id = ?");
|
|
$stmt->execute([$id]);
|
|
header('Location: users.php?msg=user_deleted');
|
|
exit;
|
|
}
|
|
|
|
if ($_POST['action'] === 'update_permissions' && has_permission('edit', 'users.php')) {
|
|
$target_user_id = $_POST['user_id'];
|
|
$permissions = $_POST['perms'] ?? []; // format: [page][action] = 1
|
|
|
|
// Clear existing permissions for this user
|
|
$stmt = db()->prepare("DELETE FROM user_permissions WHERE user_id = ?");
|
|
$stmt->execute([$target_user_id]);
|
|
|
|
$all_pages_to_save = array_keys($manageable_pages);
|
|
|
|
foreach ($all_pages_to_save as $page) {
|
|
$can_view = isset($permissions[$page]['view']) ? 1 : 0;
|
|
$can_add = isset($permissions[$page]['add']) ? 1 : 0;
|
|
$can_edit = isset($permissions[$page]['edit']) ? 1 : 0;
|
|
$can_delete = isset($permissions[$page]['delete']) ? 1 : 0;
|
|
|
|
if ($can_view || $can_add || $can_edit || $can_delete) {
|
|
$stmt = db()->prepare("INSERT INTO user_permissions (user_id, page, can_view, can_add, can_edit, can_delete) VALUES (?, ?, ?, ?, ?, ?)");
|
|
$stmt->execute([$target_user_id, $page, $can_view, $can_add, $can_edit, $can_delete]);
|
|
}
|
|
}
|
|
|
|
header('Location: users.php?msg=permissions_updated');
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// NOW Include header
|
|
$title = 'users';
|
|
require_once __DIR__ . '/includes/header.php';
|
|
|
|
$users = db()->query("SELECT u.* FROM users u")->fetchAll();
|
|
$branches = db()->query("SELECT * FROM branches")->fetchAll();
|
|
|
|
// Fetch branches for all users in one go for efficiency
|
|
$user_branches_mapping = [];
|
|
$ub_stmt = db()->query("SELECT ub.user_id, b.name_en, b.name_ar FROM user_branches ub JOIN branches b ON ub.branch_id = b.id");
|
|
while ($row = $ub_stmt->fetch()) {
|
|
$user_branches_mapping[$row['user_id']][] = $lang === 'ar' ? $row['name_ar'] : $row['name_en'];
|
|
}
|
|
|
|
// Also need branch IDs for edit modal
|
|
$user_branch_ids_mapping = [];
|
|
$ub_id_stmt = db()->query("SELECT user_id, branch_id FROM user_branches");
|
|
while ($row = $ub_id_stmt->fetch()) {
|
|
$user_branch_ids_mapping[$row['user_id']][] = (int)$row['branch_id'];
|
|
}
|
|
|
|
?>
|
|
|
|
<div class="row">
|
|
<?php if (has_permission('add', 'users.php')): ?>
|
|
<div class="col-md-4">
|
|
<div class="card p-4 border-0 shadow-sm mb-4" style="border-radius: 20px;">
|
|
<h5 class="fw-bold mb-4"><?= __('add_new_user') ?? 'Add New User' ?></h5>
|
|
<form method="POST">
|
|
<input type="hidden" name="action" value="add_user">
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('username') ?></label>
|
|
<input type="text" name="username" class="form-control" required style="border-radius: 12px;">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('password') ?></label>
|
|
<input type="password" name="password" class="form-control" required style="border-radius: 12px;">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('full_name_en') ?></label>
|
|
<input type="text" name="full_name_en" class="form-control" required style="border-radius: 12px;">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('full_name_ar') ?></label>
|
|
<input type="text" name="full_name_ar" class="form-control" style="border-radius: 12px;">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('role') ?></label>
|
|
<select name="role" class="form-select" style="border-radius: 12px;">
|
|
<option value="super_admin">Super Admin</option>
|
|
<option value="branch_manager">Branch Manager</option>
|
|
<option value="cashier" selected>Cashier</option>
|
|
<option value="limited_viewer">Limited Viewer</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('branches') ?? 'Branches' ?></label>
|
|
<div class="p-3 border rounded" style="max-height: 150px; overflow-y: auto; border-radius: 12px !important;">
|
|
<?php foreach($branches as $b): ?>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="branch_ids[]" value="<?= $b['id'] ?>" id="add_b_<?= $b['id'] ?>">
|
|
<label class="form-check-label" for="add_b_<?= $b['id'] ?>">
|
|
<?= $lang === 'ar' ? $b['name_ar'] : $b['name_en'] ?>
|
|
</label>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary w-100 py-3 fw-bold" style="border-radius: 15px;"><?= __('add_user') ?></button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<?php else: ?>
|
|
<div class="col-md-12">
|
|
<?php endif; ?>
|
|
<div class="card p-0 border-0 shadow-sm" style="border-radius: 20px; overflow: hidden;">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th class="ps-4 py-3">#</th>
|
|
<th class="py-3"><?= __('username') ?></th>
|
|
<th class="py-3"><?= __('name') ?></th>
|
|
<th class="py-3"><?= __('role') ?></th>
|
|
<th class="py-3"><?= __('branches') ?? 'Branches' ?></th>
|
|
<th class="pe-4 py-3 text-end"><?= __('actions') ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach($users as $u): ?>
|
|
<tr>
|
|
<td class="ps-4"><?= $u['id'] ?></td>
|
|
<td><?= $u['username'] ?></td>
|
|
<td class="fw-bold"><?= $lang === 'ar' ? ($u['full_name_ar'] ?: $u['full_name_en']) : $u['full_name_en'] ?></td>
|
|
<td>
|
|
<span class="badge bg-soft-info text-info px-3 py-2" style="border-radius: 8px;">
|
|
<?= $u['role'] ?>
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<?php if (isset($user_branches_mapping[$u['id']])): ?>
|
|
<?php foreach ($user_branches_mapping[$u['id']] as $bname): ?>
|
|
<span class="badge bg-light text-dark border me-1"><?= $bname ?></span>
|
|
<?php endforeach; ?>
|
|
<?php else: ?>
|
|
-
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="pe-4 text-end">
|
|
<div class="btn-group">
|
|
<?php if (has_permission('edit', 'users.php')): ?>
|
|
<button class="btn btn-sm btn-outline-primary px-3" onclick="openPermissions(<?= $u['id'] ?>, '<?= htmlspecialchars($u['username']) ?>')" style="border-radius: 8px 0 0 8px;" title="<?= __('permissions') ?>">
|
|
<i class="bi bi-shield-lock"></i>
|
|
</button>
|
|
<button class="btn btn-sm btn-outline-info px-3" onclick="editUser(<?= htmlspecialchars(json_encode($u)) ?>, <?= htmlspecialchars(json_encode($user_branch_ids_mapping[$u['id']] ?? [])) ?>)" style="border-radius: 0;" title="<?= __('edit') ?>">
|
|
<i class="bi bi-pencil-square"></i>
|
|
</button>
|
|
<?php endif; ?>
|
|
<?php if (has_permission('delete', 'users.php')): ?>
|
|
<button class="btn btn-sm btn-outline-danger px-3" onclick="deleteUser(<?= $u['id'] ?>)" style="border-radius: 0 8px 8px 0;" title="<?= __('delete') ?>" <?= $u['id'] == $_SESSION['user_id'] ? 'disabled' : '' ?>>
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edit User Modal -->
|
|
<div class="modal fade" id="editUserModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content" style="border-radius: 20px;">
|
|
<div class="modal-header border-0 p-4 pb-0">
|
|
<h5 class="modal-title fw-bold"><?= __('edit_user') ?? 'Edit User' ?></h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<form method="POST">
|
|
<input type="hidden" name="action" value="edit_user">
|
|
<input type="hidden" name="id" id="editUserId">
|
|
<div class="modal-body p-4">
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('username') ?></label>
|
|
<input type="text" name="username" id="editUsername" class="form-control" required style="border-radius: 12px;">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('password') ?> (<?= __('leave_blank_to_keep_current') ?? 'leave blank to keep current' ?>)</label>
|
|
<input type="password" name="password" class="form-control" style="border-radius: 12px;">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('full_name_en') ?></label>
|
|
<input type="text" name="full_name_en" id="editFullNameEn" class="form-control" required style="border-radius: 12px;">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('full_name_ar') ?></label>
|
|
<input type="text" name="full_name_ar" id="editFullNameAr" class="form-control" style="border-radius: 12px;">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('role') ?></label>
|
|
<select name="role" id="editRole" class="form-select" style="border-radius: 12px;">
|
|
<option value="super_admin">Super Admin</option>
|
|
<option value="branch_manager">Branch Manager</option>
|
|
<option value="cashier">Cashier</option>
|
|
<option value="limited_viewer">Limited Viewer</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold"><?= __('branches') ?? 'Branches' ?></label>
|
|
<div class="p-3 border rounded" style="max-height: 150px; overflow-y: auto; border-radius: 12px !important;">
|
|
<?php foreach($branches as $b): ?>
|
|
<div class="form-check">
|
|
<input class="form-check-input branch-checkbox" type="checkbox" name="branch_ids[]" value="<?= $b['id'] ?>" id="edit_b_<?= $b['id'] ?>">
|
|
<label class="form-check-label" for="edit_b_<?= $b['id'] ?>">
|
|
<?= $lang === 'ar' ? $b['name_ar'] : $b['name_en'] ?>
|
|
</label>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer border-0 p-4 pt-0">
|
|
<button type="button" class="btn btn-light px-4" data-bs-dismiss="modal" style="border-radius: 12px;"><?= __('cancel') ?></button>
|
|
<button type="submit" class="btn btn-primary px-4" style="border-radius: 12px;"><?= __('save_changes') ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Delete Confirm Modal -->
|
|
<form id="deleteForm" method="POST" style="display:none;">
|
|
<input type="hidden" name="action" value="delete_user">
|
|
<input type="hidden" name="id" id="deleteUserId">
|
|
</form>
|
|
|
|
<!-- Permissions Modal -->
|
|
<div class="modal fade" id="permissionsModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content" style="border-radius: 20px;">
|
|
<div class="modal-header border-0 p-4 pb-0">
|
|
<h5 class="modal-title fw-bold"><i class="bi bi-shield-lock me-2"></i> <?= __('user_permissions') ?? 'User Permissions' ?>: <span id="permsUsername"></span></h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<form method="POST">
|
|
<input type="hidden" name="action" value="update_permissions">
|
|
<input type="hidden" name="user_id" id="permsUserId">
|
|
<div class="modal-body p-4">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th><?= __('page') ?></th>
|
|
<th class="text-center"><?= __('view') ?></th>
|
|
<th class="text-center"><?= __('add') ?></th>
|
|
<th class="text-center"><?= __('edit') ?></th>
|
|
<th class="text-center"><?= __('delete') ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="permsTableBody">
|
|
<?php foreach($manageable_pages as $file => $label): ?>
|
|
<tr>
|
|
<td class="fw-bold small"><?= __($label) ?></td>
|
|
<td class="text-center">
|
|
<input class="form-check-input" type="checkbox" name="perms[<?= $file ?>][view]" id="v_<?= str_replace('.', '_', $file) ?>">
|
|
</td>
|
|
<td class="text-center">
|
|
<input class="form-check-input" type="checkbox" name="perms[<?= $file ?>][add]" id="a_<?= str_replace('.', '_', $file) ?>">
|
|
</td>
|
|
<td class="text-center">
|
|
<input class="form-check-input" type="checkbox" name="perms[<?= $file ?>][edit]" id="e_<?= str_replace('.', '_', $file) ?>">
|
|
</td>
|
|
<td class="text-center">
|
|
<input class="form-check-input" type="checkbox" name="perms[<?= $file ?>][delete]" id="d_<?= str_replace('.', '_', $file) ?>">
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer border-0 p-4 pt-0">
|
|
<button type="button" class="btn btn-light px-4" data-bs-dismiss="modal" style="border-radius: 12px;"><?= __('cancel') ?></button>
|
|
<button type="submit" class="btn btn-primary px-4" style="border-radius: 12px;"><?= __('save_changes') ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function openPermissions(userId, username) {
|
|
document.getElementById('permsUserId').value = userId;
|
|
document.getElementById('permsUsername').innerText = username;
|
|
|
|
// Reset all checkboxes
|
|
document.querySelectorAll('#permsTableBody input[type="checkbox"]').forEach(cb => cb.checked = false);
|
|
|
|
// Fetch current permissions via AJAX
|
|
fetch('api/get_user_permissions.php?user_id=' + userId)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data && Array.isArray(data)) {
|
|
data.forEach(p => {
|
|
const pageId = p.page.replace('.', '_');
|
|
const v = document.getElementById('v_' + pageId);
|
|
const a = document.getElementById('a_' + pageId);
|
|
const e = document.getElementById('e_' + pageId);
|
|
const d = document.getElementById('d_' + pageId);
|
|
|
|
if (v && p.can_view == 1) v.checked = true;
|
|
if (a && p.can_add == 1) a.checked = true;
|
|
if (e && p.can_edit == 1) e.checked = true;
|
|
if (d && p.can_delete == 1) d.checked = true;
|
|
});
|
|
}
|
|
const modal = new bootstrap.Modal(document.getElementById('permissionsModal'));
|
|
modal.show();
|
|
})
|
|
.catch(err => {
|
|
console.error('Error fetching permissions:', err);
|
|
alert('Failed to load permissions. Please try again.');
|
|
});
|
|
}
|
|
|
|
function editUser(user, branchIds) {
|
|
document.getElementById('editUserId').value = user.id;
|
|
document.getElementById('editUsername').value = user.username;
|
|
document.getElementById('editFullNameEn').value = user.full_name_en;
|
|
document.getElementById('editFullNameAr').value = user.full_name_ar || '';
|
|
document.getElementById('editRole').value = user.role;
|
|
|
|
// Reset and set checkboxes
|
|
document.querySelectorAll('.branch-checkbox').forEach(cb => {
|
|
cb.checked = branchIds.includes(parseInt(cb.value));
|
|
});
|
|
|
|
const modal = new bootstrap.Modal(document.getElementById('editUserModal'));
|
|
modal.show();
|
|
}
|
|
|
|
function deleteUser(id) {
|
|
if (confirm('<?= __('confirm_delete_user') ?? 'Are you sure you want to delete this user?' ?>')) {
|
|
document.getElementById('deleteUserId').value = id;
|
|
document.getElementById('deleteForm').submit();
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.bg-soft-info { background-color: rgba(13, 202, 240, 0.1); }
|
|
</style>
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|