« Back to History
page_permissions_ui.php
|
20260721_154033.php
Initial Bulk Import
Copy Code
<?php // page_permissions_manage_noheader.php // Standalone, NO header.php include; only minimal HTML header // Minimal HTML HEADER, no external include ?><!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"> <title>Page Permissions</title> <link rel="stylesheet" href="/erp/public/assets/css/main.css?v=20250917"> <link rel="stylesheet" href="/erp/public/assets/css/bootstrap.min.css"> <script src="/erp/public/assets/js/bootstrap.bundle.min.js" defer></script> </head><body style="background:#f6f8fa"><?php // ------------------ DB BOOTSTRAP ------------------ require_once __DIR__ . '/core/db.php'; // must set $pdo require_once __DIR__ . '/modules/activity/activity_logger.php'; // Minimal auth_user if (!function_exists('auth_user')) { function auth_user() { if (!empty($_SESSION['user'])) return $_SESSION['user']; return null; } } if (session_status() !== PHP_SESSION_ACTIVE) session_start(); // ------------------ AUTH CHECK, NO REDIRECT ------------------ $u = null; if (function_exists('auth_user')) { try { $u = auth_user(); } catch (Throwable $e) { $u = null; } } if (!$u && !empty($_SESSION['user'])) $u = $_SESSION['user']; if (!$u || empty($u['id'])) { echo '<div style="max-width:900px;margin:40px auto;padding:22px;background:#fff;border-radius:8px;font-family:Arial">'; echo '<h3>Login required</h3>'; echo '<p>Please login to the ERP first. This page will not auto-redirect to avoid loops.</p>'; echo '<p><a href="/erp/login.php" class="btn btn-primary">Go to Login</a></p>'; echo '</div>'; echo "</body></html>"; exit; } $company_id = (int)($u['company_id'] ?? 0); $user_id = (int)($u['id'] ?? 0); $user_role = (string)($u['role'] ?? ''); $allowed_roles = ['Owner','Admin']; if (!in_array($user_role, $allowed_roles, true)) { echo '<div style="max-width:900px;margin:40px auto;padding:22px;background:#fff;border-radius:8px;font-family:Arial">'; echo '<h3>Forbidden</h3><p>Only Owner/Admin can manage page permissions.</p>'; echo '</div>'; echo "</body></html>"; exit; } try { $pdo->exec(" CREATE TABLE IF NOT EXISTS page_access_matrix ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, company_id INT UNSIGNED NOT NULL, employee_id INT UNSIGNED NOT NULL, page_id INT UNSIGNED NOT NULL, allowed TINYINT(1) NOT NULL DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uniq_access (company_id, employee_id, page_id), INDEX idx_company (company_id), INDEX idx_employee (employee_id), INDEX idx_page (page_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; "); } catch (Throwable $e) {} if (empty($_SESSION['ppm_csrf'])) $_SESSION['ppm_csrf'] = bin2hex(random_bytes(16)); $CSRF = $_SESSION['ppm_csrf']; // ------------ AJAX API --------------- if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['api'])) { header('Content-Type: application/json; charset=utf-8'); $inc = $_POST['csrf'] ?? ''; if (!hash_equals($_SESSION['ppm_csrf'], (string)$inc)) { echo json_encode(['ok'=>false,'msg'=>'CSRF']); exit; } $api = $_POST['api']; try { if ($api === 'list_pages') { $st = $pdo->prepare("SELECT id, COALESCE(title,'') AS title, COALESCE(url,'') AS url, COALESCE(slug,'') AS slug FROM nav_menu_items WHERE company_id IN (0,?) AND is_enabled=1 ORDER BY title ASC"); $st->execute([$company_id]); $rows = $st->fetchAll(PDO::FETCH_ASSOC); echo json_encode(['ok'=>true,'pages'=>$rows]); exit; } if ($api === 'list_employees') { $st = $pdo->prepare("SELECT id, COALESCE(name,'') AS name, COALESCE(mobile,'') AS mobile FROM company_employee_master WHERE company_id = ? ORDER BY name ASC"); $st->execute([$company_id]); $rows = $st->fetchAll(PDO::FETCH_ASSOC); echo json_encode(['ok'=>true,'employees'=>$rows]); exit; } if ($api === 'get_permission') { $emp = (int)($_POST['employee_id'] ?? 0); $page = (int)($_POST['page_id'] ?? 0); if (!$emp || !$page) echo json_encode(['ok'=>false,'msg'=>'invalid ids']); else { $st = $pdo->prepare("SELECT allowed FROM page_access_matrix WHERE company_id=? AND employee_id=? AND page_id=? LIMIT 1"); $st->execute([$company_id,$emp,$page]); $val = $st->fetchColumn(); $val = ($val === false) ? null : (int)$val; echo json_encode(['ok'=>true,'allowed'=>$val]); exit; } exit; } if ($api === 'save_permission') { $emp = (int)($_POST['employee_id'] ?? 0); $page = (int)($_POST['page_id'] ?? 0); $allowed = isset($_POST['allowed']) ? (int)$_POST['allowed'] : 0; if (!$emp || !$page) { echo json_encode(['ok'=>false,'msg'=>'invalid ids']); exit; } $pdo->beginTransaction(); $ins = $pdo->prepare("INSERT INTO page_access_matrix (company_id, employee_id, page_id, allowed) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE allowed = VALUES(allowed), updated_at = NOW()"); $ins->execute([$company_id,$emp,$page,$allowed]); $pdo->commit(); activity_log([ 'company_id' => $company_id, 'user_id' => $user_id, 'module' => 'page_permissions', 'action_name' => 'edit', 'entity_type' => 'page_access_matrix', 'entity_id' => $emp, 'remarks' => 'Updated page access matrix entry' ]); echo json_encode(['ok'=>true,'msg'=>'Saved']); exit; } echo json_encode(['ok'=>false,'msg'=>'unknown api']); exit; } catch (Throwable $e) { if ($pdo && $pdo->inTransaction()) $pdo->rollBack(); echo json_encode(['ok'=>false,'msg'=>$e->getMessage()]); exit; } } // ---------- HTML UI ---------- ?> <div style="max-width:980px;margin:28px auto;padding:20px;background:#fff;border-radius:10px;box-shadow:0 10px 30px rgba(0,0,0,.06);font-family:Arial"> <h2 style="margin:0 0 8px 0">Page Permissions — Company: <?= htmlspecialchars($company_id) ?></h2> <div style="color:#666;margin-bottom:14px">Logged: <?= htmlspecialchars($u['name'] ?? '') ?> (<?= htmlspecialchars($user_role) ?>)</div> <div style="display:flex;gap:12px;flex-wrap:wrap"> <div style="flex:1;min-width:260px"> <label style="display:block;font-weight:600;margin-bottom:6px">Select Page</label> <select id="page_select" style="width:100%;padding:10px;border:1px solid #ddd;border-radius:6px"> <option value="">-- select page --</option> </select> </div> <div style="flex:1;min-width:260px"> <label style="display:block;font-weight:600;margin-bottom:6px">Select Employee</label> <select id="emp_select" style="width:100%;padding:10px;border:1px solid #ddd;border-radius:6px"> <option value="">-- select employee --</option> </select> </div> <div style="width:160px"> <label style="display:block;font-weight:600;margin-bottom:6px">Access Allowed</label> <select id="access_select" style="width:100%;padding:10px;border:1px solid #ddd;border-radius:6px"> <option value="1">Yes</option> <option value="0">No</option> </select> </div> </div> <div style="margin-top:16px"> <button id="btn_save" style="background:#2fbe4a;color:#fff;border:0;padding:10px 14px;border-radius:8px;cursor:pointer">Save Permission</button> <button id="btn_refresh" style="margin-left:8px;padding:10px 12px;border-radius:8px;cursor:pointer">Refresh Lists</button> <span id="status" style="margin-left:12px;color:#28a745;display:none">Saved</span> </div> <div style="margin-top:18px;color:#666;font-size:14px"> Pages loaded from <code>nav_menu_items</code>. Employees from <code>company_employee_master</code>. </div> </div> <script> const CSRF = <?= json_encode($CSRF) ?>; async function apiPost(data) { const fd = new FormData(); for (const k in data) fd.append(k, data[k]); const res = await fetch(location.pathname, { method:'POST', body: fd }); return res.json(); } async function loadPages() { const sel = document.getElementById('page_select'); sel.innerHTML = '<option value="">-- loading pages --</option>'; const j = await apiPost({ api: 'list_pages', csrf: CSRF }); sel.innerHTML = '<option value="">-- select page --</option>'; if (j.ok && Array.isArray(j.pages)) { j.pages.forEach(p => { const opt = document.createElement('option'); opt.value = p.id; opt.textContent = (p.title || p.slug || p.url); sel.appendChild(opt); }); } else { sel.innerHTML = '<option value="">-- no pages --</option>'; console.error('pages load failed', j); } } async function loadEmployees() { const sel = document.getElementById('emp_select'); sel.innerHTML = '<option value="">-- loading employees --</option>'; const j = await apiPost({ api: 'list_employees', csrf: CSRF }); sel.innerHTML = '<option value="">-- select employee --</option>'; if (j.ok && Array.isArray(j.employees)) { j.employees.forEach(e => { const opt = document.createElement('option'); opt.value = e.id; opt.textContent = (e.name || ('#'+e.id)) + (e.mobile ? ' ('+e.mobile+')' : ''); sel.appendChild(opt); }); } else { sel.innerHTML = '<option value="">-- no employees --</option>'; console.error('employees load failed', j); } } async function loadPermissionIfReady() { const p = document.getElementById('page_select').value; const e = document.getElementById('emp_select').value; if (!p || !e) return; const j = await apiPost({ api: 'get_permission', csrf: CSRF, page_id: p, employee_id: e }); if (j.ok) { if (j.allowed === null) document.getElementById('access_select').value = '1'; else document.getElementById('access_select').value = String(j.allowed); } else { console.error('get_permission failed', j); } } document.getElementById('page_select').addEventListener('change', loadPermissionIfReady); document.getElementById('emp_select').addEventListener('change', loadPermissionIfReady); document.getElementById('btn_save').addEventListener('click', async () => { const p = document.getElementById('page_select').value; const e = document.getElementById('emp_select').value; const a = document.getElementById('access_select').value; if (!p) return alert('Select page'); if (!e) return alert('Select employee'); const j = await apiPost({ api: 'save_permission', csrf: CSRF, page_id: p, employee_id: e, allowed: a }); if (j.ok) { const s = document.getElementById('status'); s.style.display = 'inline-block'; s.textContent = 'Saved'; setTimeout(()=>s.style.display='none',1800); } else { alert('Save failed: '+(j.msg||'unknown')); } }); document.getElementById('btn_refresh').addEventListener('click', ()=>{ loadPages(); loadEmployees(); }); loadPages(); loadEmployees(); </script> <?php echo "</body></html>";