Commit faa58ad5 authored by Ad Schellevis's avatar Ad Schellevis

(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
parent 8ed4bd88
<?php
/**
* Copyright (C) 2015 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\Core\Api;
use OPNsense\Base\ApiControllerBase;
use OPNsense\Base\Menu;
use OPNsense\Core\ACL;
use OPNsense\Core\Config;
/**
* Class MenuController
* @package OPNsense\Core
*/
class MenuController extends ApiControllerBase
{
/**
* @var null|string username
*/
private $username = null;
/**
* before routing event
* @param Dispatcher $dispatcher
* @return null|bool
*/
public function beforeExecuteRoute($dispatcher)
{
// disable standard authorisation, output results are filtered for logged-in user
}
/**
* traverse menu items and mark user visibility (isVisible true/false)
* @param array $menuItems menuitems from menu->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;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment