306 lines
16 KiB
PHP
306 lines
16 KiB
PHP
<?php
|
|
// admin_users.php
|
|
require_once __DIR__ . '/includes/app.php';
|
|
require_once __DIR__ . '/includes/auth.php';
|
|
|
|
require_permission('users', 'view');
|
|
|
|
$current_u = get_logged_in_user();
|
|
|
|
$action = $_GET['action'] ?? 'list';
|
|
$id = (int)($_GET['id'] ?? 0);
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$post_action = $_POST['action'] ?? $action;
|
|
$post_id = (int)($_POST['id'] ?? $id);
|
|
|
|
if ($post_action === 'delete' && $post_id > 0) {
|
|
require_permission('users', 'delete');
|
|
// Prevent deleting oneself
|
|
if ($post_id !== (int)$_SESSION['user_id']) {
|
|
$stmt = db()->prepare("DELETE FROM users WHERE id = ?");
|
|
$stmt->execute([$post_id]);
|
|
}
|
|
header('Location: ' . app_url('admin.php', ['page' => 'users']));
|
|
exit;
|
|
}
|
|
|
|
if ($post_action === 'edit' || $post_action === 'add') {
|
|
require_permission('users', $post_action === 'add' ? 'add' : 'edit');
|
|
$name = trim($_POST['name'] ?? '');
|
|
$email = trim($_POST['email'] ?? '');
|
|
$phone = trim($_POST['phone'] ?? '');
|
|
$role = $_POST['role'] ?? 'user';
|
|
if (!in_array($role, ['admin', 'user'])) {
|
|
$role = 'user';
|
|
}
|
|
$role_id = $_POST['role_id'] ?? '';
|
|
if ($role_id === '') $role_id = null;
|
|
|
|
$raw_password = $_POST['password'] ?? '';
|
|
$profile_picture = '';
|
|
$existing_password = '';
|
|
|
|
if ($post_action === 'edit' && $post_id > 0) {
|
|
$stmt = db()->prepare("SELECT profile_picture, password FROM users WHERE id = ?");
|
|
$stmt->execute([$post_id]);
|
|
$existing = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
if ($existing) {
|
|
$profile_picture = $existing['profile_picture'];
|
|
$existing_password = $existing['password'];
|
|
}
|
|
}
|
|
|
|
$upload_dir = __DIR__ . '/assets/images/uploads/';
|
|
if (!is_dir($upload_dir)) {
|
|
mkdir($upload_dir, 0777, true);
|
|
}
|
|
|
|
if (!empty($_FILES['photo']['tmp_name'])) {
|
|
$filename = 'user_' . time() . '_' . basename($_FILES['photo']['name']);
|
|
$target = $upload_dir . $filename;
|
|
if (move_uploaded_file($_FILES['photo']['tmp_name'], $target)) {
|
|
$profile_picture = 'assets/images/uploads/' . $filename;
|
|
}
|
|
}
|
|
|
|
if ($post_action === 'add') {
|
|
$final_password = $raw_password ? password_hash($raw_password, PASSWORD_DEFAULT) : '';
|
|
} else {
|
|
if ($raw_password) {
|
|
$final_password = password_hash($raw_password, PASSWORD_DEFAULT);
|
|
} else {
|
|
$final_password = $existing_password;
|
|
}
|
|
}
|
|
|
|
if ($post_action === 'edit' && $post_id > 0) {
|
|
$stmt = db()->prepare("UPDATE users SET name=?, email=?, phone=?, role=?, profile_picture=?, password=?, role_id=? WHERE id=?");
|
|
$stmt->execute([$name, $email, $phone, $role, $profile_picture, $final_password, $role_id, $post_id]);
|
|
} else {
|
|
$stmt = db()->prepare("INSERT INTO users (name, email, phone, role, profile_picture, password, role_id) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
|
$stmt->execute([$name, $email, $phone, $role, $profile_picture, $final_password, $role_id]);
|
|
}
|
|
header('Location: ' . app_url('admin.php', ['page' => 'users']));
|
|
exit;
|
|
}
|
|
}
|
|
|
|
$search = $_GET['search'] ?? '';
|
|
$page_num = max(1, (int)($_GET['p'] ?? 1));
|
|
$limit = 10;
|
|
$offset = ($page_num - 1) * $limit;
|
|
|
|
$where = "1=1";
|
|
$params = [];
|
|
if ($search) {
|
|
$where .= " AND (u.name LIKE ? OR u.email LIKE ?)";
|
|
$params[] = "%$search%";
|
|
$params[] = "%$search%";
|
|
}
|
|
|
|
$stmt = db()->prepare("SELECT COUNT(*) FROM users u WHERE $where");
|
|
$stmt->execute($params);
|
|
$total = $stmt->fetchColumn();
|
|
$total_pages = ceil($total / $limit);
|
|
|
|
$stmt = db()->prepare("SELECT u.*, r.name as role_name FROM users u LEFT JOIN roles r ON u.role_id = r.id WHERE $where ORDER BY u.id DESC LIMIT ? OFFSET ?");
|
|
$params[] = $limit;
|
|
$params[] = $offset;
|
|
foreach($params as $k => $v) {
|
|
$stmt->bindValue($k+1, $v, is_int($v) ? PDO::PARAM_INT : PDO::PARAM_STR);
|
|
}
|
|
$stmt->execute();
|
|
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$stmt = db()->query("SELECT id, name FROM roles ORDER BY name ASC");
|
|
$roles_list = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
?>
|
|
<div class="section-header mb-4 d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h1 class="section-title mb-2"><?= h(t('Platform Users', 'مستخدمي المنصة')) ?></h1>
|
|
<p class="text-secondary mb-0"><?= h(t('Manage administrators and staff.', 'إدارة المسؤولين والموظفين.')) ?></p>
|
|
</div>
|
|
<?php if (has_permission('users', 'add')): ?>
|
|
<button class="btn btn-dark" data-bs-toggle="modal" data-bs-target="#userModal" onclick="editUser(null)">
|
|
<?= h(t('Add User', 'إضافة مستخدم')) ?>
|
|
</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="panel-card mb-4">
|
|
<form method="GET" action="admin.php" class="d-flex gap-2">
|
|
<input type="hidden" name="page" value="users">
|
|
<input type="text" name="search" class="form-control" placeholder="<?= h(t('Search...', 'بحث...')) ?>" value="<?= h($search) ?>">
|
|
<button type="submit" class="btn btn-outline-dark"><?= h(t('Search', 'بحث')) ?></button>
|
|
<?php if ($search): ?>
|
|
<a href="<?= h(app_url('admin.php', ['page' => 'users'])) ?>" class="btn btn-link text-secondary"><?= h(t('Clear', 'مسح')) ?></a>
|
|
<?php endif; ?>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="panel-card p-0 overflow-hidden">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th class="px-4 py-3"><?= h(t('Name', 'الاسم')) ?></th>
|
|
<th class="py-3"><?= h(t('Email', 'البريد الإلكتروني')) ?></th>
|
|
<th class="py-3"><?= h(t('Phone', 'الهاتف')) ?></th>
|
|
<th class="py-3"><?= h(t('Role Group', 'الصلاحيات')) ?></th>
|
|
<th class="px-4 py-3 text-end"><?= h(t('Actions', 'الإجراءات')) ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($users as $u): ?>
|
|
<tr>
|
|
<td class="px-4 py-3">
|
|
<div class="d-flex align-items-center gap-3">
|
|
<?php if ($u['profile_picture']): ?>
|
|
<img src="<?= h(asset_url($u['profile_picture'])) ?>" class="rounded-circle" style="width:40px;height:40px;object-fit:cover;">
|
|
<?php else: ?>
|
|
<div class="bg-light rounded-circle d-flex align-items-center justify-content-center text-secondary fw-bold" style="width:40px;height:40px;">
|
|
<?= h(strtoupper(substr($u['name'], 0, 1))) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<div>
|
|
<div class="fw-bold text-dark"><?= h($u['name']) ?></div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td class="py-3"><?= h($u['email']) ?></td>
|
|
<td class="py-3"><?= h($u['phone']) ?></td>
|
|
<td class="py-3">
|
|
<?php if ($u['role_name']): ?>
|
|
<span class="badge bg-info text-dark"><?= h($u['role_name']) ?></span>
|
|
<?php elseif ($u['role'] === 'admin'): ?>
|
|
<span class="badge bg-primary text-white"><?= h(t('Admin', 'مسؤول')) ?></span>
|
|
<?php else: ?>
|
|
<span class="badge bg-secondary text-white"><?= h(t('User', 'مستخدم')) ?></span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="px-4 py-3 text-end">
|
|
<div class="btn-group btn-group-sm">
|
|
<?php if (has_permission('users', 'edit')): ?>
|
|
<button class="btn btn-outline-dark" onclick='editUser(<?= htmlspecialchars(json_encode($u), ENT_QUOTES) ?>)' data-bs-toggle="modal" data-bs-target="#userModal">
|
|
<svg width="16" height="16" fill="currentColor" class="me-1" viewBox="0 0 16 16"><path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/></svg><?= h(t('Edit', 'تعديل')) ?>
|
|
</button>
|
|
<?php endif; ?>
|
|
|
|
<?php if (has_permission('users', 'delete') && (int)$u['id'] !== (int)$_SESSION['user_id']): ?>
|
|
<form method="POST" action="admin_users.php" class="d-inline" onsubmit="return confirm('<?= h(t('Delete this user?', 'حذف هذا المستخدم؟')) ?>');">
|
|
<input type="hidden" name="action" value="delete">
|
|
<input type="hidden" name="id" value="<?= h($u['id']) ?>">
|
|
<button class="btn btn-outline-danger" type="submit">
|
|
<svg width="16" height="16" fill="currentColor" class="me-1" viewBox="0 0 16 16"><path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/><path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/></svg><?= h(t('Delete', 'حذف')) ?>
|
|
</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php if (empty($users)): ?>
|
|
<tr><td colspan="5" class="text-center py-4 text-secondary"><?= h(t('No users found.', 'لا يوجد مستخدمين.')) ?></td></tr>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if ($total_pages > 1): ?>
|
|
<nav class="mt-4">
|
|
<ul class="pagination justify-content-center">
|
|
<?php for($i=1; $i<=$total_pages; $i++): ?>
|
|
<li class="page-item <?= $i === $page_num ? 'active' : '' ?>">
|
|
<a class="page-link" href="<?= h(app_url('admin.php', ['page' => 'users', 'p' => $i, 'search' => $search])) ?>"><?= $i ?></a>
|
|
</li>
|
|
<?php endfor; ?>
|
|
</ul>
|
|
</nav>
|
|
<?php endif; ?>
|
|
|
|
<!-- User Modal -->
|
|
<div class="modal fade" id="userModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<form class="modal-content" method="POST" action="admin_users.php" enctype="multipart/form-data">
|
|
<input type="hidden" name="action" id="userAction" value="add">
|
|
<input type="hidden" name="id" id="userId" value="0">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="userModalTitle"><?= h(t('Add User', 'إضافة مستخدم')) ?></h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(t('Name', 'الاسم')) ?></label>
|
|
<input type="text" class="form-control" name="name" id="userName" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(t('Email', 'البريد الإلكتروني')) ?></label>
|
|
<input type="email" class="form-control" name="email" id="userEmail" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(t('Phone', 'الهاتف')) ?></label>
|
|
<input type="text" class="form-control" name="phone" id="userPhone">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(t('Role Group', 'مجموعة الصلاحيات')) ?></label>
|
|
<select class="form-select" name="role_id" id="userRoleId">
|
|
<option value=""><?= h(t('None (Basic User)', 'بدون (مستخدم عادي)')) ?></option>
|
|
<?php foreach($roles_list as $rl): ?>
|
|
<option value="<?= $rl['id'] ?>"><?= h($rl['name']) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3" style="display:none;">
|
|
<label class="form-label"><?= h(t('Role (Legacy)', 'الدور القديم')) ?></label>
|
|
<select class="form-select" name="role" id="userRole">
|
|
<option value="user"><?= h(t('User', 'مستخدم')) ?></option>
|
|
<option value="admin"><?= h(t('Admin', 'مسؤول')) ?></option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(t('Password', 'كلمة المرور')) ?> <small class="text-secondary" id="userPasswordHelp" style="display:none;">(<?= h(t('Leave blank to keep current', 'اتركه فارغاً للاحتفاظ بالحالي')) ?>)</small></label>
|
|
<input type="password" class="form-control" name="password" id="userPassword">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(t('Profile Picture', 'صورة الملف الشخصي')) ?></label>
|
|
<input type="file" class="form-control" name="photo" accept="image/*">
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal"><?= h(t('Cancel', 'إلغاء')) ?></button>
|
|
<button type="submit" class="btn btn-dark"><?= h(t('Save', 'حفظ')) ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function editUser(user) {
|
|
if (user) {
|
|
document.getElementById('userAction').value = 'edit';
|
|
document.getElementById('userId').value = user.id;
|
|
document.getElementById('userModalTitle').innerText = '<?= h(t('Edit User', 'تعديل المستخدم')) ?>';
|
|
document.getElementById('userName').value = user.name;
|
|
document.getElementById('userEmail').value = user.email;
|
|
document.getElementById('userPhone').value = user.phone || '';
|
|
document.getElementById('userRole').value = user.role;
|
|
document.getElementById('userRoleId').value = user.role_id || '';
|
|
document.getElementById('userPassword').required = false;
|
|
document.getElementById('userPasswordHelp').style.display = 'inline';
|
|
} else {
|
|
document.getElementById('userAction').value = 'add';
|
|
document.getElementById('userId').value = '0';
|
|
document.getElementById('userModalTitle').innerText = '<?= h(t('Add User', 'إضافة مستخدم')) ?>';
|
|
document.getElementById('userName').value = '';
|
|
document.getElementById('userEmail').value = '';
|
|
document.getElementById('userPhone').value = '';
|
|
document.getElementById('userRole').value = 'user';
|
|
document.getElementById('userRoleId').value = '';
|
|
document.getElementById('userPassword').required = true;
|
|
document.getElementById('userPasswordHelp').style.display = 'none';
|
|
}
|
|
}
|
|
</script>
|