adding role groups
This commit is contained in:
parent
43c2d25666
commit
547de74ee7
20
admin.php
20
admin.php
@ -180,7 +180,7 @@ render_head(
|
||||
</li>
|
||||
|
||||
<li class="nav-item w-100 mt-3 border-top pt-3">
|
||||
<a href="#settingsCollapse" data-bs-toggle="collapse" class="nav-link link-dark d-flex align-items-center justify-content-between text-secondary fw-bold px-3 py-2" aria-expanded="<?= in_array($page, ['profile', 'integrations', 'landing', 'users']) ? 'true' : 'false' ?>" aria-controls="settingsCollapse" style="font-size: 0.95rem; letter-spacing: 0.5px;">
|
||||
<a href="#settingsCollapse" data-bs-toggle="collapse" class="nav-link link-dark d-flex align-items-center justify-content-between text-secondary fw-bold px-3 py-2" aria-expanded="<?= in_array($page, ['profile', 'integrations', 'landing', 'users', 'roles']) ? 'true' : 'false' ?>" aria-controls="settingsCollapse" style="font-size: 0.95rem; letter-spacing: 0.5px;">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" class="bi bi-gear" viewBox="0 0 16 16">
|
||||
<path d="M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492M5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0"/>
|
||||
@ -193,7 +193,7 @@ render_head(
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<div class="collapse <?= in_array($page, ['profile', 'integrations', 'landing', 'users']) ? 'show' : '' ?>" id="settingsCollapse">
|
||||
<div class="collapse <?= in_array($page, ['profile', 'integrations', 'landing', 'users', 'roles']) ? 'show' : '' ?>" id="settingsCollapse">
|
||||
<ul class="nav flex-column ms-3 mb-2">
|
||||
<li class="nav-item mb-1 mt-2">
|
||||
<a href="<?= h(app_url('admin.php', ['page' => 'profile'])) ?>" class="nav-link <?= $page === 'profile' ? 'active' : 'link-dark' ?> d-flex align-items-center gap-2" <?= $page === 'profile' ? 'style="background-color: var(--accent); color: white; border-radius: 6px;"' : '' ?>>
|
||||
@ -221,7 +221,7 @@ render_head(
|
||||
<?= h(t('Landing Page', 'الصفحة الرئيسية')) ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php if (get_logged_in_user()['role'] === 'admin'): ?>
|
||||
<?php if (has_permission('users', 'view')): ?>
|
||||
<li class="nav-item">
|
||||
<a href="<?= h(app_url('admin.php', ['page' => 'users'])) ?>" class="nav-link <?= $page === 'users' ? 'active' : 'link-dark' ?> d-flex align-items-center gap-2" <?= $page === 'users' ? 'style="background-color: var(--accent); color: white; border-radius: 6px;"' : '' ?> >
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-shield-lock" viewBox="0 0 16 16">
|
||||
@ -231,6 +231,16 @@ render_head(
|
||||
<?= h(t('Platform Users', 'مستخدمي المنصة')) ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php if (has_permission('roles', 'view')): ?>
|
||||
<li class="nav-item mb-1">
|
||||
<a href="<?= h(app_url('admin.php', ['page' => 'roles'])) ?>" class="nav-link <?= $page === 'roles' ? 'active' : 'link-dark' ?> d-flex align-items-center gap-2" <?= $page === 'roles' ? 'style="background-color: var(--accent); color: white; border-radius: 6px;"' : '' ?> >
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-lines-fill" viewBox="0 0 16 16">
|
||||
<path d="M6 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-5 6s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H1zM11 3.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5zm.5 2.5a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1h-4zm2 3a.5.5 0 0 0 0 1h2a.5.5 0 0 0 0-1h-2zm0 3a.5.5 0 0 0 0 1h2a.5.5 0 0 0 0-1h-2z"/>
|
||||
</svg>
|
||||
<?= h(t('Role Groups', 'مجموعات الصلاحيات')) ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
@ -243,6 +253,7 @@ render_head(
|
||||
<main class="flex-grow-1 d-flex flex-column" style="height: calc(100vh - 61px); overflow-y: auto;">
|
||||
<div class="p-4 p-md-5 flex-grow-1">
|
||||
<?php if ($page === 'dashboard'): ?>
|
||||
<?php require_permission('dashboard', 'view'); ?>
|
||||
<div class="section-header mb-4">
|
||||
<div>
|
||||
<span class="eyebrow"><?= h(t('Admin', 'الإدارة')) ?></span>
|
||||
@ -296,6 +307,7 @@ render_head(
|
||||
</div>
|
||||
|
||||
<?php elseif ($page === 'profile'): ?>
|
||||
<?php if (get_logged_in_user()['role'] !== 'admin' || !empty(get_logged_in_user()['role_id'])) die('Access Denied'); ?>
|
||||
<?php $prof = get_platform_profile(); ?>
|
||||
<div class="section-header mb-4">
|
||||
<div>
|
||||
@ -378,6 +390,8 @@ render_head(
|
||||
<?php require_once __DIR__ . '/admin_integrations.php'; ?>
|
||||
<?php elseif ($page === 'landing'): ?>
|
||||
<?php require_once __DIR__ . '/admin_landing.php'; ?>
|
||||
<?php elseif ($page === 'roles'): ?>
|
||||
<?php require_once __DIR__ . '/admin_roles.php'; ?>
|
||||
<?php else: ?>
|
||||
<div class="section-header mb-4">
|
||||
<div>
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
<?php
|
||||
// admin_assignments.php
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
|
||||
require_permission('assignments', 'view');
|
||||
|
||||
// Initialize table if not exists
|
||||
db()->exec("CREATE TABLE IF NOT EXISTS teacher_assignments (
|
||||
@ -20,6 +23,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$post_id = (int)($_POST['id'] ?? $id);
|
||||
|
||||
if ($post_action === 'delete' && $post_id > 0) {
|
||||
require_permission('assignments', 'delete');
|
||||
$stmt = db()->prepare("DELETE FROM teacher_assignments WHERE id = ?");
|
||||
$stmt->execute([$post_id]);
|
||||
header('Location: ' . app_url('admin.php', ['page' => 'assignments']));
|
||||
@ -95,7 +99,9 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<div>
|
||||
<h1 class="section-title mb-2"><?= h(t('Teacher Assignments', 'تعيينات المعلمين')) ?></h1>
|
||||
</div>
|
||||
<?php if (has_permission('assignments', 'add')): ?>
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addAssignmentModal" style="background-color: var(--accent); border-color: var(--accent);">+ <?= h(t('Add Assignment', 'إضافة تعيين')) ?></button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="panel-card mb-4">
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
<?php
|
||||
// admin_classes.php
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
|
||||
require_permission('classes', 'view');
|
||||
|
||||
$action = $_GET['action'] ?? 'list';
|
||||
$id = (int)($_GET['id'] ?? 0);
|
||||
@ -12,6 +15,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$post_id = (int)($_POST['id'] ?? $id);
|
||||
|
||||
if ($post_action === 'delete' && $post_id > 0) {
|
||||
require_permission('classes', 'delete');
|
||||
$stmt = db()->prepare("DELETE FROM classes WHERE id = ?");
|
||||
$stmt->execute([$post_id]);
|
||||
header('Location: ' . app_url('admin.php', ['page' => 'classes']));
|
||||
@ -19,6 +23,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
if ($post_action === 'edit' || $post_action === 'add') {
|
||||
require_permission('classes', $post_action === 'add' ? 'add' : 'edit');
|
||||
$name_en = $_POST['name_en'] ?? '';
|
||||
$name_ar = $_POST['name_ar'] ?? '';
|
||||
$desc_en = $_POST['description_en'] ?? '';
|
||||
@ -64,7 +69,9 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<div>
|
||||
<h1 class="section-title mb-2"><?= h(t('Classes', 'الصفوف')) ?></h1>
|
||||
</div>
|
||||
<?php if (has_permission('classes', 'add')): ?>
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addClassModal" style="background-color: var(--accent); border-color: var(--accent);">+ <?= h(t('Add Class', 'إضافة صف')) ?></button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="panel-card mb-4">
|
||||
@ -108,12 +115,16 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<?= h(current_lang() === 'ar' ? $row['description_ar'] : $row['description_en']) ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (has_permission('classes', 'edit')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editClassModal<?= $row['id'] ?>" title="<?= h(t('Edit', 'تعديل')) ?>">
|
||||
<svg width="16" height="16" fill="currentColor" 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>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if (has_permission('classes', 'delete')): ?>
|
||||
<form method="post" action="<?= h(app_url('admin.php', ['page'=>'classes', 'action'=>'delete', 'id'=>$row['id']])) ?>" class="d-inline" onsubmit="return confirm('<?= h(t('Are you sure?', 'هل أنت متأكد؟')) ?>');">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="<?= h(t('Delete', 'حذف')) ?>"><svg width="16" height="16" fill="currentColor" 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></button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
<?php
|
||||
// admin_courses.php
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
|
||||
require_permission('courses', 'view');
|
||||
|
||||
$action = $_GET['action'] ?? 'list';
|
||||
$id = (int)($_GET['id'] ?? 0);
|
||||
@ -10,6 +13,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$post_id = (int)($_POST['id'] ?? $id);
|
||||
|
||||
if ($post_action === 'delete' && $post_id > 0) {
|
||||
require_permission('courses', 'delete');
|
||||
$stmt = db()->prepare("DELETE FROM courses WHERE id = ?");
|
||||
$stmt->execute([$post_id]);
|
||||
header('Location: ' . app_url('admin.php', ['page' => 'courses']));
|
||||
@ -33,6 +37,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
if ($post_action === 'edit' || $post_action === 'add') {
|
||||
require_permission('courses', $post_action === 'add' ? 'add' : 'edit');
|
||||
$name_en = $_POST['name_en'] ?? '';
|
||||
$name_ar = $_POST['name_ar'] ?? '';
|
||||
$desc_en = $_POST['description_en'] ?? '';
|
||||
@ -124,7 +129,8 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<h1 class="section-title mb-2"><?= h(t('Courses', 'الدورات')) ?></h1>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-2 justify-content-end">
|
||||
<form method="post" action="<?= h(app_url('admin.php', ['page'=>'courses'])) ?>" class="m-0" onsubmit="return confirm('<?= h(t('Close registration for all courses?', 'هل أنت متأكد من إغلاق التسجيل لجميع الدورات؟')) ?>');">
|
||||
<?php if (has_permission('courses', 'delete')): ?>
|
||||
<form method="post" action="<?= h(app_url('admin.php', ['page'=>'courses'])) ?>" class="m-0" onsubmit="return confirm('<?= h(t('Close registration for all courses?', 'هل أنت متأكد من إغلاق التسجيل لجميع الدورات؟')) ?>');">
|
||||
<input type="hidden" name="action" value="close_all_registration">
|
||||
<button type="submit" class="btn btn-outline-warning btn-sm"><?= h(t('Close All', 'إغلاق الكل')) ?></button>
|
||||
</form>
|
||||
@ -216,12 +222,15 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<path d="M15 14s1 0 1-1-1-4-5-4-5 3-5 4 1 1 1 1zm-7.978-1L7 12.996c.001-.264.167-1.03.76-1.72C8.312 10.629 9.282 10 11 10c1.717 0 2.687.63 3.24 1.276.593.69.758 1.457.76 1.72l-.008.002-.014.002zM11 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4m3-2a3 3 0 1 1-6 0 3 3 0 0 1 6 0M6.936 9.28a6 6 0 0 0-1.23-.247A7 7 0 0 0 5 9c-4 0-5 3-5 4q0 1 1 1h4.216A2.24 2.24 0 0 1 5 13c0-1.01.377-2.042 1.09-2.904.243-.294.526-.569.846-.816M4.92 10A5.5 5.5 0 0 0 4 13H1c0-.26.164-1.03.76-1.724.545-.636 1.492-1.256 3.16-1.275ZM1.5 5.5a3 3 0 1 1 6 0 3 3 0 0 1-6 0m3-2a2 2 0 1 0 0 4 2 2 0 0 0 0-4"/>
|
||||
</svg>
|
||||
</button>
|
||||
<?php if (has_permission('courses', 'edit')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editCourseModal<?= $row['id'] ?>" title="<?= h(t('Edit', 'تعديل')) ?>">
|
||||
<svg width="16" height="16" fill="currentColor" 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>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<form method="post" action="<?= h(app_url('admin.php', ['page'=>'courses', 'action'=>'delete', 'id'=>$row['id']])) ?>" class="d-inline" onsubmit="return confirm('<?= h(t('Are you sure?', 'هل أنت متأكد؟')) ?>');">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="<?= h(t('Delete', 'حذف')) ?>"><svg width="16" height="16" fill="currentColor" 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></button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
<?php
|
||||
// admin_plans.php
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
|
||||
require_permission('plans', 'view');
|
||||
|
||||
$action = $_GET['action'] ?? 'list';
|
||||
$id = (int)($_GET['id'] ?? 0);
|
||||
@ -10,6 +13,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$post_id = (int)($_POST['id'] ?? $id);
|
||||
|
||||
if ($post_action === 'delete' && $post_id > 0) {
|
||||
require_permission('plans', 'delete');
|
||||
$stmt = db()->prepare("DELETE FROM plans WHERE id = ?");
|
||||
$stmt->execute([$post_id]);
|
||||
header('Location: ' . app_url('admin.php', ['page' => 'plans']));
|
||||
@ -17,6 +21,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
if ($post_action === 'edit' || $post_action === 'add') {
|
||||
require_permission('plans', $post_action === 'add' ? 'add' : 'edit');
|
||||
$plan_key = $_POST['plan_key'] ?? '';
|
||||
$name_en = $_POST['name_en'] ?? '';
|
||||
$name_ar = $_POST['name_ar'] ?? '';
|
||||
@ -121,12 +126,16 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<td><?= h(format_price((float)$row['price_yearly'])) ?></td>
|
||||
<td><?= h((string)$row['subjects_limit']) ?></td>
|
||||
<td class="text-end">
|
||||
<?php if (has_permission('plans', 'edit')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editPlanModal<?= $row['id'] ?>" title="<?= h(t('Edit', 'تعديل')) ?>">
|
||||
<svg width="16" height="16" fill="currentColor" 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>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if (has_permission('plans', 'delete')): ?>
|
||||
<form method="post" action="<?= h(app_url('admin.php', ['page'=>'plans', 'action'=>'delete', 'id'=>$row['id']])) ?>" class="d-inline" onsubmit="return confirm('<?= h(t('Are you sure?', 'هل أنت متأكد؟')) ?>');">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="<?= h(t('Delete', 'حذف')) ?>"><svg width="16" height="16" fill="currentColor" 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></button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
258
admin_roles.php
Normal file
258
admin_roles.php
Normal file
@ -0,0 +1,258 @@
|
||||
<?php
|
||||
// admin_roles.php
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
|
||||
require_permission('roles', 'view');
|
||||
|
||||
$pages = [
|
||||
'dashboard' => t('Dashboard', 'لوحة التحكم'),
|
||||
'classes' => t('Classes', 'الصفوف'),
|
||||
'subjects' => t('Subjects', 'المواد'),
|
||||
'teachers' => t('Teachers', 'المعلمين'),
|
||||
'courses' => t('Courses', 'الدورات'),
|
||||
'assignments' => t('Assignments', 'الواجبات'),
|
||||
'students' => t('Students', 'الطلاب'),
|
||||
'plans' => t('Plans', 'الخطط'),
|
||||
'users' => t('Platform Users', 'مستخدمي المنصة'),
|
||||
'roles' => t('Role Groups', 'مجموعات الصلاحيات'),
|
||||
'integrations' => t('Integrations', 'عمليات الربط'),
|
||||
'landing' => t('Landing Page', 'الصفحة الرئيسية'),
|
||||
];
|
||||
|
||||
$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('roles', 'delete');
|
||||
// check if system role
|
||||
$stmt = db()->prepare("SELECT is_system FROM roles WHERE id = ?");
|
||||
$stmt->execute([$post_id]);
|
||||
$role = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if ($role && !$role['is_system']) {
|
||||
$stmt = db()->prepare("DELETE FROM roles WHERE id = ?");
|
||||
$stmt->execute([$post_id]);
|
||||
}
|
||||
header('Location: ' . app_url('admin.php', ['page' => 'roles']));
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($post_action === 'edit' || $post_action === 'add') {
|
||||
require_permission('roles', $post_action === 'add' ? 'add' : 'edit');
|
||||
$name = trim($_POST['name'] ?? '');
|
||||
$description = trim($_POST['description'] ?? '');
|
||||
$perms = $_POST['perms'] ?? []; // e.g. ['classes' => ['view'=>1, 'add'=>1]]
|
||||
|
||||
if ($post_action === 'edit' && $post_id > 0) {
|
||||
$stmt = db()->prepare("UPDATE roles SET name=?, description=? WHERE id=?");
|
||||
$stmt->execute([$name, $description, $post_id]);
|
||||
$role_id = $post_id;
|
||||
} else {
|
||||
$stmt = db()->prepare("INSERT INTO roles (name, description) VALUES (?, ?)");
|
||||
$stmt->execute([$name, $description]);
|
||||
$role_id = db()->lastInsertId();
|
||||
}
|
||||
|
||||
// update permissions
|
||||
if ($role_id) {
|
||||
$stmt = db()->prepare("DELETE FROM role_permissions WHERE role_id = ?");
|
||||
$stmt->execute([$role_id]);
|
||||
|
||||
$stmt = db()->prepare("INSERT INTO role_permissions (role_id, page, can_view, can_add, can_edit, can_delete) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
foreach ($pages as $p => $pname) {
|
||||
if (isset($perms[$p])) {
|
||||
$v = !empty($perms[$p]['view']) ? 1 : 0;
|
||||
$a = !empty($perms[$p]['add']) ? 1 : 0;
|
||||
$e = !empty($perms[$p]['edit']) ? 1 : 0;
|
||||
$d = !empty($perms[$p]['delete']) ? 1 : 0;
|
||||
if ($v || $a || $e || $d) {
|
||||
$stmt->execute([$role_id, $p, $v, $a, $e, $d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
header('Location: ' . app_url('admin.php', ['page' => 'roles']));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
$roles = db()->query("SELECT * FROM roles ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Fetch permissions for all roles
|
||||
$stmt = db()->query("SELECT * FROM role_permissions");
|
||||
$all_perms = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$role_perms = [];
|
||||
foreach ($all_perms as $p) {
|
||||
$role_perms[$p['role_id']][$p['page']] = $p;
|
||||
}
|
||||
|
||||
// Merge permissions into roles for JS
|
||||
foreach ($roles as &$r) {
|
||||
$r['permissions'] = $role_perms[$r['id']] ?? [];
|
||||
}
|
||||
unset($r);
|
||||
|
||||
?>
|
||||
<div class="section-header mb-4 d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="section-title mb-2"><?= h(t('Role Groups', 'مجموعات الصلاحيات')) ?></h1>
|
||||
<p class="text-secondary mb-0"><?= h(t('Manage roles and their page permissions.', 'إدارة الأدوار وصلاحيات الصفحات الخاصة بها.')) ?></p>
|
||||
</div>
|
||||
<?php if (has_permission('roles', 'add')): ?>
|
||||
<button class="btn btn-dark" data-bs-toggle="modal" data-bs-target="#roleModal" onclick="editRole(null)">
|
||||
<?= h(t('Add Role Group', 'إضافة مجموعة صلاحيات')) ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</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('Role Name', 'اسم الدور')) ?></th>
|
||||
<th class="py-3"><?= h(t('Description', 'الوصف')) ?></th>
|
||||
<th class="px-4 py-3 text-end"><?= h(t('Actions', 'الإجراءات')) ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($roles as $r): ?>
|
||||
<tr>
|
||||
<td class="px-4 py-3 fw-bold text-dark">
|
||||
<?= h($r['name']) ?>
|
||||
<?php if ($r['is_system']): ?>
|
||||
<span class="badge bg-secondary ms-2"><?= h(t('System', 'نظام')) ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="py-3 text-secondary"><?= h($r['description']) ?></td>
|
||||
<td class="px-4 py-3 text-end">
|
||||
<div class="btn-group btn-group-sm">
|
||||
<?php if (has_permission('roles', 'edit')): ?>
|
||||
<button class="btn btn-outline-dark" onclick='editRole(<?= htmlspecialchars(json_encode($r), ENT_QUOTES) ?>)'>
|
||||
<?= h(t($r['is_system'] ? 'View' : 'Edit', $r['is_system'] ? 'عرض' : 'تعديل')) ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!$r['is_system'] && has_permission('roles', 'delete')): ?>
|
||||
<form method="POST" action="admin_roles.php" class="d-inline" onsubmit="return confirm('<?= h(t('Delete this role?', 'حذف هذا الدور؟')) ?>');">
|
||||
<input type="hidden" name="action" value="delete">
|
||||
<input type="hidden" name="id" value="<?= h($r['id']) ?>">
|
||||
<button class="btn btn-outline-danger" type="submit">
|
||||
<?= h(t('Delete', 'حذف')) ?>
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($roles)): ?>
|
||||
<tr><td colspan="3" class="text-center py-4 text-secondary"><?= h(t('No roles found.', 'لا توجد أدوار.')) ?></td></tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Role Modal -->
|
||||
<div class="modal fade" id="roleModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<form class="modal-content" method="POST" action="admin_roles.php">
|
||||
<input type="hidden" name="action" id="roleAction" value="add">
|
||||
<input type="hidden" name="id" id="roleId" value="0">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="roleModalTitle"><?= h(t('Add Role Group', 'إضافة مجموعة صلاحيات')) ?></h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"><?= h(t('Role Name', 'اسم الدور')) ?></label>
|
||||
<input type="text" class="form-control" name="name" id="roleName" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"><?= h(t('Description', 'الوصف')) ?></label>
|
||||
<input type="text" class="form-control" name="description" id="roleDesc">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h6 class="mt-4 mb-3"><?= h(t('Permissions', 'الصلاحيات')) ?></h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-sm align-middle">
|
||||
<thead class="bg-light text-center">
|
||||
<tr>
|
||||
<th class="text-start"><?= h(t('Page', 'الصفحة')) ?></th>
|
||||
<th><?= h(t('View', 'عرض')) ?></th>
|
||||
<th><?= h(t('Add', 'إضافة')) ?></th>
|
||||
<th><?= h(t('Edit', 'تعديل')) ?></th>
|
||||
<th><?= h(t('Delete', 'حذف')) ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="permissionsTbody">
|
||||
<?php foreach($pages as $p => $pname): ?>
|
||||
<tr>
|
||||
<td class="text-start fw-bold"><?= h($pname) ?></td>
|
||||
<td class="text-center"><input class="form-check-input perm-chk perm-chk-view" type="checkbox" name="perms[<?= h($p) ?>][view]" value="1" data-page="<?= h($p) ?>"></td>
|
||||
<td class="text-center"><input class="form-check-input perm-chk perm-chk-add" type="checkbox" name="perms[<?= h($p) ?>][add]" value="1" data-page="<?= h($p) ?>"></td>
|
||||
<td class="text-center"><input class="form-check-input perm-chk perm-chk-edit" type="checkbox" name="perms[<?= h($p) ?>][edit]" value="1" data-page="<?= h($p) ?>"></td>
|
||||
<td class="text-center"><input class="form-check-input perm-chk perm-chk-delete" type="checkbox" name="perms[<?= h($p) ?>][delete]" value="1" data-page="<?= h($p) ?>"></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</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" id="btnSaveRole"><?= h(t('Save', 'حفظ')) ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function editRole(role) {
|
||||
// reset checkboxes
|
||||
document.querySelectorAll('.perm-chk').forEach(c => c.checked = false);
|
||||
|
||||
if (role) {
|
||||
document.getElementById('roleAction').value = 'edit';
|
||||
document.getElementById('roleId').value = role.id;
|
||||
document.getElementById('roleModalTitle').innerText = '<?= h(t('Edit Role Group', 'تعديل مجموعة الصلاحيات')) ?>';
|
||||
document.getElementById('roleName').value = role.name;
|
||||
document.getElementById('roleDesc').value = role.description || '';
|
||||
|
||||
if (role.permissions) {
|
||||
for (let p in role.permissions) {
|
||||
let perms = role.permissions[p];
|
||||
if (perms.can_view) { let el = document.querySelector(`input[name="perms[${p}][view]"]`); if(el) el.checked = true; }
|
||||
if (perms.can_add) { let el = document.querySelector(`input[name="perms[${p}][add]"]`); if(el) el.checked = true; }
|
||||
if (perms.can_edit) { let el = document.querySelector(`input[name="perms[${p}][edit]"]`); if(el) el.checked = true; }
|
||||
if (perms.can_delete) { let el = document.querySelector(`input[name="perms[${p}][delete]"]`); if(el) el.checked = true; }
|
||||
}
|
||||
}
|
||||
|
||||
let isSystem = role.is_system == 1;
|
||||
document.getElementById('roleName').readOnly = isSystem;
|
||||
document.getElementById('roleDesc').readOnly = isSystem;
|
||||
document.querySelectorAll('.perm-chk').forEach(c => c.disabled = isSystem);
|
||||
document.getElementById('btnSaveRole').style.display = isSystem ? 'none' : 'block';
|
||||
|
||||
} else {
|
||||
document.getElementById('roleAction').value = 'add';
|
||||
document.getElementById('roleId').value = '0';
|
||||
document.getElementById('roleModalTitle').innerText = '<?= h(t('Add Role Group', 'إضافة مجموعة صلاحيات')) ?>';
|
||||
document.getElementById('roleName').value = '';
|
||||
document.getElementById('roleDesc').value = '';
|
||||
|
||||
document.getElementById('roleName').readOnly = false;
|
||||
document.getElementById('roleDesc').readOnly = false;
|
||||
document.querySelectorAll('.perm-chk').forEach(c => c.disabled = false);
|
||||
document.getElementById('btnSaveRole').style.display = 'block';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -1,6 +1,9 @@
|
||||
<?php
|
||||
// admin_students.php
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
|
||||
require_permission('students', 'view');
|
||||
|
||||
$action = $_GET['action'] ?? 'list';
|
||||
$id = (int)($_GET['id'] ?? 0);
|
||||
@ -10,6 +13,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$post_id = (int)($_POST['id'] ?? $id);
|
||||
|
||||
if ($post_action === 'delete' && $post_id > 0) {
|
||||
require_permission('students', 'delete');
|
||||
$stmt = db()->prepare("DELETE FROM student_subscriptions WHERE id = ?");
|
||||
$stmt->execute([$post_id]);
|
||||
header('Location: ' . app_url('admin.php', ['page' => 'students']));
|
||||
@ -17,6 +21,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
if ($post_action === 'edit' || $post_action === 'add') {
|
||||
require_permission('students', $post_action === 'add' ? 'add' : 'edit');
|
||||
$full_name = $_POST['full_name'] ?? '';
|
||||
$email = $_POST['email'] ?? '';
|
||||
$whatsapp = $_POST['whatsapp'] ?? '';
|
||||
@ -140,14 +145,18 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (has_permission('students', 'edit')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editStudentModal<?= $row['id'] ?>" title="<?= h(t('Edit', 'تعديل')) ?>">
|
||||
<svg width="16" height="16" fill="currentColor" 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>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if (has_permission('students', 'delete')): ?>
|
||||
<form method="post" action="<?= h(app_url('admin.php', ['page'=>'students', 'action'=>'delete', 'id'=>$row['id']])) ?>" class="d-inline" onsubmit="return confirm('<?= h(t('Are you sure?', 'هل أنت متأكد؟')) ?>');">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="<?= h(t('Delete', 'حذف')) ?>">
|
||||
<svg width="16" height="16" fill="currentColor" 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>
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
<?php
|
||||
// admin_subjects.php
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
|
||||
require_permission('subjects', 'view');
|
||||
|
||||
$action = $_GET['action'] ?? 'list';
|
||||
$id = (int)($_GET['id'] ?? 0);
|
||||
@ -14,6 +17,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$post_id = (int)($_POST['id'] ?? $id);
|
||||
|
||||
if ($post_action === 'delete' && $post_id > 0) {
|
||||
require_permission('subjects', 'delete');
|
||||
$stmt = db()->prepare("DELETE FROM subjects WHERE id = ?");
|
||||
$stmt->execute([$post_id]);
|
||||
header('Location: ' . app_url('admin.php', ['page' => 'subjects']));
|
||||
@ -21,6 +25,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
if ($post_action === 'edit' || $post_action === 'add') {
|
||||
require_permission('subjects', $post_action === 'add' ? 'add' : 'edit');
|
||||
$class_id = !empty($_POST['class_id']) ? (int)$_POST['class_id'] : null;
|
||||
$title_en = $_POST['title_en'] ?? '';
|
||||
$title_ar = $_POST['title_ar'] ?? '';
|
||||
@ -89,7 +94,9 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<div>
|
||||
<h1 class="section-title mb-2"><?= h(t('Subjects', 'المواد')) ?></h1>
|
||||
</div>
|
||||
<?php if (has_permission('subjects', 'add')): ?>
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addSubjectModal" style="background-color: var(--accent); border-color: var(--accent);">+ <?= h(t('Add Subject', 'إضافة مادة')) ?></button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="panel-card mb-4">
|
||||
@ -149,12 +156,16 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (has_permission('subjects', 'edit')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editSubjectModal<?= $row['id'] ?>" title="<?= h(t('Edit', 'تعديل')) ?>">
|
||||
<svg width="16" height="16" fill="currentColor" 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>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if (has_permission('subjects', 'delete')): ?>
|
||||
<form method="post" action="<?= h(app_url('admin.php', ['page'=>'subjects', 'action'=>'delete', 'id'=>$row['id']])) ?>" class="d-inline" onsubmit="return confirm('<?= h(t('Are you sure?', 'هل أنت متأكد؟')) ?>');">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="<?= h(t('Delete', 'حذف')) ?>"><svg width="16" height="16" fill="currentColor" 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></button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
<?php
|
||||
// admin_teachers.php
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
|
||||
require_permission('teachers', 'view');
|
||||
|
||||
$action = $_GET['action'] ?? 'list';
|
||||
$id = (int)($_GET['id'] ?? 0);
|
||||
@ -10,6 +13,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$post_id = (int)($_POST['id'] ?? $id);
|
||||
|
||||
if ($post_action === 'delete' && $post_id > 0) {
|
||||
require_permission('teachers', 'delete');
|
||||
$stmt = db()->prepare("DELETE FROM teachers WHERE id = ?");
|
||||
$stmt->execute([$post_id]);
|
||||
header('Location: ' . app_url('admin.php', ['page' => 'teachers']));
|
||||
@ -17,6 +21,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
if ($post_action === 'edit' || $post_action === 'add') {
|
||||
require_permission('teachers', $post_action === 'add' ? 'add' : 'edit');
|
||||
$name = $_POST['name'] ?? '';
|
||||
$email = $_POST['email'] ?? '';
|
||||
$phone = $_POST['phone'] ?? '';
|
||||
@ -100,7 +105,9 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<div>
|
||||
<h1 class="section-title mb-2"><?= h(t('Teachers', 'المعلمون')) ?></h1>
|
||||
</div>
|
||||
<?php if (has_permission('teachers', 'add')): ?>
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addTeacherModal" style="background-color: var(--accent); border-color: var(--accent);">+ <?= h(t('Add Teacher', 'إضافة معلم')) ?></button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="panel-card mb-4">
|
||||
@ -153,14 +160,18 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<?php if (!empty($row['phone'])): ?><div><small><?= h($row['phone']) ?></small></div><?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (has_permission('teachers', 'edit')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editTeacherModal<?= $row['id'] ?>" title="<?= h(t('Edit', 'تعديل')) ?>">
|
||||
<svg width="16" height="16" fill="currentColor" 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>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if (has_permission('teachers', 'delete')): ?>
|
||||
<form method="post" action="<?= h(app_url('admin.php', ['page'=>'teachers', 'action'=>'delete', 'id'=>$row['id']])) ?>" class="d-inline" onsubmit="return confirm('<?= h(t('Are you sure?', 'هل أنت متأكد؟')) ?>');">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="<?= h(t('Delete', 'حذف')) ?>">
|
||||
<svg width="16" height="16" fill="currentColor" 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>
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
<?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();
|
||||
if ($current_u['role'] !== 'admin') {
|
||||
die('Access Denied');
|
||||
}
|
||||
|
||||
$action = $_GET['action'] ?? 'list';
|
||||
$id = (int)($_GET['id'] ?? 0);
|
||||
@ -15,6 +15,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$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 = ?");
|
||||
@ -25,6 +26,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
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'] ?? '');
|
||||
@ -32,6 +34,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
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 = '';
|
||||
@ -71,11 +75,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
if ($post_action === 'edit' && $post_id > 0) {
|
||||
$stmt = db()->prepare("UPDATE users SET name=?, email=?, phone=?, role=?, profile_picture=?, password=? WHERE id=?");
|
||||
$stmt->execute([$name, $email, $phone, $role, $profile_picture, $final_password, $post_id]);
|
||||
$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) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$name, $email, $phone, $role, $profile_picture, $final_password]);
|
||||
$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;
|
||||
@ -90,17 +94,17 @@ $offset = ($page_num - 1) * $limit;
|
||||
$where = "1=1";
|
||||
$params = [];
|
||||
if ($search) {
|
||||
$where .= " AND (name LIKE ? OR email LIKE ?)";
|
||||
$where .= " AND (u.name LIKE ? OR u.email LIKE ?)";
|
||||
$params[] = "%$search%";
|
||||
$params[] = "%$search%";
|
||||
}
|
||||
|
||||
$stmt = db()->prepare("SELECT COUNT(*) FROM users WHERE $where");
|
||||
$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 * FROM users WHERE $where ORDER BY id DESC LIMIT ? OFFSET ?");
|
||||
$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) {
|
||||
@ -109,15 +113,20 @@ foreach($params as $k => $v) {
|
||||
$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">
|
||||
@ -139,7 +148,7 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<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', 'الدور')) ?></th>
|
||||
<th class="py-3"><?= h(t('Role Group', 'الصلاحيات')) ?></th>
|
||||
<th class="px-4 py-3 text-end"><?= h(t('Actions', 'الإجراءات')) ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -163,7 +172,9 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<td class="py-3"><?= h($u['email']) ?></td>
|
||||
<td class="py-3"><?= h($u['phone']) ?></td>
|
||||
<td class="py-3">
|
||||
<?php if ($u['role'] === 'admin'): ?>
|
||||
<?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>
|
||||
@ -171,10 +182,13 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
</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) ?>)'>
|
||||
<?= h(t('Edit', 'تعديل')) ?>
|
||||
</button>
|
||||
<?php if ((int)$u['id'] !== (int)$_SESSION['user_id']): ?>
|
||||
<?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']) ?>">
|
||||
@ -231,7 +245,16 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<input type="text" class="form-control" name="phone" id="userPhone">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= h(t('Role', 'الدور')) ?></label>
|
||||
<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>
|
||||
@ -264,6 +287,7 @@ function editUser(user) {
|
||||
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 {
|
||||
@ -274,8 +298,9 @@ function editUser(user) {
|
||||
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>
|
||||
</script>
|
||||
57
db/migrations/migrate_roles.php
Normal file
57
db/migrations/migrate_roles.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../includes/app.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// Create roles table
|
||||
$pdo->exec("CREATE TABLE IF NOT EXISTS `roles` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`description` TEXT,
|
||||
`is_system` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;");
|
||||
|
||||
// Create role_permissions table
|
||||
$pdo->exec("CREATE TABLE IF NOT EXISTS `role_permissions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`role_id` INT NOT NULL,
|
||||
`page` VARCHAR(50) NOT NULL,
|
||||
`can_view` TINYINT(1) DEFAULT 0,
|
||||
`can_add` TINYINT(1) DEFAULT 0,
|
||||
`can_edit` TINYINT(1) DEFAULT 0,
|
||||
`can_delete` TINYINT(1) DEFAULT 0,
|
||||
UNIQUE KEY `role_page` (`role_id`, `page`),
|
||||
FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;");
|
||||
|
||||
// Alter users table to add role_id
|
||||
// Check if column exists
|
||||
$stmt = $pdo->prepare("SHOW COLUMNS FROM `users` LIKE 'role_id'");
|
||||
$stmt->execute();
|
||||
if ($stmt->rowCount() == 0) {
|
||||
$pdo->exec("ALTER TABLE `users` ADD COLUMN `role_id` INT NULL DEFAULT NULL");
|
||||
$pdo->exec("ALTER TABLE `users` ADD CONSTRAINT `fk_user_role` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE SET NULL");
|
||||
}
|
||||
|
||||
// Insert 'Super Admin' role if it doesn't exist
|
||||
$stmt = $pdo->prepare("SELECT id FROM roles WHERE name = 'Super Admin'");
|
||||
$stmt->execute();
|
||||
$adminRole = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$adminRole) {
|
||||
$pdo->exec("INSERT INTO roles (name, description, is_system) VALUES ('Super Admin', 'Full access to all pages and actions', 1)");
|
||||
$adminRoleId = $pdo->lastInsertId();
|
||||
} else {
|
||||
$adminRoleId = $adminRole['id'];
|
||||
}
|
||||
|
||||
// Assign 'Super Admin' role to all existing admins
|
||||
$stmt = $pdo->prepare("UPDATE users SET role_id = ? WHERE role = 'admin' AND role_id IS NULL");
|
||||
$stmt->execute([$adminRoleId]);
|
||||
|
||||
echo "Migration completed successfully.";
|
||||
} catch (PDOException $e) {
|
||||
echo "Migration failed: " . $e->getMessage();
|
||||
}
|
||||
@ -14,3 +14,35 @@ function get_logged_in_user() {
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
|
||||
}
|
||||
|
||||
function has_permission($page, $action = 'view') {
|
||||
$user = get_logged_in_user();
|
||||
if (!$user) return false;
|
||||
|
||||
// Super Admins bypass permissions. Fallback logic.
|
||||
if ($user['role'] === 'admin' && empty($user['role_id'])) return true;
|
||||
|
||||
if (!empty($user['role_id'])) {
|
||||
$stmt = db()->prepare("SELECT is_system FROM roles WHERE id = ?");
|
||||
$stmt->execute([$user['role_id']]);
|
||||
$role = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if ($role && $role['is_system']) return true; // Super admin
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM role_permissions WHERE role_id = ? AND page = ?");
|
||||
$stmt->execute([$user['role_id'], $page]);
|
||||
$perms = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($perms) {
|
||||
$col = 'can_' . $action;
|
||||
return !empty($perms[$col]);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function require_permission($page, $action = 'view') {
|
||||
if (!has_permission($page, $action)) {
|
||||
http_response_code(403);
|
||||
die("403 Forbidden - You don't have permission to perform this action.");
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user