From faa58ad5eddf26d6241fdfe3c299567fbee4cf92 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Thu, 17 Dec 2015 18:21:47 +0100 Subject: [PATCH] (menu system) wrap menu / acl into api controller examples: display logged in user menu : /api/core/menu/tree search items (visitable by logged in user): /api/core/menu/search/?q=dhcpv6 --- .../OPNsense/Core/Api/MenuController.php | 229 ++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 src/opnsense/mvc/app/controllers/OPNsense/Core/Api/MenuController.php diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Core/Api/MenuController.php b/src/opnsense/mvc/app/controllers/OPNsense/Core/Api/MenuController.php new file mode 100644 index 000000000..66a80d00e --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Core/Api/MenuController.php @@ -0,0 +1,229 @@ +getItems() + * @param ACL $acl acl object reference + */ + private function applyACL(& $menuItems, & $acl) + { + foreach ($menuItems as &$menuItem) { + $menuItem->isVisible = false; + if (count($menuItem->Children) > 0) { + $this->applyACL($menuItem->Children, $acl); + foreach ($menuItem->Children as $subMenuItem) { + if ($subMenuItem->isVisible) { + $menuItem->isVisible = true; + break; + } + } + } else { + if (!$acl->isPageAccessible($this->username, $menuItem->Url)) { + $menuItem->isVisible = false; + } else { + $menuItem->isVisible = true; + } + } + } + } + + /** + * search visible name of menu nodes + * @param array $menuItems + * @param string $query query string + */ + private function search(& $menuItems, $query) + { + foreach ($menuItems as &$menuItem) { + if (stripos($menuItem->VisibleName, $query) !== false) { + // match on node + continue; + } elseif (count($menuItem->Children) > 0) { + $this->search($menuItem->Children, $query); + $menuItem->isVisible = false; + foreach ($menuItem->Children as $subMenuItem) { + if ($subMenuItem->isVisible) { + $menuItem->isVisible = true; + break; + } + } + } elseif ($menuItem->isVisible && stripos($menuItem->VisibleName, $query) === false) { + $menuItem->isVisible = false; + } + } + } + + /** + * request user context sensitive menu (items) + * @param string $selected_uri selected uri + * @return array menu items + */ + private function getMenu($selected_uri) + { + // construct menu and acl and merge collected info + $menu = new Menu\MenuSystem(); + $acl= new ACL(); + + // get username into context + if ($this->session->has("Username")) { + $this->username = $this->session->get("Username"); + } + + // add interfaces to "Interfaces" menu tab... kind of a hack, may need some improvement. + $cnf = Config::getInstance(); + + $ifarr = array(); + foreach ($cnf->object()->interfaces->children() as $key => $node) { + $ifarr[$key] = $node->descr ? $node->descr->__toString() : strtoupper($key); + } + natcasesort($ifarr); + $ordid = 0; + foreach ($ifarr as $key => $descr) { + $menu->appendItem('Interfaces', $key, array( + 'url' => '/interfaces.php?if='. $key, + 'visiblename' => '[' . $descr . ']', + 'cssclass' => 'fa fa-sitemap', + 'order' => $ordid++, + )); + } + unset($ifarr); + + // fetch menu items and apply acl + $menu_items = $menu->getItems($selected_uri); + $this->applyACL($menu_items, $acl); + return $menu_items; + } + + + /** + * flatten menu structure, only returning visible entries + * @param $menu_items array containing stdClass objects + * @return array tree containing simple types + */ + private function menuToArray($menu_items) + { + $result = array(); + foreach ($menu_items as $menu_item) { + if ($menu_item->isVisible) { + $new_item = (array) $menu_item; + $new_item['Children'] = array(); + if (count($menu_item->Children) > 0) { + $new_item['Children'] = $this->menuToArray($menu_item->Children); + } + $result[] = $new_item; + } + } + return $result; + } + + /** + * extract visitable leaves from collection of menu items + * @param array $menu_items + * @param array $items result + */ + private function extractMenuLeaves($menu_items, &$items) + { + foreach ($menu_items as $menu_item) { + if (!isset($menu_item->breadcrumb)) { + $menu_item->breadcrumb = $menu_item->VisibleName; + $menu_item->depth = 1; + } + if ($menu_item->isVisible) { + if (count($menu_item->Children) > 0) { + foreach ($menu_item->Children as &$submenu) { + $submenu->breadcrumb = $menu_item->breadcrumb . "/" . $submenu->VisibleName; + $submenu->depth = $menu_item->depth + 1; + } + $this->extractMenuLeaves($menu_item->Children, $items); + } + + // if Url contains wildcard, it's only meant to further define it's parent. + if (stripos($menu_item->Url, "*") === false) { + unset($menu_item->Children); + $items[] = $menu_item; + } + } + } + } + + /** + * return menu items for this user + * @return array + */ + public function treeAction() + { + $selected_uri = $this->request->get("uri", null, null); + $menu_items = $this->getMenu($selected_uri); + return $this->menuToArray($menu_items); + } + + /** + * search menu items + * @return array + */ + public function searchAction() + { + $menu_items = $this->getMenu(null); + $query = $this->request->get("q", null, null); + $this->search($menu_items, $query); + $items = array(); + $this->extractMenuLeaves($menu_items, $items); + return $items; + } +}