false, 'error' => $msg], JSON_UNESCAPED_UNICODE); exit; } // Contexto HTML: página de error simple http_response_code($code); echo "

{$code}

" . htmlspecialchars($msg) . "

"; exit; } // ─── Utilidades de sesión ──────────────────────────────────────────────── public static function currentRole(): string { return $_SESSION['admin_user']['role'] ?? 'admin'; } public static function currentModules(): array { return $_SESSION['admin_user']['modules'] ?? []; } /** * Carga en sesión los permisos granulares (can_*) desde la BD. * Se llama desde authenticateUser() después de la Migración 001. */ public static function loadGranularPermissions(int $roleId): array { try { $db = Database::getInstance(); $rows = $db->fetchAll( "SELECT module_slug, can_view, can_create, can_edit, can_delete, can_export, extra_json FROM role_modules WHERE role_id = ?", [$roleId] ); $perms = []; foreach ($rows as $row) { $perms[$row['module_slug']] = [ 'can_view' => (bool) $row['can_view'], 'can_create' => (bool) $row['can_create'], 'can_edit' => (bool) $row['can_edit'], 'can_delete' => (bool) $row['can_delete'], 'can_export' => (bool) $row['can_export'], 'extra' => $row['extra_json'] ? json_decode($row['extra_json'], true) : [], ]; } return $perms; } catch (Exception $e) { error_log("[Rbac] Error cargando permisos: " . $e->getMessage()); return []; } } } // ─── Funciones globales de retrocompatibilidad ────────────────────────────── // Las vistas y APIs legacy que llaman hasModule(), isEnfermero(), etc. // siguen funcionando sin cambios apuntando a la clase Rbac. if (!function_exists('hasModule')) { function hasModule(string $slug): bool { return Rbac::hasModule($slug); } } if (!function_exists('canDo')) { function canDo(string $slug, string $action): bool { return Rbac::can($slug, $action); } }