Merge branch 'master' into feature/ipv6-addresses-9645-9826
This commit is contained in:
commit
2ff822c2ac
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
# namespace Icinga\Application\Controllers;
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Application\Version;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
|
||||
class AboutController extends ActionController
|
||||
{
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
# namespace Icinga\Application\Controllers;
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Forms\Authentication\LoginForm;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Url;
|
||||
|
@ -16,12 +14,15 @@ use Icinga\Web\Url;
|
|||
class AuthenticationController extends Controller
|
||||
{
|
||||
/**
|
||||
* This controller does not require authentication
|
||||
*
|
||||
* @var bool
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $requiresAuthentication = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $innerLayout = 'inline';
|
||||
|
||||
/**
|
||||
* Log into the application
|
||||
*/
|
||||
|
@ -36,6 +37,14 @@ class AuthenticationController extends Controller
|
|||
$this->redirectNow($form->getRedirectUrl());
|
||||
}
|
||||
if (! $requiresSetup) {
|
||||
if (! $this->getRequest()->hasCookieSupport()) {
|
||||
$this
|
||||
->getResponse()
|
||||
->setBody("Cookies must be enabled to run this application.\n")
|
||||
->setHttpResponseCode(403)
|
||||
->sendResponse();
|
||||
exit();
|
||||
}
|
||||
$form->handleRequest();
|
||||
}
|
||||
$this->view->form = $form;
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Modules\Module;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\Config\UserBackendConfigForm;
|
||||
use Icinga\Forms\Config\UserBackendReorderForm;
|
||||
use Icinga\Forms\Config\GeneralConfigForm;
|
||||
use Icinga\Forms\Config\ResourceConfigForm;
|
||||
use Icinga\Forms\Config\UserBackendConfigForm;
|
||||
use Icinga\Forms\Config\UserBackendReorderForm;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Security\SecurityException;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget;
|
||||
|
||||
/**
|
||||
|
@ -332,7 +335,7 @@ class ConfigController extends Controller
|
|||
public function resourceAction()
|
||||
{
|
||||
$this->assertPermission('config/application/resources');
|
||||
$this->view->resources = Config::app('resources', true)->keys();
|
||||
$this->view->resources = Config::app('resources', true);
|
||||
$this->createApplicationTabs()->activate('resource');
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Exception;
|
||||
use Zend_Controller_Action_Exception;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Forms\Dashboard\DashletForm;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget\Dashboard;
|
||||
use Icinga\Web\Widget\Tabextension\DashboardSettings;
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Icinga\Web\Response\JsonResponse;
|
||||
use Zend_Controller_Plugin_ErrorHandler;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\Http\HttpBadRequestException;
|
||||
use Icinga\Exception\Http\HttpMethodNotAllowedException;
|
||||
use Icinga\Exception\Http\HttpNotFoundException;
|
||||
use Icinga\Exception\MissingParameterException;
|
||||
|
@ -14,6 +19,9 @@ use Icinga\Web\Controller\ActionController;
|
|||
*/
|
||||
class ErrorController extends ActionController
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $requiresAuthentication = false;
|
||||
|
||||
/**
|
||||
|
@ -23,10 +31,14 @@ class ErrorController extends ActionController
|
|||
{
|
||||
$error = $this->_getParam('error_handler');
|
||||
$exception = $error->exception;
|
||||
|
||||
/** @var \Exception $exception */
|
||||
Logger::error($exception);
|
||||
Logger::error('Stacktrace: %s', $exception->getTraceAsString());
|
||||
|
||||
if (! ($isAuthenticated = $this->Auth()->isAuthenticated())) {
|
||||
$this->innerLayout = 'error';
|
||||
}
|
||||
|
||||
switch ($error->type) {
|
||||
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
|
||||
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
|
||||
|
@ -37,11 +49,13 @@ class ErrorController extends ActionController
|
|||
$path = array_shift($path);
|
||||
$this->getResponse()->setHttpResponseCode(404);
|
||||
$this->view->message = $this->translate('Page not found.');
|
||||
if ($this->Auth()->isAuthenticated() && $modules->hasInstalled($path) && ! $modules->hasEnabled($path)) {
|
||||
$this->view->message .= ' ' . sprintf(
|
||||
$this->translate('Enabling the "%s" module might help!'),
|
||||
$path
|
||||
);
|
||||
if ($isAuthenticated) {
|
||||
if ($modules->hasInstalled($path) && ! $modules->hasEnabled($path)) {
|
||||
$this->view->message .= ' ' . sprintf(
|
||||
$this->translate('Enabling the "%s" module might help!'),
|
||||
$path
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -61,6 +75,9 @@ class ErrorController extends ActionController
|
|||
'Missing parameter ' . $exception->getParameter()
|
||||
);
|
||||
break;
|
||||
case $exception instanceof HttpBadRequestException:
|
||||
$this->getResponse()->setHttpResponseCode(400);
|
||||
break;
|
||||
case $exception instanceof SecurityException:
|
||||
$this->getResponse()->setHttpResponseCode(403);
|
||||
break;
|
||||
|
@ -74,6 +91,14 @@ class ErrorController extends ActionController
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->getRequest()->isApiRequest()) {
|
||||
$this->getResponse()->json()
|
||||
->setErrorMessage($this->view->message)
|
||||
->sendResponse();
|
||||
}
|
||||
|
||||
$this->view->request = $error->request;
|
||||
$this->view->hideControls = ! $isAuthenticated;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Filter\Filter;
|
||||
use Icinga\Application\Logger;
|
||||
|
||||
/**
|
||||
* Application wide interface for filtering
|
||||
*/
|
||||
class FilterController extends ActionController
|
||||
{
|
||||
/**
|
||||
* The current filter registry
|
||||
*
|
||||
* @var Filter
|
||||
*/
|
||||
private $registry;
|
||||
|
||||
private $moduleRegistry;
|
||||
|
||||
/**
|
||||
* Entry point for filtering, uses the filter_domain and filter_module request parameter
|
||||
* to determine which filter registry should be used
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$this->registry = new Filter();
|
||||
$query = $this->getRequest()->getParam('query', '');
|
||||
$target = $this->getRequest()->getParam('filter_domain', '');
|
||||
|
||||
if ($this->getRequest()->getHeader('accept') == 'application/json') {
|
||||
$this->getResponse()->setHeader('Content-Type', 'application/json');
|
||||
$this->setupQueries(
|
||||
$target,
|
||||
$this->getParam('filter_module', '')
|
||||
);
|
||||
$this->_helper->json($this->parse($query, $target));
|
||||
} else {
|
||||
$this->setupQueries(
|
||||
$target,
|
||||
$this->getParam('filter_module')
|
||||
);
|
||||
$urlTarget = $this->parse($query, $target);
|
||||
$this->redirect($urlTarget['urlParam']);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the query handler for the given domain and module
|
||||
*
|
||||
* @param string $domain The domain to use
|
||||
* @param string $module The module to use
|
||||
*/
|
||||
private function setupQueries($domain, $module = 'default')
|
||||
{
|
||||
$class = '\\Icinga\\Module\\' . ucfirst($module) . '\\Filter\\Registry';
|
||||
$factory = strtolower($domain) . 'Filter';
|
||||
$this->moduleRegistry = $class;
|
||||
$this->registry->addDomain($class::$factory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given query text and returns the json as expected by the semantic search box
|
||||
*
|
||||
* @param String $text The query to parse
|
||||
* @return array The result structure to be returned in json format
|
||||
*/
|
||||
private function parse($text, $target)
|
||||
{
|
||||
try {
|
||||
|
||||
$queryTree = $this->registry->createQueryTreeForFilter($text);
|
||||
$registry = $this->moduleRegistry;
|
||||
return array(
|
||||
'state' => 'success',
|
||||
'proposals' => $this->registry->getProposalsForQuery($text),
|
||||
'urlParam' => $registry::getUrlForTarget($target, $queryTree),
|
||||
'valid' => count($this->registry->getIgnoredQueryParts()) === 0
|
||||
);
|
||||
} catch (\Exception $exc) {
|
||||
Logger::error($exc);
|
||||
$this->getResponse()->setHttpResponseCode(500);
|
||||
return array(
|
||||
'state' => 'error',
|
||||
'message' => 'Search service is currently not available'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\DataArray\ArrayDatasource;
|
||||
use Icinga\Data\Reducible;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\Reducible;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\Config\UserGroup\AddMemberForm;
|
||||
use Icinga\Forms\Config\UserGroup\UserGroupForm;
|
||||
|
@ -54,19 +57,12 @@ class GroupController extends AuthBackendController
|
|||
}
|
||||
|
||||
$query = $backend->select(array('group_name'));
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($query)
|
||||
->setSearchColumns(array('group', 'user'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$query->applyFilter($filterEditor->getFilter());
|
||||
$this->setupFilterControl($filterEditor);
|
||||
|
||||
$this->view->groups = $query;
|
||||
$this->view->backend = $backend;
|
||||
|
||||
$this->setupPaginationControl($query);
|
||||
$this->setupFilterControl($query);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
array(
|
||||
|
@ -101,15 +97,7 @@ class GroupController extends AuthBackendController
|
|||
->from('group_membership', array('user_name'))
|
||||
->where('group_name', $groupName);
|
||||
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($members)
|
||||
->setSearchColumns(array('user'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend', 'group')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$members->applyFilter($filterEditor->getFilter());
|
||||
|
||||
$this->setupFilterControl($filterEditor);
|
||||
$this->setupFilterControl($members, null, array('user'));
|
||||
$this->setupPaginationControl($members);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
|
@ -146,7 +134,7 @@ class GroupController extends AuthBackendController
|
|||
$removeForm->addElement('button', 'btn_submit', array(
|
||||
'escape' => false,
|
||||
'type' => 'submit',
|
||||
'class' => 'link-like',
|
||||
'class' => 'link-like spinner',
|
||||
'value' => 'btn_submit',
|
||||
'decorators' => array('ViewHelper'),
|
||||
'label' => $this->view->icon('trash'),
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
# namespace Icinga\Application\Controllers;
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Application\Benchmark;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
|
@ -18,6 +17,7 @@ class IndexController extends ActionController
|
|||
public function preDispatch()
|
||||
{
|
||||
if ($this->getRequest()->getActionName() !== 'welcome') {
|
||||
// @TODO(el): Avoid landing page redirects: https://dev.icinga.org/issues/9656
|
||||
$this->redirectNow(Url::fromRequest()->setPath('dashboard'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Web\MenuRenderer;
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Web\Hook;
|
||||
use Icinga\Web\Menu;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
* Create complex layout parts
|
||||
|
@ -19,9 +18,6 @@ class LayoutController extends ActionController
|
|||
{
|
||||
$this->setAutorefreshInterval(15);
|
||||
$this->_helper->layout()->disableLayout();
|
||||
|
||||
$url = Url::fromRequest();
|
||||
$menu = new MenuRenderer(Menu::load(), $url->getRelativeUrl());
|
||||
$this->view->menuRenderer = $menu->useCustomRenderer();
|
||||
$this->view->menuRenderer = Icinga::app()->getMenu()->getRenderer();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\ConfigObject;
|
||||
|
@ -11,8 +13,6 @@ use Icinga\Web\Widget\Tabextension\DashboardAction;
|
|||
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||
|
||||
/**
|
||||
* Class ListController
|
||||
*
|
||||
* Application wide controller for various listing actions
|
||||
*/
|
||||
class ListController extends Controller
|
||||
|
|
|
@ -0,0 +1,346 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Data\DataArray\ArrayDatasource;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Forms\Navigation\NavigationConfigForm;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
* Navigation configuration
|
||||
*/
|
||||
class NavigationController extends Controller
|
||||
{
|
||||
/**
|
||||
* The default item types provided by Icinga Web 2
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultItemTypes;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
$this->defaultItemTypes = array(
|
||||
'menu-item' => $this->translate('Menu Entry'),
|
||||
'dashlet' => 'Dashlet'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of available navigation item types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function listItemTypes()
|
||||
{
|
||||
$moduleManager = Icinga::app()->getModuleManager();
|
||||
|
||||
$types = $this->defaultItemTypes;
|
||||
foreach ($moduleManager->getLoadedModules() as $module) {
|
||||
if ($this->hasPermission($moduleManager::MODULE_PERMISSION_NS . $module->getName())) {
|
||||
$moduleTypes = $module->getNavigationItems();
|
||||
if (! empty($moduleTypes)) {
|
||||
$types = array_merge($types, $moduleTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the current user a list of his/her navigation items
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$user = $this->Auth()->getUser();
|
||||
|
||||
$ds = new ArrayDatasource(array_merge(
|
||||
Config::app('navigation')->select()->where('owner', $user->getUsername())->fetchAll(),
|
||||
iterator_to_array($user->loadNavigationConfig())
|
||||
));
|
||||
$ds->setKeyColumn('name');
|
||||
$query = $ds->select();
|
||||
|
||||
$this->view->types = $this->listItemTypes();
|
||||
$this->view->items = $query;
|
||||
|
||||
$this->getTabs()->add(
|
||||
'navigation',
|
||||
array(
|
||||
'title' => $this->translate('List and configure your own navigation items'),
|
||||
'label' => $this->translate('Navigation'),
|
||||
'url' => 'navigation'
|
||||
)
|
||||
)->activate('navigation');
|
||||
$this->setupSortControl(
|
||||
array(
|
||||
'type' => $this->translate('Type'),
|
||||
'owner' => $this->translate('Shared'),
|
||||
'name' => $this->translate('Shared Navigation')
|
||||
),
|
||||
$query
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* List all shared navigation items
|
||||
*/
|
||||
public function sharedAction()
|
||||
{
|
||||
$this->assertPermission('config/application/navigation');
|
||||
$config = Config::app('navigation');
|
||||
$config->getConfigObject()->setKeyColumn('name');
|
||||
$query = $config->select();
|
||||
|
||||
$removeForm = new Form();
|
||||
$removeForm->setUidDisabled();
|
||||
$removeForm->setAction(Url::fromPath('navigation/unshare'));
|
||||
$removeForm->addElement('hidden', 'name', array(
|
||||
'decorators' => array('ViewHelper')
|
||||
));
|
||||
$removeForm->addElement('hidden', 'redirect', array(
|
||||
'value' => Url::fromPath('navigation/shared'),
|
||||
'decorators' => array('ViewHelper')
|
||||
));
|
||||
$removeForm->addElement('button', 'btn_submit', array(
|
||||
'escape' => false,
|
||||
'type' => 'submit',
|
||||
'class' => 'link-like spinner',
|
||||
'value' => 'btn_submit',
|
||||
'decorators' => array('ViewHelper'),
|
||||
'label' => $this->view->icon('trash'),
|
||||
'title' => $this->translate('Unshare this navigation item')
|
||||
));
|
||||
|
||||
$this->view->removeForm = $removeForm;
|
||||
$this->view->types = $this->listItemTypes();
|
||||
$this->view->items = $query;
|
||||
|
||||
$this->getTabs()->add(
|
||||
'navigation/shared',
|
||||
array(
|
||||
'title' => $this->translate('List and configure shared navigation items'),
|
||||
'label' => $this->translate('Shared Navigation'),
|
||||
'url' => 'navigation/shared'
|
||||
)
|
||||
)->activate('navigation/shared');
|
||||
$this->setupSortControl(
|
||||
array(
|
||||
'type' => $this->translate('Type'),
|
||||
'owner' => $this->translate('Owner'),
|
||||
'name' => $this->translate('Shared Navigation')
|
||||
),
|
||||
$query
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a navigation item
|
||||
*/
|
||||
public function addAction()
|
||||
{
|
||||
$form = new NavigationConfigForm();
|
||||
$form->setRedirectUrl('navigation');
|
||||
$form->setItemTypes($this->listItemTypes());
|
||||
$form->setTitle($this->translate('Create New Navigation Item'));
|
||||
$form->addDescription($this->translate('Create a new navigation item, such as a menu entry or dashlet.'));
|
||||
$form->setUser($this->Auth()->getUser());
|
||||
$form->setShareConfig(Config::app('navigation'));
|
||||
$form->setOnSuccess(function (NavigationConfigForm $form) {
|
||||
$data = array_filter($form->getValues());
|
||||
|
||||
try {
|
||||
$form->add($data);
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($form->save()) {
|
||||
if (isset($data['type']) && $data['type'] === 'menu-item') {
|
||||
$form->getResponse()->setRerenderLayout();
|
||||
}
|
||||
|
||||
Notification::success(t('Navigation item successfully created'));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a navigation item
|
||||
*/
|
||||
public function editAction()
|
||||
{
|
||||
$itemName = $this->params->getRequired('name');
|
||||
$referrer = $this->params->get('referrer', 'index');
|
||||
|
||||
$form = new NavigationConfigForm();
|
||||
$form->setRedirectUrl($referrer === 'shared' ? 'navigation/shared' : 'navigation');
|
||||
$form->setItemTypes($this->listItemTypes());
|
||||
$form->setTitle(sprintf($this->translate('Edit Navigation Item %s'), $itemName));
|
||||
$form->setUser($this->Auth()->getUser());
|
||||
$form->setShareConfig(Config::app('navigation'));
|
||||
$form->setOnSuccess(function (NavigationConfigForm $form) use ($itemName) {
|
||||
$data = array_map(
|
||||
function ($v) {
|
||||
return $v !== '' ? $v : null;
|
||||
},
|
||||
$form->getValues()
|
||||
);
|
||||
|
||||
try {
|
||||
$form->edit($itemName, $data);
|
||||
} catch (NotFoundError $e) {
|
||||
throw $e;
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($form->save()) {
|
||||
if (isset($data['type']) && $data['type'] === 'menu-item') {
|
||||
$form->getResponse()->setRerenderLayout();
|
||||
}
|
||||
|
||||
Notification::success(sprintf(t('Navigation item "%s" successfully updated'), $itemName));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
try {
|
||||
$form->load($itemName);
|
||||
$form->handleRequest();
|
||||
} catch (NotFoundError $_) {
|
||||
$this->httpNotFound(sprintf($this->translate('Navigation item "%s" not found'), $itemName));
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a navigation item
|
||||
*/
|
||||
public function removeAction()
|
||||
{
|
||||
$itemName = $this->params->getRequired('name');
|
||||
|
||||
$navigationConfigForm = new NavigationConfigForm();
|
||||
$navigationConfigForm->setUser($this->Auth()->getUser());
|
||||
$navigationConfigForm->setShareConfig(Config::app('navigation'));
|
||||
$form = new ConfirmRemovalForm();
|
||||
$form->setRedirectUrl('navigation');
|
||||
$form->setTitle(sprintf($this->translate('Remove Navigation Item %s'), $itemName));
|
||||
$form->setOnSuccess(function (ConfirmRemovalForm $form) use ($itemName, $navigationConfigForm) {
|
||||
try {
|
||||
$itemConfig = $navigationConfigForm->delete($itemName);
|
||||
} catch (NotFoundError $e) {
|
||||
Notification::success(sprintf(t('Navigation Item "%s" not found. No action required'), $itemName));
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($navigationConfigForm->save()) {
|
||||
if ($itemConfig->type === 'menu-item') {
|
||||
$form->getResponse()->setRerenderLayout();
|
||||
}
|
||||
|
||||
Notification::success(sprintf(t('Navigation Item "%s" successfully removed'), $itemName));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshare a navigation item
|
||||
*/
|
||||
public function unshareAction()
|
||||
{
|
||||
$this->assertPermission('config/application/navigation');
|
||||
$this->assertHttpMethod('POST');
|
||||
|
||||
$navigationConfigForm = new NavigationConfigForm();
|
||||
$navigationConfigForm->setUser($this->Auth()->getUser());
|
||||
$navigationConfigForm->setShareConfig(Config::app('navigation'));
|
||||
|
||||
$form = new Form(array(
|
||||
'onSuccess' => function ($form) use ($navigationConfigForm) {
|
||||
$itemName = $form->getValue('name');
|
||||
|
||||
try {
|
||||
$newConfig = $navigationConfigForm->unshare($itemName);
|
||||
if ($navigationConfigForm->save()) {
|
||||
if ($newConfig->getSection($itemName)->type === 'menu-item') {
|
||||
$form->getResponse()->setRerenderLayout();
|
||||
}
|
||||
|
||||
Notification::success(sprintf(
|
||||
t('Navigation item "%s" has been unshared'),
|
||||
$form->getValue('name')
|
||||
));
|
||||
} else {
|
||||
// TODO: It failed obviously to write one of the configs, so we're leaving the user in
|
||||
// a inconsistent state. Luckily, it's nothing lost but possibly duplicated...
|
||||
Notification::error(sprintf(
|
||||
t('Failed to unshare navigation item "%s"'),
|
||||
$form->getValue('name')
|
||||
));
|
||||
}
|
||||
} catch (NotFoundError $e) {
|
||||
throw $e;
|
||||
} catch (Exception $e) {
|
||||
Notification::error($e->getMessage());
|
||||
}
|
||||
|
||||
$redirect = $form->getValue('redirect');
|
||||
if (! empty($redirect)) {
|
||||
$form->setRedirectUrl(htmlspecialchars_decode($redirect));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
));
|
||||
$form->setUidDisabled();
|
||||
$form->setSubmitLabel('btn_submit'); // Required to ensure that isSubmitted() is called
|
||||
$form->addElement('hidden', 'name', array('required' => true));
|
||||
$form->addElement('hidden', 'redirect');
|
||||
|
||||
try {
|
||||
$form->handleRequest();
|
||||
} catch (NotFoundError $_) {
|
||||
$this->httpNotFound(sprintf($this->translate('Navigation item "%s" not found'), $form->getValue('name')));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,20 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Forms\PreferenceForm;
|
||||
use Icinga\User\Preferences\PreferencesStore;
|
||||
use Icinga\Web\Controller\BasePreferenceController;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget\Tab;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Forms\PreferenceForm;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\User\Preferences\PreferencesStore;
|
||||
|
||||
/**
|
||||
* Application wide preference controller for user preferences
|
||||
*
|
||||
* @TODO(el): Rename to PreferencesController: https://dev.icinga.org/issues/10014
|
||||
*/
|
||||
class PreferenceController extends BasePreferenceController
|
||||
{
|
||||
|
@ -28,7 +32,7 @@ class PreferenceController extends BasePreferenceController
|
|||
array(
|
||||
'title' => t('Adjust the preferences of Icinga Web 2 according to your needs'),
|
||||
'label' => t('Preferences'),
|
||||
'url' => Url::fromPath('/preference')
|
||||
'url' => Url::fromPath('preference')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Exception\AlreadyExistsException;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Forms\Security\RoleForm;
|
||||
use Icinga\Web\Controller\AuthBackendController;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
/**
|
||||
* Manage user permissions and restrictions based on roles
|
||||
*
|
||||
* @TODO(el): Rename to RolesController: https://dev.icinga.org/issues/10015
|
||||
*/
|
||||
class RoleController extends AuthBackendController
|
||||
{
|
||||
/**
|
||||
|
@ -31,7 +40,7 @@ class RoleController extends AuthBackendController
|
|||
$values = $role->getValues();
|
||||
try {
|
||||
$role->add($name, $values);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
} catch (AlreadyExistsException $e) {
|
||||
$role->addError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
@ -54,19 +63,11 @@ class RoleController extends AuthBackendController
|
|||
|
||||
/**
|
||||
* Update a role
|
||||
*
|
||||
* @throws Zend_Controller_Action_Exception If the required parameter 'role' is missing or the role does not exist
|
||||
*/
|
||||
public function editAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/roles/edit');
|
||||
$name = $this->_request->getParam('role');
|
||||
if (empty($name)) {
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
sprintf($this->translate('Required parameter \'%s\' missing'), 'role'),
|
||||
400
|
||||
);
|
||||
}
|
||||
$name = $this->params->getRequired('role');
|
||||
$role = new RoleForm();
|
||||
$role->setTitle(sprintf($this->translate('Update Role %s'), $name));
|
||||
$role->setSubmitLabel($this->translate('Update Role'));
|
||||
|
@ -74,11 +75,8 @@ class RoleController extends AuthBackendController
|
|||
$role
|
||||
->setIniConfig(Config::app('roles', true))
|
||||
->load($name);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
$e->getMessage(),
|
||||
400
|
||||
);
|
||||
} catch (NotFoundError $e) {
|
||||
$this->httpNotFound($e->getMessage());
|
||||
}
|
||||
$role
|
||||
->setOnSuccess(function (RoleForm $role) use ($name) {
|
||||
|
@ -87,7 +85,7 @@ class RoleController extends AuthBackendController
|
|||
$values = $role->getValues();
|
||||
try {
|
||||
$role->update($name, $values, $oldName);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
} catch (NotFoundError $e) {
|
||||
$role->addError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
@ -105,35 +103,24 @@ class RoleController extends AuthBackendController
|
|||
|
||||
/**
|
||||
* Remove a role
|
||||
*
|
||||
* @throws Zend_Controller_Action_Exception If the required parameter 'role' is missing or the role does not exist
|
||||
*/
|
||||
public function removeAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/roles/remove');
|
||||
$name = $this->_request->getParam('role');
|
||||
if (empty($name)) {
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
sprintf($this->translate('Required parameter \'%s\' missing'), 'role'),
|
||||
400
|
||||
);
|
||||
}
|
||||
$name = $this->params->getRequired('role');
|
||||
$role = new RoleForm();
|
||||
try {
|
||||
$role
|
||||
->setIniConfig(Config::app('roles', true))
|
||||
->load($name);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
$e->getMessage(),
|
||||
400
|
||||
);
|
||||
} catch (NotFoundError $e) {
|
||||
$this->httpNotFound($e->getMessage());
|
||||
}
|
||||
$confirmation = new ConfirmRemovalForm(array(
|
||||
'onSuccess' => function (ConfirmRemovalForm $confirmation) use ($name, $role) {
|
||||
try {
|
||||
$role->remove($name);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
} catch (NotFoundError $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
@ -162,15 +149,15 @@ class RoleController extends AuthBackendController
|
|||
$tabs->add(
|
||||
'role/list',
|
||||
array(
|
||||
'title' => $this->translate(
|
||||
'baseTarget' => '_main',
|
||||
'label' => $this->translate('Roles'),
|
||||
'title' => $this->translate(
|
||||
'Configure roles to permit or restrict users and groups accessing Icinga Web 2'
|
||||
),
|
||||
'label' => $this->translate('Roles'),
|
||||
'url' => 'role/list',
|
||||
'baseTarget' => '_main'
|
||||
'url' => 'role/list'
|
||||
|
||||
)
|
||||
);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Web\Widget;
|
||||
use Icinga\Web\Widget\SearchDashboard;
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Web\FileCache;
|
||||
use Zend_Controller_Action_Exception as ActionException;
|
||||
use Icinga\Web\LessCompiler;
|
||||
|
||||
/**
|
||||
* Delivery static content to clients
|
||||
*/
|
||||
class StaticController extends ActionController
|
||||
class StaticController extends Controller
|
||||
{
|
||||
/**
|
||||
* Static routes don't require authentication
|
||||
|
@ -57,17 +59,15 @@ class StaticController extends ActionController
|
|||
*/
|
||||
public function imgAction()
|
||||
{
|
||||
// TODO(el): I think this action only retrieves images from modules
|
||||
$module = $this->_getParam('module_name');
|
||||
$file = $this->_getParam('file');
|
||||
$basedir = Icinga::app()->getModuleManager()->getModule($module)->getBaseDir();
|
||||
|
||||
$filePath = realpath($basedir . '/public/img/' . $file);
|
||||
|
||||
if (! $filePath || strpos($filePath, $basedir) !== 0) {
|
||||
throw new ActionException(sprintf(
|
||||
'%s does not exist',
|
||||
$filePath
|
||||
), 404);
|
||||
if ($filePath === false) {
|
||||
$this->httpNotFound('%s does not exist', $filePath);
|
||||
}
|
||||
if (preg_match('/\.([a-z]+)$/i', $file, $m)) {
|
||||
$extension = $m[1];
|
||||
|
@ -80,10 +80,7 @@ class StaticController extends ActionController
|
|||
header(sprintf('ETag: "%x-%x-%x"', $s['ino'], $s['size'], (float) str_pad($s['mtime'], 16, '0')));
|
||||
header('Cache-Control: public, max-age=3600');
|
||||
header('Pragma: cache');
|
||||
header('Last-Modified: ' . gmdate(
|
||||
'D, d M Y H:i:s',
|
||||
$s['mtime']
|
||||
) . ' GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $s['mtime']) . ' GMT');
|
||||
|
||||
readfile($filePath);
|
||||
}
|
||||
|
@ -100,7 +97,7 @@ class StaticController extends ActionController
|
|||
$basedir = Icinga::app()->getApplicationDir('../public/js/icinga/components/');
|
||||
$filePath = $basedir . $file;
|
||||
} else {
|
||||
if (!Icinga::app()->getModuleManager()->hasEnabled($module)) {
|
||||
if (! Icinga::app()->getModuleManager()->hasEnabled($module)) {
|
||||
Logger::error(
|
||||
'Non-existing frontend component "' . $module . '/' . $file
|
||||
. '" was requested. The module "' . $module . '" does not exist or is not active.'
|
||||
|
@ -112,7 +109,7 @@ class StaticController extends ActionController
|
|||
$filePath = $basedir . '/public/js/' . $file;
|
||||
}
|
||||
|
||||
if (!file_exists($filePath)) {
|
||||
if (! file_exists($filePath)) {
|
||||
Logger::error(
|
||||
'Non-existing frontend component "' . $module . '/' . $file
|
||||
. '" was requested, which would resolve to the the path: ' . $filePath
|
||||
|
@ -122,41 +119,41 @@ class StaticController extends ActionController
|
|||
}
|
||||
$response = $this->getResponse();
|
||||
$response->setHeader('Content-Type', 'text/javascript');
|
||||
$this->setCacheHeader(3600);
|
||||
$this->setCacheHeader();
|
||||
|
||||
$response->setHeader(
|
||||
'Last-Modified',
|
||||
gmdate(
|
||||
'D, d M Y H:i:s',
|
||||
filemtime($filePath)
|
||||
) . ' GMT'
|
||||
gmdate('D, d M Y H:i:s', filemtime($filePath)) . ' GMT'
|
||||
);
|
||||
|
||||
readfile($filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cache header for this response
|
||||
* Set cache header for the response
|
||||
*
|
||||
* @param integer $maxAge The maximum age to set
|
||||
* @param int $maxAge The maximum age to set
|
||||
*/
|
||||
private function setCacheHeader($maxAge)
|
||||
private function setCacheHeader($maxAge = 3600)
|
||||
{
|
||||
$this->_response->setHeader('Cache-Control', 'max-age=3600', true);
|
||||
$this->_response->setHeader('Pragma', 'cache', true);
|
||||
$this->_response->setHeader(
|
||||
'Expires',
|
||||
gmdate(
|
||||
'D, d M Y H:i:s',
|
||||
time()+3600
|
||||
) . ' GMT',
|
||||
true
|
||||
);
|
||||
$maxAge = (int) $maxAge;
|
||||
$this
|
||||
->getResponse()
|
||||
->setHeader('Cache-Control', sprintf('max-age=%d', $maxAge), true)
|
||||
->setHeader('Pragma', 'cache', true)
|
||||
->setHeader(
|
||||
'Expires',
|
||||
gmdate('D, d M Y H:i:s', time() + $maxAge) . ' GMT',
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send application's and modules' CSS
|
||||
*/
|
||||
public function stylesheetAction()
|
||||
{
|
||||
$lessCompiler = new \Icinga\Web\LessCompiler();
|
||||
$lessCompiler = new LessCompiler();
|
||||
$moduleManager = Icinga::app()->getModuleManager();
|
||||
|
||||
$publicDir = realpath(dirname($_SERVER['SCRIPT_FILENAME']));
|
||||
|
@ -172,7 +169,7 @@ class StaticController extends ActionController
|
|||
}
|
||||
}
|
||||
|
||||
$this->_response->setHeader('Content-Type', 'text/css');
|
||||
$this->getResponse()->setHeader('Content-Type', 'text/css');
|
||||
$this->setCacheHeader(3600);
|
||||
|
||||
$lessCompiler->printStack();
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\DataArray\ArrayDatasource;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\Config\User\CreateMembershipForm;
|
||||
use Icinga\Forms\Config\User\UserForm;
|
||||
use Icinga\Data\DataArray\ArrayDatasource;
|
||||
use Icinga\User;
|
||||
use Icinga\Web\Controller\AuthBackendController;
|
||||
use Icinga\Web\Form;
|
||||
|
@ -54,19 +57,12 @@ class UserController extends AuthBackendController
|
|||
}
|
||||
|
||||
$query = $backend->select(array('user_name'));
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($query)
|
||||
->setSearchColumns(array('user'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$query->applyFilter($filterEditor->getFilter());
|
||||
$this->setupFilterControl($filterEditor);
|
||||
|
||||
$this->view->users = $query;
|
||||
$this->view->backend = $backend;
|
||||
|
||||
$this->setupPaginationControl($query);
|
||||
$this->setupFilterControl($query);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
array(
|
||||
|
@ -100,15 +96,11 @@ class UserController extends AuthBackendController
|
|||
|
||||
$memberships = $this->loadMemberships(new User($userName))->select();
|
||||
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($memberships)
|
||||
->setSearchColumns(array('group_name'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend', 'user')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$memberships->applyFilter($filterEditor->getFilter());
|
||||
|
||||
$this->setupFilterControl($filterEditor);
|
||||
$this->setupFilterControl(
|
||||
$memberships,
|
||||
array('group_name' => t('User Group')),
|
||||
array('group_name')
|
||||
);
|
||||
$this->setupPaginationControl($memberships);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
|
@ -148,7 +140,7 @@ class UserController extends AuthBackendController
|
|||
$removeForm->addElement('button', 'btn_submit', array(
|
||||
'escape' => false,
|
||||
'type' => 'submit',
|
||||
'class' => 'link-like',
|
||||
'class' => 'link-like spinner',
|
||||
'value' => 'btn_submit',
|
||||
'decorators' => array('ViewHelper'),
|
||||
'label' => $this->view->icon('trash'),
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Forms\Config\UserGroup\UserGroupBackendForm;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
* Controller to configure user group backends
|
||||
|
@ -35,7 +37,7 @@ class UsergroupbackendController extends Controller
|
|||
*/
|
||||
public function listAction()
|
||||
{
|
||||
$this->view->backendNames = Config::app('groups')->keys();
|
||||
$this->view->backendNames = Config::app('groups');
|
||||
$this->createListTabs()->activate('usergroupbackend');
|
||||
}
|
||||
|
||||
|
|
|
@ -540,6 +540,12 @@
|
|||
"code": 59414,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "130380e481a7defc690dfb24123a1f0c",
|
||||
"css": "circle",
|
||||
"code": 59516,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "266d5d9adf15a61800477a5acf9a4462",
|
||||
"css": "chart-bar",
|
||||
|
@ -672,6 +678,12 @@
|
|||
"code": 59492,
|
||||
"src": "entypo"
|
||||
},
|
||||
{
|
||||
"uid": "p57wgnf4glngbchbucdi029iptu8oxb8",
|
||||
"css": "pin",
|
||||
"code": 59513,
|
||||
"src": "typicons"
|
||||
},
|
||||
{
|
||||
"uid": "c16a63e911bc47b46dc2a7129d2f0c46",
|
||||
"css": "down-small",
|
||||
|
|
|
@ -119,4 +119,6 @@
|
|||
.icon-down-small:before { content: '\e875'; } /* '' */
|
||||
.icon-left-small:before { content: '\e876'; } /* '' */
|
||||
.icon-right-small:before { content: '\e877'; } /* '' */
|
||||
.icon-up-small:before { content: '\e878'; } /* '' */
|
||||
.icon-up-small:before { content: '\e878'; } /* '' */
|
||||
.icon-pin:before { content: '\e879'; } /* '' */
|
||||
.icon-circle:before { content: '\e87c'; } /* '' */
|
File diff suppressed because one or more lines are too long
|
@ -119,4 +119,6 @@
|
|||
.icon-down-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-pin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-circle { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
|
@ -130,4 +130,6 @@
|
|||
.icon-down-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-pin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-circle { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
|
@ -1,10 +1,10 @@
|
|||
@font-face {
|
||||
font-family: 'ifont';
|
||||
src: url('../font/ifont.eot?54745533');
|
||||
src: url('../font/ifont.eot?54745533#iefix') format('embedded-opentype'),
|
||||
url('../font/ifont.woff?54745533') format('woff'),
|
||||
url('../font/ifont.ttf?54745533') format('truetype'),
|
||||
url('../font/ifont.svg?54745533#ifont') format('svg');
|
||||
src: url('../font/ifont.eot?82929165');
|
||||
src: url('../font/ifont.eot?82929165#iefix') format('embedded-opentype'),
|
||||
url('../font/ifont.woff?82929165') format('woff'),
|
||||
url('../font/ifont.ttf?82929165') format('truetype'),
|
||||
url('../font/ifont.svg?82929165#ifont') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
|||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
@font-face {
|
||||
font-family: 'ifont';
|
||||
src: url('../font/ifont.svg?54745533#ifont') format('svg');
|
||||
src: url('../font/ifont.svg?82929165#ifont') format('svg');
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -174,4 +174,6 @@
|
|||
.icon-down-small:before { content: '\e875'; } /* '' */
|
||||
.icon-left-small:before { content: '\e876'; } /* '' */
|
||||
.icon-right-small:before { content: '\e877'; } /* '' */
|
||||
.icon-up-small:before { content: '\e878'; } /* '' */
|
||||
.icon-up-small:before { content: '\e878'; } /* '' */
|
||||
.icon-pin:before { content: '\e879'; } /* '' */
|
||||
.icon-circle:before { content: '\e87c'; } /* '' */
|
|
@ -229,11 +229,11 @@ body {
|
|||
}
|
||||
@font-face {
|
||||
font-family: 'ifont';
|
||||
src: url('./font/ifont.eot?11424534');
|
||||
src: url('./font/ifont.eot?11424534#iefix') format('embedded-opentype'),
|
||||
url('./font/ifont.woff?11424534') format('woff'),
|
||||
url('./font/ifont.ttf?11424534') format('truetype'),
|
||||
url('./font/ifont.svg?11424534#ifont') format('svg');
|
||||
src: url('./font/ifont.eot?83291894');
|
||||
src: url('./font/ifont.eot?83291894#iefix') format('embedded-opentype'),
|
||||
url('./font/ifont.woff?83291894') format('woff'),
|
||||
url('./font/ifont.ttf?83291894') format('truetype'),
|
||||
url('./font/ifont.svg?83291894#ifont') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
@ -482,6 +482,8 @@ body {
|
|||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe878" class="the-icons span3"><i class="demo-icon icon-up-small"></i> <span class="i-name">icon-up-small</span><span class="i-code">0xe878</span></div>
|
||||
<div title="Code: 0xe879" class="the-icons span3"><i class="demo-icon icon-pin"></i> <span class="i-name">icon-pin</span><span class="i-code">0xe879</span></div>
|
||||
<div title="Code: 0xe87c" class="the-icons span3"><i class="demo-icon icon-circle"></i> <span class="i-name">icon-circle</span><span class="i-code">0xe87c</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></div>
|
||||
|
|
|
@ -27,6 +27,7 @@ class LoginForm extends Form
|
|||
$this->setRequiredCue(null);
|
||||
$this->setName('form_login');
|
||||
$this->setSubmitLabel($this->translate('Login'));
|
||||
$this->setProgressLabel($this->translate('Logging in'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,6 +25,20 @@ class ApplicationConfigForm extends Form
|
|||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'global_show_stacktraces',
|
||||
array(
|
||||
'required' => true,
|
||||
'value' => true,
|
||||
'label' => $this->translate('Show Stacktraces'),
|
||||
'description' => $this->translate(
|
||||
'Set whether to show an exception\'s stacktrace by default. This can also'
|
||||
. ' be set in a user\'s preferences with the appropriate permission.'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'global_module_path',
|
||||
|
|
|
@ -33,7 +33,23 @@ class DbResourceForm extends Form
|
|||
if (Platform::hasPostgresqlSupport()) {
|
||||
$dbChoices['pgsql'] = 'PostgreSQL';
|
||||
}
|
||||
|
||||
if (Platform::hasMssqlSupport()) {
|
||||
$dbChoices['mssql'] = 'MSSQL';
|
||||
}
|
||||
if (Platform::hasOracleSupport()) {
|
||||
$dbChoices['oracle'] = 'Oracle';
|
||||
}
|
||||
if (Platform::hasOciSupport()) {
|
||||
$dbChoices['oci'] = 'Oracle (OCI8)';
|
||||
}
|
||||
$offerPostgres = false;
|
||||
if (isset($formData['db'])) {
|
||||
if ($formData['db'] === 'pgsql') {
|
||||
$offerPostgres = true;
|
||||
}
|
||||
} elseif (key($dbChoices) === 'pgsql') {
|
||||
$offerPostgres = true;
|
||||
}
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
|
@ -68,11 +84,11 @@ class DbResourceForm extends Form
|
|||
'number',
|
||||
'port',
|
||||
array(
|
||||
'required' => true,
|
||||
'preserveDefault' => true,
|
||||
'label' => $this->translate('Port'),
|
||||
'description' => $this->translate('The port to use'),
|
||||
'value' => ! array_key_exists('db', $formData) || $formData['db'] === 'mysql' ? 3306 : 5432
|
||||
'label' => $this->translate('Port'),
|
||||
'preserveDefault' => true,
|
||||
'required' => $offerPostgres,
|
||||
'value' => $offerPostgres ? 5432 : null
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -103,6 +119,17 @@ class DbResourceForm extends Form
|
|||
'description' => $this->translate('The password to use for authentication')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'persistent',
|
||||
array(
|
||||
'description' => $this->translate(
|
||||
'Check this box for persistent database connections. Persistent connections are not closed at the'
|
||||
. ' end of a request, but are cached and re-used. This is experimental'
|
||||
),
|
||||
'label' => $this->translate('Persistent')
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
@ -81,22 +81,6 @@ class LdapResourceForm extends Form
|
|||
)
|
||||
);
|
||||
|
||||
if (isset($formData['encryption']) && $formData['encryption'] !== 'none') {
|
||||
// TODO(jom): Do not show this checkbox unless the connection is actually failing due to certificate errors
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'reqcert',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Require Certificate'),
|
||||
'description' => $this->translate(
|
||||
'When checked, the LDAP server must provide a valid and known (trusted) certificate.'
|
||||
),
|
||||
'value' => 1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'root_dn',
|
||||
|
|
|
@ -236,10 +236,10 @@ class ResourceConfigForm extends ConfigForm
|
|||
'livestatus' => 'Livestatus',
|
||||
'ssh' => $this->translate('SSH Identity'),
|
||||
);
|
||||
if ($resourceType === 'ldap' || Platform::extensionLoaded('ldap')) {
|
||||
if ($resourceType === 'ldap' || Platform::hasLdapSupport()) {
|
||||
$resourceTypes['ldap'] = 'LDAP';
|
||||
}
|
||||
if ($resourceType === 'db' || Platform::hasMysqlSupport() || Platform::hasPostgresqlSupport()) {
|
||||
if ($resourceType === 'db' || Platform::hasDatabaseSupport()) {
|
||||
$resourceTypes['db'] = $this->translate('SQL Database');
|
||||
}
|
||||
|
||||
|
@ -344,13 +344,27 @@ class ResourceConfigForm extends ConfigForm
|
|||
'submit',
|
||||
'resource_validation',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'decorators' => array('ViewHelper')
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'data-progress-label' => $this->translate('Validation In Progress'),
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
|
||||
$this->setAttrib('data-progress-element', 'resource-progress');
|
||||
$this->addElement(
|
||||
'note',
|
||||
'resource-progress',
|
||||
array(
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('Spinner', array('id' => 'resource-progress'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->addDisplayGroup(
|
||||
array('btn_submit', 'resource_validation'),
|
||||
array('btn_submit', 'resource_validation', 'resource-progress'),
|
||||
'submit_validation',
|
||||
array(
|
||||
'decorators' => array(
|
||||
|
|
|
@ -34,7 +34,7 @@ class UserForm extends RepositoryForm
|
|||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'password',
|
||||
'password',
|
||||
array(
|
||||
'required' => true,
|
||||
|
@ -56,10 +56,11 @@ class UserForm extends RepositoryForm
|
|||
$this->createInsertElements($formData);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'password',
|
||||
'password',
|
||||
array(
|
||||
'label' => $this->translate('Password')
|
||||
'description' => $this->translate('Leave empty for not updating the user\'s password'),
|
||||
'label' => $this->translate('Password'),
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -53,20 +53,6 @@ class DbBackendForm extends Form
|
|||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -32,20 +32,6 @@ class ExternalBackendForm extends Form
|
|||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The backend name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -57,20 +57,6 @@ class LdapBackendForm extends Form
|
|||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others.'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -464,9 +464,10 @@ class UserBackendConfigForm extends ConfigForm
|
|||
'submit',
|
||||
'backend_validation',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'decorators' => array('ViewHelper')
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'data-progress-label' => $this->translate('Validation In Progress'),
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
$this->addDisplayGroup(
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
namespace Icinga\Forms\Config;
|
||||
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Web\Notification;
|
||||
|
@ -28,6 +29,16 @@ class UserBackendReorderForm extends ConfigForm
|
|||
return $this->config->keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ordered backend configuration
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form
|
||||
*
|
||||
|
|
|
@ -34,20 +34,6 @@ class DbUserGroupBackendForm extends Form
|
|||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this user group backend that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -39,20 +39,6 @@ class LdapUserGroupBackendForm extends Form
|
|||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this user group backend that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -177,13 +163,25 @@ class LdapUserGroupBackendForm extends Form
|
|||
'preserveDefault' => true,
|
||||
'ignore' => $disabled,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP Group Name Attribute'),
|
||||
'label' => $this->translate('LDAP Group Name Attribute'),
|
||||
'description' => $this->translate(
|
||||
'The attribute name used for storing a group\'s name on the LDAP server.'
|
||||
),
|
||||
'value' => $defaults->group_name_attribute
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'group_member_attribute',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'ignore' => $disabled,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP Group Member Attribute'),
|
||||
'description' => $this->translate('The attribute name used for storing a group\'s members.'),
|
||||
'value' => $defaults->group_member_attribute
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'base_dn',
|
||||
|
@ -258,7 +256,7 @@ class LdapUserGroupBackendForm extends Form
|
|||
'preserveDefault' => true,
|
||||
'ignore' => $disabled,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP User Name Attribute'),
|
||||
'label' => $this->translate('LDAP User Name Attribute'),
|
||||
'description' => $this->translate(
|
||||
'The attribute name used for storing a user\'s name on the LDAP server.'
|
||||
),
|
||||
|
|
|
@ -43,7 +43,7 @@ class ConfigForm extends Form
|
|||
public function save()
|
||||
{
|
||||
try {
|
||||
$this->config->saveIni();
|
||||
$this->writeConfig($this->config);
|
||||
} catch (Exception $e) {
|
||||
$this->addDecorator('ViewScript', array(
|
||||
'viewModule' => 'default',
|
||||
|
@ -58,4 +58,14 @@ class ConfigForm extends Form
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the configuration to disk
|
||||
*
|
||||
* @param Config $config
|
||||
*/
|
||||
protected function writeConfig(Config $config)
|
||||
{
|
||||
$config->saveIni();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Navigation;
|
||||
|
||||
class DashletForm extends NavigationItemForm
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'pane',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Pane'),
|
||||
'description' => $this->translate('The name of the dashboard pane in which to display this dashlet')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'url',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Url'),
|
||||
'description' => $this->translate(
|
||||
'The url to load in the dashlet. For external urls, make sure to prepend'
|
||||
. ' an appropriate protocol identifier (e.g. http://example.tld)'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Navigation;
|
||||
|
||||
class MenuItemForm extends NavigationItemForm
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $requiresParentSelection = true;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
parent::createElements($formData);
|
||||
|
||||
// Remove _self and _next as for menu entries only _main is valid
|
||||
$this->getElement('target')->removeMultiOption('_self');
|
||||
$this->getElement('target')->removeMultiOption('_next');
|
||||
|
||||
$parentElement = $this->getParent()->getElement('parent');
|
||||
if ($parentElement !== null) {
|
||||
$parentElement->setDescription($this->translate(
|
||||
'The parent menu to assign this menu entry to. Select "None" to make this a main menu entry'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,824 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Navigation;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Authentication\Auth;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\User;
|
||||
use Icinga\Util\String;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form for managing navigation items
|
||||
*/
|
||||
class NavigationConfigForm extends ConfigForm
|
||||
{
|
||||
/**
|
||||
* The class namespace where to locate navigation type forms
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const FORM_NS = 'Forms\\Navigation';
|
||||
|
||||
/**
|
||||
* The secondary configuration to write
|
||||
*
|
||||
* This is always the reduced configuration and is only written to
|
||||
* disk once the main configuration has been successfully written.
|
||||
*
|
||||
* @var Config
|
||||
*/
|
||||
protected $secondaryConfig;
|
||||
|
||||
/**
|
||||
* The navigation item to load when displaying the form for the first time
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $itemToLoad;
|
||||
|
||||
/**
|
||||
* The user for whom to manage navigation items
|
||||
*
|
||||
* @var User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* The user's navigation configuration
|
||||
*
|
||||
* @var Config
|
||||
*/
|
||||
protected $userConfig;
|
||||
|
||||
/**
|
||||
* The shared navigation configuration
|
||||
*
|
||||
* @var Config
|
||||
*/
|
||||
protected $shareConfig;
|
||||
|
||||
/**
|
||||
* The available navigation item types
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $itemTypes;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_navigation');
|
||||
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user for whom to manage navigation items
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUser(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user for whom to manage navigation items
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user's navigation configuration
|
||||
*
|
||||
* @param Config $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUserConfig(Config $config)
|
||||
{
|
||||
$config->getConfigObject()->setKeyColumn('name');
|
||||
$this->userConfig = $config;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user's navigation configuration
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function getUserConfig()
|
||||
{
|
||||
if ($this->userConfig === null) {
|
||||
$this->setUserConfig($this->getUser()->loadNavigationConfig());
|
||||
}
|
||||
|
||||
return $this->userConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the shared navigation configuration
|
||||
*
|
||||
* @param Config $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setShareConfig(Config $config)
|
||||
{
|
||||
$config->getConfigObject()->setKeyColumn('name');
|
||||
$this->shareConfig = $config;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the shared navigation configuration
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function getShareConfig()
|
||||
{
|
||||
return $this->shareConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the available navigation item types
|
||||
*
|
||||
* @param array $itemTypes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setItemTypes(array $itemTypes)
|
||||
{
|
||||
$this->itemTypes = $itemTypes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the available navigation item types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getItemTypes()
|
||||
{
|
||||
return $this->itemTypes ?: array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of available parent items for the given type of navigation item
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $owner
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listAvailableParents($type, $owner = null)
|
||||
{
|
||||
$children = $this->itemToLoad ? $this->getFlattenedChildren($this->itemToLoad) : array();
|
||||
|
||||
$names = array();
|
||||
foreach ($this->getShareConfig() as $sectionName => $sectionConfig) {
|
||||
if (
|
||||
$sectionName !== $this->itemToLoad
|
||||
&& $sectionConfig->type === $type
|
||||
&& $sectionConfig->owner === ($owner ?: $this->getUser()->getUsername())
|
||||
&& !in_array($sectionName, $children, true)
|
||||
) {
|
||||
$names[] = $sectionName;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->getUserConfig() as $sectionName => $sectionConfig) {
|
||||
if (
|
||||
$sectionName !== $this->itemToLoad
|
||||
&& $sectionConfig->type === $type
|
||||
&& !in_array($sectionName, $children, true)
|
||||
) {
|
||||
$names[] = $sectionName;
|
||||
}
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively return all children of the given navigation item
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getFlattenedChildren($name)
|
||||
{
|
||||
$config = $this->getConfigForItem($name);
|
||||
if ($config === null) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$children = array();
|
||||
foreach ($config->toArray() as $sectionName => $sectionConfig) {
|
||||
if (isset($sectionConfig['parent']) && $sectionConfig['parent'] === $name) {
|
||||
$children[] = $sectionName;
|
||||
$children = array_merge($children, $this->getFlattenedChildren($sectionName));
|
||||
}
|
||||
}
|
||||
|
||||
return $children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the form with the given navigation item's config
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotFoundError In case no navigation item with the given name is found
|
||||
*/
|
||||
public function load($name)
|
||||
{
|
||||
if ($this->getConfigForItem($name) === null) {
|
||||
throw new NotFoundError('No navigation item called "%s" found', $name);
|
||||
}
|
||||
|
||||
$this->itemToLoad = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new navigation item
|
||||
*
|
||||
* The navigation item to add is identified by the array-key `name'.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException In case $data does not contain a navigation item name
|
||||
* @throws IcingaException In case a navigation item with the same name already exists
|
||||
*/
|
||||
public function add(array $data)
|
||||
{
|
||||
if (! isset($data['name'])) {
|
||||
throw new InvalidArgumentException('Key \'name\' missing');
|
||||
}
|
||||
|
||||
$shared = false;
|
||||
$config = $this->getUserConfig();
|
||||
if ((isset($data['users']) && $data['users']) || (isset($data['groups']) && $data['groups'])) {
|
||||
if ($this->getUser()->can('application/share/navigation')) {
|
||||
$data['owner'] = $this->getUser()->getUsername();
|
||||
$config = $this->getShareConfig();
|
||||
$shared = true;
|
||||
} else {
|
||||
unset($data['users']);
|
||||
unset($data['groups']);
|
||||
}
|
||||
} elseif (isset($data['parent']) && $data['parent'] && $this->hasBeenShared($data['parent'])) {
|
||||
$data['owner'] = $this->getUser()->getUsername();
|
||||
$config = $this->getShareConfig();
|
||||
$shared = true;
|
||||
}
|
||||
|
||||
$itemName = $data['name'];
|
||||
$exists = $config->hasSection($itemName);
|
||||
if (! $exists) {
|
||||
if ($shared) {
|
||||
$exists = $this->getUserConfig()->hasSection($itemName);
|
||||
} else {
|
||||
$exists = (bool) $this->getShareConfig()
|
||||
->select()
|
||||
->where('name', $itemName)
|
||||
->where('owner', $this->getUser()->getUsername())
|
||||
->count();
|
||||
}
|
||||
}
|
||||
|
||||
if ($exists) {
|
||||
throw new IcingaException(
|
||||
$this->translate('A navigation item with the name "%s" does already exist'),
|
||||
$itemName
|
||||
);
|
||||
}
|
||||
|
||||
unset($data['name']);
|
||||
$config->setSection($itemName, $data);
|
||||
$this->setIniConfig($config);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a navigation item
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotFoundError In case no navigation item with the given name is found
|
||||
* @throws IcingaException In case a navigation item with the same name already exists
|
||||
*/
|
||||
public function edit($name, array $data)
|
||||
{
|
||||
$config = $this->getConfigForItem($name);
|
||||
if ($config === null) {
|
||||
throw new NotFoundError('No navigation item called "%s" found', $name);
|
||||
} else {
|
||||
$itemConfig = $config->getSection($name);
|
||||
}
|
||||
|
||||
$shared = false;
|
||||
if ($this->hasBeenShared($name)) {
|
||||
if (isset($data['parent']) && $data['parent']
|
||||
? !$this->hasBeenShared($data['parent'])
|
||||
: ((! isset($data['users']) || !$data['users']) && (! isset($data['groups']) || !$data['groups']))
|
||||
) {
|
||||
// It is shared but shouldn't anymore
|
||||
$config = $this->unshare($name, isset($data['parent']) ? $data['parent'] : null);
|
||||
}
|
||||
} elseif ((isset($data['users']) && $data['users']) || (isset($data['groups']) && $data['groups'])) {
|
||||
if ($this->getUser()->can('application/share/navigation')) {
|
||||
// It is not shared yet but should be
|
||||
$this->secondaryConfig = $config;
|
||||
$config = $this->getShareConfig();
|
||||
$data['owner'] = $this->getUser()->getUsername();
|
||||
$shared = true;
|
||||
} else {
|
||||
unset($data['users']);
|
||||
unset($data['groups']);
|
||||
}
|
||||
} elseif (isset($data['parent']) && $data['parent'] && $this->hasBeenShared($data['parent'])) {
|
||||
// Its parent is shared so should it itself
|
||||
$this->secondaryConfig = $config;
|
||||
$config = $this->getShareConfig();
|
||||
$data['owner'] = $this->getUser()->getUsername();
|
||||
$shared = true;
|
||||
}
|
||||
|
||||
$oldName = null;
|
||||
if (isset($data['name'])) {
|
||||
if ($data['name'] !== $name) {
|
||||
$oldName = $name;
|
||||
$name = $data['name'];
|
||||
|
||||
$exists = $config->hasSection($name);
|
||||
if (! $exists) {
|
||||
$ownerName = $itemConfig->owner ?: $this->getUser()->getUsername();
|
||||
if ($shared || $this->hasBeenShared($oldName)) {
|
||||
if ($ownerName === $this->getUser()->getUsername()) {
|
||||
$exists = $this->getUserConfig()->hasSection($name);
|
||||
} else {
|
||||
$owner = new User($ownerName);
|
||||
$exists = $owner->loadNavigationConfig()->hasSection($name);
|
||||
}
|
||||
} else {
|
||||
$exists = (bool) $this->getShareConfig()
|
||||
->select()
|
||||
->where('name', $name)
|
||||
->where('owner', $ownerName)
|
||||
->count();
|
||||
}
|
||||
}
|
||||
|
||||
if ($exists) {
|
||||
throw new IcingaException(
|
||||
$this->translate('A navigation item with the name "%s" does already exist'),
|
||||
$name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unset($data['name']);
|
||||
}
|
||||
|
||||
$itemConfig->merge($data);
|
||||
foreach ($itemConfig->toArray() as $k => $v) {
|
||||
if ($v === null) {
|
||||
unset($itemConfig->$k);
|
||||
}
|
||||
}
|
||||
|
||||
if ($shared) {
|
||||
// Share all descendant children
|
||||
foreach ($this->getFlattenedChildren($oldName ?: $name) as $child) {
|
||||
$childConfig = $this->secondaryConfig->getSection($child);
|
||||
$this->secondaryConfig->removeSection($child);
|
||||
$childConfig->owner = $this->getUser()->getUsername();
|
||||
$config->setSection($child, $childConfig);
|
||||
}
|
||||
}
|
||||
|
||||
if ($oldName) {
|
||||
// Update the parent name on all direct children
|
||||
foreach ($config as $sectionConfig) {
|
||||
if ($sectionConfig->parent === $oldName) {
|
||||
$sectionConfig->parent = $name;
|
||||
}
|
||||
}
|
||||
|
||||
$config->removeSection($oldName);
|
||||
}
|
||||
|
||||
if ($this->secondaryConfig !== null) {
|
||||
$this->secondaryConfig->removeSection($oldName ?: $name);
|
||||
}
|
||||
|
||||
$config->setSection($name, $itemConfig);
|
||||
$this->setIniConfig($config);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a navigation item
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return ConfigObject The navigation item's config
|
||||
*
|
||||
* @throws NotFoundError In case no navigation item with the given name is found
|
||||
* @throws IcingaException In case the navigation item has still children
|
||||
*/
|
||||
public function delete($name)
|
||||
{
|
||||
$config = $this->getConfigForItem($name);
|
||||
if ($config === null) {
|
||||
throw new NotFoundError('No navigation item called "%s" found', $name);
|
||||
}
|
||||
|
||||
$children = $this->getFlattenedChildren($name);
|
||||
if (! empty($children)) {
|
||||
throw new IcingaException(
|
||||
$this->translate(
|
||||
'Unable to delete navigation item "%s". There'
|
||||
. ' are other items dependent from it: %s'
|
||||
),
|
||||
$name,
|
||||
join(', ', $children)
|
||||
);
|
||||
}
|
||||
|
||||
$section = $config->getSection($name);
|
||||
$config->removeSection($name);
|
||||
$this->setIniConfig($config);
|
||||
return $section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshare the given navigation item
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $parent
|
||||
*
|
||||
* @return Config The new config of the given navigation item
|
||||
*
|
||||
* @throws NotFoundError In case no navigation item with the given name is found
|
||||
* @throws IcingaException In case the navigation item has a parent assigned to it
|
||||
*/
|
||||
public function unshare($name, $parent = null)
|
||||
{
|
||||
$config = $this->getShareConfig();
|
||||
if (! $config->hasSection($name)) {
|
||||
throw new NotFoundError('No navigation item called "%s" found', $name);
|
||||
}
|
||||
|
||||
$itemConfig = $config->getSection($name);
|
||||
if ($parent === null) {
|
||||
$parent = $itemConfig->parent;
|
||||
}
|
||||
|
||||
if ($parent && $this->hasBeenShared($parent)) {
|
||||
throw new IcingaException(
|
||||
$this->translate(
|
||||
'Unable to unshare navigation item "%s". It is dependent from item "%s".'
|
||||
. ' Dependent items can only be unshared by unsharing their parent'
|
||||
),
|
||||
$name,
|
||||
$parent
|
||||
);
|
||||
}
|
||||
|
||||
$children = $this->getFlattenedChildren($name);
|
||||
$config->removeSection($name);
|
||||
$this->secondaryConfig = $config;
|
||||
|
||||
if (! $itemConfig->owner || $itemConfig->owner === $this->getUser()->getUsername()) {
|
||||
$config = $this->getUserConfig();
|
||||
} else {
|
||||
$owner = new User($itemConfig->owner);
|
||||
$config = $owner->loadNavigationConfig();
|
||||
}
|
||||
|
||||
foreach ($children as $child) {
|
||||
$childConfig = $this->secondaryConfig->getSection($child);
|
||||
unset($childConfig->owner);
|
||||
$this->secondaryConfig->removeSection($child);
|
||||
$config->setSection($child, $childConfig);
|
||||
}
|
||||
|
||||
unset($itemConfig->owner);
|
||||
unset($itemConfig->users);
|
||||
unset($itemConfig->groups);
|
||||
|
||||
$config->setSection($name, $itemConfig);
|
||||
$this->setIniConfig($config);
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$shared = false;
|
||||
$itemTypes = $this->getItemTypes();
|
||||
$itemType = isset($formData['type']) ? $formData['type'] : key($itemTypes);
|
||||
$itemForm = $this->getItemForm($itemType);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this navigation item that is used to differentiate it from others'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (
|
||||
(! $itemForm->requiresParentSelection() || !isset($formData['parent']) || !$formData['parent'])
|
||||
&& $this->getUser()->can('application/share/navigation')
|
||||
) {
|
||||
$checked = isset($formData['shared']) ? null : (isset($formData['users']) || isset($formData['groups']));
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'shared',
|
||||
array(
|
||||
'autosubmit' => true,
|
||||
'ignore' => true,
|
||||
'value' => $checked,
|
||||
'label' => $this->translate('Shared'),
|
||||
'description' => $this->translate('Tick this box to share this item with others')
|
||||
)
|
||||
);
|
||||
|
||||
if ($checked || (isset($formData['shared']) && $formData['shared'])) {
|
||||
$shared = true;
|
||||
$this->addElement(
|
||||
'text',
|
||||
'users',
|
||||
array(
|
||||
'label' => $this->translate('Users'),
|
||||
'description' => $this->translate(
|
||||
'Comma separated list of usernames to share this item with'
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'groups',
|
||||
array(
|
||||
'label' => $this->translate('Groups'),
|
||||
'description' => $this->translate(
|
||||
'Comma separated list of group names to share this item with'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'type',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('Type'),
|
||||
'description' => $this->translate('The type of this navigation item'),
|
||||
'multiOptions' => $itemTypes
|
||||
)
|
||||
);
|
||||
|
||||
if (! $shared && $itemForm->requiresParentSelection()) {
|
||||
if ($this->itemToLoad && $this->hasBeenShared($this->itemToLoad)) {
|
||||
$itemConfig = $this->getShareConfig()->getSection($this->itemToLoad);
|
||||
$availableParents = $this->listAvailableParents($itemType, $itemConfig->owner);
|
||||
} else {
|
||||
$availableParents = $this->listAvailableParents($itemType);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'parent',
|
||||
array(
|
||||
'allowEmpty' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('Parent'),
|
||||
'description' => $this->translate(
|
||||
'The parent item to assign this navigation item to. '
|
||||
. 'Select "None" to make this a main navigation item'
|
||||
),
|
||||
'multiOptions' => array_merge(
|
||||
array('' => $this->translate('None', 'No parent for a navigation item')),
|
||||
empty($availableParents) ? array() : array_combine($availableParents, $availableParents)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->addSubForm($itemForm, 'item_form');
|
||||
$itemForm->create($formData); // May require a parent which gets set by addSubForm()
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the configuration of the navigation item to load
|
||||
*/
|
||||
public function onRequest()
|
||||
{
|
||||
if ($this->itemToLoad) {
|
||||
$data = $this->getConfigForItem($this->itemToLoad)->getSection($this->itemToLoad)->toArray();
|
||||
$data['name'] = $this->itemToLoad;
|
||||
$this->populate($data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isValid($formData)
|
||||
{
|
||||
if (! parent::isValid($formData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$valid = true;
|
||||
if (isset($formData['users']) && $formData['users']) {
|
||||
$parsedUserRestrictions = array();
|
||||
foreach (Auth::getInstance()->getRestrictions('application/share/users') as $userRestriction) {
|
||||
$parsedUserRestrictions[] = array_map('trim', explode(',', $userRestriction));
|
||||
}
|
||||
|
||||
if (! empty($parsedUserRestrictions)) {
|
||||
$desiredUsers = array_map('trim', explode(',', $formData['users']));
|
||||
array_unshift($parsedUserRestrictions, $desiredUsers);
|
||||
$forbiddenUsers = call_user_func_array('array_diff', $parsedUserRestrictions);
|
||||
if (! empty($forbiddenUsers)) {
|
||||
$valid = false;
|
||||
$this->getElement('users')->addError(
|
||||
$this->translate(sprintf(
|
||||
'You are not permitted to share this navigation item with the following users: %s',
|
||||
implode(', ', $forbiddenUsers)
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($formData['groups']) && $formData['groups']) {
|
||||
$parsedGroupRestrictions = array();
|
||||
foreach (Auth::getInstance()->getRestrictions('application/share/groups') as $groupRestriction) {
|
||||
$parsedGroupRestrictions[] = array_map('trim', explode(',', $groupRestriction));
|
||||
}
|
||||
|
||||
if (! empty($parsedGroupRestrictions)) {
|
||||
$desiredGroups = array_map('trim', explode(',', $formData['groups']));
|
||||
array_unshift($parsedGroupRestrictions, $desiredGroups);
|
||||
$forbiddenGroups = call_user_func_array('array_diff', $parsedGroupRestrictions);
|
||||
if (! empty($forbiddenGroups)) {
|
||||
$valid = false;
|
||||
$this->getElement('groups')->addError(
|
||||
$this->translate(sprintf(
|
||||
'You are not permitted to share this navigation item with the following groups: %s',
|
||||
implode(', ', $forbiddenGroups)
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValues($suppressArrayNotation = false)
|
||||
{
|
||||
$values = parent::getValues();
|
||||
$values = array_merge($values, $values['item_form']);
|
||||
unset($values['item_form']);
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function writeConfig(Config $config)
|
||||
{
|
||||
parent::writeConfig($config);
|
||||
|
||||
if ($this->secondaryConfig !== null) {
|
||||
$this->config = $this->secondaryConfig; // Causes the config being displayed to the user in case of an error
|
||||
parent::writeConfig($this->secondaryConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the navigation configuration the given item is a part of
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Config|null In case the item is not part of any configuration
|
||||
*/
|
||||
protected function getConfigForItem($name)
|
||||
{
|
||||
if ($this->getUserConfig()->hasSection($name)) {
|
||||
return $this->getUserConfig();
|
||||
} elseif ($this->getShareConfig()->hasSection($name)) {
|
||||
if (
|
||||
$this->getShareConfig()->get($name, 'owner') === $this->getUser()->getUsername()
|
||||
|| $this->getUser()->can('config/application/navigation')
|
||||
) {
|
||||
return $this->getShareConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given navigation item has been shared
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasBeenShared($name)
|
||||
{
|
||||
return $this->getConfigForItem($name) === $this->getShareConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the form for the given type of navigation item
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return Form
|
||||
*/
|
||||
protected function getItemForm($type)
|
||||
{
|
||||
$className = String::cname($type, '-') . 'Form';
|
||||
|
||||
$form = null;
|
||||
foreach (Icinga::app()->getModuleManager()->getLoadedModules() as $module) {
|
||||
$classPath = 'Icinga\\Module\\'
|
||||
. ucfirst($module->getName())
|
||||
. '\\'
|
||||
. static::FORM_NS
|
||||
. '\\'
|
||||
. $className;
|
||||
if (class_exists($classPath)) {
|
||||
$form = new $classPath();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($form === null) {
|
||||
$classPath = 'Icinga\\' . static::FORM_NS . '\\' . $className;
|
||||
if (class_exists($classPath)) {
|
||||
$form = new $classPath();
|
||||
}
|
||||
}
|
||||
|
||||
if ($form === null) {
|
||||
Logger::debug(
|
||||
'Failed to find custom navigation item form %s for item %s. Using form NavigationItemForm now',
|
||||
$className,
|
||||
$type
|
||||
);
|
||||
|
||||
$form = new NavigationItemForm();
|
||||
} elseif (! $form instanceof NavigationItemForm) {
|
||||
throw new ProgrammingError('Class %s must inherit from NavigationItemForm', $classPath);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Navigation;
|
||||
|
||||
use Icinga\Web\Form;
|
||||
|
||||
class NavigationItemForm extends Form
|
||||
{
|
||||
/**
|
||||
* Whether to create a select input to choose a parent for a navigation item of a particular type
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $requiresParentSelection = false;
|
||||
|
||||
/**
|
||||
* Return whether to create a select input to choose a parent for a navigation item of a particular type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function requiresParentSelection()
|
||||
{
|
||||
return $this->requiresParentSelection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'select',
|
||||
'target',
|
||||
array(
|
||||
'allowEmpty' => true,
|
||||
'label' => $this->translate('Target'),
|
||||
'description' => $this->translate('The target where to open this navigation item\'s url'),
|
||||
'multiOptions' => array(
|
||||
'_blank' => $this->translate('New Window'),
|
||||
'_next' => $this->translate('New Column'),
|
||||
'_main' => $this->translate('Single Column'),
|
||||
'_self' => $this->translate('Current Column')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'url',
|
||||
array(
|
||||
'allowEmpty' => true,
|
||||
'label' => $this->translate('Url'),
|
||||
'description' => $this->translate(
|
||||
'The url of this navigation item. Leave blank if you only want the'
|
||||
. ' name being displayed. For external urls, make sure to prepend'
|
||||
. ' an appropriate protocol identifier (e.g. http://example.tld)'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'icon',
|
||||
array(
|
||||
'allowEmpty' => true,
|
||||
'label' => $this->translate('Icon'),
|
||||
'description' => $this->translate(
|
||||
'The icon of this navigation item. Leave blank if you do not want a icon being displayed'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ namespace Icinga\Forms;
|
|||
|
||||
use Exception;
|
||||
use DateTimeZone;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Authentication\Auth;
|
||||
use Icinga\User\Preferences;
|
||||
|
@ -178,6 +179,19 @@ class PreferenceForm extends Form
|
|||
)
|
||||
);
|
||||
|
||||
if (Auth::getInstance()->hasPermission('application/stacktraces')) {
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'show_stacktraces',
|
||||
array(
|
||||
'required' => true,
|
||||
'value' => $this->getDefaultShowStacktraces(),
|
||||
'label' => $this->translate('Show Stacktraces'),
|
||||
'description' => $this->translate('Set whether to show an exception\'s stacktrace.')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'show_benchmark',
|
||||
|
@ -220,8 +234,20 @@ class PreferenceForm extends Form
|
|||
)
|
||||
);
|
||||
|
||||
$this->setAttrib('data-progress-element', 'preferences-progress');
|
||||
$this->addElement(
|
||||
'note',
|
||||
'preferences-progress',
|
||||
array(
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('Spinner', array('id' => 'preferences-progress'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->addDisplayGroup(
|
||||
array('btn_submit_preferences', 'btn_submit_session'),
|
||||
array('btn_submit_preferences', 'btn_submit_session', 'preferences-progress'),
|
||||
'submit_buttons',
|
||||
array(
|
||||
'decorators' => array(
|
||||
|
@ -257,4 +283,14 @@ class PreferenceForm extends Form
|
|||
$locale = Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
||||
return $locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default global setting for show_stacktraces
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function getDefaultShowStacktraces()
|
||||
{
|
||||
return Config::app()->get('global', 'show_stacktraces', true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
|
||||
namespace Icinga\Forms\Security;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use Zend_Form_Element;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Exception\AlreadyExistsException;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Util\String;
|
||||
|
||||
|
@ -20,49 +21,72 @@ class RoleForm extends ConfigForm
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $providedPermissions = array(
|
||||
'*' => 'Allow everything (*)',
|
||||
'config/*' => 'Allow config access (config/*)',
|
||||
/*
|
||||
// [tg] seems excessive for me, hidden for rc1, tbd
|
||||
'config/application/*' => 'config/application/*',
|
||||
'config/application/general' => 'config/application/general',
|
||||
'config/application/resources' => 'config/application/resources',
|
||||
'config/application/userbackend' => 'config/application/userbackend',
|
||||
'config/application/usergroupbackend' => 'config/application/usergroupbackend',
|
||||
'config/authentication/*' => 'config/authentication/*',
|
||||
'config/authentication/users/*' => 'config/authentication/users/*',
|
||||
'config/authentication/users/show' => 'config/authentication/users/show',
|
||||
'config/authentication/users/add' => 'config/authentication/users/add',
|
||||
'config/authentication/users/edit' => 'config/authentication/users/edit',
|
||||
'config/authentication/users/remove' => 'config/authentication/users/remove',
|
||||
'config/authentication/groups/*' => 'config/authentication/groups/*',
|
||||
'config/authentication/groups/show' => 'config/authentication/groups/show',
|
||||
'config/authentication/groups/add' => 'config/authentication/groups/add',
|
||||
'config/authentication/groups/edit' => 'config/authentication/groups/edit',
|
||||
'config/authentication/groups/remove' => 'config/authentication/groups/remove',
|
||||
'config/authentication/roles/*' => 'config/authentication/roles/*',
|
||||
'config/authentication/roles/show' => 'config/authentication/roles/show',
|
||||
'config/authentication/roles/add' => 'config/authentication/roles/add',
|
||||
'config/authentication/roles/edit' => 'config/authentication/roles/edit',
|
||||
'config/authentication/roles/remove' => 'config/authentication/roles/remove',
|
||||
'config/modules' => 'config/modules'
|
||||
*/
|
||||
);
|
||||
protected $providedPermissions;
|
||||
|
||||
/**
|
||||
* Provided restrictions by currently loaded modules
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $providedRestrictions = array();
|
||||
protected $providedRestrictions;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->providedPermissions = array(
|
||||
'*' => $this->translate('Allow everything') . ' (*)',
|
||||
'application/share/navigation' => $this->translate('Allow to share navigation items')
|
||||
. ' (application/share/navigation)',
|
||||
'application/stacktraces' => $this->translate(
|
||||
'Allow to adjust in the preferences whether to show stacktraces'
|
||||
) . ' (application/stacktraces)',
|
||||
'config/*' => $this->translate('Allow config access') . ' (config/*)',
|
||||
/*
|
||||
// [tg] seems excessive for me, hidden for rc1, tbd
|
||||
'config/application/*' => 'config/application/*',
|
||||
'config/application/general' => 'config/application/general',
|
||||
'config/application/resources' => 'config/application/resources',
|
||||
'config/application/userbackend' => 'config/application/userbackend',
|
||||
'config/application/usergroupbackend' => 'config/application/usergroupbackend',
|
||||
'config/application/navigation' => 'config/application/navigation',
|
||||
'config/authentication/*' => 'config/authentication/*',
|
||||
'config/authentication/users/*' => 'config/authentication/users/*',
|
||||
'config/authentication/users/show' => 'config/authentication/users/show',
|
||||
'config/authentication/users/add' => 'config/authentication/users/add',
|
||||
'config/authentication/users/edit' => 'config/authentication/users/edit',
|
||||
'config/authentication/users/remove' => 'config/authentication/users/remove',
|
||||
'config/authentication/groups/*' => 'config/authentication/groups/*',
|
||||
'config/authentication/groups/show' => 'config/authentication/groups/show',
|
||||
'config/authentication/groups/add' => 'config/authentication/groups/add',
|
||||
'config/authentication/groups/edit' => 'config/authentication/groups/edit',
|
||||
'config/authentication/groups/remove' => 'config/authentication/groups/remove',
|
||||
'config/authentication/roles/*' => 'config/authentication/roles/*',
|
||||
'config/authentication/roles/show' => 'config/authentication/roles/show',
|
||||
'config/authentication/roles/add' => 'config/authentication/roles/add',
|
||||
'config/authentication/roles/edit' => 'config/authentication/roles/edit',
|
||||
'config/authentication/roles/remove' => 'config/authentication/roles/remove',
|
||||
'config/modules' => 'config/modules'
|
||||
*/
|
||||
);
|
||||
|
||||
$helper = new Zend_Form_Element('bogus');
|
||||
$this->providedRestrictions = array(
|
||||
$helper->filterName('application/share/users') => array(
|
||||
'name' => 'application/share/users',
|
||||
'description' => $this->translate(
|
||||
'Restrict which users this role can share items and information with'
|
||||
)
|
||||
),
|
||||
$helper->filterName('application/share/groups') => array(
|
||||
'name' => 'application/share/groups',
|
||||
'description' => $this->translate(
|
||||
'Restrict which groups this role can share items and information with'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$mm = Icinga::app()->getModuleManager();
|
||||
foreach ($mm->listInstalledModules() as $moduleName) {
|
||||
$modulePermission = $mm::MODULE_PERMISSION_NS . $moduleName;
|
||||
|
@ -162,6 +186,7 @@ class RoleForm extends ConfigForm
|
|||
* @return $this
|
||||
*
|
||||
* @throws LogicException If the config is not set
|
||||
* @throws NotFoundError If the given role does not exist
|
||||
* @see ConfigForm::setConfig() For setting the config.
|
||||
*/
|
||||
public function load($name)
|
||||
|
@ -170,10 +195,10 @@ class RoleForm extends ConfigForm
|
|||
throw new LogicException(sprintf('Can\'t load role \'%s\'. Config is not set', $name));
|
||||
}
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
throw new NotFoundError(
|
||||
$this->translate('Can\'t load role \'%s\'. Role does not exist'),
|
||||
$name
|
||||
));
|
||||
);
|
||||
}
|
||||
$role = $this->config->getSection($name)->toArray();
|
||||
$role['permissions'] = ! empty($role['permissions'])
|
||||
|
@ -196,14 +221,14 @@ class RoleForm extends ConfigForm
|
|||
/**
|
||||
* Add a role
|
||||
*
|
||||
* @param string $name The name of the role
|
||||
* @param string $name The name of the role
|
||||
* @param array $values
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws LogicException If the config is not set
|
||||
* @throws InvalidArgumentException If the role to add already exists
|
||||
* @see ConfigForm::setConfig() For setting the config.
|
||||
* @throws LogicException If the config is not set
|
||||
* @throws AlreadyExistsException If the role to add already exists
|
||||
* @see ConfigForm::setConfig() For setting the config.
|
||||
*/
|
||||
public function add($name, array $values)
|
||||
{
|
||||
|
@ -211,10 +236,10 @@ class RoleForm extends ConfigForm
|
|||
throw new LogicException(sprintf('Can\'t add role \'%s\'. Config is not set', $name));
|
||||
}
|
||||
if ($this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
throw new AlreadyExistsException(
|
||||
$this->translate('Can\'t add role \'%s\'. Role already exists'),
|
||||
$name
|
||||
));
|
||||
);
|
||||
}
|
||||
$this->config->setSection($name, $values);
|
||||
return $this;
|
||||
|
@ -223,13 +248,13 @@ class RoleForm extends ConfigForm
|
|||
/**
|
||||
* Remove a role
|
||||
*
|
||||
* @param string $name The name of the role
|
||||
* @param string $name The name of the role
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws LogicException If the config is not set
|
||||
* @throws InvalidArgumentException If the role does not exist
|
||||
* @see ConfigForm::setConfig() For setting the config.
|
||||
* @throws LogicException If the config is not set
|
||||
* @throws NotFoundError If the role does not exist
|
||||
* @see ConfigForm::setConfig() For setting the config.
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
|
@ -237,10 +262,10 @@ class RoleForm extends ConfigForm
|
|||
throw new LogicException(sprintf('Can\'t remove role \'%s\'. Config is not set', $name));
|
||||
}
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
throw new NotFoundError(
|
||||
$this->translate('Can\'t remove role \'%s\'. Role does not exist'),
|
||||
$name
|
||||
));
|
||||
);
|
||||
}
|
||||
$this->config->removeSection($name);
|
||||
return $this;
|
||||
|
@ -249,15 +274,15 @@ class RoleForm extends ConfigForm
|
|||
/**
|
||||
* Update a role
|
||||
*
|
||||
* @param string $name The possibly new name of the role
|
||||
* @param string $name The possibly new name of the role
|
||||
* @param array $values
|
||||
* @param string $oldName The name of the role to update
|
||||
* @param string $oldName The name of the role to update
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws LogicException If the config is not set
|
||||
* @throws InvalidArgumentException If the role to update does not exist
|
||||
* @see ConfigForm::setConfig() For setting the config.
|
||||
* @throws LogicException If the config is not set
|
||||
* @throws NotFoundError If the role to update does not exist
|
||||
* @see ConfigForm::setConfig() For setting the config.
|
||||
*/
|
||||
public function update($name, array $values, $oldName)
|
||||
{
|
||||
|
@ -270,10 +295,10 @@ class RoleForm extends ConfigForm
|
|||
$this->add($name, $values);
|
||||
} else {
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
throw new NotFoundError(
|
||||
$this->translate('Can\'t update role \'%s\'. Role does not exist'),
|
||||
$name
|
||||
));
|
||||
);
|
||||
}
|
||||
$this->config->setSection($name, $values);
|
||||
}
|
||||
|
|
|
@ -4,59 +4,60 @@ use Icinga\Web\Url;
|
|||
use Icinga\Web\Notification;
|
||||
use Icinga\Authentication\Auth;
|
||||
|
||||
$moduleName = $this->layout()->moduleName;
|
||||
if ($moduleName !== 'default') {
|
||||
$moduleClass = ' icinga-module module-' . $moduleName;
|
||||
} else {
|
||||
$moduleClass = '';
|
||||
}
|
||||
|
||||
if (Auth::getInstance()->isAuthenticated()):
|
||||
$moduleName = $this->layout()->moduleName;
|
||||
if ($moduleName) {
|
||||
$moduleClass = ' icinga-module module-' . $moduleName;
|
||||
} else {
|
||||
$moduleClass = '';
|
||||
}
|
||||
$refresh = '';
|
||||
if ($this->layout()->autorefreshInterval) {
|
||||
$refresh = ' data-icinga-refresh="' . $this->layout()->autorefreshInterval . '"';
|
||||
}
|
||||
|
||||
$refresh = '';
|
||||
if ($this->layout()->autorefreshInterval) {
|
||||
$refresh = ' data-icinga-refresh="' . $this->layout()->autorefreshInterval . '"';
|
||||
}
|
||||
?>
|
||||
<div id="header">
|
||||
<div id="logo" data-base-target="_main">
|
||||
<?= $this->qlink(
|
||||
'',
|
||||
'/dashboard',
|
||||
null,
|
||||
array(
|
||||
'icon' => '../logo_icinga-inv.png',
|
||||
'aria-hidden' => 'true',
|
||||
'tabindex' => -1
|
||||
)
|
||||
); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (!$this->layout()->isIframe): ?>
|
||||
<div id="sidebar">
|
||||
<?php echo $this->render('parts/navigation.phtml') ?>
|
||||
</div>
|
||||
<div id="header">
|
||||
<div id="logo">
|
||||
<?php if (Auth::getInstance()->isAuthenticated()): ?>
|
||||
<?= $this->qlink(
|
||||
'',
|
||||
'dashboard',
|
||||
null,
|
||||
array(
|
||||
'icon' => '../logo_icinga-inv.png',
|
||||
'data-base-target' => '_main',
|
||||
'aria-hidden' => 'true',
|
||||
'tabindex' => -1
|
||||
)
|
||||
); ?>
|
||||
<?php else: ?>
|
||||
<?= $this->icon('../logo_icinga-inv.png'); ?>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (! $this->layout()->isIframe): ?>
|
||||
<div id="sidebar">
|
||||
<?= $this->render('parts/navigation.phtml'); ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div id="main" role="main">
|
||||
<div id="col1" class="container<?= $moduleClass ?>"<?php if ($moduleName): ?> data-icinga-module="<?= $moduleName ?>" <?php endif ?> data-icinga-url="<?= Url::fromRequest()->without('renderLayout') ?>"<?= $refresh ?> style="display: block">
|
||||
<?= $this->render('inline.phtml') ?>
|
||||
<div id="main" role="main">
|
||||
<div id="col1" class="container<?= $moduleClass ?>"<?php if ($moduleName): ?> data-icinga-module="<?= $moduleName ?>" <?php endif ?> data-icinga-url="<?= Url::fromRequest()->without('renderLayout'); ?>"<?= $refresh; ?> style="display: block">
|
||||
<?= $this->render('inline.phtml') ?>
|
||||
</div>
|
||||
<div id="col2" class="container">
|
||||
</div>
|
||||
<div id="col3" class="container">
|
||||
</div>
|
||||
</div><!-- END of main -->
|
||||
<div id="footer">
|
||||
<ul id="notifications"><?php
|
||||
$notifications = Notification::getInstance();
|
||||
if ($notifications->hasMessages()) {
|
||||
foreach ($notifications->popMessages() as $m) {
|
||||
echo '<li class="' . $m->type . '">' . $this->escape($m->message) . '</li>';
|
||||
</div>
|
||||
<div id="footer">
|
||||
<ul id="notifications"><?php
|
||||
|
||||
$notifications = Notification::getInstance();
|
||||
if ($notifications->hasMessages()) {
|
||||
foreach ($notifications->popMessages() as $m) {
|
||||
echo '<li class="' . $m->type . '">' . $this->escape($m->message) . '</li>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?></ul>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?= $this->render('inline.phtml') ?>
|
||||
<?php endif ?>
|
||||
?></ul>
|
||||
</div>
|
|
@ -0,0 +1,8 @@
|
|||
<div class="logo">
|
||||
<div class="image">
|
||||
<img aria-hidden="true" src="<?= $this->baseUrl('img/logo_icinga_big.png'); ?>" alt="<?= $this->translate('The Icinga logo'); ?>" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="below-logo">
|
||||
<?= $this->render('inline.phtml') ?>
|
||||
</div>
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
|
||||
use Icinga\Web\JavaScript;
|
||||
use Icinga\Util\Translator;
|
||||
|
||||
if (array_key_exists('_dev', $_GET)) {
|
||||
|
@ -16,6 +15,7 @@ $lang = Translator::splitLocaleCode()->language;
|
|||
$isIframe = $this->layout()->isIframe;
|
||||
$showFullscreen = $this->layout()->showFullscreen;
|
||||
$iframeClass = $isIframe ? ' iframe' : '';
|
||||
$innerLayoutScript = $this->layout()->innerLayout . '.phtml';
|
||||
|
||||
?><!DOCTYPE html>
|
||||
<!--[if IE 8]>
|
||||
|
@ -52,7 +52,7 @@ $iframeClass = $isIframe ? ' iframe' : '';
|
|||
<body id="body">
|
||||
<pre id="responsive-debug"></pre>
|
||||
<div id="layout" class="default-layout<?php if ($showFullscreen): ?> fullscreen-layout<?php endif ?>">
|
||||
<?= $this->render('body.phtml') ?>
|
||||
<?= $this->render($innerLayoutScript); ?>
|
||||
</div>
|
||||
<iframe id="fileupload-frame-target" name="fileupload-frame-target"></iframe>
|
||||
<!--[if IE 8]>
|
||||
|
@ -63,7 +63,7 @@ $iframeClass = $isIframe ? ' iframe' : '';
|
|||
<!--<![endif]-->
|
||||
<script type="text/javascript">
|
||||
var icinga = new Icinga({
|
||||
baseUrl: '<?= $this->href('/') ?>'
|
||||
baseUrl: '<?= $this->baseUrl(); ?>'
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<?php
|
||||
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Menu;
|
||||
use Icinga\Web\MenuRenderer;
|
||||
use Icinga\Application\Icinga;
|
||||
|
||||
// Don't render a menu for unauthenticated users unless menu is auth aware
|
||||
if (! $this->auth()->isAuthenticated()) {
|
||||
|
@ -27,10 +25,7 @@ if (! $this->auth()->isAuthenticated()) {
|
|||
'layout/menu.phtml',
|
||||
'default',
|
||||
array(
|
||||
'menuRenderer' => new MenuRenderer(
|
||||
Menu::load(),
|
||||
Url::fromRequest()->without('renderLayout')->getRelativeUrl()
|
||||
)
|
||||
'menuRenderer' => Icinga::app()->getMenu()->getRenderer()
|
||||
)
|
||||
) ?>
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,7 @@ use Icinga\Web\StyleSheet;
|
|||
|
||||
|
||||
$moduleName = $this->layout()->moduleName;
|
||||
if ($moduleName) {
|
||||
if ($moduleName !== 'default') {
|
||||
$moduleClass = ' icinga-module module-' . $moduleName;
|
||||
} else {
|
||||
$moduleClass = '';
|
||||
|
|
Binary file not shown.
|
@ -2,33 +2,36 @@
|
|||
# Copyright (C) 2015 Icinga Development Team
|
||||
# This file is distributed under the same license as Icinga Web 2.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Icinga Web 2 (None)\n"
|
||||
"Project-Id-Version: Icinga Web 2\n"
|
||||
"Report-Msgid-Bugs-To: dev@icinga.org\n"
|
||||
"POT-Creation-Date: 2015-03-13 14:55+0100\n"
|
||||
"PO-Revision-Date: 2015-03-13 14:51+0100\n"
|
||||
"PO-Revision-Date: 2015-07-17 10:17+0200\n"
|
||||
"Last-Translator: Davide Demuru <davide.demuru@gmail.com>\n"
|
||||
"Language: it_IT\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Language-Team: \n"
|
||||
"X-Generator: Poedit 1.8.2\n"
|
||||
"X-Poedit-KeywordsList: translate\n"
|
||||
"X-Poedit-Basepath: ../..\n"
|
||||
"X-Poedit-SearchPath-0: .\n"
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/Form/Validator/InArray.php:16
|
||||
#, php-format
|
||||
msgid "\"%s\" is not in the list of allowed values."
|
||||
msgstr ""
|
||||
msgstr "\"%s\" non è tra i valori ammessi."
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/Form/Validator/InArray.php:19
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\"%s\" is not in the list of allowed values. Did you mean one of the "
|
||||
"following?: %s"
|
||||
msgstr ""
|
||||
msgstr "\"%s\" non è tra i valori ammessi. Intendevi uno dei seguenti?: %s"
|
||||
|
||||
#: /usr/share/icingaweb2/application/forms/Config/Authentication/ExternalBackendForm.php:56
|
||||
#: /usr/share/icingaweb2/application/forms/Config/Resource/FileResourceForm.php:50
|
||||
|
@ -38,23 +41,23 @@ msgstr "\"%value%\" non è un'espressione regolare valida"
|
|||
#: /usr/share/icingaweb2/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php:40
|
||||
#, php-format
|
||||
msgid "%d unhandled hosts down"
|
||||
msgstr ""
|
||||
msgstr "%d host down non gestiti"
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php:41
|
||||
#, php-format
|
||||
msgid "%d unhandled services critical"
|
||||
msgstr ""
|
||||
msgstr "%d servizi down non gestiti"
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/View/DateTimeRenderer.php:185
|
||||
msgctxt "timespan"
|
||||
msgid "%im %ss"
|
||||
msgstr ""
|
||||
msgstr "%im %ss"
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/Form/ErrorLabeller.php:47
|
||||
#, fuzzy, php-format
|
||||
#, php-format
|
||||
msgctxt "config.path"
|
||||
msgid "%s does not exist"
|
||||
msgstr "%s non è scrivibile"
|
||||
msgstr "%s non esiste"
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/Form/ErrorLabeller.php:48
|
||||
#, php-format
|
||||
|
@ -81,10 +84,10 @@ msgstr "%s non è nel formato previsto: %%value%%"
|
|||
#: /usr/share/icingaweb2/application/views/scripts/pivottablePagination.phtml:9
|
||||
#, php-format
|
||||
msgid "%s: %d to %d of %d (on the %s-axis)"
|
||||
msgstr "%s: %d a %d di %d (nell asse %s)"
|
||||
msgstr "%s: %d a %d di %d (dell'asse %s)"
|
||||
|
||||
#: /usr/share/icingaweb2/application/views/scripts/joystickPagination.phtml:9
|
||||
#, fuzzy, php-format
|
||||
#, php-format
|
||||
msgctxt "pagination.joystick"
|
||||
msgid "%s: Show %s %u to %u out of %u"
|
||||
msgstr "%s: Mostra %s %u a %u di %u"
|
||||
|
@ -100,7 +103,7 @@ msgstr "...e password"
|
|||
|
||||
#: /usr/share/icingaweb2/application/layouts/scripts/parts/navigation.phtml:14
|
||||
msgid "Accessibility Skip Links"
|
||||
msgstr ""
|
||||
msgstr "Salta Controllo di Accessibilità"
|
||||
|
||||
#: /usr/share/icingaweb2/application/controllers/DashboardController.php:69
|
||||
msgid "Add Dashlet To Dashboard"
|
||||
|
@ -112,9 +115,8 @@ msgid "Add To Dashboard"
|
|||
msgstr "Aggiungi alla Dashboard"
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/Widget/FilterEditor.php:327
|
||||
#, fuzzy
|
||||
msgid "Add another filter"
|
||||
msgstr "Cliccare per aggiungere un altro filtro"
|
||||
msgstr "Aggiungi un altro filtro"
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/Widget/FilterWidget.php:80
|
||||
msgid "Add filter..."
|
||||
|
@ -127,7 +129,7 @@ msgstr "Cambia la configurazione generale di Icinga Web 2"
|
|||
|
||||
#: /usr/share/icingaweb2/application/controllers/PreferenceController.php:28
|
||||
msgid "Adjust the preferences of Icinga Web 2 according to your needs"
|
||||
msgstr ""
|
||||
msgstr "Modifica le preferenze di Icinga Web 2 in base alle tue esigenze"
|
||||
|
||||
#: /usr/share/icingaweb2/application/controllers/AuthenticationController.php:111
|
||||
msgid ""
|
||||
|
@ -337,11 +339,11 @@ msgstr ""
|
|||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Chart/GridChart.php:90
|
||||
msgid "Contains data in a bar or line chart."
|
||||
msgstr ""
|
||||
msgstr "Contiene i dati in grafici a barre o linee"
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Chart/PieChart.php:56
|
||||
msgid "Contains data in a pie chart."
|
||||
msgstr ""
|
||||
msgstr "Contiene i dati in grafici a torta"
|
||||
|
||||
#: /usr/share/icingaweb2/application/forms/Config/General/ApplicationConfigForm.php:37
|
||||
msgid ""
|
||||
|
@ -622,7 +624,7 @@ msgstr "Configurazione Generale"
|
|||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Chart/GridChart.php:89
|
||||
msgid "Grid Chart"
|
||||
msgstr ""
|
||||
msgstr "Grafico a Griglia"
|
||||
|
||||
#: /usr/share/icingaweb2/application/forms/Security/RoleForm.php:98
|
||||
#: /usr/share/icingaweb2/application/views/scripts/roles/index.phtml:16
|
||||
|
@ -700,8 +702,8 @@ msgstr "Tipo \"%s\" di risorsa non valido"
|
|||
msgid ""
|
||||
"It appears that you did not configure Icinga Web 2 yet so it's not possible "
|
||||
"to log in without any defined authentication method. Please define a "
|
||||
"authentication method by following the instructions in the %1$sdocumentation%"
|
||||
"3$s or by using our %2$sweb-based setup-wizard%3$s."
|
||||
"authentication method by following the instructions in the %1$sdocumentation"
|
||||
"%3$s or by using our %2$sweb-based setup-wizard%3$s."
|
||||
msgstr ""
|
||||
"Icinga Web 2 non è stato configurato e quindi non è possibile autenticarsi "
|
||||
"senza aver definito nessun metodo di autenticazione. Si prega di definire un "
|
||||
|
@ -951,7 +953,7 @@ msgstr "Permessi"
|
|||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Chart/PieChart.php:55
|
||||
msgid "Pie Chart"
|
||||
msgstr ""
|
||||
msgstr "Grafico a Torta"
|
||||
|
||||
#: /usr/share/icingaweb2/application/views/scripts/dashboard/error.phtml:4
|
||||
msgid "Please copy the following dashboard snippet to "
|
||||
|
@ -1007,12 +1009,16 @@ msgid ""
|
|||
"Push this button to update the form to reflect the change that was made in "
|
||||
"the field on the left"
|
||||
msgstr ""
|
||||
"Premere questo bottone per aggiornare il form e mostrare i cambiamenti "
|
||||
"effettuati nel campo a sinistra"
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/Form/Decorator/Autosubmit.php:119
|
||||
msgid ""
|
||||
"Push this button to update the form to reflect the changes that were made "
|
||||
"below"
|
||||
msgstr ""
|
||||
"Premere questo bottone per aggiornare il form e mostrare i cambiamenti "
|
||||
"effettuati sotto"
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/Widget/SearchDashboard.php:63
|
||||
msgid "Ready to search"
|
||||
|
@ -1533,6 +1539,8 @@ msgid ""
|
|||
"Upon any of this form's fields were changed, this page is being updated "
|
||||
"automatically."
|
||||
msgstr ""
|
||||
"Cambiando un qualsiasi valore del form la pagina verrà ricaricata "
|
||||
"automaticamente."
|
||||
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/Form.php:693
|
||||
#: /usr/share/icingaweb2/library/Icinga/Web/Form/Decorator/Autosubmit.php:100
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<img aria-hidden="true" class="fade-in one" src="<?= $this->baseUrl('img/logo_icinga_big.png'); ?>" alt="<?= $this->translate('The Icinga logo'); ?>" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="form" data-base-target="layout">
|
||||
<div class="below-logo" data-base-target="layout">
|
||||
<h1><?= $this->translate('Welcome to Icinga Web 2'); ?></h1>
|
||||
<?php if ($requiresSetup): ?>
|
||||
<p class="config-note"><?= sprintf(
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
<?php if ($module->enabled && $module->loaded) {
|
||||
echo $this->icon('thumbs-up', sprintf($this->translate('Module %s is enabled'), $module->name));
|
||||
} elseif (! $module->enabled) {
|
||||
echo $this->icon('thumbs-down', sprintf($this->translate('Module %s is disabled'), $module->name));
|
||||
echo $this->icon('block', sprintf($this->translate('Module %s is disabled'), $module->name));
|
||||
} else { // ! $module->loaded
|
||||
echo $this->icon('thumbs-down', sprintf($this->translate('Module %s has failed to load'), $module->name));
|
||||
echo $this->icon('block', sprintf($this->translate('Module %s has failed to load'), $module->name));
|
||||
}
|
||||
|
||||
echo $this->qlink(
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<?= $tabs; ?>
|
||||
</div>
|
||||
<div class="content" data-base-target="_next">
|
||||
<a href="<?= $this->href('/config/createresource'); ?>">
|
||||
<a href="<?= $this->href('config/createresource'); ?>">
|
||||
<?= $this->icon('plus'); ?> <?= $this->translate('Create A New Resource'); ?>
|
||||
</a>
|
||||
<table class="action alternating" id="resource-edit-table">
|
||||
|
@ -11,15 +11,38 @@
|
|||
<th style="width: 5em"><?= $this->translate('Remove'); ?></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->resources as $name): ?>
|
||||
<?php foreach ($this->resources as $name => $value): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
switch ($value->type) {
|
||||
case 'db':
|
||||
$icon = 'database';
|
||||
break;
|
||||
case 'ldap':
|
||||
$icon = 'sitemap';
|
||||
break;
|
||||
case 'livestatus':
|
||||
$icon = 'flash';
|
||||
break;
|
||||
case 'ssh':
|
||||
$icon = 'user';
|
||||
break;
|
||||
case 'file':
|
||||
case 'ini':
|
||||
$icon = 'doc-text';
|
||||
break;
|
||||
default:
|
||||
$icon = 'edit';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
<?= $this->qlink(
|
||||
$name,
|
||||
'config/editresource',
|
||||
array('resource' => $name),
|
||||
array(
|
||||
'icon' => 'edit',
|
||||
'icon' => $icon,
|
||||
'title' => sprintf($this->translate('Edit resource %s'), $name)
|
||||
)
|
||||
); ?>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<?= $tabs; ?>
|
||||
</div>
|
||||
<div class="content" data-base-target="_next">
|
||||
<a href="<?= $this->href('/config/createuserbackend'); ?>">
|
||||
<a href="<?= $this->href('config/createuserbackend'); ?>">
|
||||
<?= $this->icon('plus'); ?><?= $this->translate('Create A New User Backend'); ?>
|
||||
</a>
|
||||
<div id="authentication-reorder-form">
|
||||
|
|
|
@ -11,10 +11,16 @@
|
|||
<div class="content">
|
||||
<h1><?= $this->escape($this->translate('Welcome to Icinga Web!')) ?></h1>
|
||||
<p>
|
||||
<?= sprintf(
|
||||
<?php if (! $this->hasPermission('config/modules')) {
|
||||
echo $this->escape($this->translate(
|
||||
'Currently there is no dashlet available. Please contact the administrator.'
|
||||
));
|
||||
} else {
|
||||
printf(
|
||||
$this->escape($this->translate('Currently there is no dashlet available. This might change once you enabled some of the available %s.')),
|
||||
$this->qlink($this->translate('modules'), 'config/modules')
|
||||
) ?>
|
||||
);
|
||||
} ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<?php if (! $hideControls): ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs->showOnlyCloseButton() ?>
|
||||
<?= $tabs->showOnlyCloseButton(); ?>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p><strong><?= nl2br($this->escape($message)) ?></strong></p>
|
||||
<?php if (isset($stackTrace)) : ?>
|
||||
<hr />
|
||||
<pre><?= $this->escape($stackTrace) ?></pre>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p><strong><?= nl2br($this->escape($message)); ?></strong></p>
|
||||
<?php if (isset($stackTrace)): ?>
|
||||
<hr />
|
||||
<pre><?= $this->escape($stackTrace) ?></pre>
|
||||
<?php endif ?>
|
||||
</div>
|
|
@ -6,8 +6,12 @@
|
|||
<th style="width: 5em"><?= $this->translate('Order'); ?></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $backendNames = $form->getBackendOrder(); ?>
|
||||
<?php for ($i = 0; $i < count($backendNames); $i++): ?>
|
||||
<?php
|
||||
$backendNames = $form->getBackendOrder();
|
||||
$backendConfigs = $form->getConfig();
|
||||
for ($i = 0; $i < count($backendNames); $i++):
|
||||
$type = $backendConfigs->getSection($backendNames[$i])->get('backend');
|
||||
?>
|
||||
<tr>
|
||||
<td class="action">
|
||||
<?= $this->qlink(
|
||||
|
@ -15,7 +19,8 @@
|
|||
'config/edituserbackend',
|
||||
array('backend' => $backendNames[$i]),
|
||||
array(
|
||||
'icon' => 'edit',
|
||||
'icon' => $type === 'external' ?
|
||||
'magic' : ($type === 'ldap' || $type === 'msldap' ? 'sitemap' : 'database'),
|
||||
'class' => 'rowaction',
|
||||
'title' => sprintf($this->translate('rEdit user backend %s'), $backendNames[$i])
|
||||
)
|
||||
|
@ -34,7 +39,7 @@
|
|||
</td>
|
||||
<td data-base-target="_self">
|
||||
<?php if ($i > 0): ?>
|
||||
<button type="submit" name="backend_newpos" class="link-like icon-only" value="<?= sprintf(
|
||||
<button type="submit" name="backend_newpos" class="link-like icon-only animated move-up" value="<?= sprintf(
|
||||
'%s|%s',
|
||||
$backendNames[$i],
|
||||
$i - 1
|
||||
|
@ -48,7 +53,7 @@
|
|||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if ($i + 1 < count($backendNames)): ?>
|
||||
<button type="submit" name="backend_newpos" class="link-like icon-only" value="<?= sprintf(
|
||||
<button type="submit" name="backend_newpos" class="link-like icon-only animated move-down" value="<?= sprintf(
|
||||
'%s|%s',
|
||||
$backendNames[$i],
|
||||
$i + 1
|
||||
|
|
|
@ -12,8 +12,5 @@ if ($searchDashboard->search('dummy')->getPane('search')->hasDashlets()): ?>
|
|||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
/>
|
||||
</form>
|
||||
<? endif; ?>
|
||||
<nav>
|
||||
<h1 id="navigation" class="sr-only"><?= t('Navigation'); ?></h1>
|
||||
<?= $menuRenderer; ?>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
<?= $menuRenderer->setHeading(t('Navigation'))->setElementTag('nav'); ?>
|
|
@ -0,0 +1,6 @@
|
|||
<div class="controls">
|
||||
<?= $tabs->showOnlyCloseButton(); ?>
|
||||
</div>
|
||||
<div class="content">
|
||||
<?= $form; ?>
|
||||
</div>
|
|
@ -0,0 +1,53 @@
|
|||
<?php if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs; ?>
|
||||
<?= $this->sortBox; ?>
|
||||
<?= $this->limiter; ?>
|
||||
<?= $this->paginator; ?>
|
||||
<?= $this->filterEditor; ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="content" data-base-target="_next">
|
||||
<a href="<?= $this->href('navigation/add'); ?>">
|
||||
<?= $this->icon('plus'); ?> <?= $this->translate('Create A New Navigation Item'); ?>
|
||||
</a>
|
||||
<?php if (count($items) === 0): ?>
|
||||
<p><?= $this->translate('You did not create any navigation item yet'); ?></p>
|
||||
<?php else: ?>
|
||||
<table class="action alternating">
|
||||
<thead>
|
||||
<th><?= $this->translate('Navigation'); ?></th>
|
||||
<th style="width: 10em"><?= $this->translate('Type'); ?></th>
|
||||
<th style="width: 5em"><?= $this->translate('Shared'); ?></th>
|
||||
<th style="width: 5em"><?= $this->translate('Remove'); ?></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($items as $name => $item): ?>
|
||||
<tr>
|
||||
<td><?= $this->qlink(
|
||||
$name,
|
||||
'navigation/edit',
|
||||
array('name' => $name),
|
||||
array(
|
||||
'title' => sprintf($this->translate('Edit navigation item %s'), $name)
|
||||
)
|
||||
); ?></td>
|
||||
<td><?= $item->type && isset($types[$item->type])
|
||||
? $this->escape($types[$item->type])
|
||||
: $this->escape($this->translate('Unknown')); ?></td>
|
||||
<td><?= $item->owner ? $this->translate('Yes') : $this->translate('No'); ?></td>
|
||||
<td><?= $this->qlink(
|
||||
'',
|
||||
'navigation/remove',
|
||||
array('name' => $name),
|
||||
array(
|
||||
'icon' => 'trash',
|
||||
'title' => sprintf($this->translate('Remove navigation item %s'), $name)
|
||||
)
|
||||
); ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif ?>
|
||||
</div>
|
|
@ -0,0 +1,58 @@
|
|||
<?php if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs; ?>
|
||||
<?= $this->sortBox; ?>
|
||||
<?= $this->limiter; ?>
|
||||
<?= $this->paginator; ?>
|
||||
<?= $this->filterEditor; ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="content" data-base-target="_next">
|
||||
<?php if (count($items) === 0): ?>
|
||||
<p><?= $this->translate('There are currently no navigation items being shared'); ?></p>
|
||||
<?php else: ?>
|
||||
<table class="action alternating">
|
||||
<thead>
|
||||
<th><?= $this->translate('Shared Navigation'); ?></th>
|
||||
<th style="width: 10em"><?= $this->translate('Type'); ?></th>
|
||||
<th style="width: 10em"><?= $this->translate('Owner'); ?></th>
|
||||
<th style="width: 5em"><?= $this->translate('Unshare'); ?></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($items as $name => $item): ?>
|
||||
<tr>
|
||||
<td><?= $this->qlink(
|
||||
$name,
|
||||
'navigation/edit',
|
||||
array(
|
||||
'name' => $name,
|
||||
'referrer' => 'shared'
|
||||
),
|
||||
array(
|
||||
'title' => sprintf($this->translate('Edit shared navigation item %s'), $name)
|
||||
)
|
||||
); ?></td>
|
||||
<td><?= $item->type && isset($types[$item->type])
|
||||
? $this->escape($types[$item->type])
|
||||
: $this->escape($this->translate('Unknown')); ?></td>
|
||||
<td><?= $this->escape($item->owner); ?></td>
|
||||
<?php if ($item->parent): ?>
|
||||
<td><?= $this->icon(
|
||||
'block',
|
||||
sprintf(
|
||||
$this->translate(
|
||||
'This is a child of the navigation item %1$s. You can'
|
||||
. ' only unshare this item by unsharing %1$s'
|
||||
),
|
||||
$item->parent
|
||||
)
|
||||
); ?></td>
|
||||
<?php else: ?>
|
||||
<td data-base-target="_self"><?= $removeForm->setDefault('name', $name); ?></td>
|
||||
<?php endif ?>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif ?>
|
||||
</div>
|
|
@ -19,14 +19,19 @@
|
|||
<tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($backendNames as $backendName): ?>
|
||||
<?php foreach ($backendNames as $backendName => $config):
|
||||
$type = $config->get('backend');
|
||||
?>
|
||||
<tr>
|
||||
<td class="backend-name">
|
||||
<?= $this->qlink(
|
||||
$backendName,
|
||||
'usergroupbackend/edit',
|
||||
array('backend' => $backendName),
|
||||
array('title' => sprintf($this->translate('Edit user group backend %s'), $backendName))
|
||||
array(
|
||||
'icon' => $type === 'external' ? 'magic' : ($type === 'ldap' || $type === 'msldap' ? 'sitemap' : 'database'),
|
||||
'title' => sprintf($this->translate('Edit user group backend %s'), $backendName)
|
||||
)
|
||||
); ?>
|
||||
</td>
|
||||
<td class="backend-remove"><?= $this->qlink(
|
||||
|
|
|
@ -43,6 +43,7 @@ Directive | Description
|
|||
**resource** | The name of the LDAP resource defined in [resources.ini](resources.md#resources).
|
||||
**user_class** | LDAP user class.
|
||||
**user_name_attribute** | LDAP attribute which contains the username.
|
||||
**filter** | LDAP search filter.
|
||||
|
||||
**Example:**
|
||||
|
||||
|
@ -52,6 +53,7 @@ backend = ldap
|
|||
resource = my_ldap
|
||||
user_class = inetOrgPerson
|
||||
user_name_attribute = uid
|
||||
filter = "memberOf=cn=icinga_users,cn=groups,cn=accounts,dc=icinga,dc=org"
|
||||
```
|
||||
|
||||
Note that in case the set *user_name_attribute* holds multiple values it is required that all of its
|
||||
|
@ -62,14 +64,14 @@ with Icinga Web 2 (e.g. an alias) no matter what the primary user id might actua
|
|||
|
||||
Directive | Description
|
||||
------------------------|------------
|
||||
**backend** | `ad`
|
||||
**backend** | `msldap`
|
||||
**resource** | The name of the LDAP resource defined in [resources.ini](resources.md#resources).
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
[auth_ad]
|
||||
backend = ad
|
||||
backend = msldap
|
||||
resource = my_ad
|
||||
```
|
||||
|
||||
|
|
|
@ -101,12 +101,11 @@ The packages for Debian wheezy depend on other packages which are distributed as
|
|||
### <a id="installing-from-package-example"></a> Installing Icinga Web 2
|
||||
|
||||
You can install Icinga Web 2 by using your distribution's package manager to install the `icingaweb2` package.
|
||||
Below is a list with examples for various distributions. The additional package `icingacli` is necessary
|
||||
for being able to follow further steps in this guide.
|
||||
Below is a list with examples for various distributions. The additional package `icingacli` is necessary on RPM based systems for being able to follow further steps in this guide. In DEB based systems, the icingacli binary is included in the icingaweb2 package.
|
||||
|
||||
**Debian and Ubuntu**:
|
||||
````
|
||||
apt-get install icingaweb2 icingacli
|
||||
apt-get install icingaweb2
|
||||
````
|
||||
For Debian wheezy please read the [package repositories notes](#package-repositories-wheezy-notes).
|
||||
|
||||
|
@ -275,9 +274,11 @@ The first release candidate of Icinga Web 2 introduces the following non-backwar
|
|||
`icingaweb_group_membership` were altered to ensure referential integrity.
|
||||
Please use the upgrade script located in **etc/schema/** to update your
|
||||
database schema
|
||||
|
||||
* Users who are using PostgreSQL < v9.1 are required to upgrade their
|
||||
environment to v9.1+ as this is the new minimum required version
|
||||
for utilizing PostgreSQL as database backend
|
||||
|
||||
* The restrictions `monitoring/hosts/filter` and `monitoring/services/filter`
|
||||
provided by the monitoring module were merged together. The new
|
||||
restriction is called `monitoring/filter/objects` and supports only a
|
||||
|
@ -287,12 +288,21 @@ The first release candidate of Icinga Web 2 introduces the following non-backwar
|
|||
## <a id="upgrading-to-2.0.0"></a> Upgrading to Icinga Web 2 2.0.0
|
||||
|
||||
* Icinga Web 2 installations from package on RHEL/CentOS 7 now depend on `php-ZendFramework` which is available through
|
||||
the [EPEL repository](http://fedoraproject.org/wiki/EPEL). Before, Zend was installed as Icinga Web 2 vendor library
|
||||
through the package `icingaweb2-vendor-zend`. After upgrading, please make sure to remove the package
|
||||
`icingaweb2-vendor-zend`.
|
||||
the [EPEL repository](http://fedoraproject.org/wiki/EPEL). Before, Zend was installed as Icinga Web 2 vendor library
|
||||
through the package `icingaweb2-vendor-zend`. After upgrading, please make sure to remove the package
|
||||
`icingaweb2-vendor-zend`.
|
||||
|
||||
* Icinga Web 2 version 2.0.0 requires permissions for accessing modules. Those permissions are automatically generated
|
||||
for each installed module in the format `module/<moduleName>`. Administrators have to grant the module permissions to
|
||||
users and/or user groups in the roles configuration for permitting access to specific modules.
|
||||
In addition, restrictions provided by modules are now configurable for each installed module too. Before,
|
||||
a module had to be enabled before having the possibility to configure restrictions.
|
||||
for each installed module in the format `module/<moduleName>`. Administrators have to grant the module permissions to
|
||||
users and/or user groups in the roles configuration for permitting access to specific modules.
|
||||
In addition, restrictions provided by modules are now configurable for each installed module too. Before,
|
||||
a module had to be enabled before having the possibility to configure restrictions.
|
||||
|
||||
* The **instances.ini** configuration file provided by the monitoring module
|
||||
has been renamed to **commandtransports.ini**. The content and location of
|
||||
the file remains unchanged.
|
||||
|
||||
* The location of a user's preferences has been changed from
|
||||
**<config-dir>/preferences/<username>.ini** to
|
||||
**<config-dir>/preferences/<username>/config.ini**.
|
||||
The content of the file remains unchanged.
|
||||
|
|
|
@ -78,9 +78,9 @@ abstract class ApplicationBootstrap
|
|||
protected $configDir;
|
||||
|
||||
/**
|
||||
* Icinga auto loader
|
||||
* Icinga class loader
|
||||
*
|
||||
* @var Loader
|
||||
* @var ClassLoader
|
||||
*/
|
||||
private $loader;
|
||||
|
||||
|
@ -183,7 +183,7 @@ abstract class ApplicationBootstrap
|
|||
/**
|
||||
* Getter for class loader
|
||||
*
|
||||
* @return Loader
|
||||
* @return ClassLoader
|
||||
*/
|
||||
public function getLoader()
|
||||
{
|
||||
|
@ -339,15 +339,15 @@ abstract class ApplicationBootstrap
|
|||
}
|
||||
|
||||
/**
|
||||
* Setup Icinga auto loader
|
||||
* Setup Icinga class loader
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setupAutoloader()
|
||||
{
|
||||
require $this->libDir . '/Icinga/Application/Loader.php';
|
||||
require $this->libDir . '/Icinga/Application/ClassLoader.php';
|
||||
|
||||
$this->loader = new Loader();
|
||||
$this->loader = new ClassLoader();
|
||||
$this->loader->registerNamespace('Icinga', $this->libDir. '/Icinga');
|
||||
$this->loader->register();
|
||||
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Application;
|
||||
|
||||
/**
|
||||
* PSR-4 class loader
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/**
|
||||
* Namespace separator
|
||||
*/
|
||||
const NAMESPACE_SEPARATOR = '\\';
|
||||
|
||||
/**
|
||||
* Namespaces
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $namespaces = array();
|
||||
|
||||
/**
|
||||
* Register a base directory for a namespace prefix
|
||||
*
|
||||
* @param string $namespace
|
||||
* @param string $directory
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function registerNamespace($namespace, $directory)
|
||||
{
|
||||
$this->namespaces[$namespace] = $directory;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether a namespace exists
|
||||
*
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasNamespace($namespace)
|
||||
{
|
||||
return array_key_exists($namespace, $this->namespaces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source file of the given class or interface
|
||||
*
|
||||
* @param string $class Name of the class or interface
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getSourceFile($class)
|
||||
{
|
||||
foreach ($this->namespaces as $namespace => $dir) {
|
||||
if ($class === strstr($class, $namespace)) {
|
||||
$classPath = str_replace(
|
||||
self::NAMESPACE_SEPARATOR,
|
||||
DIRECTORY_SEPARATOR,
|
||||
substr($class, strlen($namespace))
|
||||
) . '.php';
|
||||
if (file_exists($file = $dir . $classPath)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the given class or interface
|
||||
*
|
||||
* @param string $class Name of the class or interface
|
||||
*
|
||||
* @return bool Whether the class or interface has been loaded
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->getSourceFile($class)) {
|
||||
require $file;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register {@link loadClass()} as an autoloader
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister {@link loadClass()} as an autoloader
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister this as an autoloader
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->unregister();
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ use Icinga\Data\ConfigObject;
|
|||
use Icinga\Data\Selectable;
|
||||
use Icinga\Data\SimpleQuery;
|
||||
use Icinga\File\Ini\IniWriter;
|
||||
use Icinga\File\Ini\IniParser;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
|
||||
/**
|
||||
|
@ -313,9 +314,7 @@ class Config implements Countable, Iterator, Selectable
|
|||
if ($filepath === false) {
|
||||
$emptyConfig->setConfigFile($file);
|
||||
} elseif (is_readable($filepath)) {
|
||||
$config = new static(new ConfigObject(parse_ini_file($filepath, true)));
|
||||
$config->setConfigFile($filepath);
|
||||
return $config;
|
||||
return IniParser::parseIniFile($filepath);
|
||||
} elseif (@file_exists($filepath)) {
|
||||
throw new NotReadableError(t('Cannot read config file "%s". Permission denied'), $filepath);
|
||||
}
|
||||
|
@ -359,11 +358,7 @@ class Config implements Countable, Iterator, Selectable
|
|||
*/
|
||||
protected function getIniWriter($filePath = null, $fileMode = null)
|
||||
{
|
||||
return new IniWriter(array(
|
||||
'config' => $this,
|
||||
'filename' => $filePath,
|
||||
'filemode' => $fileMode
|
||||
));
|
||||
return new IniWriter($this, $filePath, $fileMode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -418,7 +413,6 @@ class Config implements Countable, Iterator, Selectable
|
|||
static::resolvePath('modules/' . $modulename . '/' . $configname . '.ini')
|
||||
);
|
||||
}
|
||||
|
||||
return $moduleConfigs[$configname];
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@ namespace Icinga\Application;
|
|||
|
||||
require_once dirname(__FILE__) . '/ApplicationBootstrap.php';
|
||||
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Response;
|
||||
|
||||
/**
|
||||
* Use this if you want to make use of Icinga functionality in other web projects
|
||||
*
|
||||
|
@ -16,6 +19,40 @@ require_once dirname(__FILE__) . '/ApplicationBootstrap.php';
|
|||
*/
|
||||
class EmbeddedWeb extends ApplicationBootstrap
|
||||
{
|
||||
/**
|
||||
* Request object
|
||||
*
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Response
|
||||
*
|
||||
* @var Response
|
||||
*/
|
||||
protected $response;
|
||||
|
||||
/**
|
||||
* Get the request
|
||||
*
|
||||
* @return Request
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Embedded bootstrap parts
|
||||
*
|
||||
|
@ -26,10 +63,34 @@ class EmbeddedWeb extends ApplicationBootstrap
|
|||
{
|
||||
return $this
|
||||
->setupZendAutoloader()
|
||||
->loadConfig()
|
||||
->setupErrorHandling()
|
||||
->loadConfig()
|
||||
->setupRequest()
|
||||
->setupResponse()
|
||||
->setupTimezone()
|
||||
->setupModuleManager()
|
||||
->loadEnabledModules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupRequest()
|
||||
{
|
||||
$this->request = new Request();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the response
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupResponse()
|
||||
{
|
||||
$this->response = new Response();
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Application;
|
||||
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
|
||||
class Loader
|
||||
{
|
||||
/**
|
||||
* Namespace separator
|
||||
*/
|
||||
const NAMESPACE_SEPARATOR = '\\';
|
||||
|
||||
/**
|
||||
* List of namespaces
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $namespaces = array();
|
||||
|
||||
/**
|
||||
* Detach spl autoload method from stack
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->unRegister();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new namespace for directory
|
||||
*
|
||||
* @param string $namespace
|
||||
* @param string $directory
|
||||
*
|
||||
* @throws ProgrammingError
|
||||
*/
|
||||
public function registerNamespace($namespace, $directory)
|
||||
{
|
||||
if (!is_dir($directory)) {
|
||||
throw new ProgrammingError(
|
||||
'Directory "%s" for namespace "%s" does not exist',
|
||||
$directory,
|
||||
$namespace
|
||||
);
|
||||
}
|
||||
|
||||
$this->namespaces[$namespace] = $directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a namespace exists
|
||||
*
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasNamespace($namespace)
|
||||
{
|
||||
return array_key_exists($namespace, $this->namespaces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class loader
|
||||
*
|
||||
* Ignores all but classes in registered namespaces.
|
||||
*
|
||||
* @param string $class
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
$namespace = $this->getNamespaceForClass($class);
|
||||
|
||||
if ($namespace) {
|
||||
$file = $this->namespaces[$namespace] . preg_replace('/^' . preg_quote($namespace) . '/', '', $class);
|
||||
$file = str_replace(self::NAMESPACE_SEPARATOR, '/', $file) . '.php';
|
||||
|
||||
if (@file_exists($file)) {
|
||||
require_once $file;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if we have a registered namespaces for this class
|
||||
*
|
||||
* Return is the longest match in the array found
|
||||
*
|
||||
* @param string $className
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
private function getNamespaceForClass($className)
|
||||
{
|
||||
$testNamespace = '';
|
||||
$testLength = 0;
|
||||
|
||||
foreach (array_keys($this->namespaces) as $namespace) {
|
||||
$stub = preg_replace(
|
||||
'/^' . preg_quote($namespace) . '(' . preg_quote(self::NAMESPACE_SEPARATOR) . '|$)/', '', $className
|
||||
);
|
||||
$length = strlen($className) - strlen($stub);
|
||||
if ($length > $testLength) {
|
||||
$testLength = $length;
|
||||
$testNamespace = $namespace;
|
||||
}
|
||||
}
|
||||
|
||||
if ($testLength > 0) {
|
||||
return $testNamespace;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Effectively registers the autoloader the PHP/SPL way
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
// Think about to add class pathes to php include path
|
||||
// this could be faster (tg)
|
||||
spl_autoload_register(array(&$this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach autoloader from spl registration
|
||||
*/
|
||||
public function unRegister()
|
||||
{
|
||||
spl_autoload_unregister(array(&$this, 'loadClass'));
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ class StdoutWriter extends LogWriter
|
|||
$color = 'red';
|
||||
break;
|
||||
case Logger::WARNING:
|
||||
$color = 'orange';
|
||||
$color = 'yellow';
|
||||
break;
|
||||
case Logger::INFO:
|
||||
$color = 'green';
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Application\Modules;
|
||||
|
||||
/**
|
||||
* Container for module dashboards
|
||||
*/
|
||||
class DashboardContainer extends NavigationItemContainer
|
||||
{
|
||||
/**
|
||||
* This dashboard's dashlets
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dashlets;
|
||||
|
||||
/**
|
||||
* Set this dashboard's dashlets
|
||||
*
|
||||
* @param array $dashlets
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDashlets(array $dashlets)
|
||||
{
|
||||
$this->dashlets = $dashlets;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this dashboard's dashlets
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDashlets()
|
||||
{
|
||||
return $this->dashlets ?: array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new dashlet
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $url
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function add($name, $url)
|
||||
{
|
||||
$this->dashlets[$name] = $url;
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -281,7 +281,10 @@ class Manager
|
|||
public function disableModule($name)
|
||||
{
|
||||
if (! $this->hasEnabled($name)) {
|
||||
return $this;
|
||||
throw new ConfigurationError(
|
||||
'Cannot disable module "%s". Module is not installed.',
|
||||
$name
|
||||
);
|
||||
}
|
||||
|
||||
if (! is_writable($this->enableDir)) {
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Application\Modules;
|
||||
|
||||
/**
|
||||
* Container for module menu items
|
||||
*/
|
||||
class MenuItemContainer extends NavigationItemContainer
|
||||
{
|
||||
/**
|
||||
* This menu item's children
|
||||
*
|
||||
* @var MenuItemContainer[]
|
||||
*/
|
||||
protected $children;
|
||||
|
||||
/**
|
||||
* Set this menu item's children
|
||||
*
|
||||
* @param MenuItemContainer[] $children
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setChildren(array $children)
|
||||
{
|
||||
$this->children = $children;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this menu item's children
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getChildren()
|
||||
{
|
||||
return $this->children ?: array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new sub menu
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $properties
|
||||
*
|
||||
* @return MenuItemContainer The newly added sub menu
|
||||
*/
|
||||
public function add($name, array $properties = array())
|
||||
{
|
||||
$child = new MenuItemContainer($name, $properties);
|
||||
$this->children[] = $child;
|
||||
return $child;
|
||||
}
|
||||
}
|
|
@ -4,23 +4,24 @@
|
|||
namespace Icinga\Application\Modules;
|
||||
|
||||
use Exception;
|
||||
use Zend_Controller_Router_Route;
|
||||
use Zend_Controller_Router_Route_Abstract;
|
||||
use Zend_Controller_Router_Route as Route;
|
||||
use Zend_Controller_Router_Route_Regex as RegexRoute;
|
||||
use Zend_Controller_Router_Route_Regex;
|
||||
use Icinga\Application\ApplicationBootstrap;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Web\Hook;
|
||||
use Icinga\Web\Menu;
|
||||
use Icinga\Web\Widget;
|
||||
use Icinga\Web\Widget\Dashboard\Pane;
|
||||
use Icinga\Application\Modules\DashboardContainer;
|
||||
use Icinga\Application\Modules\MenuItemContainer;
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Module\Setup\SetupWizard;
|
||||
use Icinga\Util\File;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Web\Controller\Dispatcher;
|
||||
use Icinga\Web\Hook;
|
||||
use Icinga\Web\Navigation\Navigation;
|
||||
use Icinga\Web\Widget;
|
||||
|
||||
/**
|
||||
* Module handling
|
||||
|
@ -162,6 +163,20 @@ class Module
|
|||
*/
|
||||
private $app;
|
||||
|
||||
/**
|
||||
* The CSS/LESS files this module provides
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $cssFiles = array();
|
||||
|
||||
/**
|
||||
* The Javascript files this module provides
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $jsFiles = array();
|
||||
|
||||
/**
|
||||
* Routes to add to the route chain
|
||||
*
|
||||
|
@ -174,7 +189,7 @@ class Module
|
|||
/**
|
||||
* A set of menu elements
|
||||
*
|
||||
* @var array
|
||||
* @var MenuItemContainer[]
|
||||
*/
|
||||
protected $menuItems = array();
|
||||
|
||||
|
@ -206,6 +221,13 @@ class Module
|
|||
*/
|
||||
protected $userGroupBackends = array();
|
||||
|
||||
/**
|
||||
* This module's configurable navigation items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $navigationItems = array();
|
||||
|
||||
/**
|
||||
* Create a new module object
|
||||
*
|
||||
|
@ -262,38 +284,98 @@ class Module
|
|||
}
|
||||
|
||||
/**
|
||||
* Get all pane items
|
||||
* Return this module's dashboard
|
||||
*
|
||||
* @return array
|
||||
* @return Navigation
|
||||
*/
|
||||
public function getPaneItems()
|
||||
public function getDashboard()
|
||||
{
|
||||
$this->launchConfigScript();
|
||||
return $this->paneItems;
|
||||
return $this->createDashboard($this->paneItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a pane to dashboard
|
||||
* Create and return a new navigation for the given dashboard panes
|
||||
*
|
||||
* @param string $name
|
||||
* @param DashboardContainer[] $panes
|
||||
*
|
||||
* @return Pane
|
||||
* @return Navigation
|
||||
*/
|
||||
protected function dashboard($name)
|
||||
public function createDashboard(array $panes)
|
||||
{
|
||||
$this->paneItems[$name] = new Pane($name);
|
||||
$navigation = new Navigation();
|
||||
foreach ($panes as $pane) {
|
||||
/** @var DashboardContainer $pane */
|
||||
$dashlets = array();
|
||||
foreach ($pane->getDashlets() as $dashletName => $dashletUrl) {
|
||||
$dashlets[$this->translate($dashletName)] = $dashletUrl;
|
||||
}
|
||||
|
||||
$navigation->addItem(
|
||||
$pane->getName(),
|
||||
array_merge(
|
||||
$pane->getProperties(),
|
||||
array(
|
||||
'label' => $this->translate($pane->getName()),
|
||||
'type' => 'dashboard-pane',
|
||||
'dashlets' => $dashlets
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $navigation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or get a dashboard pane
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $properties
|
||||
*
|
||||
* @return DashboardContainer
|
||||
*/
|
||||
protected function dashboard($name, array $properties = array())
|
||||
{
|
||||
if (array_key_exists($name, $this->paneItems)) {
|
||||
$this->paneItems[$name]->setProperties($properties);
|
||||
} else {
|
||||
$this->paneItems[$name] = new DashboardContainer($name, $properties);
|
||||
}
|
||||
|
||||
return $this->paneItems[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all menu items
|
||||
* Return this module's menu
|
||||
*
|
||||
* @return array
|
||||
* @return Navigation
|
||||
*/
|
||||
public function getMenuItems()
|
||||
public function getMenu()
|
||||
{
|
||||
$this->launchConfigScript();
|
||||
return $this->menuItems;
|
||||
return $this->createMenu($this->menuItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new navigation for the given menu items
|
||||
*
|
||||
* @param MenuItemContainer[] $items
|
||||
*
|
||||
* @return Navigation
|
||||
*/
|
||||
private function createMenu(array $items)
|
||||
{
|
||||
$navigation = new Navigation();
|
||||
foreach ($items as $item) {
|
||||
/** @var MenuItemContainer $item */
|
||||
$navigationItem = $navigation->createItem($item->getName(), $item->getProperties());
|
||||
$navigationItem->setChildren($this->createMenu($item->getChildren()));
|
||||
$navigationItem->setLabel($this->translate($item->getName()));
|
||||
$navigation->addItem($navigationItem);
|
||||
}
|
||||
|
||||
return $navigation;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -302,14 +384,14 @@ class Module
|
|||
* @param string $name
|
||||
* @param array $properties
|
||||
*
|
||||
* @return Menu
|
||||
* @return MenuItemContainer
|
||||
*/
|
||||
protected function menuSection($name, array $properties = array())
|
||||
{
|
||||
if (array_key_exists($name, $this->menuItems)) {
|
||||
$this->menuItems[$name]->setProperties($properties);
|
||||
} else {
|
||||
$this->menuItems[$name] = new Menu($name, new ConfigObject($properties));
|
||||
$this->menuItems[$name] = new MenuItemContainer($name, $properties);
|
||||
}
|
||||
|
||||
return $this->menuItems[$name];
|
||||
|
@ -388,6 +470,19 @@ class Module
|
|||
return $manager->getModule($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an additional CSS/LESS file
|
||||
*
|
||||
* @param string $path The path to the file, relative to self::$cssdir
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function provideCssFile($path)
|
||||
{
|
||||
$this->cssFiles[] = $this->cssdir . DIRECTORY_SEPARATOR . $path;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if module provides css
|
||||
*
|
||||
|
@ -395,7 +490,12 @@ class Module
|
|||
*/
|
||||
public function hasCss()
|
||||
{
|
||||
return file_exists($this->getCssFilename());
|
||||
if (file_exists($this->getCssFilename())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->launchConfigScript();
|
||||
return !empty($this->cssFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -408,6 +508,32 @@ class Module
|
|||
return $this->cssdir . '/module.less';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CSS/LESS files this module provides
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCssFiles()
|
||||
{
|
||||
$this->launchConfigScript();
|
||||
$files = $this->cssFiles;
|
||||
$files[] = $this->getCssFilename();
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an additional Javascript file
|
||||
*
|
||||
* @param string $path The path to the file, relative to self::$jsdir
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function provideJsFile($path)
|
||||
{
|
||||
$this->jsFiles[] = $this->jsdir . DIRECTORY_SEPARATOR . $path;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if module provides js
|
||||
*
|
||||
|
@ -415,7 +541,12 @@ class Module
|
|||
*/
|
||||
public function hasJs()
|
||||
{
|
||||
return file_exists($this->getJsFilename());
|
||||
if (file_exists($this->getJsFilename())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->launchConfigScript();
|
||||
return !empty($this->jsFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -428,6 +559,19 @@ class Module
|
|||
return $this->jsdir . '/module.js';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Javascript files this module provides
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJsFiles()
|
||||
{
|
||||
$this->launchConfigScript();
|
||||
$files = $this->jsFiles;
|
||||
$files[] = $this->getJsFilename();
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the module name
|
||||
*
|
||||
|
@ -694,6 +838,7 @@ class Module
|
|||
{
|
||||
$this->launchConfigScript();
|
||||
$tabs = Widget::create('tabs');
|
||||
/** @var \Icinga\Web\Widget\Tabs $tabs */
|
||||
$tabs->add('info', array(
|
||||
'url' => 'config/module',
|
||||
'urlParams' => array('name' => $this->getName()),
|
||||
|
@ -753,6 +898,17 @@ class Module
|
|||
return $this->userGroupBackends;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this module's configurable navigation items
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getNavigationItems()
|
||||
{
|
||||
$this->launchConfigScript();
|
||||
return $this->navigationItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a named permission
|
||||
*
|
||||
|
@ -858,7 +1014,21 @@ class Module
|
|||
}
|
||||
|
||||
/**
|
||||
* Register module namespaces on the autoloader
|
||||
* Provide a new type of configurable navigation item with a optional label
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $label
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function provideNavigationItem($type, $label = null)
|
||||
{
|
||||
$this->navigationItems[$type] = $label ?: $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register module namespaces on our class loader
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
@ -868,16 +1038,17 @@ class Module
|
|||
return $this;
|
||||
}
|
||||
|
||||
$loader = $this->app->getLoader();
|
||||
$moduleName = ucfirst($this->getName());
|
||||
|
||||
$moduleLibraryDir = $this->getLibDir(). '/'. $moduleName;
|
||||
if (is_dir($moduleLibraryDir)) {
|
||||
$this->app->getLoader()->registerNamespace('Icinga\\Module\\' . $moduleName, $moduleLibraryDir);
|
||||
$loader->registerNamespace('Icinga\\Module\\' . $moduleName, $moduleLibraryDir);
|
||||
}
|
||||
|
||||
$moduleFormDir = $this->getFormDir();
|
||||
if (is_dir($moduleFormDir)) {
|
||||
$this->app->getLoader()->registerNamespace('Icinga\\Module\\' . $moduleName. '\\Forms', $moduleFormDir);
|
||||
$loader->registerNamespace('Icinga\\Module\\' . $moduleName. '\\Forms', $moduleFormDir);
|
||||
}
|
||||
|
||||
$this->registeredAutoloader = true;
|
||||
|
@ -939,19 +1110,23 @@ class Module
|
|||
*/
|
||||
protected function registerWebIntegration()
|
||||
{
|
||||
if (!$this->app->isWeb()) {
|
||||
if (! $this->app->isWeb()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (file_exists($this->controllerdir) && is_dir($this->controllerdir)) {
|
||||
$moduleControllerDir = $this->getControllerDir();
|
||||
if (is_dir($moduleControllerDir)) {
|
||||
$this->app->getfrontController()->addControllerDirectory(
|
||||
$this->controllerdir,
|
||||
$this->name
|
||||
$moduleControllerDir,
|
||||
$this->getName()
|
||||
);
|
||||
$this->app->getLoader()->registerNamespace(
|
||||
'Icinga\\Module\\' . ucfirst($this->getName()) . '\\' . Dispatcher::CONTROLLER_NAMESPACE,
|
||||
$moduleControllerDir
|
||||
);
|
||||
}
|
||||
|
||||
$this->registerLocales()
|
||||
->registerRoutes();
|
||||
$this
|
||||
->registerLocales()
|
||||
->registerRoutes();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -963,27 +1138,30 @@ class Module
|
|||
protected function registerRoutes()
|
||||
{
|
||||
$router = $this->app->getFrontController()->getRouter();
|
||||
/** @var \Zend_Controller_Router_Rewrite $router */
|
||||
foreach ($this->routes as $name => $route) {
|
||||
$router->addRoute($name, $route);
|
||||
}
|
||||
$router->addRoute(
|
||||
$this->name . '_jsprovider',
|
||||
new Route(
|
||||
new Zend_Controller_Router_Route(
|
||||
'js/' . $this->name . '/:file',
|
||||
array(
|
||||
'action' => 'javascript',
|
||||
'controller' => 'static',
|
||||
'action' =>'javascript',
|
||||
'module' => 'default',
|
||||
'module_name' => $this->name
|
||||
)
|
||||
)
|
||||
);
|
||||
$router->addRoute(
|
||||
$this->name . '_img',
|
||||
new RegexRoute(
|
||||
new Zend_Controller_Router_Route_Regex(
|
||||
'img/' . $this->name . '/(.+)',
|
||||
array(
|
||||
'controller' => 'static',
|
||||
'action' => 'img',
|
||||
'controller' => 'static',
|
||||
'module' => 'default',
|
||||
'module_name' => $this->name
|
||||
),
|
||||
array(
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Application\Modules;
|
||||
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
|
||||
/**
|
||||
* Container for module navigation items
|
||||
*/
|
||||
abstract class NavigationItemContainer
|
||||
{
|
||||
/**
|
||||
* This navigation item's name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* This navigation item's properties
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $properties;
|
||||
|
||||
/**
|
||||
* Create a new NavigationItemContainer
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $properties
|
||||
*/
|
||||
public function __construct($name, array $properties = array())
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->properties = $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this menu item's name
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this menu item's name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this menu item's properties
|
||||
*
|
||||
* @param array $properties
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProperties(array $properties)
|
||||
{
|
||||
$this->properties = $properties;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this menu item's properties
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getProperties()
|
||||
{
|
||||
return $this->properties ?: array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow dynamic setters and getters for properties
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws ProgrammingError In case the called method is not supported
|
||||
*/
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
if (method_exists($this, $name)) {
|
||||
return call_user_method_array($name, $this, $arguments);
|
||||
}
|
||||
|
||||
$type = substr($name, 0, 3);
|
||||
if ($type !== 'set' && $type !== 'get') {
|
||||
throw new ProgrammingError(
|
||||
'Dynamic method %s is not supported. Only getters (get*) and setters (set*) are.',
|
||||
$name
|
||||
);
|
||||
}
|
||||
|
||||
$propertyName = strtolower(join('_', preg_split('~(?=[A-Z])~', lcfirst(substr($name, 3)))));
|
||||
if ($type === 'set') {
|
||||
$this->properties[$propertyName] = $arguments[0];
|
||||
return $this;
|
||||
} else { // $type === 'get'
|
||||
return array_key_exists($propertyName, $this->properties) ? $this->properties[$propertyName] : null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -318,6 +318,41 @@ class Platform
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a LDAP server
|
||||
*
|
||||
* Checks whether the ldap extension is loaded
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasLdapSupport()
|
||||
{
|
||||
return static::extensionLoaded('ldap');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to any of the supported database servers
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasDatabaseSupport()
|
||||
{
|
||||
return static::hasMssqlSupport() || static::hasMysqlSupport() || static::hasOciSupport()
|
||||
|| static::hasOracleSupport() || static::hasPostgresqlSupport();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a MSSQL database
|
||||
*
|
||||
* Checks whether the mssql pdo extension has been loaded and Zend framework adapter for MSSQL is available
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasMssqlSupport()
|
||||
{
|
||||
return static::extensionLoaded('mssql') && static::classExists('Zend_Db_Adapter_Pdo_Mssql');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a MySQL database
|
||||
*
|
||||
|
@ -330,6 +365,30 @@ class Platform
|
|||
return static::extensionLoaded('mysql') && static::classExists('Zend_Db_Adapter_Pdo_Mysql');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a Oracle database using OCI8
|
||||
*
|
||||
* Checks whether the OCI8 extension has been loaded and the Zend framework adapter for Oracle is available
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasOciSupport()
|
||||
{
|
||||
return static::extensionLoaded('oci8') && static::classExists('Zend_Db_Adapter_Oracle');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a Oracle database using PDO_OCI
|
||||
*
|
||||
* Checks whether the OCI PDO extension has been loaded and the Zend framework adapter for Oci is available
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasOracleSupport()
|
||||
{
|
||||
return static::extensionLoaded('pdo_oci') && static::classExists('Zend_Db_Adapter_Pdo_Mysql');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a PostgreSQL database
|
||||
*
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
|
||||
namespace Icinga\Application;
|
||||
|
||||
/**
|
||||
* Retrieve the version of Icinga Web 2
|
||||
*/
|
||||
class Version
|
||||
{
|
||||
/**
|
||||
* Get the version of this instance of Icinga Web 2
|
||||
*
|
||||
* @return array|bool array on success, false otherwise
|
||||
* @return array|false array on success, false otherwise
|
||||
*/
|
||||
public static function get()
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace Icinga\Application;
|
||||
|
||||
require_once __DIR__ . '/ApplicationBootstrap.php';
|
||||
require_once __DIR__ . '/EmbeddedWeb.php';
|
||||
|
||||
use Zend_Controller_Action_HelperBroker;
|
||||
use Zend_Controller_Front;
|
||||
|
@ -11,14 +11,13 @@ use Zend_Controller_Router_Route;
|
|||
use Zend_Layout;
|
||||
use Zend_Paginator;
|
||||
use Zend_View_Helper_PaginationControl;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Authentication\Auth;
|
||||
use Icinga\User;
|
||||
use Icinga\Util\TimezoneDetect;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Web\Controller\Dispatcher;
|
||||
use Icinga\Web\Navigation\Navigation;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Response;
|
||||
use Icinga\Web\Session;
|
||||
use Icinga\Web\Session\Session as BaseSession;
|
||||
use Icinga\Web\View;
|
||||
|
@ -28,11 +27,11 @@ use Icinga\Web\View;
|
|||
*
|
||||
* Usage example:
|
||||
* <code>
|
||||
* use Icinga\Application\EmbeddedWeb;
|
||||
* EmbeddedWeb::start();
|
||||
* use Icinga\Application\Web;
|
||||
* Web::start();
|
||||
* </code>
|
||||
*/
|
||||
class Web extends ApplicationBootstrap
|
||||
class Web extends EmbeddedWeb
|
||||
{
|
||||
/**
|
||||
* View object
|
||||
|
@ -48,20 +47,6 @@ class Web extends ApplicationBootstrap
|
|||
*/
|
||||
private $frontController;
|
||||
|
||||
/**
|
||||
* Request object
|
||||
*
|
||||
* @var Request
|
||||
*/
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* Response
|
||||
*
|
||||
* @var Response
|
||||
*/
|
||||
protected $response;
|
||||
|
||||
/**
|
||||
* Session object
|
||||
*
|
||||
|
@ -100,14 +85,14 @@ class Web extends ApplicationBootstrap
|
|||
->setupNotifications()
|
||||
->setupRequest()
|
||||
->setupResponse()
|
||||
->setupUserBackendFactory()
|
||||
->setupUser()
|
||||
->setupTimezone()
|
||||
->setupLogger()
|
||||
->setupInternationalization()
|
||||
->setupZendMvc()
|
||||
->setupFormNamespace()
|
||||
->setupNamespaces()
|
||||
->setupModuleManager()
|
||||
->setupUserBackendFactory()
|
||||
->loadSetupModuleIfNecessary()
|
||||
->loadEnabledModules()
|
||||
->setupRoute()
|
||||
|
@ -145,26 +130,6 @@ class Web extends ApplicationBootstrap
|
|||
return $this->frontController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the request
|
||||
*
|
||||
* @return Request
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for view
|
||||
*
|
||||
|
@ -175,6 +140,204 @@ class Web extends ApplicationBootstrap
|
|||
return $this->viewRenderer;
|
||||
}
|
||||
|
||||
private function hasAccessToSharedNavigationItem(& $config)
|
||||
{
|
||||
// TODO: Provide a more sophisticated solution
|
||||
|
||||
if (isset($config['owner']) && $config['owner'] === $this->user->getUsername()) {
|
||||
unset($config['owner']);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($config['users'])) {
|
||||
$users = array_map('trim', explode(',', strtolower($config['users'])));
|
||||
if (in_array($this->user->getUsername(), $users, true)) {
|
||||
unset($config['users']);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($config['groups'])) {
|
||||
$groups = array_map('trim', explode(',', strtolower($config['groups'])));
|
||||
$userGroups = array_map('strtolower', $this->user->getGroups());
|
||||
$matches = array_intersect($userGroups, $groups);
|
||||
if (! empty($matches)) {
|
||||
unset($config['groups']);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and return the shared navigation of the given type
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return Navigation
|
||||
*/
|
||||
public function getSharedNavigation($type)
|
||||
{
|
||||
$config = Config::app('navigation')->getConfigObject();
|
||||
$config->setKeyColumn('name');
|
||||
|
||||
if ($type === 'dashboard-pane') {
|
||||
$panes = array();
|
||||
foreach ($config->select()->where('type', 'dashlet') as $dashletName => $dashletConfig) {
|
||||
if ($this->hasAccessToSharedNavigationItem($dashletConfig)) {
|
||||
// TODO: Throw ConfigurationError if pane or url is missing
|
||||
$panes[$dashletConfig->pane][$dashletName] = $dashletConfig->url;
|
||||
}
|
||||
}
|
||||
|
||||
$navigation = new Navigation();
|
||||
foreach ($panes as $paneName => $dashlets) {
|
||||
$navigation->addItem(
|
||||
$paneName,
|
||||
array(
|
||||
'type' => 'dashboard-pane',
|
||||
'dashlets' => $dashlets
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$items = array();
|
||||
foreach ($config->select()->where('type', $type) as $name => $typeConfig) {
|
||||
if ($this->hasAccessToSharedNavigationItem($typeConfig)) {
|
||||
$items[$name] = $typeConfig;
|
||||
}
|
||||
}
|
||||
|
||||
$navigation = Navigation::fromConfig($items);
|
||||
}
|
||||
|
||||
return $navigation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the app's menu
|
||||
*
|
||||
* @return Navigation
|
||||
*/
|
||||
public function getMenu()
|
||||
{
|
||||
if ($this->user !== null) {
|
||||
$menu = array(
|
||||
'dashboard' => array(
|
||||
'label' => t('Dashboard'),
|
||||
'url' => 'dashboard',
|
||||
'icon' => 'dashboard',
|
||||
'priority' => 10
|
||||
),
|
||||
'system' => array(
|
||||
'label' => t('System'),
|
||||
'icon' => 'services',
|
||||
'priority' => 700,
|
||||
'renderer' => array(
|
||||
'SummaryNavigationItemRenderer',
|
||||
'state' => 'critical'
|
||||
),
|
||||
'children' => array(
|
||||
'about' => array(
|
||||
'label' => t('About'),
|
||||
'url' => 'about',
|
||||
'priority' => 701
|
||||
)
|
||||
)
|
||||
),
|
||||
'configuration' => array(
|
||||
'label' => t('Configuration'),
|
||||
'icon' => 'wrench',
|
||||
'permission' => 'config/*',
|
||||
'priority' => 800,
|
||||
'children' => array(
|
||||
'application' => array(
|
||||
'label' => t('Application'),
|
||||
'url' => 'config/general',
|
||||
'permission' => 'config/application/*',
|
||||
'priority' => 810
|
||||
),
|
||||
'navigation' => array(
|
||||
'label' => t('Shared Navigation'),
|
||||
'url' => 'navigation/shared',
|
||||
'permission' => 'config/application/navigation',
|
||||
'priority' => 820,
|
||||
),
|
||||
'authentication' => array(
|
||||
'label' => t('Authentication'),
|
||||
'url' => 'config/userbackend',
|
||||
'permission' => 'config/authentication/*',
|
||||
'priority' => 830
|
||||
),
|
||||
'roles' => array(
|
||||
'label' => t('Roles'),
|
||||
'url' => 'role/list',
|
||||
'permission' => 'config/authentication/roles/show',
|
||||
'priority' => 840
|
||||
),
|
||||
'users' => array(
|
||||
'label' => t('Users'),
|
||||
'url' => 'user/list',
|
||||
'permission' => 'config/authentication/users/show',
|
||||
'priority' => 850
|
||||
),
|
||||
'groups' => array(
|
||||
'label' => t('Usergroups'),
|
||||
'url' => 'group/list',
|
||||
'permission' => 'config/authentication/groups/show',
|
||||
'priority' => 860
|
||||
),
|
||||
'modules' => array(
|
||||
'label' => t('Modules'),
|
||||
'url' => 'config/modules',
|
||||
'permission' => 'config/modules',
|
||||
'priority' => 890
|
||||
)
|
||||
)
|
||||
),
|
||||
'user' => array(
|
||||
'label' => $this->user->getUsername(),
|
||||
'icon' => 'user',
|
||||
'priority' => 900,
|
||||
'children' => array(
|
||||
'preferences' => array(
|
||||
'label' => t('Preferences'),
|
||||
'url' => 'preference',
|
||||
'priority' => 910
|
||||
),
|
||||
'navigation' => array(
|
||||
'label' => t('Navigation'),
|
||||
'url' => 'navigation',
|
||||
'priority' => 920
|
||||
),
|
||||
'logout' => array(
|
||||
'label' => t('Logout'),
|
||||
'url' => 'authentication/logout',
|
||||
'priority' => 990,
|
||||
'renderer' => array(
|
||||
'NavigationItemRenderer',
|
||||
'target' => '_self'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (Logger::writesToFile()) {
|
||||
$menu['system']['children']['application_log'] = array(
|
||||
'label' => t('Application Log'),
|
||||
'url' => 'list/applicationlog',
|
||||
'priority' => 710
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$menu = array();
|
||||
}
|
||||
|
||||
return Navigation::fromArray($menu)->load('menu-item');
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch public interface
|
||||
*/
|
||||
|
@ -211,7 +374,7 @@ class Web extends ApplicationBootstrap
|
|||
$auth = Auth::getInstance();
|
||||
if ($auth->isAuthenticated()) {
|
||||
$user = $auth->getUser();
|
||||
$this->request->setUser($user);
|
||||
$this->getRequest()->setUser($user);
|
||||
$this->user = $user;
|
||||
}
|
||||
return $this;
|
||||
|
@ -239,28 +402,6 @@ class Web extends ApplicationBootstrap
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
private function setupRequest()
|
||||
{
|
||||
$this->request = new Request();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the response
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupResponse()
|
||||
{
|
||||
$this->response = new Response();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate front controller
|
||||
*
|
||||
|
@ -269,11 +410,22 @@ class Web extends ApplicationBootstrap
|
|||
private function setupFrontController()
|
||||
{
|
||||
$this->frontController = Zend_Controller_Front::getInstance();
|
||||
$this->frontController->setRequest($this->request);
|
||||
$this->frontController->setDispatcher(new Dispatcher());
|
||||
$this->frontController->setRequest($this->getRequest());
|
||||
$this->frontController->setControllerDirectory($this->getApplicationDir('/controllers'));
|
||||
|
||||
$displayExceptions = $this->config->get('global', 'show_stacktraces', true);
|
||||
if ($this->user !== null && $this->user->can('application/stacktraces')) {
|
||||
$displayExceptions = $this->user->getPreferences()->getValue(
|
||||
'icingaweb',
|
||||
'show_stacktraces',
|
||||
$displayExceptions
|
||||
);
|
||||
}
|
||||
|
||||
$this->frontController->setParams(
|
||||
array(
|
||||
'displayExceptions' => true
|
||||
'displayExceptions' => $displayExceptions
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
|
@ -355,16 +507,22 @@ class Web extends ApplicationBootstrap
|
|||
}
|
||||
|
||||
/**
|
||||
* Setup an autoloader namespace for Icinga\Forms
|
||||
* Setup class loader namespaces for Icinga\Controllers and Icinga\Forms
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
private function setupFormNamespace()
|
||||
private function setupNamespaces()
|
||||
{
|
||||
$this->getLoader()->registerNamespace(
|
||||
'Icinga\\Forms',
|
||||
$this->getApplicationDir('forms')
|
||||
);
|
||||
$this
|
||||
->getLoader()
|
||||
->registerNamespace(
|
||||
'Icinga\\' . Dispatcher::CONTROLLER_NAMESPACE,
|
||||
$this->getApplicationDir('controllers')
|
||||
)
|
||||
->registerNamespace(
|
||||
'Icinga\\Forms',
|
||||
$this->getApplicationDir('forms')
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,23 @@
|
|||
|
||||
use Icinga\Util\Translator;
|
||||
|
||||
|
||||
/**
|
||||
* No-op translate
|
||||
*
|
||||
* Supposed to be used for marking a string as available for translation without actually translating it immediately.
|
||||
* The returned string is the one given in the input. This does only work with the standard gettext macros t() and mt().
|
||||
*
|
||||
* @param string $messageId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function N_($messageId)
|
||||
{
|
||||
return $messageId;
|
||||
}
|
||||
|
||||
|
||||
if (extension_loaded('gettext')) {
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,11 +3,9 @@
|
|||
|
||||
namespace Icinga\Application;
|
||||
|
||||
use Icinga\Application\EmbeddedWeb;
|
||||
use Icinga\Application\Web;
|
||||
use Icinga\Web\StyleSheet;
|
||||
use Icinga\Web\JavaScript;
|
||||
use Icinga\Chart\Inline\PieChart;
|
||||
use Icinga\Web\JavaScript;
|
||||
use Icinga\Web\StyleSheet;
|
||||
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
|
|
|
@ -61,7 +61,14 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns = array('user');
|
||||
protected $blacklistedQueryColumns = array('user');
|
||||
|
||||
/**
|
||||
* The search columns being provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchColumns = array('user');
|
||||
|
||||
/**
|
||||
* The default sort rules to be applied on a query
|
||||
|
@ -98,6 +105,23 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's filter columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeFilterColumns()
|
||||
{
|
||||
$userLabel = t('Username') . ' ' . t('(Case insensitive)');
|
||||
return array(
|
||||
$userLabel => 'user',
|
||||
t('Username') => 'user_name',
|
||||
t('Active') => 'is_active',
|
||||
t('Created At') => 'created_at',
|
||||
t('Last Modified') => 'last_modified'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a table row with the given data
|
||||
*
|
||||
|
@ -260,7 +284,7 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
|
|||
$insp->write($this->ds->inspect());
|
||||
try {
|
||||
$users = $this->select()->where('is_active', true)->count();
|
||||
if ($users >= 1) {
|
||||
if ($users > 0) {
|
||||
$insp->write(sprintf('%s active users', $users));
|
||||
} else {
|
||||
return $insp->error('0 active users', $users);
|
||||
|
|
|
@ -50,7 +50,14 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns = array('user');
|
||||
protected $blacklistedQueryColumns = array('user');
|
||||
|
||||
/**
|
||||
* The search columns being provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchColumns = array('user');
|
||||
|
||||
/**
|
||||
* The default sort rules to be applied on a query
|
||||
|
@ -243,6 +250,21 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's filter columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeFilterColumns()
|
||||
{
|
||||
return array(
|
||||
t('Username') => 'user_name',
|
||||
t('Active') => 'is_active',
|
||||
t('Created At') => 'created_at',
|
||||
t('Last Modified') => 'last_modified'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's conversion rules
|
||||
*
|
||||
|
@ -342,7 +364,12 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
|
|||
return false;
|
||||
}
|
||||
|
||||
return $this->ds->testCredentials($userDn, $password);
|
||||
$testCredentialsResult = $this->ds->testCredentials($userDn, $password);
|
||||
if ($testCredentialsResult) {
|
||||
$user->setAdditional('ldap_dn', $userDn);
|
||||
}
|
||||
|
||||
return $testCredentialsResult;
|
||||
} catch (LdapException $e) {
|
||||
throw new AuthenticationException(
|
||||
'Failed to authenticate user "%s" against backend "%s". An exception was thrown:',
|
||||
|
|
|
@ -71,7 +71,14 @@ class DbUserGroupBackend extends DbRepository implements UserGroupBackendInterfa
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns = array('group', 'user');
|
||||
protected $blacklistedQueryColumns = array('group', 'user');
|
||||
|
||||
/**
|
||||
* The search columns being provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchColumns = array('group', 'user');
|
||||
|
||||
/**
|
||||
* The value conversion rules to apply on a query or statement
|
||||
|
@ -97,6 +104,26 @@ class DbUserGroupBackend extends DbRepository implements UserGroupBackendInterfa
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's filter columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeFilterColumns()
|
||||
{
|
||||
$userLabel = t('Username') . ' ' . t('(Case insensitive)');
|
||||
$groupLabel = t('User Group') . ' ' . t('(Case insensitive)');
|
||||
return array(
|
||||
$userLabel => 'user',
|
||||
t('Username') => 'user_name',
|
||||
$groupLabel => 'group',
|
||||
t('User Group') => 'group_name',
|
||||
t('Parent') => 'parent',
|
||||
t('Created At') => 'created_at',
|
||||
t('Last Modified') => 'last_modified'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a table row with the given data
|
||||
*
|
||||
|
|
|
@ -32,7 +32,14 @@ class IniUserGroupBackend extends IniRepository implements UserGroupBackendInter
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns = array('group');
|
||||
protected $blacklistedQueryColumns = array('group');
|
||||
|
||||
/**
|
||||
* The search columns being provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchColumns = array('group');
|
||||
|
||||
/**
|
||||
* The value conversion rules to apply on a query or statement
|
||||
|
@ -55,6 +62,21 @@ class IniUserGroupBackend extends IniRepository implements UserGroupBackendInter
|
|||
$this->ds->getConfigObject()->setKeyColumn('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's filter columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeFilterColumns()
|
||||
{
|
||||
return array(
|
||||
t('User Group') => 'group',
|
||||
t('Parent') => 'parent',
|
||||
t('Created At') => 'created_at',
|
||||
t('Last Modified') => 'last_modified'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new group to this backend
|
||||
*
|
||||
|
|
|
@ -12,6 +12,7 @@ use Icinga\Protocol\Ldap\Expression;
|
|||
use Icinga\Repository\LdapRepository;
|
||||
use Icinga\Repository\RepositoryQuery;
|
||||
use Icinga\User;
|
||||
use Icinga\Application\Logger;
|
||||
|
||||
class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBackendInterface
|
||||
{
|
||||
|
@ -83,7 +84,14 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns = array('group', 'user');
|
||||
protected $blacklistedQueryColumns = array('group', 'user');
|
||||
|
||||
/**
|
||||
* The search columns being provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchColumns = array('group', 'user');
|
||||
|
||||
/**
|
||||
* The default sort rules to be applied on a query
|
||||
|
@ -457,6 +465,21 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||
return array('group' => $columns, 'group_membership' => $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's filter columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeFilterColumns()
|
||||
{
|
||||
return array(
|
||||
t('Username') => 'user',
|
||||
t('User Group') => 'group_name',
|
||||
t('Created At') => 'created_at',
|
||||
t('Last Modified') => 'last_modified'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's conversion rules
|
||||
*
|
||||
|
@ -510,18 +533,26 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||
*/
|
||||
public function getMemberships(User $user)
|
||||
{
|
||||
$userQuery = $this->ds
|
||||
->select()
|
||||
->from($this->userClass)
|
||||
->where($this->userNameAttribute, $user->getUsername())
|
||||
->setBase($this->userBaseDn)
|
||||
->setUsePagedResults(false);
|
||||
if ($this->userFilter) {
|
||||
$userQuery->where(new Expression($this->userFilter));
|
||||
}
|
||||
if ($this->groupClass === 'posixGroup') {
|
||||
// Posix group only uses simple user name
|
||||
$userDn = $user->getUsername();
|
||||
} else {
|
||||
// LDAP groups use the complete DN
|
||||
if (($userDn = $user->getAdditional('ldap_dn')) === null) {
|
||||
$userQuery = $this->ds
|
||||
->select()
|
||||
->from($this->userClass)
|
||||
->where($this->userNameAttribute, $user->getUsername())
|
||||
->setBase($this->userBaseDn)
|
||||
->setUsePagedResults(false);
|
||||
if ($this->userFilter) {
|
||||
$userQuery->where(new Expression($this->userFilter));
|
||||
}
|
||||
|
||||
if (($userDn = $userQuery->fetchDn()) === null) {
|
||||
return array();
|
||||
if (($userDn = $userQuery->fetchDn()) === null) {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$groupQuery = $this->ds
|
||||
|
@ -533,10 +564,12 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||
$groupQuery->where(new Expression($this->groupFilter));
|
||||
}
|
||||
|
||||
Logger::debug('Fetching groups for user %s using filter %s.', $user->getUsername(), $groupQuery->__toString());
|
||||
$groups = array();
|
||||
foreach ($groupQuery as $row) {
|
||||
$groups[] = $row->{$this->groupNameAttribute};
|
||||
}
|
||||
Logger::debug('Fetched %d groups: %s.', count($groups), join(', ', $groups));
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
|
|
@ -273,30 +273,10 @@ class Loader
|
|||
|
||||
protected function searchMatch($needle, $haystack)
|
||||
{
|
||||
$stack = $haystack;
|
||||
$search = $needle;
|
||||
$this->lastSuggestions = array();
|
||||
while (strlen($search) > 0) {
|
||||
$len = strlen($search);
|
||||
foreach ($stack as & $s) {
|
||||
$s = substr($s, 0, $len);
|
||||
}
|
||||
|
||||
$res = array_keys($stack, $search, true);
|
||||
if (count($res) === 1) {
|
||||
$found = $haystack[$res[0]];
|
||||
if (substr($found, 0, strlen($needle)) === $needle) {
|
||||
return $found;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} elseif (count($res) > 1) {
|
||||
foreach ($res as $key) {
|
||||
$this->lastSuggestions[] = $haystack[$key];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$search = substr($search, 0, -1);
|
||||
$this->lastSuggestions = preg_grep(sprintf('/^%s.*$/', preg_quote($needle, '/')), $haystack);
|
||||
$match = array_search($needle, $haystack, true);
|
||||
if (false !== $match) {
|
||||
return $haystack[$match];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -173,8 +173,10 @@ class ConfigObject extends ArrayDatasource implements Iterator, ArrayAccess
|
|||
/**
|
||||
* Add a new property or section
|
||||
*
|
||||
* @param string $key The name of the new property or section
|
||||
* @param mixed $value The value to set for the new property or section
|
||||
* @param string $key The name of the new property or section
|
||||
* @param mixed $value The value to set for the new property or section
|
||||
*
|
||||
* @throws ProgrammingError If the key is null
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
|
@ -254,7 +256,7 @@ class ConfigObject extends ArrayDatasource implements Iterator, ArrayAccess
|
|||
/**
|
||||
* Merge the given data with this config
|
||||
*
|
||||
* @param array|Config $data An array or a config
|
||||
* @param array|ConfigObject $data An array or a config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
|
|
@ -80,7 +80,7 @@ class ArrayDatasource implements Selectable
|
|||
*/
|
||||
public function select()
|
||||
{
|
||||
return new SimpleQuery($this);
|
||||
return new SimpleQuery(clone $this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -43,7 +43,7 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp
|
|||
private $dbType;
|
||||
|
||||
/**
|
||||
* @var Zend_Db_Adapter_Abstract
|
||||
* @var \Zend_Db_Adapter_Abstract
|
||||
*/
|
||||
private $dbAdapter;
|
||||
|
||||
|
@ -62,8 +62,7 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp
|
|||
private static $driverOptions = array(
|
||||
PDO::ATTR_TIMEOUT => 10,
|
||||
PDO::ATTR_CASE => PDO::CASE_LOWER,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
// TODO: allow configurable PDO::ATTR_PERSISTENT => true
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -112,7 +111,7 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp
|
|||
/**
|
||||
* Getter for the Zend_Db_Adapter
|
||||
*
|
||||
* @return Zend_Db_Adapter_Abstract
|
||||
* @return \Zend_Db_Adapter_Abstract
|
||||
*/
|
||||
public function getDbAdapter()
|
||||
{
|
||||
|
@ -131,11 +130,16 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp
|
|||
'username' => $this->config->username,
|
||||
'password' => $this->config->password,
|
||||
'dbname' => $this->config->dbname,
|
||||
'persistent' => (bool) $this->config->get('persistent', false),
|
||||
'options' => & $genericAdapterOptions,
|
||||
'driver_options' => & $driverOptions
|
||||
);
|
||||
$this->dbType = strtolower($this->config->get('db', 'mysql'));
|
||||
switch ($this->dbType) {
|
||||
case 'mssql':
|
||||
$adapter = 'Pdo_Mssql';
|
||||
$adapterParamaters['pdoType'] = $this->config->get('pdoType', 'dblib');
|
||||
break;
|
||||
case 'mysql':
|
||||
$adapter = 'Pdo_Mysql';
|
||||
/*
|
||||
|
@ -150,19 +154,21 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp
|
|||
. 'NO_AUTO_CREATE_USER,ANSI_QUOTES,PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION\';';
|
||||
$adapterParamaters['port'] = $this->config->get('port', 3306);
|
||||
break;
|
||||
case 'oci':
|
||||
$adapter = 'Oracle';
|
||||
unset($adapterParamaters['options']);
|
||||
unset($adapterParamaters['driver_options']);
|
||||
$adapterParamaters['driver_options'] = array(
|
||||
'lob_as_string' => true
|
||||
);
|
||||
break;
|
||||
case 'oracle':
|
||||
$adapter = 'Pdo_Oci';
|
||||
break;
|
||||
case 'pgsql':
|
||||
$adapter = 'Pdo_Pgsql';
|
||||
$adapterParamaters['port'] = $this->config->get('port', 5432);
|
||||
break;
|
||||
/*case 'oracle':
|
||||
if ($this->dbtype === 'oracle') {
|
||||
$attributes['persistent'] = true;
|
||||
}
|
||||
$this->db = ZfDb::factory($adapter, $attributes);
|
||||
if ($adapter === 'Oracle') {
|
||||
$this->db->setLobAsString(false);
|
||||
}
|
||||
break;*/
|
||||
default:
|
||||
throw new ConfigurationError(
|
||||
'Backend "%s" is not supported',
|
||||
|
|
|
@ -47,16 +47,6 @@ class DbQuery extends SimpleQuery
|
|||
*/
|
||||
protected $useSubqueryCount = false;
|
||||
|
||||
/**
|
||||
* Set the count maximum
|
||||
*
|
||||
* If the count maximum is set, count queries will not count more than that many rows. You should set this
|
||||
* property only for really heavy queries.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $maxCount;
|
||||
|
||||
/**
|
||||
* Count query result
|
||||
*
|
||||
|
@ -333,19 +323,16 @@ class DbQuery extends SimpleQuery
|
|||
{
|
||||
// TODO: there may be situations where we should clone the "select"
|
||||
$count = $this->dbSelect();
|
||||
$group = $this->getGroup();
|
||||
if ($group) {
|
||||
$count->group($group);
|
||||
}
|
||||
$this->applyFilterSql($count);
|
||||
if ($this->useSubqueryCount || $this->group) {
|
||||
$group = $this->getGroup();
|
||||
if ($this->useSubqueryCount || $group) {
|
||||
$count->columns($this->columns);
|
||||
if ($group) {
|
||||
$count->group($group);
|
||||
}
|
||||
$columns = array('cnt' => 'COUNT(*)');
|
||||
return $this->db->select()->from($count, $columns);
|
||||
}
|
||||
if ($this->maxCount !== null) {
|
||||
return $this->db->select()->from($count->limit($this->maxCount));
|
||||
}
|
||||
|
||||
$count->columns(array('cnt' => 'COUNT(*)'));
|
||||
return $count;
|
||||
|
|
|
@ -227,6 +227,8 @@ abstract class Filter
|
|||
* Create filter from queryString
|
||||
*
|
||||
* This is still pretty basic, need improvement
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function fromQueryString($query)
|
||||
{
|
||||
|
|
|
@ -97,18 +97,41 @@ class FilterExpression extends Filter
|
|||
|
||||
public function matches($row)
|
||||
{
|
||||
if (! isset($row->{$this->column})) {
|
||||
// TODO: REALLY? Exception?
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_array($this->expression)) {
|
||||
return in_array($row->{$this->column}, $this->expression);
|
||||
} elseif (strpos($this->expression, '*') === false) {
|
||||
return (string) $row->{$this->column} === (string) $this->expression;
|
||||
} else {
|
||||
$parts = preg_split('~\*~', $this->expression);
|
||||
foreach ($parts as & $part) {
|
||||
$part = preg_quote($part);
|
||||
}
|
||||
$pattern = '/^' . implode('.*', $parts) . '$/';
|
||||
return (bool) preg_match($pattern, $row->{$this->column});
|
||||
}
|
||||
|
||||
$expression = (string) $this->expression;
|
||||
if (strpos($expression, '*') === false) {
|
||||
if (is_array($row->{$this->column})) {
|
||||
return in_array($expression, $row->{$this->column});
|
||||
}
|
||||
|
||||
return (string) $row->{$this->column} === $expression;
|
||||
}
|
||||
|
||||
$parts = array();
|
||||
foreach (preg_split('~\*~', $expression) as $part) {
|
||||
$parts[] = preg_quote($part);
|
||||
}
|
||||
$pattern = '/^' . implode('.*', $parts) . '$/';
|
||||
|
||||
if (is_array($row->{$this->column})) {
|
||||
foreach ($row->{$this->column} as $candidate) {
|
||||
if (preg_match($pattern, $candidate)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) preg_match($pattern, $row->{$this->column});
|
||||
}
|
||||
|
||||
public function andFilter(Filter $filter)
|
||||
|
|
|
@ -5,21 +5,4 @@ namespace Icinga\Data\Filter;
|
|||
|
||||
class FilterMatch extends FilterExpression
|
||||
{
|
||||
public function matches($row)
|
||||
{
|
||||
if (! isset($row->{$this->column})) {
|
||||
// TODO: REALLY? Exception?
|
||||
return false;
|
||||
}
|
||||
$expression = (string) $this->expression;
|
||||
if (strpos($expression, '*') === false) {
|
||||
return (string) $row->{$this->column} === $expression;
|
||||
} else {
|
||||
$parts = array();
|
||||
foreach (preg_split('/\*/', $expression) as $part) {
|
||||
$parts[] = preg_quote($part);
|
||||
}
|
||||
return preg_match('/^' . implode('.*', $parts) . '$/', $row->{$this->column});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,15 +7,6 @@ class FilterMatchNot extends FilterExpression
|
|||
{
|
||||
public function matches($row)
|
||||
{
|
||||
$expression = (string) $this->expression;
|
||||
if (strpos($expression, '*') === false) {
|
||||
return (string) $row->{$this->column} !== $expression;
|
||||
} else {
|
||||
$parts = array();
|
||||
foreach (preg_split('/\*/', $expression) as $part) {
|
||||
$parts[] = preg_quote($part);
|
||||
}
|
||||
return ! preg_match('/^' . implode('.*', $parts) . '$/', $row->{$this->column});
|
||||
}
|
||||
return !parent::matches($row);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Data;
|
||||
|
||||
interface FilterColumns
|
||||
{
|
||||
/**
|
||||
* Return a filterable's filter columns with their optional label as key
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFilterColumns();
|
||||
|
||||
/**
|
||||
* Return a filterable's search columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSearchColumns();
|
||||
}
|
|
@ -4,12 +4,11 @@
|
|||
namespace Icinga\Data;
|
||||
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\SimpleQuery;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Web\Paginator\Adapter\QueryAdapter;
|
||||
use Zend_Paginator;
|
||||
|
||||
class PivotTable
|
||||
class PivotTable implements Sortable
|
||||
{
|
||||
/**
|
||||
* The query to fetch as pivot table
|
||||
|
@ -19,53 +18,74 @@ class PivotTable
|
|||
protected $baseQuery;
|
||||
|
||||
/**
|
||||
* The query to fetch the x axis labels
|
||||
*
|
||||
* @var SimpleQuery
|
||||
*/
|
||||
protected $xAxisQuery;
|
||||
|
||||
/**
|
||||
* The query to fetch the y axis labels
|
||||
*
|
||||
* @var SimpleQuery
|
||||
*/
|
||||
protected $yAxisQuery;
|
||||
|
||||
/**
|
||||
* The column that contains the labels for the x axis
|
||||
* X-axis pivot column
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $xAxisColumn;
|
||||
|
||||
/**
|
||||
* The column that contains the labels for the y axis
|
||||
* Y-axis pivot column
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $yAxisColumn;
|
||||
|
||||
/**
|
||||
* The filter being applied on the query for the x axis
|
||||
* Column for sorting the result set
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $order = array();
|
||||
|
||||
/**
|
||||
* The filter being applied on the query for the x-axis
|
||||
*
|
||||
* @var Filter
|
||||
*/
|
||||
protected $xAxisFilter;
|
||||
|
||||
/**
|
||||
* The filter being applied on the query for the y axis
|
||||
* The filter being applied on the query for the y-axis
|
||||
*
|
||||
* @var Filter
|
||||
*/
|
||||
protected $yAxisFilter;
|
||||
|
||||
/**
|
||||
* The query to fetch the leading x-axis rows and their headers
|
||||
*
|
||||
* @var SimpleQuery
|
||||
*/
|
||||
protected $xAxisQuery;
|
||||
|
||||
/**
|
||||
* The query to fetch the leading y-axis rows and their headers
|
||||
*
|
||||
* @var SimpleQuery
|
||||
*/
|
||||
protected $yAxisQuery;
|
||||
|
||||
/**
|
||||
* X-axis header column
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $xAxisHeader;
|
||||
|
||||
/**
|
||||
* Y-axis header column
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $yAxisHeader;
|
||||
|
||||
/**
|
||||
* Create a new pivot table
|
||||
*
|
||||
* @param SimpleQuery $query The query to fetch as pivot table
|
||||
* @param string $xAxisColumn The column that contains the labels for the x axis
|
||||
* @param string $yAxisColumn The column that contains the labels for the y axis
|
||||
* @param SimpleQuery $query The query to fetch as pivot table
|
||||
* @param string $xAxisColumn X-axis pivot column
|
||||
* @param string $yAxisColumn Y-axis pivot column
|
||||
*/
|
||||
public function __construct(SimpleQuery $query, $xAxisColumn, $yAxisColumn)
|
||||
{
|
||||
|
@ -75,7 +95,32 @@ class PivotTable
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the filter to apply on the query for the x axis
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasOrder()
|
||||
{
|
||||
return ! empty($this->order);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function order($field, $direction = null)
|
||||
{
|
||||
$this->order[$field] = $direction;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter to apply on the query for the x-axis
|
||||
*
|
||||
* @param Filter $filter
|
||||
*
|
||||
|
@ -88,7 +133,7 @@ class PivotTable
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the filter to apply on the query for the y axis
|
||||
* Set the filter to apply on the query for the y-axis
|
||||
*
|
||||
* @param Filter $filter
|
||||
*
|
||||
|
@ -100,6 +145,56 @@ class PivotTable
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the x-axis header
|
||||
*
|
||||
* Defaults to {@link $xAxisColumn} in case no x-axis header has been set using {@link setXAxisHeader()}
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getXAxisHeader()
|
||||
{
|
||||
return $this->xAxisHeader !== null ? $this->xAxisHeader : $this->xAxisColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the x-axis header
|
||||
*
|
||||
* @param string $xAxisHeader
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setXAxisHeader($xAxisHeader)
|
||||
{
|
||||
$this->xAxisHeader = (string) $xAxisHeader;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the y-axis header
|
||||
*
|
||||
* Defaults to {@link $yAxisColumn} in case no x-axis header has been set using {@link setYAxisHeader()}
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getYAxisHeader()
|
||||
{
|
||||
return $this->yAxisHeader !== null ? $this->yAxisHeader : $this->yAxisColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the y-axis header
|
||||
*
|
||||
* @param string $yAxisHeader
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setYAxisHeader($yAxisHeader)
|
||||
{
|
||||
$this->yAxisHeader = (string) $yAxisHeader;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value for the given request parameter
|
||||
*
|
||||
|
@ -107,7 +202,7 @@ class PivotTable
|
|||
* @param string $param The parameter name to return
|
||||
* @param int $default The default value to return
|
||||
*
|
||||
* @return int
|
||||
* @return int
|
||||
*/
|
||||
protected function getPaginationParameter($axis, $param, $default = null)
|
||||
{
|
||||
|
@ -125,23 +220,25 @@ class PivotTable
|
|||
/**
|
||||
* Query horizontal (x) axis
|
||||
*
|
||||
* @return SimpleQuery
|
||||
* @return SimpleQuery
|
||||
*/
|
||||
protected function queryXAxis()
|
||||
{
|
||||
if ($this->xAxisQuery === null) {
|
||||
$this->xAxisQuery = clone $this->baseQuery;
|
||||
$this->xAxisQuery->group($this->xAxisColumn);
|
||||
$this->xAxisQuery->columns(array($this->xAxisColumn));
|
||||
$this->xAxisQuery->setUseSubqueryCount();
|
||||
$xAxisHeader = $this->getXAxisHeader();
|
||||
$columns = array($this->xAxisColumn, $xAxisHeader);
|
||||
$this->xAxisQuery->group(array_unique($columns)); // xAxisColumn and header may be the same column
|
||||
$this->xAxisQuery->columns($columns);
|
||||
|
||||
if ($this->xAxisFilter !== null) {
|
||||
$this->xAxisQuery->addFilter($this->xAxisFilter);
|
||||
}
|
||||
|
||||
if (! $this->xAxisQuery->hasOrder($this->xAxisColumn)) {
|
||||
$this->xAxisQuery->order($this->xAxisColumn, 'asc');
|
||||
}
|
||||
$this->xAxisQuery->order(
|
||||
$xAxisHeader,
|
||||
isset($this->order[$xAxisHeader]) ? $this->order[$xAxisHeader] : self::SORT_ASC
|
||||
);
|
||||
}
|
||||
|
||||
return $this->xAxisQuery;
|
||||
|
@ -150,30 +247,31 @@ class PivotTable
|
|||
/**
|
||||
* Query vertical (y) axis
|
||||
*
|
||||
* @return SimpleQuery
|
||||
* @return SimpleQuery
|
||||
*/
|
||||
protected function queryYAxis()
|
||||
{
|
||||
if ($this->yAxisQuery === null) {
|
||||
$this->yAxisQuery = clone $this->baseQuery;
|
||||
$this->yAxisQuery->group($this->yAxisColumn);
|
||||
$this->yAxisQuery->columns(array($this->yAxisColumn));
|
||||
$this->yAxisQuery->setUseSubqueryCount();
|
||||
$yAxisHeader = $this->getYAxisHeader();
|
||||
$columns = array($this->yAxisColumn, $yAxisHeader);
|
||||
$this->yAxisQuery->group(array_unique($columns)); // yAxisColumn and header may be the same column
|
||||
$this->yAxisQuery->columns($columns);
|
||||
|
||||
if ($this->yAxisFilter !== null) {
|
||||
$this->yAxisQuery->addFilter($this->yAxisFilter);
|
||||
}
|
||||
|
||||
if (! $this->yAxisQuery->hasOrder($this->yAxisColumn)) {
|
||||
$this->yAxisQuery->order($this->yAxisColumn, 'asc');
|
||||
}
|
||||
$this->yAxisQuery->order(
|
||||
$yAxisHeader,
|
||||
isset($this->order[$yAxisHeader]) ? $this->order[$yAxisHeader] : self::SORT_ASC
|
||||
);
|
||||
}
|
||||
|
||||
return $this->yAxisQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pagination adapter for the x axis query
|
||||
* Return a pagination adapter for the x-axis query
|
||||
*
|
||||
* $limit and $page are taken from the current request if not given.
|
||||
*
|
||||
|
@ -204,7 +302,7 @@ class PivotTable
|
|||
}
|
||||
|
||||
/**
|
||||
* Return a pagination adapter for the y axis query
|
||||
* Return a pagination adapter for the y-axis query
|
||||
*
|
||||
* $limit and $page are taken from the current request if not given.
|
||||
*
|
||||
|
@ -235,9 +333,9 @@ class PivotTable
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the pivot table as array
|
||||
* Return the pivot table as an array of pivot data and pivot header
|
||||
*
|
||||
* @return array
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
|
@ -245,33 +343,39 @@ class PivotTable
|
|||
($this->xAxisFilter === null && $this->yAxisFilter === null)
|
||||
|| ($this->xAxisFilter !== null && $this->yAxisFilter !== null)
|
||||
) {
|
||||
$xAxis = $this->queryXAxis()->fetchColumn();
|
||||
$yAxis = $this->queryYAxis()->fetchColumn();
|
||||
$xAxis = $this->queryXAxis()->fetchPairs();
|
||||
$yAxis = $this->queryYAxis()->fetchPairs();
|
||||
} else {
|
||||
if ($this->xAxisFilter !== null) {
|
||||
$xAxis = $this->queryXAxis()->fetchColumn();
|
||||
$yAxis = $this->queryYAxis()->where($this->xAxisColumn, $xAxis)->fetchColumn();
|
||||
$xAxis = $this->queryXAxis()->fetchPairs();
|
||||
$yAxis = $this->queryYAxis()->where($this->xAxisColumn, $xAxis)->fetchPairs();
|
||||
} else { // $this->yAxisFilter !== null
|
||||
$yAxis = $this->queryYAxis()->fetchColumn();
|
||||
$xAxis = $this->queryXAxis()->where($this->yAxisColumn, $yAxis)->fetchColumn();
|
||||
$yAxis = $this->queryYAxis()->fetchPairs();
|
||||
$xAxis = $this->queryXAxis()->where($this->yAxisColumn, $yAxis)->fetchPairs();
|
||||
}
|
||||
}
|
||||
$pivotData = array();
|
||||
$pivotHeader = array(
|
||||
'cols' => $xAxis,
|
||||
'rows' => $yAxis
|
||||
);
|
||||
if (! empty($xAxis) && ! empty($yAxis)) {
|
||||
$xAxisKeys = array_keys($xAxis);
|
||||
$yAxisKeys = array_keys($yAxis);
|
||||
$this->baseQuery
|
||||
->where($this->xAxisColumn, $xAxisKeys)
|
||||
->where($this->yAxisColumn, $yAxisKeys);
|
||||
|
||||
$pivot = array();
|
||||
if (!empty($xAxis) && !empty($yAxis)) {
|
||||
$this->baseQuery->where($this->xAxisColumn, $xAxis)->where($this->yAxisColumn, $yAxis);
|
||||
|
||||
foreach ($yAxis as $yLabel) {
|
||||
foreach ($xAxis as $xLabel) {
|
||||
$pivot[$yLabel][$xLabel] = null;
|
||||
foreach ($yAxisKeys as $yAxisKey) {
|
||||
foreach ($xAxisKeys as $xAxisKey) {
|
||||
$pivotData[$yAxisKey][$xAxisKey] = null;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->baseQuery as $row) {
|
||||
$pivot[$row->{$this->yAxisColumn}][$row->{$this->xAxisColumn}] = $row;
|
||||
$pivotData[$row->{$this->yAxisColumn}][$row->{$this->xAxisColumn}] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
return $pivot;
|
||||
return array($pivotData, $pivotHeader);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,6 +143,16 @@ class SimpleQuery implements QueryInterface, Queryable, Iterator
|
|||
return $this->ds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current position of this query's iterator
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getIteratorPosition()
|
||||
{
|
||||
return $this->iteratorPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start or rewind the iteration
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Exception;
|
||||
|
||||
/**
|
||||
* Exception thrown if something to add already exists
|
||||
*/
|
||||
class AlreadyExistsException extends IcingaException
|
||||
{
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Exception\Http;
|
||||
|
||||
/**
|
||||
* Exception thrown for sending a HTTP 400 response w/ a custom message
|
||||
*/
|
||||
class HttpBadRequestException extends HttpException
|
||||
{
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue