adding permissions
This commit is contained in:
parent
607b9d8838
commit
37abbe5d1e
@ -2,8 +2,8 @@
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
require_once __DIR__ . '/mail/MailService.php';
|
||||
|
||||
// Only admins can access this page
|
||||
if (!isAdmin()) {
|
||||
// Only users with settings view permission can access this page
|
||||
if (!canView('settings')) {
|
||||
redirect("index.php");
|
||||
}
|
||||
|
||||
@ -12,8 +12,12 @@ $error_msg = '';
|
||||
|
||||
// Handle Re-enable SMTP
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['enable_smtp'])) {
|
||||
db()->query("UPDATE smtp_settings SET is_enabled = 1, consecutive_failures = 0 WHERE id = 1");
|
||||
$_SESSION['success'] = 'تم إعادة تفعيل SMTP وتصفير عداد الأخطاء';
|
||||
if (canEdit('settings')) {
|
||||
db()->query("UPDATE smtp_settings SET is_enabled = 1, consecutive_failures = 0 WHERE id = 1");
|
||||
$_SESSION['success'] = 'تم إعادة تفعيل SMTP وتصفير عداد الأخطاء';
|
||||
} else {
|
||||
$_SESSION['error'] = 'عذراً، ليس لديك الصلاحية لتعديل الإعدادات';
|
||||
}
|
||||
redirect('charity-settings.php');
|
||||
}
|
||||
|
||||
@ -27,101 +31,125 @@ $smtp = $stmt->fetch();
|
||||
|
||||
// Handle Charity Settings Update
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_charity'])) {
|
||||
$charity_name = $_POST['charity_name'];
|
||||
$charity_email = $_POST['charity_email'];
|
||||
$charity_phone = $_POST['charity_phone'];
|
||||
$charity_address = $_POST['charity_address'];
|
||||
$charity_logo = $charity['charity_logo'];
|
||||
$charity_favicon = $charity['charity_favicon'];
|
||||
if (!canEdit('settings')) {
|
||||
$_SESSION['error'] = 'عذراً، ليس لديك الصلاحية لتعديل الإعدادات';
|
||||
} else {
|
||||
$charity_name = $_POST['charity_name'];
|
||||
$charity_email = $_POST['charity_email'];
|
||||
$charity_phone = $_POST['charity_phone'];
|
||||
$charity_address = $_POST['charity_address'];
|
||||
$charity_logo = $charity['charity_logo'];
|
||||
$charity_favicon = $charity['charity_favicon'];
|
||||
|
||||
$upload_dir = 'uploads/charity/';
|
||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0775, true);
|
||||
$upload_dir = 'uploads/charity/';
|
||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0775, true);
|
||||
|
||||
if (isset($_FILES['charity_logo']) && $_FILES['charity_logo']['error'] === UPLOAD_ERR_OK) {
|
||||
$file_ext = pathinfo($_FILES['charity_logo']['name'], PATHINFO_EXTENSION);
|
||||
$new_logo = 'logo_' . time() . '.' . $file_ext;
|
||||
if (move_uploaded_file($_FILES['charity_logo']['tmp_name'], $upload_dir . $new_logo)) {
|
||||
$charity_logo = $upload_dir . $new_logo;
|
||||
if (isset($_FILES['charity_logo']) && $_FILES['charity_logo']['error'] === UPLOAD_ERR_OK) {
|
||||
$file_ext = pathinfo($_FILES['charity_logo']['name'], PATHINFO_EXTENSION);
|
||||
$new_logo = 'logo_' . time() . '.' . $file_ext;
|
||||
if (move_uploaded_file($_FILES['charity_logo']['tmp_name'], $upload_dir . $new_logo)) {
|
||||
$charity_logo = $upload_dir . $new_logo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_FILES['charity_favicon']) && $_FILES['charity_favicon']['error'] === UPLOAD_ERR_OK) {
|
||||
$file_ext = pathinfo($_FILES['charity_favicon']['name'], PATHINFO_EXTENSION);
|
||||
$new_favicon = 'favicon_' . time() . '.' . $file_ext;
|
||||
if (move_uploaded_file($_FILES['charity_favicon']['tmp_name'], $upload_dir . $new_favicon)) {
|
||||
$charity_favicon = $upload_dir . $new_favicon;
|
||||
if (isset($_FILES['charity_favicon']) && $_FILES['charity_favicon']['error'] === UPLOAD_ERR_OK) {
|
||||
$file_ext = pathinfo($_FILES['charity_favicon']['name'], PATHINFO_EXTENSION);
|
||||
$new_favicon = 'favicon_' . time() . '.' . $file_ext;
|
||||
if (move_uploaded_file($_FILES['charity_favicon']['tmp_name'], $upload_dir . $new_favicon)) {
|
||||
$charity_favicon = $upload_dir . $new_favicon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$stmt = db()->prepare("UPDATE charity_settings SET charity_name = ?, charity_email = ?, charity_phone = ?, charity_address = ?, charity_logo = ?, charity_favicon = ? WHERE id = 1");
|
||||
$stmt->execute([$charity_name, $charity_email, $charity_phone, $charity_address, $charity_logo, $charity_favicon]);
|
||||
$_SESSION['success'] = 'تم تحديث إعدادات النظام بنجاح';
|
||||
$stmt = db()->prepare("UPDATE charity_settings SET charity_name = ?, charity_email = ?, charity_phone = ?, charity_address = ?, charity_logo = ?, charity_favicon = ? WHERE id = 1");
|
||||
$stmt->execute([$charity_name, $charity_email, $charity_phone, $charity_address, $charity_logo, $charity_favicon]);
|
||||
$_SESSION['success'] = 'تم تحديث إعدادات النظام بنجاح';
|
||||
}
|
||||
redirect('charity-settings.php');
|
||||
}
|
||||
|
||||
// Handle SMTP Settings Update
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_smtp'])) {
|
||||
$stmt = db()->prepare("UPDATE smtp_settings SET smtp_host = ?, smtp_port = ?, smtp_secure = ?, smtp_user = ?, smtp_pass = ?, from_email = ?, from_name = ?, reply_to = ?, max_failures = ? WHERE id = 1");
|
||||
$stmt->execute([
|
||||
$_POST['smtp_host'],
|
||||
(int)$_POST['smtp_port'],
|
||||
$_POST['smtp_secure'],
|
||||
$_POST['smtp_user'],
|
||||
$_POST['smtp_pass'],
|
||||
$_POST['from_email'],
|
||||
$_POST['from_name'],
|
||||
$_POST['reply_to'],
|
||||
(int)$_POST['max_failures']
|
||||
]);
|
||||
$_SESSION['success'] = 'تم تحديث إعدادات البريد (SMTP) بنجاح';
|
||||
if (!canEdit('settings')) {
|
||||
$_SESSION['error'] = 'عذراً، ليس لديك الصلاحية لتعديل الإعدادات';
|
||||
} else {
|
||||
$stmt = db()->prepare("UPDATE smtp_settings SET smtp_host = ?, smtp_port = ?, smtp_secure = ?, smtp_user = ?, smtp_pass = ?, from_email = ?, from_name = ?, reply_to = ?, max_failures = ? WHERE id = 1");
|
||||
$stmt->execute([
|
||||
$_POST['smtp_host'],
|
||||
(int)$_POST['smtp_port'],
|
||||
$_POST['smtp_secure'],
|
||||
$_POST['smtp_user'],
|
||||
$_POST['smtp_pass'],
|
||||
$_POST['from_email'],
|
||||
$_POST['from_name'],
|
||||
$_POST['reply_to'],
|
||||
(int)$_POST['max_failures']
|
||||
]);
|
||||
$_SESSION['success'] = 'تم تحديث إعدادات البريد (SMTP) بنجاح';
|
||||
}
|
||||
redirect('charity-settings.php');
|
||||
}
|
||||
|
||||
// Handle Test Email
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['test_email_addr'])) {
|
||||
$to = $_POST['test_email_addr'];
|
||||
$res = MailService::sendMail($to, "رسالة تجريبية - Test Email", "<p>إذا كنت ترى هذه الرسالة، فإن إعدادات SMTP تعمل بشكل صحيح.</p>");
|
||||
if ($res['success']) {
|
||||
$_SESSION['success'] = "تم إرسال الرسالة التجريبية بنجاح إلى $to";
|
||||
if (!canEdit('settings')) {
|
||||
$_SESSION['error'] = 'عذراً، ليس لديك الصلاحية للقيام بهذا الإجراء';
|
||||
} else {
|
||||
$_SESSION['error'] = "فشل إرسال الرسالة التجريبية: " . $res['error'];
|
||||
$to = $_POST['test_email_addr'];
|
||||
$res = MailService::sendMail($to, "رسالة تجريبية - Test Email", "<p>إذا كنت ترى هذه الرسالة، فإن إعدادات SMTP تعمل بشكل صحيح.</p>");
|
||||
if ($res['success']) {
|
||||
$_SESSION['success'] = "تم إرسال الرسالة التجريبية بنجاح إلى $to";
|
||||
} else {
|
||||
$_SESSION['error'] = "فشل إرسال الرسالة التجريبية: " . $res['error'];
|
||||
}
|
||||
}
|
||||
redirect('charity-settings.php');
|
||||
}
|
||||
|
||||
// Handle Status Operations
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_status'])) {
|
||||
$name = $_POST['status_name'];
|
||||
$color = $_POST['status_color'];
|
||||
$is_default = isset($_POST['is_default']) ? 1 : 0;
|
||||
if ($is_default) db()->query("UPDATE mailbox_statuses SET is_default = 0");
|
||||
$stmt = db()->prepare("INSERT INTO mailbox_statuses (name, color, is_default) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$name, $color, $is_default]);
|
||||
$_SESSION['success'] = 'تم إضافة نوع الحالة بنجاح';
|
||||
if (!canEdit('settings')) {
|
||||
$_SESSION['error'] = 'عذراً، ليس لديك الصلاحية لتعديل الإعدادات';
|
||||
} else {
|
||||
$name = $_POST['status_name'];
|
||||
$color = $_POST['status_color'];
|
||||
$is_default = isset($_POST['is_default']) ? 1 : 0;
|
||||
if ($is_default) db()->query("UPDATE mailbox_statuses SET is_default = 0");
|
||||
$stmt = db()->prepare("INSERT INTO mailbox_statuses (name, color, is_default) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$name, $color, $is_default]);
|
||||
$_SESSION['success'] = 'تم إضافة نوع الحالة بنجاح';
|
||||
}
|
||||
redirect('charity-settings.php');
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_status'])) {
|
||||
$id = $_POST['status_id'];
|
||||
$name = $_POST['status_name'];
|
||||
$color = $_POST['status_color'];
|
||||
$is_default = isset($_POST['is_default']) ? 1 : 0;
|
||||
if ($is_default) db()->query("UPDATE mailbox_statuses SET is_default = 0");
|
||||
$stmt = db()->prepare("UPDATE mailbox_statuses SET name = ?, color = ?, is_default = ? WHERE id = ?");
|
||||
$stmt->execute([$name, $color, $is_default, $id]);
|
||||
$_SESSION['success'] = 'تم تحديث نوع الحالة بنجاح';
|
||||
if (!canEdit('settings')) {
|
||||
$_SESSION['error'] = 'عذراً، ليس لديك الصلاحية لتعديل الإعدادات';
|
||||
} else {
|
||||
$id = $_POST['status_id'];
|
||||
$name = $_POST['status_name'];
|
||||
$color = $_POST['status_color'];
|
||||
$is_default = isset($_POST['is_default']) ? 1 : 0;
|
||||
if ($is_default) db()->query("UPDATE mailbox_statuses SET is_default = 0");
|
||||
$stmt = db()->prepare("UPDATE mailbox_statuses SET name = ?, color = ?, is_default = ? WHERE id = ?");
|
||||
$stmt->execute([$name, $color, $is_default, $id]);
|
||||
$_SESSION['success'] = 'تم تحديث نوع الحالة بنجاح';
|
||||
}
|
||||
redirect('charity-settings.php');
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_status'])) {
|
||||
$id = $_POST['status_id'];
|
||||
$count = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE status_id = ?");
|
||||
$count->execute([$id]);
|
||||
if ($count->fetchColumn() > 0) {
|
||||
$_SESSION['error'] = 'لا يمكن حذف هذه الحالة لأنها مستخدمة في بعض السجلات';
|
||||
if (!canDelete('settings')) {
|
||||
$_SESSION['error'] = 'عذراً، ليس لديك الصلاحية لحذف الإعدادات';
|
||||
} else {
|
||||
db()->prepare("DELETE FROM mailbox_statuses WHERE id = ?")->execute([$id]);
|
||||
$_SESSION['success'] = 'تم حذف نوع الحالة بنجاح';
|
||||
$id = $_POST['status_id'];
|
||||
$count = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE status_id = ?");
|
||||
$count->execute([$id]);
|
||||
if ($count->fetchColumn() > 0) {
|
||||
$_SESSION['error'] = 'لا يمكن حذف هذه الحالة لأنها مستخدمة في بعض السجلات';
|
||||
} else {
|
||||
db()->prepare("DELETE FROM mailbox_statuses WHERE id = ?")->execute([$id]);
|
||||
$_SESSION['success'] = 'تم حذف نوع الحالة بنجاح';
|
||||
}
|
||||
}
|
||||
redirect('charity-settings.php');
|
||||
}
|
||||
@ -228,7 +256,9 @@ $post_max = ini_get('post_max_size');
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-end mt-4">
|
||||
<?php if (canEdit('settings')): ?>
|
||||
<button type="submit" class="btn btn-dark px-4">حفظ جميع التغييرات</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -240,9 +270,11 @@ $post_max = ini_get('post_max_size');
|
||||
<?php if (!$smtp['is_enabled']): ?>
|
||||
<div class="alert alert-danger py-2 px-3 mb-0 d-flex align-items-center">
|
||||
<small><i class="fas fa-exclamation-triangle me-2"></i> SMTP معطل حالياً</small>
|
||||
<?php if (canEdit('settings')): ?>
|
||||
<form method="POST" class="ms-3">
|
||||
<button type="submit" name="enable_smtp" class="btn btn-sm btn-outline-danger">تفعيل الآن</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="badge bg-success p-2">
|
||||
@ -301,7 +333,9 @@ $post_max = ini_get('post_max_size');
|
||||
<input type="number" name="max_failures" class="form-control" value="<?= htmlspecialchars($smtp['max_failures'] ?? 5) ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php if (canEdit('settings')): ?>
|
||||
<button type="submit" class="btn btn-primary">حفظ إعدادات البريد</button>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
<div class="mt-5 p-4 bg-light rounded border">
|
||||
@ -310,7 +344,7 @@ $post_max = ini_get('post_max_size');
|
||||
<form method="POST">
|
||||
<div class="input-group" style="max-width: 450px;">
|
||||
<input type="email" name="test_email_addr" class="form-control" placeholder="بريد الوجهة (example@mail.com)" required>
|
||||
<button class="btn btn-secondary" type="submit"><i class="fas fa-paper-plane me-2"></i> إرسال اختبار</button>
|
||||
<button class="btn btn-secondary" type="submit" <?= !canEdit('settings') ? 'disabled' : '' ?>><i class="fas fa-paper-plane me-2"></i> إرسال اختبار</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -320,7 +354,9 @@ $post_max = ini_get('post_max_size');
|
||||
<div class="tab-pane fade" id="statuses" role="tabpanel">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h5 class="fw-bold text-primary mb-0">أنواع حالات البريد</h5>
|
||||
<?php if (canAdd('settings')): ?>
|
||||
<button class="btn btn-sm btn-primary" onclick="new bootstrap.Modal(document.getElementById('addStatusModal')).show()"><i class="fas fa-plus me-2"></i> إضافة حالة جديدة</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
@ -345,8 +381,10 @@ $post_max = ini_get('post_max_size');
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?php if (canEdit('settings')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" onclick="editStatus(<?= $status['id'] ?>, '<?= htmlspecialchars($status['name'], ENT_QUOTES) ?>', '<?= $status['color'] ?>', <?= $status['is_default'] ?>)"><i class="fas fa-edit"></i></button>
|
||||
<?php if (!$status['is_default']): ?>
|
||||
<?php endif; ?>
|
||||
<?php if (canDelete('settings') && !$status['is_default']): ?>
|
||||
<form method="POST" onsubmit="return confirm('هل أنت متأكد من حذف هذه الحالة؟');" style="display:inline;">
|
||||
<input type="hidden" name="status_id" value="<?= $status['id'] ?>">
|
||||
<input type="hidden" name="delete_status" value="1">
|
||||
@ -429,7 +467,9 @@ $post_max = ini_get('post_max_size');
|
||||
<h6 class="fw-bold mb-2 text-warning-emphasis"><i class="fas fa-tools me-2"></i> أدوات الصيانة</h6>
|
||||
<p class="small mb-3">هذه الأدوات مخصصة لمدير النظام فقط. يرجى توخي الحذر عند الاستخدام.</p>
|
||||
<div class="d-flex gap-2">
|
||||
<?php if (canEdit('settings')): ?>
|
||||
<button class="btn btn-sm btn-outline-warning" onclick="alert('قريباً: نسخة احتياطية لقاعدة البيانات')"><i class="fas fa-database me-1"></i> نسخة احتياطية</button>
|
||||
<?php endif; ?>
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="location.reload()"><i class="fas fa-sync-alt me-1"></i> تحديث الحالة</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -547,4 +587,4 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
50
db/migrations/013_add_page_permissions.sql
Normal file
50
db/migrations/013_add_page_permissions.sql
Normal file
@ -0,0 +1,50 @@
|
||||
-- Migration: Add per-page granular permissions
|
||||
CREATE TABLE IF NOT EXISTS user_permissions (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_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 user_page (user_id, page),
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Seed permissions for existing users based on their roles
|
||||
-- Inbound Mail
|
||||
INSERT IGNORE INTO user_permissions (user_id, page, can_view, can_add, can_edit, can_delete)
|
||||
SELECT id, 'inbound', can_view, can_add, can_edit, can_delete FROM users;
|
||||
|
||||
-- Outbound Mail
|
||||
INSERT IGNORE INTO user_permissions (user_id, page, can_view, can_add, can_edit, can_delete)
|
||||
SELECT id, 'outbound', can_view, can_add, can_edit, can_delete FROM users;
|
||||
|
||||
-- Internal Mail
|
||||
INSERT IGNORE INTO user_permissions (user_id, page, can_view, can_add, can_edit, can_delete)
|
||||
SELECT id, 'internal', can_view, can_add, can_edit, can_delete FROM users;
|
||||
|
||||
-- Users (Only Admins)
|
||||
INSERT IGNORE INTO user_permissions (user_id, page, can_view, can_add, can_edit, can_delete)
|
||||
SELECT id, 'users',
|
||||
IF(role = 'admin', 1, 0),
|
||||
IF(role = 'admin', 1, 0),
|
||||
IF(role = 'admin', 1, 0),
|
||||
IF(role = 'admin', 1, 0)
|
||||
FROM users;
|
||||
|
||||
-- Settings (Only Admins)
|
||||
INSERT IGNORE INTO user_permissions (user_id, page, can_view, can_add, can_edit, can_delete)
|
||||
SELECT id, 'settings',
|
||||
IF(role = 'admin', 1, 0),
|
||||
IF(role = 'admin', 1, 0),
|
||||
IF(role = 'admin', 1, 0),
|
||||
IF(role = 'admin', 1, 0)
|
||||
FROM users;
|
||||
|
||||
-- Reports
|
||||
INSERT IGNORE INTO user_permissions (user_id, page, can_view, can_add, can_edit, can_delete)
|
||||
SELECT id, 'reports',
|
||||
IF(role IN ('admin', 'clerk'), 1, 0),
|
||||
0, 0, 0
|
||||
FROM users;
|
||||
18
inbound.php
18
inbound.php
@ -3,7 +3,7 @@ require_once __DIR__ . '/includes/header.php';
|
||||
require_once __DIR__ . '/mail/MailService.php';
|
||||
|
||||
// Check if user has view permission
|
||||
if (!canView()) {
|
||||
if (!canView('inbound')) {
|
||||
redirect('index.php');
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$action = $_POST['action'] ?? '';
|
||||
|
||||
// Permission checks for POST actions
|
||||
if (($action === 'add' && !canAdd()) || ($action === 'edit' && !canEdit())) {
|
||||
if (($action === 'add' && !canAdd('inbound')) || ($action === 'edit' && !canEdit('inbound'))) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية للقيام بهذا الإجراء';
|
||||
} else {
|
||||
$type = 'inbound';
|
||||
@ -134,7 +134,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
// Delete action
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id'])) {
|
||||
if (!canDelete()) {
|
||||
if (!canDelete('inbound')) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية لحذف السجلات';
|
||||
} else {
|
||||
$id = $_GET['id'];
|
||||
@ -206,7 +206,7 @@ $users_list = db()->query("SELECT id, full_name FROM users ORDER BY full_name")-
|
||||
// Handle Deep Link for Edit
|
||||
$deepLinkData = null;
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id'])) {
|
||||
if (canEdit()) {
|
||||
if (canEdit('inbound')) {
|
||||
$stmt = db()->prepare("SELECT * FROM mailbox WHERE id = ? AND type = 'inbound'");
|
||||
$stmt->execute([$_GET['id']]);
|
||||
$deepLinkData = $stmt->fetch();
|
||||
@ -229,7 +229,7 @@ function getStatusBadgeInList($mail) {
|
||||
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">البريد الوارد</h1>
|
||||
<?php if (canAdd()): ?>
|
||||
<?php if (canAdd('inbound')): ?>
|
||||
<button type="button" class="btn btn-primary shadow-sm" onclick="openMailModal('add')">
|
||||
<i class="fas fa-plus-circle me-1"></i> إضافة جديد
|
||||
</button>
|
||||
@ -317,14 +317,14 @@ function getStatusBadgeInList($mail) {
|
||||
<td class="pe-4 text-center">
|
||||
<a href="view_mail.php?id=<?= $mail['id'] ?>" class="btn btn-sm btn-outline-info" title="عرض التفاصيل"><i class="fas fa-eye"></i></a>
|
||||
|
||||
<?php if (canEdit()): ?>
|
||||
<?php if (canEdit('inbound')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary"
|
||||
onclick='openMailModal("edit", <?= json_encode($mail) ?>)' title="تعديل">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canDelete()): ?>
|
||||
<?php if (canDelete('inbound')): ?>
|
||||
<a href="javascript:void(0)" onclick="confirmDelete(<?= $mail['id'] ?>)" class="btn btn-sm btn-outline-danger" title="حذف"><i class="fas fa-trash"></i></a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
@ -363,7 +363,7 @@ function getStatusBadgeInList($mail) {
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (canAdd() || canEdit()): ?>
|
||||
<?php if (canAdd('inbound') || canEdit('inbound')): ?>
|
||||
<!-- Mail Modal -->
|
||||
<div class="modal fade" id="mailModal" tabindex="-1" aria-labelledby="mailModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
@ -555,4 +555,4 @@ function confirmDelete(id) {
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
@ -9,7 +9,6 @@ function isLoggedIn() {
|
||||
}
|
||||
|
||||
function isAdmin() {
|
||||
// Check session first
|
||||
if (isset($_SESSION['user_role']) && strtolower($_SESSION['user_role']) === 'admin') return true;
|
||||
if (isset($_SESSION['role']) && strtolower($_SESSION['role']) === 'admin') return true;
|
||||
return false;
|
||||
@ -25,29 +24,40 @@ function redirect($path) {
|
||||
}
|
||||
|
||||
// Permission helpers
|
||||
function canView() {
|
||||
function canView($page = null) {
|
||||
if (isAdmin()) return true;
|
||||
if ($page) {
|
||||
return $_SESSION['permissions'][$page]['view'] ?? false;
|
||||
}
|
||||
return $_SESSION['can_view'] ?? false;
|
||||
}
|
||||
|
||||
function canAdd() {
|
||||
function canAdd($page = null) {
|
||||
if (isAdmin()) return true;
|
||||
if ($page) {
|
||||
return $_SESSION['permissions'][$page]['add'] ?? false;
|
||||
}
|
||||
return $_SESSION['can_add'] ?? false;
|
||||
}
|
||||
|
||||
function canEdit() {
|
||||
function canEdit($page = null) {
|
||||
if (isAdmin()) return true;
|
||||
if ($page) {
|
||||
return $_SESSION['permissions'][$page]['edit'] ?? false;
|
||||
}
|
||||
return $_SESSION['can_edit'] ?? false;
|
||||
}
|
||||
|
||||
function canViewInternal() {
|
||||
function canDelete($page = null) {
|
||||
if (isAdmin()) return true;
|
||||
return canView();
|
||||
if ($page) {
|
||||
return $_SESSION['permissions'][$page]['delete'] ?? false;
|
||||
}
|
||||
return $_SESSION['can_delete'] ?? false;
|
||||
}
|
||||
|
||||
function canDelete() {
|
||||
if (isAdmin()) return true;
|
||||
return $_SESSION['can_delete'] ?? false;
|
||||
function canViewInternal() {
|
||||
return canView('internal');
|
||||
}
|
||||
|
||||
// Fetch user info (theme and permissions)
|
||||
@ -67,6 +77,22 @@ if (isLoggedIn()) {
|
||||
$_SESSION['name'] = $current_user['full_name'] ?: $current_user['username'];
|
||||
$_SESSION['user_role'] = strtolower($current_user['role']);
|
||||
$_SESSION['role'] = strtolower($current_user['role']);
|
||||
|
||||
// Load granular permissions
|
||||
if (!isset($_SESSION['permissions']) || empty($_SESSION['permissions'])) {
|
||||
$perm_stmt = db()->prepare("SELECT * FROM user_permissions WHERE user_id = ?");
|
||||
$perm_stmt->execute([$_SESSION['user_id']]);
|
||||
$perms = $perm_stmt->fetchAll();
|
||||
$_SESSION['permissions'] = [];
|
||||
foreach ($perms as $p) {
|
||||
$_SESSION['permissions'][$p['page']] = [
|
||||
'view' => (bool)$p['can_view'],
|
||||
'add' => (bool)$p['can_add'],
|
||||
'edit' => (bool)$p['can_edit'],
|
||||
'delete' => (bool)$p['can_delete']
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,18 +261,27 @@ $charity_info = $charity_stmt->fetch();
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<?php if (canView('inbound') || canView('outbound')): ?>
|
||||
<div class="sidebar-heading">البريد الخارجي</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canView('inbound')): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'inbound.php' ? 'active' : '' ?>" href="inbound.php">
|
||||
<a class="nav-link <?= (basename($_SERVER['PHP_SELF']) == 'inbound.php' && !isset($_GET['my_tasks'])) ? 'active' : '' ?>" href="inbound.php">
|
||||
<i class="fas fa-download me-2"></i> البريد الوارد
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canView('outbound')): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'outbound.php' ? 'active' : '' ?>" href="outbound.php">
|
||||
<i class="fas fa-upload me-2"></i> البريد الصادر
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canView('internal')): ?>
|
||||
<div class="sidebar-heading">البريد الداخلي</div>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'internal_inbox.php' ? 'active' : '' ?>" href="internal_inbox.php">
|
||||
@ -258,28 +293,38 @@ $charity_info = $charity_stmt->fetch();
|
||||
<i class="fas fa-paper-plane me-2"></i> الصادر الداخلي
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="sidebar-heading">التقارير</div>
|
||||
<?php if (isAdmin()): ?>
|
||||
<?php if (canView('reports')): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'overdue_report.php' ? 'active' : '' ?>" href="overdue_report.php">
|
||||
<i class="fas fa-clock me-2"></i> بريد متأخر
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canView('inbound')): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= (basename($_SERVER['PHP_SELF']) == 'inbound.php' && isset($_GET['my_tasks'])) ? 'active' : '' ?>" href="inbound.php?my_tasks=1">
|
||||
<i class="fas fa-tasks me-2"></i> مهامي الحالية
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isAdmin()): ?>
|
||||
<?php if (canView('users') || canView('settings')): ?>
|
||||
<div class="sidebar-heading">الإدارة</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canView('users')): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'users.php' ? 'active' : '' ?>" href="users.php">
|
||||
<i class="fas fa-users me-2"></i> إدارة المستخدمين
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canView('settings')): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= (basename($_SERVER['PHP_SELF']) == 'charity-settings.php' && !isset($_GET['tab'])) ? 'active' : '' ?>" href="charity-settings.php" onclick="localStorage.setItem('activeSettingsTab', '#general');">
|
||||
<i class="fas fa-cog me-2"></i> الإعدادات
|
||||
@ -344,4 +389,4 @@ $charity_info = $charity_stmt->fetch();
|
||||
</nav>
|
||||
|
||||
<div class="main-content">
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
190
index.php
190
index.php
@ -10,8 +10,8 @@ $user_id = $_SESSION['user_id'];
|
||||
$is_admin = isAdmin();
|
||||
|
||||
// Stats
|
||||
$total_inbound = db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'inbound'")->fetchColumn();
|
||||
$total_outbound = db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'outbound'")->fetchColumn();
|
||||
$total_inbound = canView('inbound') ? db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'inbound'")->fetchColumn() : 0;
|
||||
$total_outbound = canView('outbound') ? db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'outbound'")->fetchColumn() : 0;
|
||||
|
||||
// Fetch statuses for badge and count
|
||||
$statuses_data = db()->query("SELECT * FROM mailbox_statuses")->fetchAll(PDO::FETCH_UNIQUE);
|
||||
@ -26,35 +26,60 @@ foreach ($statuses_data as $id => $s) {
|
||||
}
|
||||
$in_progress_count = 0;
|
||||
if ($in_progress_id) {
|
||||
$stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE status_id = ?");
|
||||
$stmt->execute([$in_progress_id]);
|
||||
$in_progress_count = $stmt->fetchColumn();
|
||||
$where_types = [];
|
||||
if (canView('inbound')) $where_types[] = "'inbound'";
|
||||
if (canView('outbound')) $where_types[] = "'outbound'";
|
||||
|
||||
if (!empty($where_types)) {
|
||||
$types_sql = implode(',', $where_types);
|
||||
$stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE status_id = ? AND type IN ($types_sql)");
|
||||
$stmt->execute([$in_progress_id]);
|
||||
$in_progress_count = $stmt->fetchColumn();
|
||||
}
|
||||
}
|
||||
|
||||
// My Assignments
|
||||
$my_assignments = db()->prepare("SELECT m.*, s.name as status_name, s.color as status_color
|
||||
FROM mailbox m
|
||||
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
||||
WHERE m.assigned_to = ?
|
||||
ORDER BY m.created_at DESC LIMIT 5");
|
||||
$my_assignments->execute([$user_id]);
|
||||
$my_assignments = $my_assignments->fetchAll();
|
||||
$my_assignments = [];
|
||||
$assignment_types = [];
|
||||
if (canView('inbound')) $assignment_types[] = "'inbound'";
|
||||
if (canView('outbound')) $assignment_types[] = "'outbound'";
|
||||
if (canView('internal')) $assignment_types[] = "'internal'";
|
||||
|
||||
if (!empty($assignment_types)) {
|
||||
$types_sql = implode(',', $assignment_types);
|
||||
$my_assignments = db()->prepare("SELECT m.*, s.name as status_name, s.color as status_color
|
||||
FROM mailbox m
|
||||
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
||||
WHERE m.assigned_to = ? AND m.type IN ($types_sql)
|
||||
ORDER BY m.created_at DESC LIMIT 5");
|
||||
$my_assignments->execute([$user_id]);
|
||||
$my_assignments = $my_assignments->fetchAll();
|
||||
}
|
||||
|
||||
// Recent Mail (Global for Admin/Clerk, otherwise limited)
|
||||
$recent_mail_query = "SELECT m.*, s.name as status_name, s.color as status_color, u.full_name as assigned_to_name
|
||||
FROM mailbox m
|
||||
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
||||
LEFT JOIN users u ON m.assigned_to = u.id";
|
||||
$recent_mail = [];
|
||||
$recent_types = [];
|
||||
if (canView('inbound')) $recent_types[] = "'inbound'";
|
||||
if (canView('outbound')) $recent_types[] = "'outbound'";
|
||||
|
||||
if (!$is_admin && ($_SESSION['user_role'] ?? '') !== 'clerk') {
|
||||
$recent_mail_query .= " WHERE m.assigned_to = ? OR m.created_by = ?";
|
||||
$recent_stmt = db()->prepare($recent_mail_query . " ORDER BY m.created_at DESC LIMIT 10");
|
||||
$recent_stmt->execute([$user_id, $user_id]);
|
||||
} else {
|
||||
$recent_stmt = db()->prepare($recent_mail_query . " ORDER BY m.created_at DESC LIMIT 10");
|
||||
$recent_stmt->execute();
|
||||
if (!empty($recent_types)) {
|
||||
$types_sql = implode(',', $recent_types);
|
||||
$recent_mail_query = "SELECT m.*, s.name as status_name, s.color as status_color, u.full_name as assigned_to_name
|
||||
FROM mailbox m
|
||||
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
||||
LEFT JOIN users u ON m.assigned_to = u.id
|
||||
WHERE m.type IN ($types_sql)";
|
||||
|
||||
if (!$is_admin && ($_SESSION['user_role'] ?? '') !== 'clerk') {
|
||||
$recent_mail_query .= " AND (m.assigned_to = ? OR m.created_by = ?)";
|
||||
$recent_stmt = db()->prepare($recent_mail_query . " ORDER BY m.created_at DESC LIMIT 10");
|
||||
$recent_stmt->execute([$user_id, $user_id]);
|
||||
} else {
|
||||
$recent_stmt = db()->prepare($recent_mail_query . " ORDER BY m.created_at DESC LIMIT 10");
|
||||
$recent_stmt->execute();
|
||||
}
|
||||
$recent_mail = $recent_stmt->fetchAll();
|
||||
}
|
||||
$recent_mail = $recent_stmt->fetchAll();
|
||||
|
||||
function getStatusBadge($mail) {
|
||||
$status_name = $mail['status_name'] ?? 'غير معروف';
|
||||
@ -74,33 +99,44 @@ function getStatusBadge($mail) {
|
||||
<h1 class="h2">لوحة التحكم الإدارية</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<div class="btn-group me-2">
|
||||
<?php if (canView('settings')): ?>
|
||||
<a href="charity-settings.php" class="btn btn-sm btn-outline-dark"><i class="fas fa-cog me-1"></i> الإعدادات</a>
|
||||
<?php endif; ?>
|
||||
<?php if (canAdd('inbound')): ?>
|
||||
<a href="inbound.php?action=add" class="btn btn-sm btn-outline-primary">إضافة بريد وارد</a>
|
||||
<?php endif; ?>
|
||||
<?php if (canAdd('outbound')): ?>
|
||||
<a href="outbound.php" class="btn btn-sm btn-outline-secondary">إضافة بريد صادر</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Overdue Alert -->
|
||||
<?php
|
||||
$overdue_count = db()->query("SELECT COUNT(*) FROM mailbox WHERE due_date < CURDATE() AND status_id IN (SELECT id FROM mailbox_statuses WHERE name != 'closed')")->fetchColumn();
|
||||
if ($overdue_count > 0):
|
||||
?>
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-danger shadow-sm border-0 d-flex align-items-center justify-content-between mb-0">
|
||||
<div>
|
||||
<i class="fas fa-exclamation-triangle fs-4 me-3"></i>
|
||||
<span class="fw-bold">هناك <?= $overdue_count ?> مهام متأخرة تتطلب انتباهك!</span>
|
||||
if (canView('reports')):
|
||||
$overdue_count = db()->query("SELECT COUNT(*) FROM mailbox WHERE due_date < CURDATE() AND status_id IN (SELECT id FROM mailbox_statuses WHERE name != 'closed') AND type != 'internal'")->fetchColumn();
|
||||
if ($overdue_count > 0):
|
||||
?>
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-danger shadow-sm border-0 d-flex align-items-center justify-content-between mb-0">
|
||||
<div>
|
||||
<i class="fas fa-exclamation-triangle fs-4 me-3"></i>
|
||||
<span class="fw-bold">هناك <?= $overdue_count ?> مهام متأخرة تتطلب انتباهك!</span>
|
||||
</div>
|
||||
<a href="overdue_report.php" class="btn btn-danger btn-sm">عرض التقرير</a>
|
||||
</div>
|
||||
<a href="overdue_report.php" class="btn btn-danger btn-sm">عرض التقرير</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
endif;
|
||||
endif;
|
||||
?>
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<div class="row g-4 mb-4">
|
||||
<?php if (canView('inbound')): ?>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 p-3 shadow-sm border-0 border-start border-primary border-4">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
@ -114,6 +150,9 @@ if ($overdue_count > 0):
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canView('outbound')): ?>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 p-3 shadow-sm border-0 border-start border-success border-4">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
@ -127,6 +166,9 @@ if ($overdue_count > 0):
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canView('inbound') || canView('outbound')): ?>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 p-3 shadow-sm border-0 border-start border-info border-4">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
@ -140,6 +182,9 @@ if ($overdue_count > 0):
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canView('users')): ?>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 p-3 shadow-sm border-0 border-start border-warning border-4">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
@ -153,6 +198,7 @@ if ($overdue_count > 0):
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($my_assignments)): ?>
|
||||
@ -204,6 +250,7 @@ if ($overdue_count > 0):
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($recent_mail)): ?>
|
||||
<!-- Recent Mail -->
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-header bg-white py-3">
|
||||
@ -228,48 +275,43 @@ if ($overdue_count > 0):
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if ($recent_mail): ?>
|
||||
<?php foreach ($recent_mail as $mail): ?>
|
||||
<tr style="cursor: pointer;" onclick="window.location='view_mail.php?id=<?= $mail['id'] ?>'">
|
||||
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
||||
<td>
|
||||
<?php if ($mail['type'] == 'inbound'): ?>
|
||||
<span class="text-primary"><i class="fas fa-arrow-down me-1"></i> وارد</span>
|
||||
<?php else: ?>
|
||||
<span class="text-success"><i class="fas fa-arrow-up me-1"></i> صادر</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= htmlspecialchars($mail['subject']) ?></td>
|
||||
<td>
|
||||
<?php if ($mail['due_date']): ?>
|
||||
<small class="<?= (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed') ? 'text-danger fw-bold' : 'text-muted' ?>">
|
||||
<?= $mail['due_date'] ?>
|
||||
</small>
|
||||
<?php else: ?>
|
||||
<small class="text-muted">-</small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= htmlspecialchars($mail['sender'] ?: $mail['recipient']) ?></td>
|
||||
<td>
|
||||
<?php if ($mail['assigned_to_name']): ?>
|
||||
<small><i class="fas fa-user-tag me-1 text-muted"></i> <?= htmlspecialchars($mail['assigned_to_name']) ?></small>
|
||||
<?php else: ?>
|
||||
<small class="text-muted">غير معين</small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= getStatusBadge($mail) ?></td>
|
||||
<td class="pe-4 text-center"><?= date('Y-m-d', strtotime($mail['date_registered'])) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<tr>
|
||||
<td colspan="8" class="text-center py-4 text-muted">لا يوجد بريد مسجل حالياً</td>
|
||||
<?php foreach ($recent_mail as $mail): ?>
|
||||
<tr style="cursor: pointer;" onclick="window.location='view_mail.php?id=<?= $mail['id'] ?>'">
|
||||
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
||||
<td>
|
||||
<?php if ($mail['type'] == 'inbound'): ?>
|
||||
<span class="text-primary"><i class="fas fa-arrow-down me-1"></i> وارد</span>
|
||||
<?php else: ?>
|
||||
<span class="text-success"><i class="fas fa-arrow-up me-1"></i> صادر</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= htmlspecialchars($mail['subject']) ?></td>
|
||||
<td>
|
||||
<?php if ($mail['due_date']): ?>
|
||||
<small class="<?= (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed') ? 'text-danger fw-bold' : 'text-muted' ?>">
|
||||
<?= $mail['due_date'] ?>
|
||||
</small>
|
||||
<?php else: ?>
|
||||
<small class="text-muted">-</small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= htmlspecialchars($mail['sender'] ?: $mail['recipient']) ?></td>
|
||||
<td>
|
||||
<?php if ($mail['assigned_to_name']): ?>
|
||||
<small><i class="fas fa-user-tag me-1 text-muted"></i> <?= htmlspecialchars($mail['assigned_to_name']) ?></small>
|
||||
<?php else: ?>
|
||||
<small class="text-muted">غير معين</small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= getStatusBadge($mail) ?></td>
|
||||
<td class="pe-4 text-center"><?= date('Y-m-d', strtotime($mail['date_registered'])) ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
@ -1,9 +1,9 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
|
||||
// Every logged-in user can access their own internal mail
|
||||
if (!isLoggedIn()) {
|
||||
redirect('login.php');
|
||||
// Every logged-in user can access their own internal mail if they have permission
|
||||
if (!canView('internal')) {
|
||||
redirect('index.php');
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
@ -61,9 +61,11 @@ function getStatusBadgeInternal($mail) {
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2"><i class="fas fa-inbox me-2 text-primary"></i> بريد الموظفين - الوارد</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<?php if (canAdd('internal')): ?>
|
||||
<a href="internal_outbox.php?action=compose" class="btn btn-primary shadow-sm">
|
||||
<i class="fas fa-paper-plane me-1"></i> إرسال رسالة جديدة
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -161,4 +163,4 @@ function getStatusBadgeInternal($mail) {
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
@ -2,8 +2,8 @@
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
require_once __DIR__ . '/mail/MailService.php';
|
||||
|
||||
if (!isLoggedIn()) {
|
||||
redirect('login.php');
|
||||
if (!canView('internal')) {
|
||||
redirect('index.php');
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
@ -12,68 +12,72 @@ $error = '';
|
||||
|
||||
// Handle composing a new message
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'compose') {
|
||||
$recipient_id = $_POST['recipient_id'] ?? null;
|
||||
$subject = $_POST['subject'] ?? '';
|
||||
$description = $_POST['description'] ?? '';
|
||||
$type = 'internal';
|
||||
$ref_no = generateRefNo('internal');
|
||||
$date_registered = date('Y-m-d');
|
||||
$default_status_id = db()->query("SELECT id FROM mailbox_statuses WHERE is_default = 1 LIMIT 1")->fetchColumn() ?: 1;
|
||||
if (!canAdd('internal')) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية لإرسال رسائل';
|
||||
} else {
|
||||
$recipient_id = $_POST['recipient_id'] ?? null;
|
||||
$subject = $_POST['subject'] ?? '';
|
||||
$description = $_POST['description'] ?? '';
|
||||
$type = 'internal';
|
||||
$ref_no = generateRefNo('internal');
|
||||
$date_registered = date('Y-m-d');
|
||||
$default_status_id = db()->query("SELECT id FROM mailbox_statuses WHERE is_default = 1 LIMIT 1")->fetchColumn() ?: 1;
|
||||
|
||||
if ($recipient_id && $subject) {
|
||||
try {
|
||||
db()->beginTransaction();
|
||||
$stmt = db()->prepare("INSERT INTO mailbox (type, ref_no, date_registered, subject, description, status_id, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$type, $ref_no, $date_registered, $subject, $description, $default_status_id, $recipient_id, $user_id]);
|
||||
$mail_id = db()->lastInsertId();
|
||||
|
||||
// Handle Attachments
|
||||
if (!empty($_FILES['attachments']['name'][0])) {
|
||||
$upload_dir = 'uploads/attachments/';
|
||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
|
||||
if ($recipient_id && $subject) {
|
||||
try {
|
||||
db()->beginTransaction();
|
||||
$stmt = db()->prepare("INSERT INTO mailbox (type, ref_no, date_registered, subject, description, status_id, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$type, $ref_no, $date_registered, $subject, $description, $default_status_id, $recipient_id, $user_id]);
|
||||
$mail_id = db()->lastInsertId();
|
||||
|
||||
// Handle Attachments
|
||||
if (!empty($_FILES['attachments']['name'][0])) {
|
||||
$upload_dir = 'uploads/attachments/';
|
||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
|
||||
|
||||
foreach ($_FILES['attachments']['name'] as $key => $name) {
|
||||
if ($_FILES['attachments']['error'][$key] === 0) {
|
||||
$file_name = time() . '_' . basename($name);
|
||||
$target_path = $upload_dir . $file_name;
|
||||
if (move_uploaded_file($_FILES['attachments']['tmp_name'][$key], $target_path)) {
|
||||
$stmt = db()->prepare("INSERT INTO attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$mail_id, $name, $target_path, $name, $_FILES['attachments']['size'][$key]]);
|
||||
foreach ($_FILES['attachments']['name'] as $key => $name) {
|
||||
if ($_FILES['attachments']['error'][$key] === 0) {
|
||||
$file_name = time() . '_' . basename($name);
|
||||
$target_path = $upload_dir . $file_name;
|
||||
if (move_uploaded_file($_FILES['attachments']['tmp_name'][$key], $target_path)) {
|
||||
$stmt = db()->prepare("INSERT INTO attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$mail_id, $name, $target_path, $name, $_FILES['attachments']['size'][$key]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify recipient
|
||||
$stmt_recp = db()->prepare("SELECT full_name, email FROM users WHERE id = ?");
|
||||
$stmt_recp->execute([$recipient_id]);
|
||||
$recipient = $stmt_recp->fetch();
|
||||
|
||||
if ($recipient && !empty($recipient['email'])) {
|
||||
$email_subject = "رسالة داخلية جديدة من " . $_SESSION['name'];
|
||||
$htmlBody = "
|
||||
<div dir='rtl' style='font-family: Arial, sans-serif;'>
|
||||
<h3>لديك رسالة داخلية جديدة</h3>
|
||||
<p><strong>الموضوع:</strong> " . htmlspecialchars($subject) . "</p>
|
||||
<p><strong>المرسل:</strong> " . htmlspecialchars($_SESSION['name']) . "</p>
|
||||
<hr>
|
||||
<div>" . $description . "</div>
|
||||
<br>
|
||||
<p>يمكنك الرد من خلال النظام.</p>
|
||||
</div>
|
||||
";
|
||||
MailService::sendMail($recipient['email'], $email_subject, $htmlBody);
|
||||
}
|
||||
|
||||
db()->commit();
|
||||
$_SESSION['success'] = 'تم إرسال الرسالة بنجاح';
|
||||
redirect('internal_outbox.php');
|
||||
} catch (PDOException $e) {
|
||||
db()->rollBack();
|
||||
$error = 'حدث خطأ: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
// Notify recipient
|
||||
$stmt_recp = db()->prepare("SELECT full_name, email FROM users WHERE id = ?");
|
||||
$stmt_recp->execute([$recipient_id]);
|
||||
$recipient = $stmt_recp->fetch();
|
||||
|
||||
if ($recipient && !empty($recipient['email'])) {
|
||||
$email_subject = "رسالة داخلية جديدة من " . $_SESSION['username'];
|
||||
$htmlBody = "
|
||||
<div dir='rtl' style='font-family: Arial, sans-serif;'>
|
||||
<h3>لديك رسالة داخلية جديدة</h3>
|
||||
<p><strong>الموضوع:</strong> " . htmlspecialchars($subject) . "</p>
|
||||
<p><strong>المرسل:</strong> " . htmlspecialchars($_SESSION['username']) . "</p>
|
||||
<hr>
|
||||
<div>" . $description . "</div>
|
||||
<br>
|
||||
<p>يمكنك الرد من خلال النظام.</p>
|
||||
</div>
|
||||
";
|
||||
MailService::sendMail($recipient['email'], $email_subject, $htmlBody);
|
||||
}
|
||||
|
||||
db()->commit();
|
||||
$_SESSION['success'] = 'تم إرسال الرسالة بنجاح';
|
||||
redirect('internal_outbox.php');
|
||||
} catch (PDOException $e) {
|
||||
db()->rollBack();
|
||||
$error = 'حدث خطأ: ' . $e->getMessage();
|
||||
} else {
|
||||
$error = 'يرجى اختيار المرسل إليه وكتابة الموضوع';
|
||||
}
|
||||
} else {
|
||||
$error = 'يرجى اختيار المرسل إليه وكتابة الموضوع';
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,9 +147,11 @@ function getStatusBadgeInternal($mail) {
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2"><i class="fas fa-paper-plane me-2 text-success"></i> بريد الموظفين - الصادر</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<?php if (canAdd('internal')): ?>
|
||||
<button type="button" class="btn btn-primary shadow-sm" data-bs-toggle="modal" data-bs-target="#composeModal">
|
||||
<i class="fas fa-plus-circle me-1"></i> إنشاء رسالة جديدة
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -296,20 +302,22 @@ function getStatusBadgeInternal($mail) {
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
ClassicEditor
|
||||
.create(document.querySelector('#composeEditor'), {
|
||||
language: 'ar',
|
||||
toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo'],
|
||||
direction: 'rtl'
|
||||
})
|
||||
.then(editor => {
|
||||
// Force RTL style on editable area
|
||||
editor.ui.view.editable.element.style.direction = 'rtl';
|
||||
editor.ui.view.editable.element.style.textAlign = 'right';
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
if (typeof ClassicEditor !== 'undefined') {
|
||||
ClassicEditor
|
||||
.create(document.querySelector('#composeEditor'), {
|
||||
language: 'ar',
|
||||
toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo'],
|
||||
direction: 'rtl'
|
||||
})
|
||||
.then(editor => {
|
||||
// Force RTL style on editable area
|
||||
editor.ui.view.editable.element.style.direction = 'rtl';
|
||||
editor.ui.view.editable.element.style.textAlign = 'right';
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
<?php if (isset($_GET['action']) && $_GET['action'] === 'compose'): ?>
|
||||
var myModal = new bootstrap.Modal(document.getElementById('composeModal'));
|
||||
@ -318,4 +326,4 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
18
outbound.php
18
outbound.php
@ -3,7 +3,7 @@ require_once __DIR__ . '/includes/header.php';
|
||||
require_once __DIR__ . '/mail/MailService.php';
|
||||
|
||||
// Check if user has view permission
|
||||
if (!canView()) {
|
||||
if (!canView('outbound')) {
|
||||
redirect('index.php');
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$action = $_POST['action'] ?? '';
|
||||
|
||||
// Permission checks for POST actions
|
||||
if (($action === 'add' && !canAdd()) || ($action === 'edit' && !canEdit())) {
|
||||
if (($action === 'add' && !canAdd('outbound')) || ($action === 'edit' && !canEdit('outbound'))) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية للقيام بهذا الإجراء';
|
||||
} else {
|
||||
$type = 'outbound';
|
||||
@ -147,7 +147,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
// Delete action
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id'])) {
|
||||
if (!canDelete()) {
|
||||
if (!canDelete('outbound')) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية لحذف السجلات';
|
||||
} else {
|
||||
$id = $_GET['id'];
|
||||
@ -219,7 +219,7 @@ $users_list = db()->query("SELECT id, full_name FROM users ORDER BY full_name")-
|
||||
// Handle Deep Link for Edit
|
||||
$deepLinkData = null;
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id'])) {
|
||||
if (canEdit()) {
|
||||
if (canEdit('outbound')) {
|
||||
$stmt = db()->prepare("SELECT * FROM mailbox WHERE id = ? AND type = 'outbound'");
|
||||
$stmt->execute([$_GET['id']]);
|
||||
$deepLinkData = $stmt->fetch();
|
||||
@ -242,7 +242,7 @@ function getStatusBadgeInList($mail) {
|
||||
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">البريد الصادر</h1>
|
||||
<?php if (canAdd()): ?>
|
||||
<?php if (canAdd('outbound')): ?>
|
||||
<button type="button" class="btn btn-primary shadow-sm" onclick="openMailModal('add')">
|
||||
<i class="fas fa-plus-circle me-1"></i> إضافة جديد
|
||||
</button>
|
||||
@ -330,14 +330,14 @@ function getStatusBadgeInList($mail) {
|
||||
<td class="pe-4 text-center">
|
||||
<a href="view_mail.php?id=<?= $mail['id'] ?>" class="btn btn-sm btn-outline-info" title="عرض التفاصيل"><i class="fas fa-eye"></i></a>
|
||||
|
||||
<?php if (canEdit()): ?>
|
||||
<?php if (canEdit('outbound')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary"
|
||||
onclick='openMailModal("edit", <?= json_encode($mail) ?>)' title="تعديل">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canDelete()): ?>
|
||||
<?php if (canDelete('outbound')): ?>
|
||||
<a href="javascript:void(0)" onclick="confirmDelete(<?= $mail['id'] ?>)" class="btn btn-sm btn-outline-danger" title="حذف"><i class="fas fa-trash"></i></a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
@ -376,7 +376,7 @@ function getStatusBadgeInList($mail) {
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (canAdd() || canEdit()): ?>
|
||||
<?php if (canAdd('outbound') || canEdit('outbound')): ?>
|
||||
<!-- Mail Modal -->
|
||||
<div class="modal fade" id="mailModal" tabindex="-1" aria-labelledby="mailModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
@ -603,4 +603,4 @@ function confirmDelete(id) {
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
require_once 'includes/header.php';
|
||||
|
||||
if (!isAdmin()) {
|
||||
if (!canView('reports')) {
|
||||
redirect('index.php');
|
||||
}
|
||||
|
||||
@ -123,4 +123,4 @@ $users = db()->query("SELECT id, full_name FROM users ORDER BY full_name")->fetc
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once 'includes/footer.php'; ?>
|
||||
<?php require_once 'includes/footer.php'; ?>
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
|
||||
// Check if user has view permission
|
||||
if (!canView()) {
|
||||
// If they can't even view, they shouldn't be here, but header.php already handles basic login.
|
||||
if (!isLoggedIn()) {
|
||||
redirect('login.php');
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
@ -16,42 +16,61 @@ $stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE assigned_to = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$my_total_assignments = $stmt->fetchColumn();
|
||||
|
||||
$stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE assigned_to = ? AND status != 'closed'");
|
||||
$stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE assigned_to = ? AND status_id IN (SELECT id FROM mailbox_statuses WHERE name != 'closed')");
|
||||
$stmt->execute([$user_id]);
|
||||
$my_pending_tasks = $stmt->fetchColumn();
|
||||
|
||||
// Global Stats (for Clerks or if we want to show them)
|
||||
$total_inbound = db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'inbound'")->fetchColumn();
|
||||
$total_outbound = db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'outbound'")->fetchColumn();
|
||||
$total_inbound = canView('inbound') ? db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'inbound'")->fetchColumn() : 0;
|
||||
$total_outbound = canView('outbound') ? db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'outbound'")->fetchColumn() : 0;
|
||||
|
||||
// Fetch statuses for badge and count
|
||||
$statuses_data = db()->query("SELECT * FROM mailbox_statuses")->fetchAll(PDO::FETCH_UNIQUE);
|
||||
|
||||
// My Assignments
|
||||
$my_assignments = db()->prepare("SELECT m.*, s.name as status_name, s.color as status_color
|
||||
FROM mailbox m
|
||||
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
||||
WHERE m.assigned_to = ?
|
||||
ORDER BY m.created_at DESC LIMIT 10");
|
||||
$my_assignments->execute([$user_id]);
|
||||
$my_assignments = $my_assignments->fetchAll();
|
||||
$my_assignments = [];
|
||||
$assignment_types = [];
|
||||
if (canView('inbound')) $assignment_types[] = "'inbound'";
|
||||
if (canView('outbound')) $assignment_types[] = "'outbound'";
|
||||
if (canView('internal')) $assignment_types[] = "'internal'";
|
||||
|
||||
if (!empty($assignment_types)) {
|
||||
$types_sql = implode(',', $assignment_types);
|
||||
$my_assignments = db()->prepare("SELECT m.*, s.name as status_name, s.color as status_color
|
||||
FROM mailbox m
|
||||
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
||||
WHERE m.assigned_to = ? AND m.type IN ($types_sql)
|
||||
ORDER BY m.created_at DESC LIMIT 10");
|
||||
$my_assignments->execute([$user_id]);
|
||||
$my_assignments = $my_assignments->fetchAll();
|
||||
}
|
||||
|
||||
// Recent Activity
|
||||
$recent_query = "SELECT m.*, s.name as status_name, s.color as status_color, u.full_name as assigned_to_name
|
||||
FROM mailbox m
|
||||
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
||||
LEFT JOIN users u ON m.assigned_to = u.id";
|
||||
$recent_activity = [];
|
||||
$recent_types = [];
|
||||
if (canView('inbound')) $recent_types[] = "'inbound'";
|
||||
if (canView('outbound')) $recent_types[] = "'outbound'";
|
||||
if (canView('internal')) $recent_types[] = "'internal'";
|
||||
|
||||
if ($is_admin || $is_clerk) {
|
||||
// Admins and Clerks see all recent activity EXCEPT internal mail they are not part of
|
||||
$recent_stmt = db()->prepare($recent_query . " WHERE m.type != 'internal' OR m.assigned_to = ? OR m.created_by = ? ORDER BY m.updated_at DESC LIMIT 10");
|
||||
$recent_stmt->execute([$user_id, $user_id]);
|
||||
} else {
|
||||
// Staff see only theirs
|
||||
$recent_stmt = db()->prepare($recent_query . " WHERE m.assigned_to = ? OR m.created_by = ? ORDER BY m.updated_at DESC LIMIT 10");
|
||||
$recent_stmt->execute([$user_id, $user_id]);
|
||||
if (!empty($recent_types)) {
|
||||
$types_sql = implode(',', $recent_types);
|
||||
$recent_query = "SELECT m.*, s.name as status_name, s.color as status_color, u.full_name as assigned_to_name
|
||||
FROM mailbox m
|
||||
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
||||
LEFT JOIN users u ON m.assigned_to = u.id
|
||||
WHERE m.type IN ($types_sql)";
|
||||
|
||||
if ($is_admin || $is_clerk) {
|
||||
// Admins and Clerks see all recent activity EXCEPT internal mail they are not part of
|
||||
$recent_stmt = db()->prepare($recent_query . " AND (m.type != 'internal' OR m.assigned_to = ? OR m.created_by = ?) ORDER BY m.updated_at DESC LIMIT 10");
|
||||
$recent_stmt->execute([$user_id, $user_id]);
|
||||
} else {
|
||||
// Staff see only theirs
|
||||
$recent_stmt = db()->prepare($recent_query . " AND (m.assigned_to = ? OR m.created_by = ?) ORDER BY m.updated_at DESC LIMIT 10");
|
||||
$recent_stmt->execute([$user_id, $user_id]);
|
||||
}
|
||||
$recent_activity = $recent_stmt->fetchAll();
|
||||
}
|
||||
$recent_activity = $recent_stmt->fetchAll();
|
||||
|
||||
function getStatusBadge($mail) {
|
||||
$status_name = $mail['status_name'] ?? 'غير معروف';
|
||||
@ -74,7 +93,7 @@ function getStatusBadge($mail) {
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center position-relative">
|
||||
<div>
|
||||
<h2 class="fw-bold mb-1">مرحباً، <?= htmlspecialchars($current_user['full_name'] ?? $_SESSION['username']) ?>!</h2>
|
||||
<h2 class="fw-bold mb-1">مرحباً، <?= htmlspecialchars($current_user['full_name'] ?? $_SESSION['name']) ?>!</h2>
|
||||
<p class="mb-0 opacity-75">
|
||||
أنت مسجل كـ <strong>
|
||||
<?php
|
||||
@ -135,6 +154,7 @@ function getStatusBadge($mail) {
|
||||
|
||||
<?php if ($is_admin || $is_clerk): ?>
|
||||
<!-- Admin/Clerk specific stats -->
|
||||
<?php if (canView('inbound')): ?>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 p-3 shadow-sm border-0 border-start border-info border-4">
|
||||
<div class="d-flex align-items-center">
|
||||
@ -148,6 +168,8 @@ function getStatusBadge($mail) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (canView('outbound')): ?>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 p-3 shadow-sm border-0 border-start border-success border-4">
|
||||
<div class="d-flex align-items-center">
|
||||
@ -161,6 +183,7 @@ function getStatusBadge($mail) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<!-- Staff specific stats -->
|
||||
<div class="col-md-3">
|
||||
@ -198,6 +221,7 @@ function getStatusBadge($mail) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
@ -208,8 +232,10 @@ function getStatusBadge($mail) {
|
||||
<div class="card-header bg-white py-3 border-bottom d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0 fw-bold"><i class="fas fa-clipboard-list me-2 text-primary"></i> مهامي المسندة</h5>
|
||||
<div class="btn-group">
|
||||
<?php if (canAdd()): ?>
|
||||
<?php if (canAdd('inbound')): ?>
|
||||
<a href="inbound.php?action=add" class="btn btn-sm btn-outline-primary">إضافة وارد</a>
|
||||
<?php endif; ?>
|
||||
<?php if (canAdd('outbound')): ?>
|
||||
<a href="outbound.php" class="btn btn-sm btn-outline-success">إضافة صادر</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@ -227,7 +253,7 @@ function getStatusBadge($mail) {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if ($my_assignments): ?>
|
||||
<?php if (!empty($my_assignments)): ?>
|
||||
<?php foreach ($my_assignments as $mail): ?>
|
||||
<tr style="cursor: pointer;" onclick="window.location='view_mail.php?id=<?= $mail['id'] ?>'">
|
||||
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
||||
@ -270,7 +296,7 @@ function getStatusBadge($mail) {
|
||||
</div>
|
||||
<div class="card-body p-0" style="max-height: 500px; overflow-y: auto;">
|
||||
<div class="list-group list-group-flush">
|
||||
<?php if ($recent_activity): ?>
|
||||
<?php if (!empty($recent_activity)): ?>
|
||||
<?php foreach ($recent_activity as $act): ?>
|
||||
<a href="view_mail.php?id=<?= $act['id'] ?>" class="list-group-item list-group-item-action p-3 border-0 border-bottom">
|
||||
<div class="d-flex w-100 justify-content-between mb-1">
|
||||
@ -294,10 +320,12 @@ function getStatusBadge($mail) {
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-light text-center py-2">
|
||||
<?php if (canView('inbound')): ?>
|
||||
<a href="inbound.php" class="small text-decoration-none">عرض كافة المراسلات <i class="fas fa-chevron-left ms-1"></i></a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
290
users.php
290
users.php
@ -1,13 +1,22 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
|
||||
if (!isAdmin()) {
|
||||
if (!canView('users')) {
|
||||
redirect('index.php');
|
||||
}
|
||||
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
$modules = [
|
||||
'inbound' => 'البريد الوارد',
|
||||
'outbound' => 'البريد الصادر',
|
||||
'internal' => 'البريد الداخلي',
|
||||
'users' => 'إدارة المستخدمين',
|
||||
'settings' => 'الإعدادات',
|
||||
'reports' => 'التقارير'
|
||||
];
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$action = $_POST['action'] ?? '';
|
||||
$username = $_POST['username'] ?? '';
|
||||
@ -16,21 +25,39 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$password = $_POST['password'] ?? '';
|
||||
$id = $_POST['id'] ?? 0;
|
||||
|
||||
// Permissions
|
||||
$can_view = isset($_POST['can_view']) ? 1 : 0;
|
||||
$can_add = isset($_POST['can_add']) ? 1 : 0;
|
||||
$can_edit = isset($_POST['can_edit']) ? 1 : 0;
|
||||
$can_delete = isset($_POST['can_delete']) ? 1 : 0;
|
||||
// Global permissions (legacy/fallback)
|
||||
$can_view = isset($_POST['can_view_global']) ? 1 : 0;
|
||||
$can_add = isset($_POST['can_add_global']) ? 1 : 0;
|
||||
$can_edit = isset($_POST['can_edit_global']) ? 1 : 0;
|
||||
$can_delete = isset($_POST['can_delete_global']) ? 1 : 0;
|
||||
|
||||
if ($action === 'add') {
|
||||
if (!canAdd('users')) redirect('users.php');
|
||||
if ($username && $password && $full_name) {
|
||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
try {
|
||||
$stmt = db()->prepare("INSERT INTO users (username, password, full_name, role, can_view, can_add, can_edit, can_delete) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$pdo = db();
|
||||
$pdo->beginTransaction();
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO users (username, password, full_name, role, can_view, can_add, can_edit, can_delete) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$username, $hashed_password, $full_name, $role, $can_view, $can_add, $can_edit, $can_delete]);
|
||||
$user_id = $pdo->lastInsertId();
|
||||
|
||||
// Save page permissions
|
||||
$perm_stmt = $pdo->prepare("INSERT INTO user_permissions (user_id, page, can_view, can_add, can_edit, can_delete) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
foreach ($modules as $module => $label) {
|
||||
$m_view = isset($_POST["perm_{$module}_view"]) ? 1 : 0;
|
||||
$m_add = isset($_POST["perm_{$module}_add"]) ? 1 : 0;
|
||||
$m_edit = isset($_POST["perm_{$module}_edit"]) ? 1 : 0;
|
||||
$m_delete = isset($_POST["perm_{$module}_delete"]) ? 1 : 0;
|
||||
$perm_stmt->execute([$user_id, $module, $m_view, $m_add, $m_edit, $m_delete]);
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
$_SESSION['success'] = 'تم إضافة المستخدم بنجاح';
|
||||
redirect('users.php');
|
||||
} catch (PDOException $e) {
|
||||
if (isset($pdo)) $pdo->rollBack();
|
||||
if ($e->getCode() == 23000) {
|
||||
$error = 'اسم المستخدم موجود مسبقاً';
|
||||
} else {
|
||||
@ -41,19 +68,43 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$error = 'يرجى ملء جميع الحقول المطلوبة';
|
||||
}
|
||||
} elseif ($action === 'edit') {
|
||||
if (!canEdit('users')) redirect('users.php');
|
||||
if ($username && $full_name && $id) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$pdo->beginTransaction();
|
||||
|
||||
if ($password) {
|
||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$stmt = db()->prepare("UPDATE users SET username = ?, full_name = ?, role = ?, password = ?, can_view = ?, can_add = ?, can_edit = ?, can_delete = ? WHERE id = ?");
|
||||
$stmt = $pdo->prepare("UPDATE users SET username = ?, full_name = ?, role = ?, password = ?, can_view = ?, can_add = ?, can_edit = ?, can_delete = ? WHERE id = ?");
|
||||
$stmt->execute([$username, $full_name, $role, $hashed_password, $can_view, $can_add, $can_edit, $can_delete, $id]);
|
||||
} else {
|
||||
$stmt = db()->prepare("UPDATE users SET username = ?, full_name = ?, role = ?, can_view = ?, can_add = ?, can_edit = ?, can_delete = ? WHERE id = ?");
|
||||
$stmt = $pdo->prepare("UPDATE users SET username = ?, full_name = ?, role = ?, can_view = ?, can_add = ?, can_edit = ?, can_delete = ? WHERE id = ?");
|
||||
$stmt->execute([$username, $full_name, $role, $can_view, $can_add, $can_edit, $can_delete, $id]);
|
||||
}
|
||||
|
||||
// Update page permissions
|
||||
$pdo->prepare("DELETE FROM user_permissions WHERE user_id = ?")->execute([$id]);
|
||||
$perm_stmt = $pdo->prepare("INSERT INTO user_permissions (user_id, page, can_view, can_add, can_edit, can_delete) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
foreach ($modules as $module => $label) {
|
||||
$m_view = isset($_POST["perm_{$module}_view"]) ? 1 : 0;
|
||||
$m_add = isset($_POST["perm_{$module}_add"]) ? 1 : 0;
|
||||
$m_edit = isset($_POST["perm_{$module}_edit"]) ? 1 : 0;
|
||||
$m_delete = isset($_POST["perm_{$module}_delete"]) ? 1 : 0;
|
||||
$perm_stmt->execute([$id, $module, $m_view, $m_add, $m_edit, $m_delete]);
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
// Refresh own session if editing self
|
||||
if ($id == $_SESSION['user_id']) {
|
||||
unset($_SESSION['permissions']);
|
||||
}
|
||||
|
||||
$_SESSION['success'] = 'تم تحديث بيانات المستخدم بنجاح';
|
||||
redirect('users.php');
|
||||
} catch (PDOException $e) {
|
||||
if (isset($pdo)) $pdo->rollBack();
|
||||
$error = 'حدث خطأ: ' . $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
@ -63,6 +114,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id'])) {
|
||||
if (!canDelete('users')) redirect('users.php');
|
||||
if ($_GET['id'] != $_SESSION['user_id']) {
|
||||
$stmt = db()->prepare("DELETE FROM users WHERE id = ?");
|
||||
$stmt->execute([$_GET['id']]);
|
||||
@ -86,20 +138,32 @@ if (isset($_SESSION['error'])) {
|
||||
$stmt = db()->query("SELECT * FROM users ORDER BY created_at DESC");
|
||||
$users = $stmt->fetchAll();
|
||||
|
||||
// Fetch permissions for all users
|
||||
$user_perms = [];
|
||||
$perm_stmt = db()->query("SELECT * FROM user_permissions");
|
||||
while ($row = $perm_stmt->fetch()) {
|
||||
$user_perms[$row['user_id']][$row['page']] = $row;
|
||||
}
|
||||
|
||||
// Handle Deep Link for Edit
|
||||
$deepLinkData = null;
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id'])) {
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$_GET['id']]);
|
||||
$deepLinkData = $stmt->fetch();
|
||||
if ($deepLinkData) {
|
||||
$deepLinkData['page_permissions'] = $user_perms[$deepLinkData['id']] ?? [];
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">إدارة المستخدمين والصلاحيات</h1>
|
||||
<?php if (canAdd('users')): ?>
|
||||
<button type="button" class="btn btn-primary shadow-sm" onclick="openUserModal('add')">
|
||||
<i class="fas fa-user-plus me-1"></i> إضافة مستخدم جديد
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($success): ?>
|
||||
@ -125,7 +189,6 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
||||
<th class="ps-4">الاسم الكامل</th>
|
||||
<th>اسم المستخدم</th>
|
||||
<th>الدور</th>
|
||||
<th>الصلاحيات</th>
|
||||
<th>تاريخ الإنشاء</th>
|
||||
<th class="pe-4 text-center">الإجراءات</th>
|
||||
</tr>
|
||||
@ -144,21 +207,15 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
||||
<span class="badge bg-secondary">موظف</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex gap-1">
|
||||
<span class="badge <?= $user['can_view'] ? 'bg-success' : 'bg-light text-muted' ?>" title="عرض">ع</span>
|
||||
<span class="badge <?= $user['can_add'] ? 'bg-success' : 'bg-light text-muted' ?>" title="إضافة">إ</span>
|
||||
<span class="badge <?= $user['can_edit'] ? 'bg-success' : 'bg-light text-muted' ?>" title="تعديل">ت</span>
|
||||
<span class="badge <?= $user['can_delete'] ? 'bg-success' : 'bg-light text-muted' ?>" title="حذف">ح</span>
|
||||
</div>
|
||||
</td>
|
||||
<td><?= $user['created_at'] ?></td>
|
||||
<td class="pe-4 text-center">
|
||||
<?php if (canEdit('users')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary"
|
||||
onclick="openUserModal('edit', <?= htmlspecialchars(json_encode($user), ENT_QUOTES, 'UTF-8') ?>)">
|
||||
<i class="fas fa-edit"></i> تعديل
|
||||
onclick="openUserModal('edit', <?= htmlspecialchars(json_encode(array_merge($user, ['page_permissions' => $user_perms[$user['id']] ?? []])), ENT_QUOTES, 'UTF-8') ?>)">
|
||||
<i class="fas fa-edit"></i> تعديل الصلاحيات
|
||||
</button>
|
||||
<?php if ($user['id'] != $_SESSION['user_id']): ?>
|
||||
<?php endif; ?>
|
||||
<?php if (canDelete('users') && $user['id'] != $_SESSION['user_id']): ?>
|
||||
<a href="javascript:void(0)" onclick="confirmDelete(<?= $user['id'] ?>)" class="btn btn-sm btn-outline-danger">
|
||||
<i class="fas fa-trash"></i> حذف
|
||||
</a>
|
||||
@ -174,7 +231,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
||||
|
||||
<!-- User Modal -->
|
||||
<div class="modal fade" id="userModal" tabindex="-1" aria-labelledby="userModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title fw-bold" id="userModalLabel">إضافة مستخدم جديد</h5>
|
||||
@ -185,56 +242,74 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
||||
<input type="hidden" name="action" id="modalAction" value="add">
|
||||
<input type="hidden" name="id" id="modalId" value="0">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold">الاسم الكامل</label>
|
||||
<input type="text" name="full_name" id="modalFullName" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold">اسم المستخدم</label>
|
||||
<input type="text" name="username" id="modalUsername" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold">كلمة المرور <span id="pwdHint" class="text-muted small"></span></label>
|
||||
<input type="password" name="password" id="modalPassword" class="form-control">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold">الدور</label>
|
||||
<select name="role" id="modalRole" class="form-select" onchange="applyRolePresets(this.value)">
|
||||
<option value="staff">موظف</option>
|
||||
<option value="clerk">كاتب</option>
|
||||
<option value="admin">مدير</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold d-block">الصلاحيات</label>
|
||||
<div class="row g-2 bg-light p-3 rounded">
|
||||
<div class="col-6">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="can_view" id="permView" value="1">
|
||||
<label class="form-check-label" for="permView">عرض البيانات</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="can_add" id="permAdd" value="1">
|
||||
<label class="form-check-label" for="permAdd">إضافة سجلات</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="can_edit" id="permEdit" value="1">
|
||||
<label class="form-check-label" for="permEdit">تعديل سجلات</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="can_delete" id="permDelete" value="1">
|
||||
<label class="form-check-label" for="permDelete">حذف سجلات</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label fw-bold">الاسم الكامل</label>
|
||||
<input type="text" name="full_name" id="modalFullName" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label fw-bold">اسم المستخدم</label>
|
||||
<input type="text" name="username" id="modalUsername" class="form-control" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label fw-bold">كلمة المرور <span id="pwdHint" class="text-muted small"></span></label>
|
||||
<input type="password" name="password" id="modalPassword" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label fw-bold">الدور</label>
|
||||
<select name="role" id="modalRole" class="form-select" onchange="applyRolePresets(this.value)">
|
||||
<option value="staff">موظف</option>
|
||||
<option value="clerk">كاتب</option>
|
||||
<option value="admin">مدير</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h6 class="fw-bold mb-3"><i class="fas fa-lock me-2 text-primary"></i> صلاحيات الوصول لكل صفحة</h6>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-sm align-middle">
|
||||
<thead class="bg-light">
|
||||
<tr class="text-center">
|
||||
<th class="text-start ps-3">الصفحة / الموديول</th>
|
||||
<th>عرض</th>
|
||||
<th>إضافة</th>
|
||||
<th>تعديل</th>
|
||||
<th>حذف</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($modules as $key => $label): ?>
|
||||
<tr class="text-center">
|
||||
<td class="text-start ps-3 fw-bold"><?= $label ?></td>
|
||||
<td>
|
||||
<input class="form-check-input" type="checkbox" name="perm_<?= $key ?>_view" id="perm_<?= $key ?>_view" value="1">
|
||||
</td>
|
||||
<td>
|
||||
<input class="form-check-input" type="checkbox" name="perm_<?= $key ?>_add" id="perm_<?= $key ?>_add" value="1">
|
||||
</td>
|
||||
<td>
|
||||
<input class="form-check-input" type="checkbox" name="perm_<?= $key ?>_edit" id="perm_<?= $key ?>_edit" value="1">
|
||||
</td>
|
||||
<td>
|
||||
<input class="form-check-input" type="checkbox" name="perm_<?= $key ?>_delete" id="perm_<?= $key ?>_delete" value="1">
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Hidden legacy fields for backward compatibility if needed -->
|
||||
<input type="hidden" name="can_view_global" id="permViewGlobal" value="1">
|
||||
<input type="hidden" name="can_add_global" id="permAddGlobal" value="0">
|
||||
<input type="hidden" name="can_edit_global" id="permEditGlobal" value="0">
|
||||
<input type="hidden" name="can_delete_global" id="permDeleteGlobal" value="0">
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
||||
@ -247,22 +322,34 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
||||
|
||||
<script>
|
||||
let userModal;
|
||||
const modules = <?= json_encode(array_keys($modules)) ?>;
|
||||
|
||||
function applyRolePresets(role) {
|
||||
const view = document.getElementById('permView');
|
||||
const add = document.getElementById('permAdd');
|
||||
const edit = document.getElementById('permEdit');
|
||||
const del = document.getElementById('permDelete');
|
||||
|
||||
if (role === 'admin') {
|
||||
view.checked = add.checked = edit.checked = del.checked = true;
|
||||
} else if (role === 'clerk') {
|
||||
view.checked = add.checked = edit.checked = true;
|
||||
del.checked = false;
|
||||
} else {
|
||||
view.checked = true;
|
||||
add.checked = edit.checked = del.checked = false;
|
||||
}
|
||||
modules.forEach(m => {
|
||||
const view = document.getElementById(`perm_${m}_view`);
|
||||
const add = document.getElementById(`perm_${m}_add`);
|
||||
const edit = document.getElementById(`perm_${m}_edit`);
|
||||
const del = document.getElementById(`perm_${m}_delete`);
|
||||
|
||||
if (role === 'admin') {
|
||||
view.checked = add.checked = edit.checked = del.checked = true;
|
||||
} else if (role === 'clerk') {
|
||||
if (m === 'users' || m === 'settings') {
|
||||
view.checked = add.checked = edit.checked = del.checked = false;
|
||||
} else {
|
||||
view.checked = add.checked = edit.checked = true;
|
||||
del.checked = (m === 'reports' ? false : false);
|
||||
}
|
||||
} else {
|
||||
if (m === 'inbound' || m === 'outbound' || m === 'internal') {
|
||||
view.checked = true;
|
||||
add.checked = (m === 'internal'); // Staff can send internal mail
|
||||
edit.checked = del.checked = false;
|
||||
} else {
|
||||
view.checked = add.checked = edit.checked = del.checked = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openUserModal(action, data = null) {
|
||||
@ -287,13 +374,6 @@ function openUserModal(action, data = null) {
|
||||
username: document.getElementById('modalUsername'),
|
||||
role: document.getElementById('modalRole')
|
||||
};
|
||||
|
||||
const perms = {
|
||||
can_view: document.getElementById('permView'),
|
||||
can_add: document.getElementById('permAdd'),
|
||||
can_edit: document.getElementById('permEdit'),
|
||||
can_delete: document.getElementById('permDelete')
|
||||
};
|
||||
|
||||
modalAction.value = action;
|
||||
|
||||
@ -313,10 +393,13 @@ function openUserModal(action, data = null) {
|
||||
});
|
||||
|
||||
// Set permissions checkboxes
|
||||
perms.can_view.checked = data.can_view == 1;
|
||||
perms.can_add.checked = data.can_add == 1;
|
||||
perms.can_edit.checked = data.can_edit == 1;
|
||||
perms.can_delete.checked = data.can_delete == 1;
|
||||
modules.forEach(m => {
|
||||
const p = data.page_permissions && data.page_permissions[m] ? data.page_permissions[m] : {};
|
||||
document.getElementById(`perm_${m}_view`).checked = p.can_view == 1;
|
||||
document.getElementById(`perm_${m}_add`).checked = p.can_add == 1;
|
||||
document.getElementById(`perm_${m}_edit`).checked = p.can_edit == 1;
|
||||
document.getElementById(`perm_${m}_delete`).checked = p.can_delete == 1;
|
||||
});
|
||||
|
||||
modalPassword.required = false;
|
||||
pwdHint.textContent = '(اتركه فارغاً للحفاظ على كلمة المرور الحالية)';
|
||||
@ -328,18 +411,6 @@ function openUserModal(action, data = null) {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
<?php if ($deepLinkData): ?>
|
||||
openUserModal('edit', <?= json_encode($deepLinkData) ?>);
|
||||
<?php elseif ($error && isset($_POST['action'])): ?>
|
||||
const errorData = <?= json_encode([
|
||||
'id' => $_POST['id'] ?? 0,
|
||||
'username' => $_POST['username'] ?? '',
|
||||
'full_name' => $_POST['full_name'] ?? '',
|
||||
'role' => $_POST['role'] ?? 'staff',
|
||||
'can_view' => $_POST['can_view'] ?? 0,
|
||||
'can_add' => $_POST['can_add'] ?? 0,
|
||||
'can_edit' => $_POST['can_edit'] ?? 0,
|
||||
'can_delete' => $_POST['can_delete'] ?? 0
|
||||
]) ?>;
|
||||
openUserModal('<?= $_POST['action'] ?>', errorData);
|
||||
<?php elseif (isset($_GET['action']) && $_GET['action'] === 'add'): ?>
|
||||
openUserModal('add');
|
||||
<?php endif; ?>
|
||||
@ -381,6 +452,9 @@ function confirmDelete(id) {
|
||||
background-color: #198754;
|
||||
border-color: #198754;
|
||||
}
|
||||
.table-sm th, .table-sm td {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
@ -2,11 +2,6 @@
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
require_once __DIR__ . '/mail/MailService.php';
|
||||
|
||||
// Check if user has view permission
|
||||
if (!canView()) {
|
||||
redirect('index.php');
|
||||
}
|
||||
|
||||
$id = $_GET['id'] ?? 0;
|
||||
if (!$id) redirect('index.php');
|
||||
|
||||
@ -22,6 +17,11 @@ $mail = $stmt->fetch();
|
||||
|
||||
if (!$mail) redirect('index.php');
|
||||
|
||||
// Check if user has view permission for this mail type
|
||||
if (!canView($mail['type'])) {
|
||||
redirect('index.php');
|
||||
}
|
||||
|
||||
// Security check for internal mail: only sender or recipient can view
|
||||
// Even admins should only see their own internal mail for privacy
|
||||
if ($mail['type'] === 'internal') {
|
||||
@ -35,7 +35,8 @@ $error = '';
|
||||
|
||||
// Handle Comment submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_comment'])) {
|
||||
if (!canEdit() && $mail['type'] !== 'internal') {
|
||||
// For internal mail, users can always comment if involved. For others, check edit permission.
|
||||
if ($mail['type'] !== 'internal' && !canEdit($mail['type'])) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية لإضافة تعليقات';
|
||||
} else {
|
||||
$comment = $_POST['comment'] ?? '';
|
||||
@ -52,11 +53,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_comment'])) {
|
||||
$referred_user = $stmt_u->fetch();
|
||||
|
||||
if ($referred_user && !empty($referred_user['email'])) {
|
||||
$sender_name = $_SESSION['full_name'] ?? 'زميلك';
|
||||
$sender_name = $_SESSION['name'] ?? 'زميلك';
|
||||
$mail_subject = "إحالة بريد: " . $mail['subject'];
|
||||
$mail_link = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]" . dirname($_SERVER['PHP_SELF']) . "/view_mail.php?id=" . $id;
|
||||
|
||||
$html = "
|
||||
<div dir='rtl'>
|
||||
<h3>مرحباً " . htmlspecialchars($referred_user['full_name']) . "</h3>
|
||||
<p>قام <strong>" . htmlspecialchars($sender_name) . "</strong> بإحالة بريد إليك مع التعليق التالي:</p>
|
||||
<blockquote style='background: #f9f9f9; padding: 10px; border-left: 5px solid #ccc;'>
|
||||
@ -68,6 +70,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_comment'])) {
|
||||
<li><strong>الموضوع:</strong> " . htmlspecialchars($mail['subject']) . "</li>
|
||||
</ul>
|
||||
<p><a href='{$mail_link}' style='display: inline-block; padding: 10px 20px; background-color: #007bff; color: white; text-decoration: none; border-radius: 5px;'>عرض البريد</a></p>
|
||||
</div>
|
||||
";
|
||||
|
||||
$txt = "قام {$sender_name} بإحالة بريد إليك: {$mail['subject']}\n\nالتعليق: {$comment}\n\nعرض البريد: {$mail_link}";
|
||||
@ -84,7 +87,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_comment'])) {
|
||||
|
||||
// Handle Attachment upload
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['attachment'])) {
|
||||
if (!canEdit() && $mail['type'] !== 'internal') {
|
||||
if ($mail['type'] !== 'internal' && !canEdit($mail['type'])) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية لرفع مرفقات';
|
||||
} else {
|
||||
$file = $_FILES['attachment'];
|
||||
@ -110,7 +113,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['attachment'])) {
|
||||
|
||||
// Handle Attachment deletion
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_attachment'])) {
|
||||
if (!canDelete() && $mail['type'] !== 'internal') {
|
||||
if ($mail['type'] !== 'internal' && !canDelete($mail['type'])) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية لحذف المرفقات';
|
||||
} else {
|
||||
$attachment_id = $_POST['attachment_id'] ?? 0;
|
||||
@ -182,7 +185,7 @@ if ($mail['type'] == 'internal') {
|
||||
<h1 class="h2">تفاصيل <?= $type_label ?></h1>
|
||||
<div class="btn-group">
|
||||
<a href="<?= $back_link ?>" class="btn btn-outline-secondary">عودة للقائمة</a>
|
||||
<?php if (canEdit() && $mail['type'] !== 'internal'): ?>
|
||||
<?php if ($mail['type'] !== 'internal' && canEdit($mail['type'])): ?>
|
||||
<a href="<?= $mail['type'] ?>.php?action=edit&id=<?= $mail['id'] ?>" class="btn btn-outline-primary">تعديل البيانات</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@ -315,6 +318,7 @@ if ($mail['type'] == 'internal') {
|
||||
<h5 class="mb-0 fw-bold">الردود والمتابعة</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if ($mail['type'] === 'internal' || canEdit($mail['type'])): ?>
|
||||
<form method="POST" class="mb-4 bg-light p-3 rounded border">
|
||||
<div class="mb-2">
|
||||
<label class="form-label small fw-bold">إضافة <?= $mail['type'] == 'internal' ? 'رد' : 'تعليق' ?></label>
|
||||
@ -334,6 +338,7 @@ if ($mail['type'] == 'internal') {
|
||||
<?php endif; ?>
|
||||
<button type="submit" name="add_comment" class="btn btn-sm btn-primary">إرسال <?= $mail['type'] == 'internal' ? 'الرد' : 'التعليق' ?></button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="comment-list">
|
||||
<?php if ($mail_comments): foreach ($mail_comments as $c): ?>
|
||||
@ -366,6 +371,7 @@ if ($mail['type'] == 'internal') {
|
||||
<h5 class="mb-0 fw-bold">المرفقات</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if ($mail['type'] === 'internal' || canEdit($mail['type'])): ?>
|
||||
<form method="POST" enctype="multipart/form-data" class="mb-4">
|
||||
<div class="mb-2">
|
||||
<label class="form-label small mb-1">اسم المرفق (يظهر في القائمة)</label>
|
||||
@ -375,6 +381,7 @@ if ($mail['type'] == 'internal') {
|
||||
</div>
|
||||
<button type="submit" class="btn btn-sm btn-secondary w-100">رفع ملف</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="list-group list-group-flush">
|
||||
<?php if ($mail_attachments): foreach ($mail_attachments as $a): ?>
|
||||
@ -397,7 +404,7 @@ if ($mail['type'] == 'internal') {
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canDelete() || $mail['type'] == 'internal'): ?>
|
||||
<?php if ($mail['type'] == 'internal' || canDelete($mail['type'])): ?>
|
||||
<form method="POST" class="d-inline delete-attachment-form">
|
||||
<input type="hidden" name="attachment_id" value="<?= $a['id'] ?>">
|
||||
<input type="hidden" name="delete_attachment" value="1">
|
||||
@ -479,22 +486,28 @@ if ($mail['type'] == 'internal') {
|
||||
document.querySelectorAll('.delete-btn').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const form = this.closest('form');
|
||||
Swal.fire({
|
||||
title: 'هل أنت متأكد؟',
|
||||
text: "سيتم حذف المرفق نهائياً!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#d33',
|
||||
cancelButtonColor: '#3085d6',
|
||||
confirmButtonText: 'نعم، احذف',
|
||||
cancelButtonText: 'إلغاء'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
if (typeof Swal !== 'undefined') {
|
||||
Swal.fire({
|
||||
title: 'هل أنت متأكد؟',
|
||||
text: "سيتم حذف المرفق نهائياً!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#d33',
|
||||
cancelButtonColor: '#3085d6',
|
||||
confirmButtonText: 'نعم، احذف',
|
||||
cancelButtonText: 'إلغاء'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (confirm('هل أنت متأكد من الحذف؟')) {
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
Loading…
x
Reference in New Issue
Block a user