Merge branch 'master' into feature/improve-multi-select-view-8565
Conflicts: modules/monitoring/application/controllers/HostsController.php modules/monitoring/application/controllers/ServicesController.php modules/monitoring/application/views/scripts/hosts/show.phtml modules/monitoring/application/views/scripts/list/hosts.phtml modules/monitoring/application/views/scripts/partials/host/objects-header.phtml modules/monitoring/application/views/scripts/partials/service/objects-header.phtml modules/monitoring/application/views/scripts/services/show.phtml modules/monitoring/public/css/module.less public/js/icinga/behavior/tooltip.js
This commit is contained in:
commit
25f397042b
|
@ -90,7 +90,7 @@ class icingaweb2_dev (
|
|||
source => $name,
|
||||
}
|
||||
|
||||
icingaweb2::config::general { [ 'config', 'resources' ]:
|
||||
icingaweb2::config::general { [ 'config', 'resources', 'roles' ]:
|
||||
source => $name,
|
||||
replace => false,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[admins]
|
||||
users = icingaadmin
|
||||
permissions = *
|
5
AUTHORS
5
AUTHORS
|
@ -1,5 +1,6 @@
|
|||
Alexander Fuhr <alexander.fuhr@netways.de>
|
||||
Alexander Klimov <alexander.klimov@netways.de>
|
||||
ayoubabid <ayoubabid@users.noreply.github.com>
|
||||
baufrecht <baufrecht@users.noreply.github.com>
|
||||
Bernd Erk <bernd.erk@icinga.org>
|
||||
Boden Garman <boden.garman@spintel.net.au>
|
||||
|
@ -11,8 +12,9 @@ Goran Rakic <grakic@devbase.net>
|
|||
Gunnar Beutner <gunnar.beutner@netways.de>
|
||||
Jannis Moßhammer <jannis.mosshammer@netways.de>
|
||||
Johannes Meyer <johannes.meyer@netways.de>
|
||||
Marius Hein <marius.hein@netways.de>
|
||||
Louis Sautier <sautier.louis@gmail.com>
|
||||
Marcus Cobden <marcus@marcuscobden.co.uk>
|
||||
Marius Hein <marius.hein@netways.de>
|
||||
Markus Frosch <markus@lazyfrosch.de>
|
||||
Matthias Jentsch <matthias.jentsch@netways.de>
|
||||
Michael Friedrich <michael.friedrich@netways.de>
|
||||
|
@ -22,4 +24,3 @@ Sylph Lin <sylph.lin@gmail.com>
|
|||
Thomas Gelf <thomas.gelf@netways.de>
|
||||
Tom Ford <exptom@users.noreply.github.com>
|
||||
Ulf Lange <mopp@gmx.net>
|
||||
ayoubabid <ayoubabid@users.noreply.github.com>
|
||||
|
|
|
@ -102,21 +102,21 @@ class AuthenticationController extends ActionController
|
|||
$this->view->form->addError(
|
||||
$this->translate(
|
||||
'No authentication methods available. Did you create'
|
||||
. ' authentication.ini when setting up Icinga Web 2?'
|
||||
. ' authentication.ini when setting up Icinga Web 2?'
|
||||
)
|
||||
);
|
||||
} else if ($backendsTried === $backendsWithError) {
|
||||
$this->view->form->addError(
|
||||
$this->translate(
|
||||
'All configured authentication methods failed.'
|
||||
. ' Please check the system log or Icinga Web 2 log for more information.'
|
||||
. ' Please check the system log or Icinga Web 2 log for more information.'
|
||||
)
|
||||
);
|
||||
} elseif ($backendsWithError) {
|
||||
$this->view->form->addError(
|
||||
$this->translate(
|
||||
'Please note that not all authentication methods were available.'
|
||||
. ' Check the system log or Icinga Web 2 log for more information.'
|
||||
. ' Check the system log or Icinga Web 2 log for more information.'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ class AuthenticationController extends ActionController
|
|||
$this->view->form->addError($e->getMessage());
|
||||
}
|
||||
|
||||
$this->view->requiresExternalAuth = $triedOnlyExternalAuth && !$auth->isAuthenticated();
|
||||
$this->view->requiresExternalAuth = $triedOnlyExternalAuth && ! $auth->isAuthenticated();
|
||||
$this->view->requiresSetup = Icinga::app()->requiresSetup();
|
||||
}
|
||||
|
||||
|
|
|
@ -11,19 +11,19 @@ use Icinga\Forms\Config\GeneralConfigForm;
|
|||
use Icinga\Forms\Config\ResourceConfigForm;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Security\SecurityException;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Widget;
|
||||
|
||||
/**
|
||||
* Application and module configuration
|
||||
*/
|
||||
class ConfigController extends ActionController
|
||||
class ConfigController extends Controller
|
||||
{
|
||||
/**
|
||||
* The first allowed config action according to the user's permissions
|
||||
*
|
||||
* @type string
|
||||
* @var string
|
||||
*/
|
||||
protected $firstAllowedAction;
|
||||
|
||||
|
@ -37,7 +37,7 @@ class ConfigController extends ActionController
|
|||
$tabs = $this->getTabs();
|
||||
$auth = $this->Auth();
|
||||
$allowedActions = array();
|
||||
if ($auth->hasPermission('system/config/application')) {
|
||||
if ($auth->hasPermission('config/application/general')) {
|
||||
$tabs->add('application', array(
|
||||
'title' => $this->translate('Adjust the general configuration of Icinga Web 2'),
|
||||
'label' => $this->translate('Application'),
|
||||
|
@ -45,7 +45,7 @@ class ConfigController extends ActionController
|
|||
));
|
||||
$allowedActions[] = 'application';
|
||||
}
|
||||
if ($auth->hasPermission('system/config/authentication')) {
|
||||
if ($auth->hasPermission('config/application/authentication')) {
|
||||
$tabs->add('authentication', array(
|
||||
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
|
||||
'label' => $this->translate('Authentication'),
|
||||
|
@ -53,7 +53,7 @@ class ConfigController extends ActionController
|
|||
));
|
||||
$allowedActions[] = 'authentication';
|
||||
}
|
||||
if ($auth->hasPermission('system/config/resources')) {
|
||||
if ($auth->hasPermission('config/application/resources')) {
|
||||
$tabs->add('resource', array(
|
||||
'title' => $this->translate('Configure which resources are being utilized by Icinga Web 2'),
|
||||
'label' => $this->translate('Resources'),
|
||||
|
@ -61,7 +61,7 @@ class ConfigController extends ActionController
|
|||
));
|
||||
$allowedActions[] = 'resource';
|
||||
}
|
||||
if ($auth->hasPermission('system/config/roles')) {
|
||||
if ($auth->hasPermission('config/application/roles')) {
|
||||
$tabs->add('roles', array(
|
||||
'title' => $this->translate(
|
||||
'Configure roles to permit or restrict users and groups accessing Icinga Web 2'
|
||||
|
@ -72,7 +72,6 @@ class ConfigController extends ActionController
|
|||
$allowedActions[] = 'roles';
|
||||
}
|
||||
$this->firstAllowedAction = array_shift($allowedActions);
|
||||
$this->getTabs()->setTitle($this->translate('Config Navigation'));
|
||||
}
|
||||
|
||||
public function devtoolsAction()
|
||||
|
@ -103,7 +102,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function applicationAction()
|
||||
{
|
||||
$this->assertPermission('system/config/application');
|
||||
$this->assertPermission('config/application/general');
|
||||
$form = new GeneralConfigForm();
|
||||
$form->setIniConfig(Config::app());
|
||||
$form->handleRequest();
|
||||
|
@ -131,26 +130,35 @@ class ConfigController extends ActionController
|
|||
->order('enabled', 'desc')
|
||||
->order('name')
|
||||
->paginate();
|
||||
$this->setupLimitControl();
|
||||
$this->setupPaginationControl($this->view->modules);
|
||||
// TODO: Not working
|
||||
/*$this->setupSortControl(array(
|
||||
'name' => $this->translate('Modulename'),
|
||||
'path' => $this->translate('Installation Path'),
|
||||
'enabled' => $this->translate('State')
|
||||
));*/
|
||||
}
|
||||
|
||||
public function moduleAction()
|
||||
{
|
||||
$name = $this->getParam('name');
|
||||
$app = Icinga::app();
|
||||
$manager = $app->getModuleManager();
|
||||
$name = $this->getParam('name');
|
||||
if ($manager->hasInstalled($name)) {
|
||||
$this->view->moduleData = Icinga::app()
|
||||
->getModuleManager()
|
||||
->select()
|
||||
->from('modules')
|
||||
->where('name', $name)
|
||||
->fetchRow();
|
||||
$module = new Module($app, $name, $manager->getModuleDir($name));
|
||||
$this->view->moduleData = $manager->select()->from('modules')->where('name', $name)->fetchRow();
|
||||
if ($manager->hasLoaded($name)) {
|
||||
$module = $manager->getModule($name);
|
||||
} else {
|
||||
$module = new Module($app, $name, $manager->getModuleDir($name));
|
||||
}
|
||||
|
||||
$this->view->module = $module;
|
||||
$this->view->tabs = $module->getConfigTabs()->activate('info');
|
||||
} else {
|
||||
$this->view->module = false;
|
||||
$this->view->tabs = null;
|
||||
}
|
||||
$this->view->tabs = $module->getConfigTabs()->activate('info');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -158,12 +166,11 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function moduleenableAction()
|
||||
{
|
||||
$this->assertPermission('system/config/modules');
|
||||
$this->assertPermission('config/modules');
|
||||
$module = $this->getParam('name');
|
||||
$manager = Icinga::app()->getModuleManager();
|
||||
try {
|
||||
$manager->enableModule($module);
|
||||
$manager->loadModule($module);
|
||||
Notification::success(sprintf($this->translate('Module "%s" enabled'), $module));
|
||||
$this->rerenderLayout()->reloadCss()->redirectNow('config/modules');
|
||||
} catch (Exception $e) {
|
||||
|
@ -179,7 +186,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function moduledisableAction()
|
||||
{
|
||||
$this->assertPermission('system/config/modules');
|
||||
$this->assertPermission('config/modules');
|
||||
$module = $this->getParam('name');
|
||||
$manager = Icinga::app()->getModuleManager();
|
||||
try {
|
||||
|
@ -199,7 +206,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function authenticationAction()
|
||||
{
|
||||
$this->assertPermission('system/config/authentication');
|
||||
$this->assertPermission('config/application/authentication');
|
||||
$form = new AuthenticationBackendReorderForm();
|
||||
$form->setIniConfig(Config::app('authentication'));
|
||||
$form->handleRequest();
|
||||
|
@ -214,7 +221,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function createauthenticationbackendAction()
|
||||
{
|
||||
$this->assertPermission('system/config/authentication');
|
||||
$this->assertPermission('config/application/authentication');
|
||||
$form = new AuthenticationBackendConfigForm();
|
||||
$form->setTitle($this->translate('Create New Authentication Backend'));
|
||||
$form->addDescription($this->translate(
|
||||
|
@ -236,7 +243,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function editauthenticationbackendAction()
|
||||
{
|
||||
$this->assertPermission('system/config/authentication');
|
||||
$this->assertPermission('config/application/authentication');
|
||||
$form = new AuthenticationBackendConfigForm();
|
||||
$form->setTitle($this->translate('Edit Backend'));
|
||||
$form->setIniConfig(Config::app('authentication'));
|
||||
|
@ -254,7 +261,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function removeauthenticationbackendAction()
|
||||
{
|
||||
$this->assertPermission('system/config/authentication');
|
||||
$this->assertPermission('config/application/authentication');
|
||||
$form = new ConfirmRemovalForm(array(
|
||||
'onSuccess' => function ($form) {
|
||||
$configForm = new AuthenticationBackendConfigForm();
|
||||
|
@ -292,7 +299,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function resourceAction()
|
||||
{
|
||||
$this->assertPermission('system/config/resources');
|
||||
$this->assertPermission('config/application/resources');
|
||||
$this->view->resources = Config::app('resources', true)->keys();
|
||||
$this->view->tabs->activate('resource');
|
||||
}
|
||||
|
@ -302,7 +309,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function createresourceAction()
|
||||
{
|
||||
$this->assertPermission('system/config/resources');
|
||||
$this->assertPermission('config/application/resources');
|
||||
$form = new ResourceConfigForm();
|
||||
$form->setTitle($this->translate('Create A New Resource'));
|
||||
$form->addDescription($this->translate('Resources are entities that provide data to Icinga Web 2.'));
|
||||
|
@ -319,7 +326,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function editresourceAction()
|
||||
{
|
||||
$this->assertPermission('system/config/resources');
|
||||
$this->assertPermission('config/application/resources');
|
||||
$form = new ResourceConfigForm();
|
||||
$form->setTitle($this->translate('Edit Existing Resource'));
|
||||
$form->setIniConfig(Config::app('resources'));
|
||||
|
@ -335,7 +342,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function removeresourceAction()
|
||||
{
|
||||
$this->assertPermission('system/config/resources');
|
||||
$this->assertPermission('config/application/resources');
|
||||
$form = new ConfirmRemovalForm(array(
|
||||
'onSuccess' => function ($form) {
|
||||
$configForm = new ResourceConfigForm();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\MissingParameterException;
|
||||
use Icinga\Security\SecurityException;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
|
||||
|
@ -33,7 +34,11 @@ class ErrorController extends ActionController
|
|||
$path = preg_split('~/~', $path);
|
||||
$path = array_shift($path);
|
||||
$this->getResponse()->setHttpResponseCode(404);
|
||||
$this->view->message = $this->translate('Page not found.');
|
||||
$title = preg_replace('/\r?\n.*$/s', '', $exception->getMessage());
|
||||
$this->view->title = 'Server error: ' . $title;
|
||||
if ($this->getInvokeArg('displayExceptions')) {
|
||||
$this->view->stackTrace = $exception->getTraceAsString();
|
||||
}
|
||||
if ($modules->hasInstalled($path) && ! $modules->hasEnabled($path)) {
|
||||
$this->view->message .= ' ' . sprintf(
|
||||
$this->translate('Enabling the "%s" module might help!'),
|
||||
|
@ -42,19 +47,26 @@ class ErrorController extends ActionController
|
|||
}
|
||||
|
||||
break;
|
||||
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_OTHER:
|
||||
if ($exception instanceof SecurityException) {
|
||||
$this->getResponse()->setHttpResponseCode(403);
|
||||
$this->view->message = $exception->getMessage();
|
||||
break;
|
||||
}
|
||||
// Move to default
|
||||
default:
|
||||
switch (true) {
|
||||
case $exception instanceof SecurityException:
|
||||
$this->getResponse()->setHttpResponseCode(403);
|
||||
break;
|
||||
case $exception instanceof MissingParameterException:
|
||||
$this->getResponse()->setHttpResponseCode(400);
|
||||
$this->getResponse()->setHeader(
|
||||
'X-Status-Reason',
|
||||
'Missing parameter ' . $exception->getParameter()
|
||||
);
|
||||
break;
|
||||
default:
|
||||
$this->getResponse()->setHttpResponseCode(500);
|
||||
break;
|
||||
}
|
||||
$title = preg_replace('/\r?\n.*$/s', '', $exception->getMessage());
|
||||
$this->getResponse()->setHttpResponseCode(500);
|
||||
$this->view->title = 'Server error: ' . $title;
|
||||
$this->view->message = $exception->getMessage();
|
||||
if ($this->getInvokeArg('displayExceptions') == true) {
|
||||
if ($this->getInvokeArg('displayExceptions')) {
|
||||
$this->view->stackTrace = $exception->getTraceAsString();
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
use Icinga\Module\Monitoring\Controller;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Protocol\File\FileReader;
|
||||
|
@ -28,7 +31,7 @@ class ListController extends Controller
|
|||
'list/'
|
||||
. str_replace(' ', '', $action)
|
||||
)
|
||||
))->activate($action);
|
||||
))->extend(new OutputFormat())->extend(new DashboardAction())->activate($action);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,16 +44,16 @@ class ListController extends Controller
|
|||
}
|
||||
|
||||
$this->addTitleTab('application log');
|
||||
$pattern = '/^(?<datetime>[0-9]{4}(-[0-9]{2}){2}' // date
|
||||
. 'T[0-9]{2}(:[0-9]{2}){2}([\\+\\-][0-9]{2}:[0-9]{2})?)' // time
|
||||
. ' - (?<loglevel>[A-Za-z]+)' // loglevel
|
||||
. ' - (?<message>.*)$/'; // message
|
||||
|
||||
$loggerWriter = Logger::getInstance()->getWriter();
|
||||
$resource = new FileReader(new ConfigObject(array(
|
||||
'filename' => $loggerWriter->getPath(),
|
||||
'fields' => $pattern
|
||||
'filename' => Config::app()->get('logging', 'file'),
|
||||
'fields' => '/(?<!.)(?<datetime>[0-9]{4}(?:-[0-9]{2}){2}' // date
|
||||
. 'T[0-9]{2}(?::[0-9]{2}){2}(?:[\+\-][0-9]{2}:[0-9]{2})?)' // time
|
||||
. ' - (?<loglevel>[A-Za-z]+) - (?<message>.*)(?!.)/msS' // loglevel, message
|
||||
)));
|
||||
$this->view->logData = $resource->select()->order('DESC')->paginate();
|
||||
|
||||
$this->setupLimitControl();
|
||||
$this->setupPaginationControl($this->view->logData);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,24 +20,24 @@ class RolesController extends ActionController
|
|||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->assertPermission('system/config/roles');
|
||||
$this->assertPermission('config/application/roles');
|
||||
$tabs = $this->getTabs();
|
||||
$auth = $this->Auth();
|
||||
if ($auth->hasPermission('system/config/application')) {
|
||||
if ($auth->hasPermission('config/application/general')) {
|
||||
$tabs->add('application', array(
|
||||
'title' => $this->translate('Adjust the general configuration of Icinga Web 2'),
|
||||
'label' => $this->translate('Application'),
|
||||
'url' => 'config'
|
||||
));
|
||||
}
|
||||
if ($auth->hasPermission('system/config/authentication')) {
|
||||
if ($auth->hasPermission('config/application/authentication')) {
|
||||
$tabs->add('authentication', array(
|
||||
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
|
||||
'label' => $this->translate('Authentication'),
|
||||
'url' => 'config/authentication'
|
||||
));
|
||||
}
|
||||
if ($auth->hasPermission('system/config/resources')) {
|
||||
if ($auth->hasPermission('config/application/resources')) {
|
||||
$tabs->add('resource', array(
|
||||
'title' => $this->translate('Configure which resources are being utilized by Icinga Web 2'),
|
||||
'label' => $this->translate('Resources'),
|
||||
|
@ -51,7 +51,6 @@ class RolesController extends ActionController
|
|||
'label' => $this->translate('Roles'),
|
||||
'url' => 'roles'
|
||||
));
|
||||
$this->getTabs()->setTitle($this->translate('Role Configuration'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,8 @@ class AutoRefreshForm extends Form
|
|||
public function init()
|
||||
{
|
||||
$this->setName('form_auto_refresh');
|
||||
// Post against the current location
|
||||
$this->setAction('');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,7 +34,7 @@ class DbBackendForm extends Form
|
|||
*
|
||||
* @param array $resources The resources to choose from
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
|
|
|
@ -53,7 +53,7 @@ class ExternalBackendForm extends Form
|
|||
return @preg_match($value, '') !== false;
|
||||
});
|
||||
$callbackValidator->setMessage(
|
||||
$this->translate('"%value%" is not a valid regular expression'),
|
||||
$this->translate('"%value%" is not a valid regular expression.'),
|
||||
Zend_Validate_Callback::INVALID_VALUE
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -62,9 +62,10 @@ class ExternalBackendForm extends Form
|
|||
array(
|
||||
'label' => $this->translate('Filter Pattern'),
|
||||
'description' => $this->translate(
|
||||
'The regular expression to use to strip specific parts off from usernames.'
|
||||
. ' Leave empty if you do not want to strip off anything'
|
||||
'The filter to use to strip specific parts off from usernames.'
|
||||
. ' Leave empty if you do not want to strip off anything.'
|
||||
),
|
||||
'requirement' => $this->translate('The filter pattern must be a valid regular expression.'),
|
||||
'validators' => array($callbackValidator)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -35,7 +35,7 @@ class LdapBackendForm extends Form
|
|||
*
|
||||
* @param array $resources The resources to choose from
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ class LdapBackendForm extends Form
|
|||
'required' => true,
|
||||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
'The name of this authentication provider that is used to differentiate it from others.'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -64,8 +64,10 @@ class LdapBackendForm extends Form
|
|||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('LDAP Resource'),
|
||||
'description' => $this->translate('The resource to use for authenticating with this provider'),
|
||||
'label' => $this->translate('LDAP Connection'),
|
||||
'description' => $this->translate(
|
||||
'The LDAP connection to use for authenticating with this provider.'
|
||||
),
|
||||
'multiOptions' => false === empty($this->resources)
|
||||
? array_combine($this->resources, $this->resources)
|
||||
: array()
|
||||
|
@ -77,10 +79,40 @@ class LdapBackendForm extends Form
|
|||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('LDAP User Object Class'),
|
||||
'description' => $this->translate('The object class used for storing users on the ldap server'),
|
||||
'description' => $this->translate('The object class used for storing users on the LDAP server.'),
|
||||
'value' => 'inetOrgPerson'
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'filter',
|
||||
array(
|
||||
'allowEmpty' => true,
|
||||
'label' => $this->translate('LDAP Filter'),
|
||||
'description' => $this->translate(
|
||||
'An additional filter to use when looking up users using the specified connection. '
|
||||
. 'Leave empty to not to use any additional filter rules.'
|
||||
),
|
||||
'requirement' => $this->translate(
|
||||
'The filter needs to be expressed as standard LDAP expression, without'
|
||||
. ' outer parentheses. (e.g. &(foo=bar)(bar=foo) or foo=bar)'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Callback',
|
||||
false,
|
||||
array(
|
||||
'callback' => function ($v) {
|
||||
return strpos($v, '(') !== 0;
|
||||
},
|
||||
'messages' => array(
|
||||
'callbackValue' => $this->translate('The filter must not be wrapped in parantheses.')
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_name_attribute',
|
||||
|
@ -88,7 +120,7 @@ class LdapBackendForm extends Form
|
|||
'required' => true,
|
||||
'label' => $this->translate('LDAP User Name Attribute'),
|
||||
'description' => $this->translate(
|
||||
'The attribute name used for storing the user name on the ldap server'
|
||||
'The attribute name used for storing the user name on the LDAP server.'
|
||||
),
|
||||
'value' => 'uid'
|
||||
)
|
||||
|
@ -106,10 +138,10 @@ class LdapBackendForm extends Form
|
|||
'base_dn',
|
||||
array(
|
||||
'required' => false,
|
||||
'label' => $this->translate('Base DN'),
|
||||
'label' => $this->translate('LDAP Base DN'),
|
||||
'description' => $this->translate(
|
||||
'The path where users can be found on the ldap server. Leave ' .
|
||||
'empty to select all users available on the specified resource.'
|
||||
'The path where users can be found on the LDAP server. Leave ' .
|
||||
'empty to select all users available using the specified connection.'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -142,11 +174,17 @@ class LdapBackendForm extends Form
|
|||
ResourceFactory::createResource($form->getResourceConfig()),
|
||||
$form->getElement('user_class')->getValue(),
|
||||
$form->getElement('user_name_attribute')->getValue(),
|
||||
$form->getElement('base_dn')->getValue()
|
||||
$form->getElement('base_dn')->getValue(),
|
||||
$form->getElement('filter')->getValue()
|
||||
);
|
||||
$ldapUserBackend->assertAuthenticationPossible();
|
||||
} catch (AuthenticationException $e) {
|
||||
$form->addError($e->getMessage());
|
||||
if (($previous = $e->getPrevious()) !== null) {
|
||||
$form->addError($previous->getMessage());
|
||||
} else {
|
||||
$form->addError($e->getMessage());
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
$form->addError(sprintf($form->translate('Unable to validate authentication: %s'), $e->getMessage()));
|
||||
|
|
|
@ -38,7 +38,7 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
*
|
||||
* @param Config $resources The resource configuration
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setResourceConfig(Config $resourceConfig)
|
||||
{
|
||||
|
@ -82,7 +82,7 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
*
|
||||
* @param array $values The values to extend the configuration with
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does already exist
|
||||
*/
|
||||
|
@ -159,7 +159,7 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
* @param string $name The name of the backend to be moved
|
||||
* @param int $position The new (absolute) position of the backend
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does not exist
|
||||
*/
|
||||
|
|
|
@ -51,7 +51,7 @@ class AuthenticationBackendReorderForm extends ConfigForm
|
|||
|
||||
try {
|
||||
if ($configForm->move($backendName, $position)->save()) {
|
||||
Notification::success($this->translate('Authentication order updated!'));
|
||||
Notification::success($this->translate('Authentication order updated'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ class LoggingConfigForm extends Form
|
|||
'description' => $this->translate(
|
||||
'The name of the application by which to prefix syslog messages.'
|
||||
),
|
||||
'requirement' => $this->translate('The application prefix must not contain whitespace.'),
|
||||
'value' => 'icingaweb2',
|
||||
'validators' => array(
|
||||
array(
|
||||
|
|
|
@ -49,6 +49,7 @@ class DbResourceForm extends Form
|
|||
'db',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('Database Type'),
|
||||
'description' => $this->translate('The type of SQL database'),
|
||||
'multiOptions' => $dbChoices
|
||||
|
@ -68,10 +69,11 @@ class DbResourceForm extends Form
|
|||
'number',
|
||||
'port',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Port'),
|
||||
'description' => $this->translate('The port to use'),
|
||||
'value' => 3306
|
||||
'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
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
namespace Icinga\Forms\Config\Resource;
|
||||
|
||||
use Zend_Validate_Callback;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
|
@ -42,13 +43,22 @@ class FileResourceForm extends Form
|
|||
'validators' => array('ReadablePathValidator')
|
||||
)
|
||||
);
|
||||
$callbackValidator = new Zend_Validate_Callback(function ($value) {
|
||||
return @preg_match($value, '') !== false;
|
||||
});
|
||||
$callbackValidator->setMessage(
|
||||
$this->translate('"%value%" is not a valid regular expression.'),
|
||||
Zend_Validate_Callback::INVALID_VALUE
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'fields',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Pattern'),
|
||||
'description' => $this->translate('The regular expression by which to identify columns')
|
||||
'description' => $this->translate('The pattern by which to identify columns.'),
|
||||
'requirement' => $this->translate('The column pattern must be a valid regular expression.'),
|
||||
'validators' => array($callbackValidator)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ use Exception;
|
|||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Protocol\Ldap\Connection;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying ldap resources
|
||||
|
@ -26,6 +27,10 @@ class LdapResourceForm extends Form
|
|||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$defaultPort = ! array_key_exists('encryption', $formData) || $formData['encryption'] !== Connection::LDAPS
|
||||
? 389
|
||||
: 636;
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
|
@ -51,12 +56,48 @@ class LdapResourceForm extends Form
|
|||
'number',
|
||||
'port',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Port'),
|
||||
'description' => $this->translate('The port of the LDAP server to use for authentication'),
|
||||
'value' => 389
|
||||
'required' => true,
|
||||
'preserveDefault' => true,
|
||||
'label' => $this->translate('Port'),
|
||||
'description' => $this->translate('The port of the LDAP server to use for authentication'),
|
||||
'value' => $defaultPort
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'encryption',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('Encryption'),
|
||||
'description' => $this->translate(
|
||||
'Whether to encrypt communication. Choose STARTTLS or LDAPS for encrypted communication or'
|
||||
. ' none for unencrypted communication'
|
||||
),
|
||||
'multiOptions' => array(
|
||||
'none' => $this->translate('None', 'resource.ldap.encryption'),
|
||||
Connection::STARTTLS => 'STARTTLS',
|
||||
Connection::LDAPS => 'LDAPS'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
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',
|
||||
|
@ -119,12 +160,15 @@ class LdapResourceForm extends Form
|
|||
$form->getElement('bind_pw')->getValue()
|
||||
)
|
||||
) {
|
||||
throw new Exception();
|
||||
throw new Exception(); // TODO: Get the exact error message
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$form->addError(
|
||||
$form->translate('Connectivity validation failed, connection to the given resource not possible.')
|
||||
);
|
||||
$msg = $form->translate('Connectivity validation failed, connection to the given resource not possible.');
|
||||
if (($error = $e->getMessage())) {
|
||||
$msg .= ' (' . $error . ')';
|
||||
}
|
||||
|
||||
$form->addError($msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ class ResourceConfigForm extends ConfigForm
|
|||
*
|
||||
* @param array $values The values to extend the configuration with
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*
|
||||
* @thrwos InvalidArgumentException In case the resource does already exist
|
||||
*/
|
||||
|
|
|
@ -25,7 +25,7 @@ class ConfigForm extends Form
|
|||
*
|
||||
* @param Config $config The configuration to use
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setIniConfig(Config $config)
|
||||
{
|
||||
|
|
|
@ -148,9 +148,9 @@ class DashletForm extends Form
|
|||
$this->populate(array(
|
||||
'pane' => $dashlet->getPane()->getName(),
|
||||
'org_pane' => $dashlet->getPane()->getName(),
|
||||
'dashlet' => $dashlet->getTitle(),
|
||||
'org_dashlet' => $dashlet->getTitle(),
|
||||
'url' => $dashlet->getUrl()
|
||||
'dashlet' => $dashlet->getTitle(),
|
||||
'org_dashlet' => $dashlet->getTitle(),
|
||||
'url' => $dashlet->getUrl()->getRelativeUrl()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ class PreferenceForm extends Form
|
|||
*
|
||||
* @param Preferences $preferences The preferences to work with
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setPreferences(Preferences $preferences)
|
||||
{
|
||||
|
@ -61,17 +61,18 @@ class PreferenceForm extends Form
|
|||
*
|
||||
* @param PreferencesStore $store The preference store to use
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setStore(PreferencesStore $store)
|
||||
{
|
||||
$this->store = $store;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist preferences
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
|
|
|
@ -18,39 +18,39 @@ class RoleForm extends ConfigForm
|
|||
/**
|
||||
* Provided permissions by currently loaded modules
|
||||
*
|
||||
* @type array
|
||||
* @var array
|
||||
*/
|
||||
protected $providedPermissions = array(
|
||||
'*' => '*',
|
||||
'system/config/*' => 'system/config/*',
|
||||
'system/config/application' => 'system/config/application',
|
||||
'system/config/authentication' => 'system/config/authentication',
|
||||
'system/config/modules' => 'system/config/modules',
|
||||
'system/config/resources' => 'system/config/resources',
|
||||
'system/config/roles' => 'system/config/roles'
|
||||
'*' => '*',
|
||||
'config/*' => 'config/*',
|
||||
'config/application/*' => 'config/application/*',
|
||||
'config/application/general' => 'config/application/general',
|
||||
'config/application/authentication' => 'config/application/authentication',
|
||||
'config/application/resources' => 'config/application/resources',
|
||||
'config/application/roles' => 'config/application/roles',
|
||||
'config/modules' => 'config/modules'
|
||||
);
|
||||
|
||||
/**
|
||||
* Provided restrictions by currently loaded modules
|
||||
*
|
||||
* @type array
|
||||
* @var array
|
||||
*/
|
||||
protected $providedRestrictions = array();
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::init() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$helper = new Zend_Form_Element('bogus');
|
||||
foreach (Icinga::app()->getModuleManager()->getLoadedModules() as $module) {
|
||||
foreach ($module->getProvidedPermissions() as $permission) {
|
||||
/** @type object $permission */
|
||||
/** @var object $permission */
|
||||
$this->providedPermissions[$permission->name] = $permission->name . ': ' . $permission->description;
|
||||
}
|
||||
foreach ($module->getProvidedRestrictions() as $restriction) {
|
||||
/** @type object $restriction */
|
||||
/** @var object $restriction */
|
||||
$name = $helper->filterName($restriction->name); // Zend only permits alphanumerics, the underscore,
|
||||
// the circumflex and any ASCII character in range
|
||||
// \x7f to \xff (127 to 255)
|
||||
|
@ -68,8 +68,7 @@ class RoleForm extends ConfigForm
|
|||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData = array())
|
||||
{
|
||||
|
@ -253,8 +252,7 @@ class RoleForm extends ConfigForm
|
|||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Zend_Form::getValues() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValues($suppressArrayNotation = false)
|
||||
{
|
||||
|
|
|
@ -29,7 +29,16 @@ if ($notifications->hasMessages()) {
|
|||
}
|
||||
?></ul>
|
||||
<div id="logo" data-base-target="_main">
|
||||
<img aria-hidden="true" src="<?= $this->href('img/logo_icinga-inv.png') ?>" class="logo" alt="<?= t('Dashboard') ?>" />
|
||||
<?= $this->qlink(
|
||||
'',
|
||||
'/dashboard',
|
||||
null,
|
||||
array(
|
||||
'icon' => '../logo_icinga-inv.png',
|
||||
'aria-hidden' => 'true',
|
||||
'tabindex' => -1
|
||||
)
|
||||
); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ if (! $this->auth()->isAuthenticated()) {
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="menu" data-last-update="<?= (time() - 14) ?>000" data-base-target="_main" class="container"
|
||||
<div id="menu" data-last-update="-1" data-base-target="_main" class="container"
|
||||
data-icinga-url="<?= $this->href('layout/menu') ?>" data-icinga-refresh="15">
|
||||
<?= $this->partial(
|
||||
'layout/menu.phtml',
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -130,8 +130,8 @@ msgid "Authentication backend name missing"
|
|||
msgstr "Falta o nome do backend de autenticação"
|
||||
|
||||
#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendReorderForm.php:55
|
||||
msgid "Authentication order updated!"
|
||||
msgstr "Ordem da autenticação atualizada!"
|
||||
msgid "Authentication order updated"
|
||||
msgstr "Ordem da autenticação atualizada"
|
||||
|
||||
#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:307
|
||||
msgid "Autologin"
|
||||
|
|
|
@ -37,7 +37,7 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
|
|||
/**
|
||||
* Helper entry point
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function dateFormat()
|
||||
{
|
||||
|
|
|
@ -9,39 +9,39 @@
|
|||
-->
|
||||
<div class="content">
|
||||
<div class="alert alert-warning" id="logout-status">
|
||||
<b> <?= t('Logging out...'); ?> </b> <br />
|
||||
<?= t(
|
||||
'If this message does not disappear, it might be necessary to quit the ' .
|
||||
'current session manually by clearing the cache, or by closing the current ' .
|
||||
'browser session.'
|
||||
<b><?= $this->translate('Logging out...'); ?></b>
|
||||
<br>
|
||||
<?= $this->translate(
|
||||
'If this message does not disappear, it might be necessary to quit the'
|
||||
. ' current session manually by clearing the cache, or by closing the current'
|
||||
. ' browser session.'
|
||||
); ?>
|
||||
</div>
|
||||
|
||||
<div class="container" >
|
||||
<a href="<?= $this->href('dashboard/index'); ?>"> <?= t('Login'); ?></a>
|
||||
<div class="container">
|
||||
<a href="<?= $this->href('dashboard/index?renderLayout'); ?>"><?= $this->translate('Login'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
/**
|
||||
/*
|
||||
* When JavaScript is available, trigger an XmlHTTPRequest with the non-existing user 'logout' and abort it
|
||||
* before it is able to finish. This will cause the browser to show a new authentication prompt in the next
|
||||
* request.
|
||||
*/
|
||||
$(document).ready(function() {
|
||||
msg = $('#logout-status');
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var msg = document.getElementById('logout-status');
|
||||
try {
|
||||
if (navigator.userAgent.toLowerCase().indexOf('msie') !== -1) {
|
||||
document.execCommand('ClearAuthenticationCache');
|
||||
} else {
|
||||
var xhttp = getXMLHttpRequest();
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.open('GET', 'arbitrary url', true, 'logout', 'logout');
|
||||
xhttp.send('');
|
||||
xhttp.abort();
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
msg.html('<?= t('Logout successful!'); ?>');
|
||||
msg.removeClass();
|
||||
msg.addClass('alert alert-success');
|
||||
msg.innerHTML = '<?= $this->translate('Logout successful!'); ?>';
|
||||
msg.className = 'alert alert-success';
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,20 +2,9 @@
|
|||
<?= $tabs; ?>
|
||||
</div>
|
||||
<div class="content" data-base-target="_next">
|
||||
<h1 tabindex="-1" id="authentication-configuration">
|
||||
<?= $this->translate('Authentication Configuration'); ?>
|
||||
</h1>
|
||||
<h2 tabindex="-1" id="authentication-new-backend" class="sr-only">
|
||||
<?= t('New Authentication Backend'); ?>
|
||||
</h2>
|
||||
<p>
|
||||
<a href="<?= $this->href('/config/createAuthenticationBackend'); ?>">
|
||||
<?= $this->icon('plus'); ?><?= $this->translate('Create A New Authentication Backend'); ?>
|
||||
</a>
|
||||
</p>
|
||||
<h2 tabindex="-1" id="authentication-reorder" class="sr-only">
|
||||
<?= t('Reorder Authentication Backends'); ?>
|
||||
</h2>
|
||||
<a href="<?= $this->href('/config/createAuthenticationBackend'); ?>">
|
||||
<?= $this->icon('plus'); ?><?= $this->translate('Create A New Authentication Backend'); ?>
|
||||
</a>
|
||||
<div id="authentication-reorder-form">
|
||||
<?= $form; ?>
|
||||
</div>
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
<?= $this->tabs ?>
|
||||
</div>
|
||||
<div class="content">
|
||||
<h1 tabindex="-1">
|
||||
<?= $this->escape($module->getTitle()) ?>
|
||||
</h1>
|
||||
<?php if (! $module): ?>
|
||||
<?= $this->translate('There is no such module installed.') ?>
|
||||
<?php return; endif ?>
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
<?php if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
<?= $this->paginationControl($modules) ?>
|
||||
<?= $this->tabs; ?>
|
||||
<?= $this->sortBox; ?>
|
||||
<?= $this->limiter; ?>
|
||||
<?= $this->paginator; ?>
|
||||
<?= $this->filterEditor; ?>
|
||||
</div>
|
||||
|
||||
<?php endif ?>
|
||||
<div class="content">
|
||||
<h1 tabindex="-1"><?= $this->translate('Installed Modules') ?></h1>
|
||||
<table class="action" data-base-target="_next">
|
||||
<tbody>
|
||||
<?php foreach ($modules as $module): ?>
|
||||
|
|
|
@ -2,20 +2,9 @@
|
|||
<?= $tabs; ?>
|
||||
</div>
|
||||
<div class="content" data-base-target="_next">
|
||||
<h1 tabindex="-1" id="resource-index">
|
||||
<?= t('Resource Configuration'); ?>
|
||||
</h1>
|
||||
<h2 tabindex="-1" id="resource-new-resource" class="sr-only">
|
||||
<?= t('Create New Resource'); ?>
|
||||
</h2>
|
||||
<p>
|
||||
<a href="<?= $this->href('/config/createresource'); ?>">
|
||||
<?= $this->icon('plus'); ?> <?= $this->translate('Create A New Resource'); ?>
|
||||
</a>
|
||||
</p>
|
||||
<h2 tabindex="-1" id="resource-edit-resource" class="sr-only">
|
||||
<?= t('Edit Existing Resources'); ?>
|
||||
</h2>
|
||||
<a href="<?= $this->href('/config/createresource'); ?>">
|
||||
<?= $this->icon('plus'); ?> <?= $this->translate('Create A New Resource'); ?>
|
||||
</a>
|
||||
<table class="action" id="resource-edit-table">
|
||||
<thead>
|
||||
<th><?= $this->translate('Resource'); ?></th>
|
||||
|
|
|
@ -55,8 +55,8 @@
|
|||
</td>
|
||||
<td style="table-layout: fixed; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
<?= $this->qlink(
|
||||
$dashlet->getUrl(),
|
||||
$dashlet->getUrl(),
|
||||
$dashlet->getUrl()->getRelativeUrl(),
|
||||
$dashlet->getUrl()->getRelativeUrl(),
|
||||
null,
|
||||
array('title' => sprintf($this->translate('Show dashlet %s'), $dashlet->getTitle()))
|
||||
); ?>
|
||||
|
@ -78,4 +78,4 @@
|
|||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,7 @@ use Icinga\Web\Widget\SearchDashboard;
|
|||
<? if (SearchDashboard::search('dummy')->getPane('search')->hasDashlets()): ?>
|
||||
<form action="<?= $this->href('search') ?>" method="get" role="search">
|
||||
<input
|
||||
type="text" name="q" id="search" class="search" placeholder="<?= $this->translate('Search...') ?>"
|
||||
type="text" name="q" id="search" class="search" placeholder="<?= $this->translate('Search') ?> …"
|
||||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
/>
|
||||
</form>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<?php if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs->render($this) ?>
|
||||
<div style="margin-top: 1em"></div>
|
||||
<?= $this->logData ?>
|
||||
<?= $this->tabs; ?>
|
||||
<?= $this->sortBox; ?>
|
||||
<?= $this->limiter; ?>
|
||||
<?= $this->paginator; ?>
|
||||
<?= $this->filterEditor; ?>
|
||||
</div>
|
||||
|
||||
<?php endif ?>
|
||||
<div class="content">
|
||||
<?php if ($this->logData !== null): ?>
|
||||
<table class="action">
|
||||
|
@ -16,7 +19,7 @@
|
|||
<?= $this->escape($value->loglevel) ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= $this->escape($value->message) ?>
|
||||
<?= nl2br($this->escape($value->message), false) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
<?= $tabs ?>
|
||||
</div>
|
||||
<div class="content">
|
||||
<h1 tabindex="-1" id="roles-index">
|
||||
<?= $this->translate('Roles') ?>
|
||||
</h1>
|
||||
<div>
|
||||
<?php /** @var \Icinga\Application\Config $roles */ if ($roles->isEmpty()): ?>
|
||||
<?= $this->translate('No roles found.') ?>
|
||||
|
@ -70,9 +67,6 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<?php endif ?>
|
||||
<h2 tabindex="-1" id="roles-index-new" class="sr-only">
|
||||
<?= $this->translate('Create New Role'); ?>
|
||||
</h2>
|
||||
<a data-base-target="_next" href="<?= $this->href('roles/new') ?>">
|
||||
<?= $this->translate('Create a New Role') ?>
|
||||
</a>
|
||||
|
|
|
@ -107,7 +107,7 @@ Icinga Web 2 uses the MD5 based BSD password algorithm. For generating a passwor
|
|||
command:
|
||||
|
||||
````
|
||||
openssl passwd -1 "password"
|
||||
openssl passwd -1 password
|
||||
````
|
||||
|
||||
> Note: The switch to `openssl passwd` is the **number one** (`-1`) for using the MD5 based BSD password algorithm.
|
||||
|
|
|
@ -3,21 +3,133 @@
|
|||
The preferred way of installing Icinga Web 2 is to use the official package repositories depending on which operating
|
||||
system and distribution you are running. But it is also possible to install Icinga Web 2 directly from source.
|
||||
|
||||
## <a id="installation-requirements"></a> Installing Requirements
|
||||
## <a id="installing-requirements"></a> Installing Requirements
|
||||
|
||||
* A web server, e.g. Apache or nginx
|
||||
* PHP >= 5.3.0 w/ gettext and OpenSSL support
|
||||
* MySQL or PostgreSQL PHP libraries when using a database for authentication or storing user preferences into a database
|
||||
* PHP >= 5.3.0 w/ gettext, intl and OpenSSL support
|
||||
* MySQL or PostgreSQL PHP libraries when using a database for authentication or for storing preferences into a database
|
||||
* LDAP PHP library when using Active Directory or LDAP for authentication
|
||||
* Icinga 1.x w/ Livestatus or IDO, Icinga 2 w/ Livestatus or IDO feature enabled
|
||||
* Icinga 1.x w/ Livestatus or IDO; Icinga 2.x w/ Livestatus or IDO feature enabled
|
||||
* MySQL or PostgreSQL PHP libraries when using IDO
|
||||
|
||||
## <a id="installation-from-package"></a> Installing Icinga Web 2 from Package
|
||||
## <a id="installing-from-package"></a> Installing Icinga Web 2 from Package
|
||||
|
||||
A guide on how to install Icinga Web 2 from package will follow shortly.
|
||||
Below is a list of official package repositories for installing Icinga Web 2 for various operating systems.
|
||||
|
||||
## <a id="installation-from-source"></a> Installing Icinga Web 2 from Source
|
||||
Distribution | Repository
|
||||
------------------------|---------------------------
|
||||
Debian | [debmon](http://debmon.org/packages/debmon-wheezy/icingaweb2), [Icinga Repository](http://packages.icinga.org/debian/)
|
||||
Ubuntu | [Icinga Repository](http://packages.icinga.org/ubuntu/)
|
||||
RHEL/CentOS | [Icinga Repository](http://packages.icinga.org/epel/)
|
||||
openSUSE | [Icinga Repository](http://packages.icinga.org/openSUSE/)
|
||||
SLES | [Icinga Repository](http://packages.icinga.org/SUSE/)
|
||||
Gentoo | -
|
||||
FreeBSD | -
|
||||
ArchLinux | [Upstream](https://aur.archlinux.org/packages/icingaweb2)
|
||||
|
||||
**Step 1: Getting the Source**
|
||||
Packages for distributions other than the ones listed above may also be available.
|
||||
Please contact your distribution packagers.
|
||||
|
||||
### <a id="package-repositories"></a> Setting up Package Repositories
|
||||
|
||||
You need to add the Icinga repository to your package management configuration for installing Icinga Web 2.
|
||||
Below is a list with examples for various distributions.
|
||||
|
||||
Debian (debmon):
|
||||
````
|
||||
wget -O - http://debmon.org/debmon/repo.key 2>/dev/null | apt-key add -
|
||||
echo 'deb http://debmon.org/debmon debmon-wheezy main' >/etc/apt/sources.list.d/debmon.list
|
||||
apt-get update
|
||||
````
|
||||
|
||||
Ubuntu Trusty:
|
||||
````
|
||||
wget -O - http://packages.icinga.org/icinga.key | apt-key add -
|
||||
add-apt-repository 'deb http://packages.icinga.org/ubuntu icinga-trusty main'
|
||||
apt-get update
|
||||
````
|
||||
|
||||
For other Ubuntu versions just replace trusty with your distribution's code name.
|
||||
|
||||
RHEL and CentOS:
|
||||
````
|
||||
rpm --import http://packages.icinga.org/icinga.key
|
||||
curl -o /etc/yum.repos.d/ICINGA-release.repo http://packages.icinga.org/epel/ICINGA-release.repo
|
||||
yum makecache
|
||||
````
|
||||
|
||||
Fedora:
|
||||
````
|
||||
rpm --import http://packages.icinga.org/icinga.key
|
||||
curl -o /etc/yum.repos.d/ICINGA-release.repo http://packages.icinga.org/fedora/ICINGA-release.repo
|
||||
yum makecache
|
||||
````
|
||||
|
||||
SLES 11:
|
||||
````
|
||||
zypper ar http://packages.icinga.org/SUSE/ICINGA-release-11.repo
|
||||
zypper ref
|
||||
````
|
||||
|
||||
SLES 12:
|
||||
````
|
||||
zypper ar http://packages.icinga.org/SUSE/ICINGA-release.repo
|
||||
zypper ref
|
||||
````
|
||||
|
||||
openSUSE:
|
||||
````
|
||||
zypper ar http://packages.icinga.org/openSUSE/ICINGA-release.repo
|
||||
zypper ref
|
||||
````
|
||||
|
||||
The packages for RHEL/CentOS depend on other packages which are distributed as part of the
|
||||
[EPEL repository](http://fedoraproject.org/wiki/EPEL). Please make sure to enable this repository by following
|
||||
[these instructions](http://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F).
|
||||
|
||||
### <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.
|
||||
|
||||
Debian and Ubuntu:
|
||||
````
|
||||
apt-get install icingaweb2
|
||||
````
|
||||
|
||||
RHEL, CentOS and Fedora:
|
||||
````
|
||||
yum install icingaweb2
|
||||
````
|
||||
|
||||
SLES and openSUSE:
|
||||
````
|
||||
zypper install icingaweb2
|
||||
````
|
||||
|
||||
### <a id="preparing-web-setup-from-package"></a> Preparing Web Setup
|
||||
|
||||
You can set up Icinga Web 2 quickly and easily with the Icinga Web 2 setup wizard which is available the first time
|
||||
you visit Icinga Web 2 in your browser. When using the web setup you are required to authenticate using a token.
|
||||
In order to generate a token use the `icingacli`:
|
||||
````
|
||||
icingacli setup token create
|
||||
````
|
||||
|
||||
In case you do not remember the token you can show it using the `icingacli`:
|
||||
````
|
||||
icingacli setup token show
|
||||
````
|
||||
|
||||
Finally visit Icinga Web 2 in your browser to access the setup wizard and complete the installation:
|
||||
`/icingaweb2/setup`.
|
||||
|
||||
## <a id="installing-from-source"></a> Installing Icinga Web 2 from Source
|
||||
|
||||
Although the preferred way of installing Icinga Web 2 is to use packages, it is also possible to install Icinga Web 2
|
||||
directly from source.
|
||||
|
||||
### <a id="getting-the-source"></a> Getting the Source
|
||||
|
||||
First of all, you need to download the sources. Icinga Web 2 is available through a Git repository. You can clone this
|
||||
repository either via git or http protocol using the following URLs:
|
||||
|
@ -33,7 +145,7 @@ This version also offers snapshots for easy download which you can use if you do
|
|||
git clone git://git.icinga.org/icingaweb2.git
|
||||
````
|
||||
|
||||
**Step 2: Install the Source**
|
||||
### <a id="installing-from-source-example"></a> Installing Icinga Web 2
|
||||
|
||||
Choose a target directory and move Icinga Web 2 there.
|
||||
|
||||
|
@ -41,7 +153,7 @@ Choose a target directory and move Icinga Web 2 there.
|
|||
mv icingaweb2 /usr/share/icingaweb2
|
||||
````
|
||||
|
||||
**Step 3: Configuring the Web Server**
|
||||
### <a id="configuring-web-server"></a> Configuring the Web Server
|
||||
|
||||
Use `icingacli` to generate web server configuration for either Apache or nginx.
|
||||
|
||||
|
@ -57,13 +169,15 @@ nginx:
|
|||
|
||||
Save the output as new file in your webserver's configuration directory.
|
||||
|
||||
Example for Apache on RHEL/CentOS:
|
||||
Example for Apache on RHEL or CentOS:
|
||||
````
|
||||
./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public > /etc/httpd/conf.d/icingaweb2.conf
|
||||
````
|
||||
|
||||
### <a id="preparing-web-setup-from-source"></a> Preparing Web Setup
|
||||
|
||||
**Step 4: Preparing Web Setup**
|
||||
You can set up Icinga Web 2 quickly and easily with the Icinga Web 2 setup wizard which is available the first time
|
||||
you visit Icinga Web 2 in your browser. Please follow the steps listed below for preparing the web setup.
|
||||
|
||||
Because both web and CLI must have access to configuration and logs, permissions will be managed using a special
|
||||
system group. The web server user and CLI user have to be added to this system group.
|
||||
|
@ -102,6 +216,7 @@ Use `icingacli` to create the configuration directory which defaults to **/etc/i
|
|||
./bin/icingacli setup config directory
|
||||
````
|
||||
|
||||
|
||||
When using the web setup you are required to authenticate using a token. In order to generate a token use the
|
||||
`icingacli`:
|
||||
````
|
||||
|
@ -113,11 +228,10 @@ In case you do not remember the token you can show it using the `icingacli`:
|
|||
./bin/icingacli setup token show
|
||||
````
|
||||
|
||||
**Step 5: Web Setup**
|
||||
Finally visit Icinga Web 2 in your browser to access the setup wizard and complete the installation:
|
||||
`/icingaweb2/setup`.
|
||||
|
||||
Visit Icinga Web 2 in your browser and complete installation using the web setup: /icingaweb2/setup
|
||||
|
||||
## Upgrading to Icinga Web 2 Beta 2
|
||||
## <a id="upgrading-to-beta2"></a> Upgrading to Icinga Web 2 Beta 2
|
||||
|
||||
Icinga Web 2 Beta 2 introduces access control based on roles for secured actions. If you've already set up Icinga Web 2,
|
||||
you are required to create the file **roles.ini** beneath Icinga Web 2's configuration directory with the following
|
||||
|
@ -133,3 +247,8 @@ After please log out from Icinga Web 2 and log in again for having all permissio
|
|||
If you delegated authentication to your web server using the `autologin` backend, you have to switch to the `external`
|
||||
authentication backend to be able to log in again. The new name better reflects what’s going on. A similar change
|
||||
affects environments that opted for not storing preferences, your new backend is `none`.
|
||||
|
||||
## <a id="upgrading-to-beta3"></a> Upgrading to Icinga Web 2 Beta 3
|
||||
|
||||
Because Icinga Web 2 Beta 3 does not introduce any backward incompatible change you don't have to change your
|
||||
configuration files after upgrading to Icinga Web 2 Beta 3.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+
|
||||
|
||||
%define revision 2.rc1
|
||||
%define revision 3.beta3
|
||||
|
||||
Name: icingaweb2
|
||||
Version: 2.0.0
|
||||
|
|
|
@ -115,7 +115,7 @@ abstract class ApplicationBootstrap
|
|||
/**
|
||||
* Whether Icinga Web 2 requires setup
|
||||
*
|
||||
* @type bool
|
||||
* @var bool
|
||||
*/
|
||||
protected $requiresSetup = false;
|
||||
|
||||
|
@ -506,12 +506,21 @@ abstract class ApplicationBootstrap
|
|||
protected function setupLogger()
|
||||
{
|
||||
if ($this->config->hasSection('logging')) {
|
||||
$loggingConfig = $this->config->getSection('logging');
|
||||
|
||||
try {
|
||||
Logger::create($this->config->getSection('logging'));
|
||||
Logger::create($loggingConfig);
|
||||
} catch (ConfigurationError $e) {
|
||||
Logger::error($e);
|
||||
Logger::getInstance()->registerConfigError($e->getMessage());
|
||||
|
||||
try {
|
||||
Logger::getInstance()->setLevel($loggingConfig->get('level', Logger::ERROR));
|
||||
} catch (ConfigurationError $e) {
|
||||
Logger::getInstance()->registerConfigError($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ class Config implements Countable, Iterator
|
|||
*
|
||||
* @param string $filepath The path to the ini file
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setConfigFile($filepath)
|
||||
{
|
||||
|
@ -223,7 +223,7 @@ class Config implements Countable, Iterator
|
|||
* @param string $name
|
||||
* @param array|ConfigObject $config
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setSection($name, $config = null)
|
||||
{
|
||||
|
@ -242,7 +242,7 @@ class Config implements Countable, Iterator
|
|||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function removeSection($name)
|
||||
{
|
||||
|
|
|
@ -20,7 +20,7 @@ class EmbeddedWeb extends ApplicationBootstrap
|
|||
* Embedded bootstrap parts
|
||||
*
|
||||
* @see ApplicationBootstrap::bootstrap
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function bootstrap()
|
||||
{
|
||||
|
|
|
@ -67,6 +67,13 @@ class Logger
|
|||
*/
|
||||
protected $level;
|
||||
|
||||
/**
|
||||
* Error messages to be displayed prior to any other log message
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $configErrors = array();
|
||||
|
||||
/**
|
||||
* Create a new logger object
|
||||
*
|
||||
|
@ -81,39 +88,71 @@ class Logger
|
|||
throw new ConfigurationError('Required logging configuration directive \'log\' missing');
|
||||
}
|
||||
|
||||
if (($level = $config->level) !== null) {
|
||||
if (is_numeric($level)) {
|
||||
$level = (int) $level;
|
||||
if (! isset(static::$levels[$level])) {
|
||||
throw new ConfigurationError(
|
||||
'Can\'t set logging level %d. Logging level is not defined. Use one of %s or one of the'
|
||||
. ' Logger\'s constants.',
|
||||
$level,
|
||||
implode(', ', array_keys(static::$levels))
|
||||
);
|
||||
}
|
||||
$this->level = $level;
|
||||
} else {
|
||||
$level = strtoupper($level);
|
||||
$levels = array_flip(static::$levels);
|
||||
if (! isset($levels[$level])) {
|
||||
throw new ConfigurationError(
|
||||
'Can\'t set logging level "%s". Logging level is not defined. Use one of %s.',
|
||||
$level,
|
||||
implode(', ', array_keys($levels))
|
||||
);
|
||||
}
|
||||
$this->level = $levels[$level];
|
||||
}
|
||||
} else {
|
||||
$this->level = static::ERROR;
|
||||
}
|
||||
$this->setLevel($config->get('level', static::ERROR));
|
||||
|
||||
if (strtolower($config->get('log', 'syslog')) !== 'none') {
|
||||
$this->writer = $this->createWriter($config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the logging level to use
|
||||
*
|
||||
* @param mixed $level
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws ConfigurationError In case the given level is invalid
|
||||
*/
|
||||
public function setLevel($level)
|
||||
{
|
||||
if (is_numeric($level)) {
|
||||
$level = (int) $level;
|
||||
if (! isset(static::$levels[$level])) {
|
||||
throw new ConfigurationError(
|
||||
'Can\'t set logging level %d. Logging level is invalid. Use one of %s or one of the'
|
||||
. ' Logger\'s constants.',
|
||||
$level,
|
||||
implode(', ', array_keys(static::$levels))
|
||||
);
|
||||
}
|
||||
|
||||
$this->level = $level;
|
||||
} else {
|
||||
$level = strtoupper($level);
|
||||
$levels = array_flip(static::$levels);
|
||||
if (! isset($levels[$level])) {
|
||||
throw new ConfigurationError(
|
||||
'Can\'t set logging level "%s". Logging level is invalid. Use one of %s.',
|
||||
$level,
|
||||
implode(', ', array_keys($levels))
|
||||
);
|
||||
}
|
||||
|
||||
$this->level = $levels[$level];
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given message as config error
|
||||
*
|
||||
* Config errors are logged every time a log message is being logged.
|
||||
*
|
||||
* @param mixed $arg,... A string, exception or format-string + substitutions
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function registerConfigError()
|
||||
{
|
||||
if (func_num_args() > 0) {
|
||||
$this->configErrors[] = static::formatMessage(func_get_args());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new logger object
|
||||
*
|
||||
|
@ -156,6 +195,10 @@ class Logger
|
|||
public function log($level, $message)
|
||||
{
|
||||
if ($this->writer !== null && $this->level <= $level) {
|
||||
foreach ($this->configErrors as $error_message) {
|
||||
$this->writer->log(static::ERROR, $error_message);
|
||||
}
|
||||
|
||||
$this->writer->log($level, $message);
|
||||
}
|
||||
}
|
||||
|
@ -271,7 +314,7 @@ class Logger
|
|||
*/
|
||||
public static function writesToSyslog()
|
||||
{
|
||||
return static::$instance && static::$instance instanceof SyslogWriter;
|
||||
return static::$instance && static::$instance->getWriter() instanceof SyslogWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -281,7 +324,7 @@ class Logger
|
|||
*/
|
||||
public static function writesToFile()
|
||||
{
|
||||
return static::$instance && static::$instance instanceof FileWriter;
|
||||
return static::$instance && static::$instance->getWriter() instanceof FileWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -67,6 +67,6 @@ class SyslogWriter extends LogWriter
|
|||
public function log($level, $message)
|
||||
{
|
||||
openlog($this->ident, LOG_PID, $this->facility);
|
||||
syslog(static::$severityMap[$level], $message);
|
||||
syslog(static::$severityMap[$level], str_replace("\n", ' ', $message));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ use Icinga\Exception\ConfigurationError;
|
|||
use Icinga\Exception\SystemPermissionException;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
|
||||
/**
|
||||
* Module manager that handles detecting, enabling and disabling of modules
|
||||
|
@ -102,6 +101,16 @@ class Manager
|
|||
*/
|
||||
private function detectEnabledModules()
|
||||
{
|
||||
if (! file_exists($parent = dirname($this->enableDir))) {
|
||||
return;
|
||||
}
|
||||
if (! is_readable($parent)) {
|
||||
throw new NotReadableError(
|
||||
'Cannot read enabled modules. Module directory\'s parent directory "%s" is not readable',
|
||||
$parent
|
||||
);
|
||||
}
|
||||
|
||||
if (! file_exists($this->enableDir)) {
|
||||
return;
|
||||
}
|
||||
|
@ -156,7 +165,7 @@ class Manager
|
|||
/**
|
||||
* Try to set all enabled modules in loaded sate
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
* @see Manager::loadModule()
|
||||
*/
|
||||
public function loadEnabledModules()
|
||||
|
@ -173,7 +182,7 @@ class Manager
|
|||
* @param string $name The name of the module to load
|
||||
* @param mixed $basedir Optional module base directory
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function loadModule($name, $basedir = null)
|
||||
{
|
||||
|
@ -197,9 +206,8 @@ class Manager
|
|||
*
|
||||
* @param string $name The module to enable
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
* @throws ConfigurationError When trying to enable a module that is not installed
|
||||
* @throws NotFoundError In case the "enabledModules" directory does not exist
|
||||
* @throws SystemPermissionException When insufficient permissions for the application exist
|
||||
*/
|
||||
public function enableModule($name)
|
||||
|
@ -218,14 +226,15 @@ class Manager
|
|||
if (! is_dir($this->enableDir) && !@mkdir($this->enableDir, 02770, true)) {
|
||||
$error = error_get_last();
|
||||
throw new SystemPermissionException(
|
||||
'Failed to create enabledModule directory "%s" (%s)',
|
||||
'Failed to create enabledModules directory "%s" (%s)',
|
||||
$this->enableDir,
|
||||
$error['message']
|
||||
);
|
||||
} elseif (! is_writable($this->enableDir)) {
|
||||
throw new SystemPermissionException(
|
||||
'Cannot enable module "%s". Insufficient system permissions for enabling modules.',
|
||||
$name
|
||||
'Cannot enable module "%s". Check the permissions for the enabledModules directory: %s',
|
||||
$name,
|
||||
$this->enableDir
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -237,10 +246,11 @@ class Manager
|
|||
$error = error_get_last();
|
||||
if (strstr($error["message"], "File exists") === false) {
|
||||
throw new SystemPermissionException(
|
||||
'Could not enable module "%s" due to file system errors. '
|
||||
'Cannot enable module "%s" at %s due to file system errors. '
|
||||
. 'Please check path and mounting points because this is not a permission error. '
|
||||
. 'Primary error was: %s',
|
||||
$name,
|
||||
$this->enableDir,
|
||||
$error['message']
|
||||
);
|
||||
}
|
||||
|
@ -252,39 +262,44 @@ class Manager
|
|||
}
|
||||
|
||||
/**
|
||||
* Disable the given module and remove it's enabled state
|
||||
* Disable the given module and remove its enabled state
|
||||
*
|
||||
* @param string $name The name of the module to disable
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*
|
||||
* @throws ConfigurationError When the module is not installed or it's not a symlink
|
||||
* @throws SystemPermissionException When the module can't be disabled
|
||||
* @throws SystemPermissionException When insufficient permissions for the application exist
|
||||
*/
|
||||
public function disableModule($name)
|
||||
{
|
||||
if (! $this->hasEnabled($name)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (! is_writable($this->enableDir)) {
|
||||
throw new SystemPermissionException(
|
||||
'Could not disable module. Module path is not writable.'
|
||||
'Cannot disable module "%s". Check the permissions for the enabledModules directory: %s',
|
||||
$name,
|
||||
$this->enableDir
|
||||
);
|
||||
}
|
||||
|
||||
$link = $this->enableDir . DIRECTORY_SEPARATOR . $name;
|
||||
if (! file_exists($link)) {
|
||||
throw new ConfigurationError(
|
||||
'Could not disable module. The module %s was not found.',
|
||||
'Cannot disable module "%s". Module is not installed.',
|
||||
$name
|
||||
);
|
||||
}
|
||||
if (! is_link($link)) {
|
||||
throw new ConfigurationError(
|
||||
'Could not disable module. The module "%s" is not a symlink. '
|
||||
'Cannot disable module %s at %s. '
|
||||
. 'It looks like you have installed this module manually and moved it to your module folder. '
|
||||
. 'In order to dynamically enable and disable modules, you have to create a symlink to '
|
||||
. 'the enabled_modules folder.',
|
||||
$name
|
||||
. 'the enabledModules folder.',
|
||||
$name,
|
||||
$this->enableDir
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -292,10 +307,11 @@ class Manager
|
|||
if (! @unlink($link)) {
|
||||
$error = error_get_last();
|
||||
throw new SystemPermissionException(
|
||||
'Could not disable module "%s" due to file system errors. '
|
||||
'Cannot enable module "%s" at %s due to file system errors. '
|
||||
. 'Please check path and mounting points because this is not a permission error. '
|
||||
. 'Primary error was: %s',
|
||||
$name,
|
||||
$this->enableDir,
|
||||
$error['message']
|
||||
);
|
||||
}
|
||||
|
@ -491,7 +507,7 @@ class Manager
|
|||
*
|
||||
* @param array $availableDirs Installed modules location
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function detectInstalledModules(array $availableDirs = null)
|
||||
{
|
||||
|
|
|
@ -113,6 +113,13 @@ class Module
|
|||
*/
|
||||
private $triedToLaunchConfigScript = false;
|
||||
|
||||
/**
|
||||
* Whether this module has been registered
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $registered = false;
|
||||
|
||||
/**
|
||||
* Provided permissions
|
||||
*
|
||||
|
@ -177,14 +184,18 @@ class Module
|
|||
protected $searchUrls = array();
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
* @param string $url
|
||||
* Provide a search URL
|
||||
*
|
||||
* @param string $title
|
||||
* @param string $url
|
||||
* @param int $priority
|
||||
*/
|
||||
public function provideSearchUrl($title, $url)
|
||||
public function provideSearchUrl($title, $url, $priority = 0)
|
||||
{
|
||||
$searchUrl = (object) array(
|
||||
'title' => $title,
|
||||
'url' => $url
|
||||
'title' => (string) $title,
|
||||
'url' => (string) $url,
|
||||
'priority' => (int) $priority
|
||||
);
|
||||
|
||||
$this->searchUrls[] = $searchUrl;
|
||||
|
@ -279,6 +290,10 @@ class Module
|
|||
*/
|
||||
public function register()
|
||||
{
|
||||
if ($this->registered) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->registerAutoloader();
|
||||
try {
|
||||
$this->launchRunScript();
|
||||
|
@ -291,10 +306,22 @@ class Module
|
|||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->registerWebIntegration();
|
||||
$this->registered = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this module has been registered
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRegistered()
|
||||
{
|
||||
return $this->registered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for an enabled module by name
|
||||
*
|
||||
|
@ -725,7 +752,7 @@ class Module
|
|||
* @param string $name Unique tab name
|
||||
* @param string $config Tab config
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function provideConfigTab($name, $config = array())
|
||||
{
|
||||
|
@ -742,7 +769,7 @@ class Module
|
|||
*
|
||||
* @param string $className The name of the class
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function provideSetupWizard($className)
|
||||
{
|
||||
|
@ -753,7 +780,7 @@ class Module
|
|||
/**
|
||||
* Register new namespaces on the autoloader
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function registerAutoloader()
|
||||
{
|
||||
|
@ -775,7 +802,7 @@ class Module
|
|||
/**
|
||||
* Bind text domain for i18n
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function registerLocales()
|
||||
{
|
||||
|
@ -822,7 +849,7 @@ class Module
|
|||
*
|
||||
* Add controller directory to mvc
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function registerWebIntegration()
|
||||
{
|
||||
|
@ -845,7 +872,7 @@ class Module
|
|||
/**
|
||||
* Add routes for static content and any route added via addRoute() to the route chain
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
* @see addRoute()
|
||||
*/
|
||||
protected function registerRoutes()
|
||||
|
@ -885,7 +912,7 @@ class Module
|
|||
/**
|
||||
* Run module bootstrap script
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function launchRunScript()
|
||||
{
|
||||
|
@ -897,7 +924,7 @@ class Module
|
|||
*
|
||||
* @param string $file File to include
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function includeScript($file)
|
||||
{
|
||||
|
@ -913,7 +940,7 @@ class Module
|
|||
*/
|
||||
protected function launchConfigScript()
|
||||
{
|
||||
if ($this->triedToLaunchConfigScript) {
|
||||
if ($this->triedToLaunchConfigScript || !$this->registered) {
|
||||
return;
|
||||
}
|
||||
$this->triedToLaunchConfigScript = true;
|
||||
|
@ -931,7 +958,7 @@ class Module
|
|||
* @param string $class
|
||||
* @param string $key
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function registerHook($name, $class, $key = null)
|
||||
{
|
||||
|
@ -950,7 +977,7 @@ class Module
|
|||
* @param string $name Name of the route
|
||||
* @param Zend_Controller_Router_Route_Abstract $route Instance of the route
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
* @see registerRoutes()
|
||||
*/
|
||||
protected function addRoute($name, Zend_Controller_Router_Route_Abstract $route)
|
||||
|
|
|
@ -182,19 +182,24 @@ class Platform
|
|||
}
|
||||
|
||||
/**
|
||||
* Return whether the given Zend framework class exists
|
||||
* Return whether the given class exists
|
||||
*
|
||||
* @param string $name The name of the class to check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function zendClassExists($name)
|
||||
public static function classExists($name)
|
||||
{
|
||||
if (@class_exists($name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (@include str_replace('_', '/', $name) . '.php') !== false;
|
||||
if (strpos($name, '_') !== false) {
|
||||
// Assume it's a Zend-Framework class
|
||||
return (@include str_replace('_', '/', $name) . '.php') !== false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -206,7 +211,7 @@ class Platform
|
|||
*/
|
||||
public static function hasMysqlSupport()
|
||||
{
|
||||
return static::extensionLoaded('mysql') && static::zendClassExists('Zend_Db_Adapter_Pdo_Mysql');
|
||||
return static::extensionLoaded('mysql') && static::classExists('Zend_Db_Adapter_Pdo_Mysql');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,6 +223,6 @@ class Platform
|
|||
*/
|
||||
public static function hasPostgresqlSupport()
|
||||
{
|
||||
return static::extensionLoaded('pgsql') && static::zendClassExists('Zend_Db_Adapter_Pdo_Pgsql');
|
||||
return static::extensionLoaded('pgsql') && static::classExists('Zend_Db_Adapter_Pdo_Pgsql');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,28 +5,23 @@ namespace Icinga\Application;
|
|||
|
||||
require_once __DIR__ . '/ApplicationBootstrap.php';
|
||||
|
||||
use Icinga\Authentication\Manager as AuthenticationManager;
|
||||
use Icinga\Authentication\Manager;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Util\TimezoneDetect;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Response;
|
||||
use Icinga\Web\View;
|
||||
use Icinga\Web\Session\Session as BaseSession;
|
||||
use Icinga\Web\Session;
|
||||
use Icinga\User;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Util\DateTimeFactory;
|
||||
use DateTimeZone;
|
||||
use Exception;
|
||||
use Zend_Controller_Action_HelperBroker;
|
||||
use Zend_Controller_Front;
|
||||
use Zend_Controller_Router_Route;
|
||||
use Zend_Layout;
|
||||
use Zend_Paginator;
|
||||
use Zend_View_Helper_PaginationControl;
|
||||
use Zend_Controller_Action_HelperBroker as ActionHelperBroker;
|
||||
use Zend_Controller_Router_Route;
|
||||
use Zend_Controller_Front;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Authentication\Manager;
|
||||
use Icinga\User;
|
||||
use Icinga\Util\TimezoneDetect;
|
||||
use Icinga\Util\Translator;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Use this if you want to make use of Icinga functionality in other web projects
|
||||
|
@ -84,7 +79,7 @@ class Web extends ApplicationBootstrap
|
|||
/**
|
||||
* Initialize all together
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function bootstrap()
|
||||
{
|
||||
|
@ -95,6 +90,7 @@ class Web extends ApplicationBootstrap
|
|||
->loadConfig()
|
||||
->setupResourceFactory()
|
||||
->setupSession()
|
||||
->setupNotifications()
|
||||
->setupUser()
|
||||
->setupTimezone()
|
||||
->setupLogger()
|
||||
|
@ -112,7 +108,7 @@ class Web extends ApplicationBootstrap
|
|||
/**
|
||||
* Prepare routing
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
private function setupRoute()
|
||||
{
|
||||
|
@ -161,44 +157,39 @@ class Web extends ApplicationBootstrap
|
|||
/**
|
||||
* Prepare Zend MVC Base
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
private function setupZendMvc()
|
||||
{
|
||||
// TODO: Replace Zend_Application:
|
||||
Zend_Layout::startMvc(
|
||||
array(
|
||||
'layout' => 'layout',
|
||||
'layoutPath' => $this->getApplicationDir('/layouts/scripts')
|
||||
)
|
||||
);
|
||||
|
||||
$this->setupFrontController();
|
||||
$this->setupViewRenderer();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create user object
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
private function setupUser()
|
||||
{
|
||||
$authenticationManager = AuthenticationManager::getInstance();
|
||||
|
||||
if ($authenticationManager->isAuthenticated() === true) {
|
||||
$this->user = $authenticationManager->getUser();
|
||||
$auth = Manager::getInstance();
|
||||
if ($auth->isAuthenticated()) {
|
||||
$this->user = $auth->getUser();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a session provider
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
private function setupSession()
|
||||
{
|
||||
|
@ -206,85 +197,82 @@ class Web extends ApplicationBootstrap
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize notifications to remove them immediately from session
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
private function setupNotifications()
|
||||
{
|
||||
Notification::getInstance();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject dependencies into request
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
private function setupRequest()
|
||||
{
|
||||
$this->request = new Request();
|
||||
|
||||
if ($this->user instanceof User) {
|
||||
$this->request->setUser($this->user);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate front controller
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
private function setupFrontController()
|
||||
{
|
||||
$this->frontController = Zend_Controller_Front::getInstance();
|
||||
|
||||
$this->frontController->setRequest($this->request);
|
||||
|
||||
$this->frontController->setControllerDirectory($this->getApplicationDir('/controllers'));
|
||||
|
||||
$this->frontController->setParams(
|
||||
array(
|
||||
'displayExceptions' => true
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register helper paths and views for renderer
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
private function setupViewRenderer()
|
||||
{
|
||||
$view = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
|
||||
/** @var \Zend_Controller_Action_Helper_ViewRenderer $view */
|
||||
$view = ActionHelperBroker::getStaticHelper('viewRenderer');
|
||||
$view->setView(new View());
|
||||
|
||||
$view->view->addHelperPath($this->getApplicationDir('/views/helpers'));
|
||||
|
||||
$view->view->setEncoding('UTF-8');
|
||||
$view->view->headTitle()->prepend($this->config->get('global', 'project', 'Icinga'));
|
||||
|
||||
$view->view->headTitle()->setSeparator(' :: ');
|
||||
|
||||
$this->viewRenderer = $view;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure pagination settings
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
private function setupPagination()
|
||||
{
|
||||
|
||||
Zend_Paginator::addScrollingStylePrefixPath(
|
||||
'Icinga_Web_Paginator_ScrollingStyle',
|
||||
'Icinga/Web/Paginator/ScrollingStyle'
|
||||
);
|
||||
|
||||
Zend_Paginator::setDefaultScrollingStyle('SlidingWithBorder');
|
||||
Zend_View_Helper_PaginationControl::setDefaultViewPartial(
|
||||
array('mixedPagination.phtml', 'default')
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -307,26 +295,30 @@ class Web extends ApplicationBootstrap
|
|||
/**
|
||||
* Setup internationalization using gettext
|
||||
*
|
||||
* Uses the preferred user language or the configured default and system default, respectively.
|
||||
* Uses the preferred user language or the browser suggested language or our default.
|
||||
*
|
||||
* @return self
|
||||
* @return string Detected locale code
|
||||
*
|
||||
* @see Translator::DEFAULT_LOCALE For the the default locale code.
|
||||
*/
|
||||
protected function detectLocale()
|
||||
{
|
||||
$auth = Manager::getInstance();
|
||||
if (! $auth->isAuthenticated()
|
||||
|| ($locale = $auth->getUser()->getPreferences()->getValue('icingaweb', 'language')) === null
|
||||
&& isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])
|
||||
if ($auth->isAuthenticated()
|
||||
&& ($locale = $auth->getUser()->getPreferences()->getValue('icingaweb', 'language')) !== null
|
||||
) {
|
||||
$locale = Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
||||
return $locale;
|
||||
}
|
||||
return $locale;
|
||||
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
return Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
||||
}
|
||||
return Translator::DEFAULT_LOCALE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup an autoloader namespace for Icinga\Forms
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
private function setupFormNamespace()
|
||||
{
|
||||
|
@ -337,4 +329,3 @@ class Web extends ApplicationBootstrap
|
|||
return $this;
|
||||
}
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
|
|
@ -96,10 +96,15 @@ class DbUserBackend extends UserBackend
|
|||
'SELECT password_hash FROM icingaweb_user WHERE name = :name AND active = 1'
|
||||
);
|
||||
}
|
||||
|
||||
$stmt->execute(array(':name' => $username));
|
||||
$stmt->bindColumn(1, $lob, PDO::PARAM_LOB);
|
||||
$stmt->fetch(PDO::FETCH_BOUND);
|
||||
return is_resource($lob) ? stream_get_contents($lob) : $lob;
|
||||
if (is_resource($lob)) {
|
||||
$lob = stream_get_contents($lob);
|
||||
}
|
||||
|
||||
return $this->conn->getDbType() === 'pgsql' ? pg_unescape_bytea($lob) : $lob;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,7 @@ use Icinga\Protocol\Ldap\Query;
|
|||
use Icinga\Protocol\Ldap\Connection;
|
||||
use Icinga\Exception\AuthenticationException;
|
||||
use Icinga\Protocol\Ldap\Exception as LdapException;
|
||||
use Icinga\Protocol\Ldap\Expression;
|
||||
|
||||
class LdapUserBackend extends UserBackend
|
||||
{
|
||||
|
@ -25,17 +26,55 @@ class LdapUserBackend extends UserBackend
|
|||
|
||||
protected $userNameAttribute;
|
||||
|
||||
protected $customFilter;
|
||||
|
||||
protected $groupOptions;
|
||||
|
||||
public function __construct(Connection $conn, $userClass, $userNameAttribute, $baseDn, $groupOptions = null)
|
||||
{
|
||||
/**
|
||||
* Normed attribute names based on known LDAP environments
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $normedAttributes = array(
|
||||
'uid' => 'uid',
|
||||
'user' => 'user',
|
||||
'inetorgperson' => 'inetOrgPerson',
|
||||
'samaccountname' => 'sAMAccountName'
|
||||
);
|
||||
|
||||
public function __construct(
|
||||
Connection $conn,
|
||||
$userClass,
|
||||
$userNameAttribute,
|
||||
$baseDn,
|
||||
$cutomFilter,
|
||||
$groupOptions = null
|
||||
) {
|
||||
$this->conn = $conn;
|
||||
$this->baseDn = trim($baseDn) !== '' ? $baseDn : $conn->getDN();
|
||||
$this->userClass = $userClass;
|
||||
$this->userNameAttribute = $userNameAttribute;
|
||||
$this->baseDn = trim($baseDn) ?: $conn->getDN();
|
||||
$this->userClass = $this->getNormedAttribute($userClass);
|
||||
$this->userNameAttribute = $this->getNormedAttribute($userNameAttribute);
|
||||
$this->customFilter = trim($cutomFilter);
|
||||
$this->groupOptions = $groupOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the given attribute name normed to known LDAP enviroments, if possible
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getNormedAttribute($name)
|
||||
{
|
||||
$loweredName = strtolower($name);
|
||||
if (array_key_exists($loweredName, $this->normedAttributes)) {
|
||||
return $this->normedAttributes[$loweredName];
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query to select all usernames
|
||||
*
|
||||
|
@ -43,12 +82,18 @@ class LdapUserBackend extends UserBackend
|
|||
*/
|
||||
protected function selectUsers()
|
||||
{
|
||||
return $this->conn->select()->setBase($this->baseDn)->from(
|
||||
$query = $this->conn->select()->setBase($this->baseDn)->from(
|
||||
$this->userClass,
|
||||
array(
|
||||
$this->userNameAttribute
|
||||
)
|
||||
);
|
||||
|
||||
if ($this->customFilter) {
|
||||
$query->addFilter(new Expression($this->customFilter));
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,9 +133,10 @@ class LdapUserBackend extends UserBackend
|
|||
|
||||
if ($result === null) {
|
||||
throw new AuthenticationException(
|
||||
'No objects with objectClass="%s" in DN="%s" found.',
|
||||
'No objects with objectClass="%s" in DN="%s" found. (Filter: %s)',
|
||||
$this->userClass,
|
||||
$this->baseDn
|
||||
$this->baseDn,
|
||||
$this->customFilter ?: 'None'
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ abstract class UserBackend implements Countable
|
|||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
|
@ -103,6 +103,7 @@ abstract class UserBackend implements Countable
|
|||
$backendConfig->get('user_class', 'user'),
|
||||
$backendConfig->get('user_name_attribute', 'sAMAccountName'),
|
||||
$backendConfig->get('base_dn', $resource->getDN()),
|
||||
$backendConfig->get('filter'),
|
||||
$groupOptions
|
||||
);
|
||||
break;
|
||||
|
@ -130,6 +131,7 @@ abstract class UserBackend implements Countable
|
|||
$backendConfig->user_class,
|
||||
$backendConfig->user_name_attribute,
|
||||
$backendConfig->get('base_dn', $resource->getDN()),
|
||||
$backendConfig->get('filter'),
|
||||
$groupOptions
|
||||
);
|
||||
break;
|
||||
|
|
|
@ -16,7 +16,7 @@ use Icinga\Chart\Unit\LinearUnit;
|
|||
/**
|
||||
* Axis class for the GridChart class.
|
||||
*
|
||||
* Implements drawing functions for the axis and it's labels but delegates tick and label calculations
|
||||
* Implements drawing functions for the axis and its labels but delegates tick and label calculations
|
||||
* to the AxisUnit implementations
|
||||
*
|
||||
* @see GridChart
|
||||
|
@ -115,7 +115,7 @@ class Axis implements Drawable
|
|||
*
|
||||
* @param AxisUnit $unit The AxisUnit implementation to use for the x axis
|
||||
*
|
||||
* @return self This Axis Object
|
||||
* @return $this This Axis Object
|
||||
* @see Axis::CalendarUnit
|
||||
* @see Axis::LinearUnit
|
||||
*/
|
||||
|
@ -130,7 +130,7 @@ class Axis implements Drawable
|
|||
*
|
||||
* @param AxisUnit $unit The AxisUnit implementation to use for the y axis
|
||||
*
|
||||
* @return self This Axis Object
|
||||
* @return $this This Axis Object
|
||||
* @see Axis::CalendarUnit
|
||||
* @see Axis::LinearUnit
|
||||
*/
|
||||
|
@ -331,7 +331,7 @@ class Axis implements Drawable
|
|||
*
|
||||
* @param string $label The label to use for the y axis
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setYLabel($label)
|
||||
{
|
||||
|
@ -346,7 +346,7 @@ class Axis implements Drawable
|
|||
*
|
||||
* @param int $xMin The minimum value to use for the x axis
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setXMin($xMin)
|
||||
{
|
||||
|
@ -361,7 +361,7 @@ class Axis implements Drawable
|
|||
*
|
||||
* @param int $yMin The minimum value to use for the x axis
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setYMin($yMin)
|
||||
{
|
||||
|
@ -376,7 +376,7 @@ class Axis implements Drawable
|
|||
*
|
||||
* @param int $xMax The minimum value to use for the x axis
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setXMax($xMax)
|
||||
{
|
||||
|
@ -391,7 +391,7 @@ class Axis implements Drawable
|
|||
*
|
||||
* @param int $yMax The minimum value to use for the y axis
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setYMax($yMax)
|
||||
{
|
||||
|
|
|
@ -132,7 +132,7 @@ class GridChart extends Chart
|
|||
*
|
||||
* @param array $axis,... The line definitions to draw
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function drawLines(array $axis)
|
||||
{
|
||||
|
@ -146,7 +146,7 @@ class GridChart extends Chart
|
|||
* Refer to the graphs.md for a detailed list of allowed attributes
|
||||
*
|
||||
* @param array $axis
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function drawBars(array $axis)
|
||||
{
|
||||
|
@ -215,7 +215,7 @@ class GridChart extends Chart
|
|||
* @param string $yAxisLabel The label to use for the y axis
|
||||
* @param string $axisName The name of the axis, for now 'default'
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setAxisLabel($xAxisLabel, $yAxisLabel, $axisName = 'default')
|
||||
{
|
||||
|
@ -229,7 +229,7 @@ class GridChart extends Chart
|
|||
* @param AxisUnit $unit The unit for the x axis
|
||||
* @param string $axisName The name of the axis to set the label for, currently only 'default'
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setXAxis(AxisUnit $unit, $axisName = 'default')
|
||||
{
|
||||
|
@ -243,7 +243,7 @@ class GridChart extends Chart
|
|||
* @param AxisUnit $unit The unit for the y axis
|
||||
* @param string $axisName The name of the axis to set the label for, currently only 'default'
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setYAxis(AxisUnit $unit, $axisName = 'default')
|
||||
{
|
||||
|
@ -276,7 +276,7 @@ class GridChart extends Chart
|
|||
* @param Axis $axis The new axis to use
|
||||
* @param string $name The name of the axis, currently only 'default'
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setAxis(Axis $axis, $name = 'default')
|
||||
{
|
||||
|
@ -290,7 +290,7 @@ class GridChart extends Chart
|
|||
* @param Axis $axis The axis object to add
|
||||
* @param string $name The name of the axis
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function addAxis(Axis $axis, $name)
|
||||
{
|
||||
|
@ -307,7 +307,7 @@ class GridChart extends Chart
|
|||
* @param int $yMin The minimum value for the y axis or null to use a dynamic value
|
||||
* @param string $axisName The name of the axis to set the minimum, currently only 'default'
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setAxisMin($xMin = null, $yMin = null, $axisName = 'default')
|
||||
{
|
||||
|
@ -324,7 +324,7 @@ class GridChart extends Chart
|
|||
* @param int $yMax The maximum value for the y axis or null to use a dynamic value
|
||||
* @param string $axisName The name of the axis to set the maximum, currently only 'default'
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setAxisMax($xMax = null, $yMax = null, $axisName = 'default')
|
||||
{
|
||||
|
|
|
@ -107,7 +107,7 @@ class PieChart extends Chart
|
|||
*
|
||||
* @param array $dataSet,... The pie definition, see graphs.md for further details concerning the format
|
||||
*
|
||||
* @return self Fluent interface
|
||||
* @return $this Fluent interface
|
||||
*/
|
||||
public function drawPie(array $dataSet)
|
||||
{
|
||||
|
@ -272,7 +272,7 @@ class PieChart extends Chart
|
|||
*
|
||||
* @param string $type Either self::STACKED or self::ROW
|
||||
*
|
||||
* @return self Fluent interface
|
||||
* @return $this Fluent interface
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
|
@ -283,7 +283,7 @@ class PieChart extends Chart
|
|||
/**
|
||||
* Hide the caption from this PieChart
|
||||
*
|
||||
* @return self Fluent interface
|
||||
* @return $this Fluent interface
|
||||
*/
|
||||
public function disableLegend()
|
||||
{
|
||||
|
|
|
@ -77,7 +77,7 @@ class Path extends Styleable implements Drawable
|
|||
*
|
||||
* @param array $points Either a single [x, y] point or an array of x, y points
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function append(array $points)
|
||||
{
|
||||
|
@ -96,7 +96,7 @@ class Path extends Styleable implements Drawable
|
|||
*
|
||||
* @param array $points Either a single [x, y] point or an array of x, y points
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function prepend(array $points)
|
||||
{
|
||||
|
@ -115,7 +115,7 @@ class Path extends Styleable implements Drawable
|
|||
*
|
||||
* @param boolean $bool True to draw discrete or false to draw straight lines between points
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setDiscrete($bool)
|
||||
{
|
||||
|
@ -126,7 +126,7 @@ class Path extends Styleable implements Drawable
|
|||
/**
|
||||
* Mark this path as containing absolute coordinates
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function toAbsolute()
|
||||
{
|
||||
|
|
|
@ -189,7 +189,7 @@ class PieSlice extends Animatable implements Drawable
|
|||
*
|
||||
* @param int $x The new x position
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setX($x)
|
||||
{
|
||||
|
@ -202,7 +202,7 @@ class PieSlice extends Animatable implements Drawable
|
|||
*
|
||||
* @param int $y The new y position
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setY($y)
|
||||
{
|
||||
|
@ -215,7 +215,7 @@ class PieSlice extends Animatable implements Drawable
|
|||
*
|
||||
* @param DOMElement $group The label group
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setLabelGroup(DOMElement $group)
|
||||
{
|
||||
|
@ -228,7 +228,7 @@ class PieSlice extends Animatable implements Drawable
|
|||
*
|
||||
* @param string $caption The caption for this element
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setCaption($caption)
|
||||
{
|
||||
|
@ -241,7 +241,7 @@ class PieSlice extends Animatable implements Drawable
|
|||
*
|
||||
* @param int $offset The offset for the caption handle
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setCaptionOffset($offset)
|
||||
{
|
||||
|
@ -254,7 +254,7 @@ class PieSlice extends Animatable implements Drawable
|
|||
*
|
||||
* @param int $bound The offset for the caption text
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setOuterCaptionBound($bound)
|
||||
{
|
||||
|
|
|
@ -59,7 +59,7 @@ class Styleable
|
|||
*
|
||||
* @param string $width The stroke with with unit
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setStrokeWidth($width)
|
||||
{
|
||||
|
@ -72,7 +72,7 @@ class Styleable
|
|||
*
|
||||
* @param string $color The color to set for the stroke
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setStrokeColor($color)
|
||||
{
|
||||
|
@ -85,7 +85,7 @@ class Styleable
|
|||
*
|
||||
* @param string $styles The styles to set additionally
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setAdditionalStyle($styles)
|
||||
{
|
||||
|
@ -98,7 +98,7 @@ class Styleable
|
|||
*
|
||||
* @param string $color The color to use for filling or null to use no fill
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setFill($color = null)
|
||||
{
|
||||
|
@ -111,7 +111,7 @@ class Styleable
|
|||
*
|
||||
* @param string $id The id to set for this element
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setId($id)
|
||||
{
|
||||
|
|
|
@ -104,7 +104,7 @@ class Text extends Styleable implements Drawable
|
|||
*
|
||||
* @param string $size The font size including a unit
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setFontSize($size)
|
||||
{
|
||||
|
@ -117,7 +117,7 @@ class Text extends Styleable implements Drawable
|
|||
*
|
||||
* @param String $align Value how to align
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setAlignment($align)
|
||||
{
|
||||
|
@ -130,7 +130,7 @@ class Text extends Styleable implements Drawable
|
|||
*
|
||||
* @param string $weight The weight of the string
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function setFontWeight($weight)
|
||||
{
|
||||
|
|
|
@ -110,7 +110,7 @@ class CalendarUnit extends LinearUnit
|
|||
* @param array $dataset The dataset to update
|
||||
* @param int $idx The index to use for determining the data
|
||||
*
|
||||
* @return self Fluid interface
|
||||
* @return $this Fluid interface
|
||||
*/
|
||||
public function addValues(array $dataset, $idx = 0)
|
||||
{
|
||||
|
|
|
@ -74,7 +74,7 @@ class LinearUnit implements AxisUnit
|
|||
* @param array $dataset The dataset to add
|
||||
* @param int $idx The idx (0 for x, 1 for y)
|
||||
*
|
||||
* @return self Fluent interface
|
||||
* @return $this Fluent interface
|
||||
*/
|
||||
public function addValues(array $dataset, $idx = 0)
|
||||
{
|
||||
|
|
|
@ -65,7 +65,7 @@ class LogarithmicUnit implements AxisUnit
|
|||
* @param array $dataset The dataset to add
|
||||
* @param int $idx The idx (0 for x, 1 for y)
|
||||
*
|
||||
* @return self Fluent interface
|
||||
* @return $this Fluent interface
|
||||
*/
|
||||
public function addValues(array $dataset, $idx = 0)
|
||||
{
|
||||
|
|
|
@ -15,7 +15,7 @@ class StaticAxis implements AxisUnit
|
|||
* @param array $dataset The dataset that will be shown in the Axis
|
||||
* @param int $idx The idx in the dataset (0 for x, 1 for y)
|
||||
*
|
||||
* @return self Fluent interface
|
||||
* @return $this Fluent interface
|
||||
*/
|
||||
public function addValues(array $dataset, $idx = 0)
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ abstract class Command
|
|||
protected $docs;
|
||||
|
||||
/**
|
||||
* @type Params
|
||||
* @var Params
|
||||
*/
|
||||
protected $params;
|
||||
protected $screen;
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
namespace Icinga\Cli;
|
||||
|
||||
use Icinga\Exception\MissingParameterException;
|
||||
|
||||
/**
|
||||
* Params
|
||||
*
|
||||
|
@ -155,13 +157,36 @@ class Params
|
|||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require a parameter
|
||||
*
|
||||
* @param string $name Name of the parameter
|
||||
* @param bool $strict Whether the parameter's value must not be the empty string
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws MissingParameterException If the parameter was not given
|
||||
*/
|
||||
public function req($name, $strict = true)
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
$value = $this->get($name);
|
||||
if (! $strict || strlen($value) > 0) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
$e = new MissingParameterException(t('Required parameter \'%s\' missing'), $name);
|
||||
$e->setParameter($name);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value for the given option
|
||||
*
|
||||
* @param string $key The option name
|
||||
* @param mixed $value The value to set
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
|
@ -174,7 +199,7 @@ class Params
|
|||
*
|
||||
* @param string|array $keys The option or options to remove
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function remove($keys = array())
|
||||
{
|
||||
|
@ -238,7 +263,7 @@ class Params
|
|||
*
|
||||
* @param mixed $key The argument
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function unshift($key)
|
||||
{
|
||||
|
|
|
@ -274,7 +274,7 @@ class ConfigObject implements Countable, Iterator, ArrayAccess
|
|||
*
|
||||
* @param array|Config $data An array or a config
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function merge($data)
|
||||
{
|
||||
|
|
|
@ -183,7 +183,7 @@ class DbConnection implements Selectable
|
|||
*
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setTablePrefix($prefix)
|
||||
{
|
||||
|
|
|
@ -63,7 +63,7 @@ class PivotTable
|
|||
/**
|
||||
* Prepare the queries used for the pre processing
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function prepareQueries()
|
||||
{
|
||||
|
@ -82,7 +82,7 @@ class PivotTable
|
|||
/**
|
||||
* Set a default sorting for the x- and y-axis without losing any existing rules
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function adjustSorting()
|
||||
{
|
||||
|
|
|
@ -106,7 +106,7 @@ class SimpleQuery implements QueryInterface, Queryable
|
|||
*
|
||||
* Query will return all available columns if none are given here
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function from($target, array $fields = null)
|
||||
{
|
||||
|
@ -125,7 +125,7 @@ class SimpleQuery implements QueryInterface, Queryable
|
|||
* @param string $condition
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function where($condition, $value = null)
|
||||
{
|
||||
|
@ -161,6 +161,26 @@ class SimpleQuery implements QueryInterface, Queryable
|
|||
throw new IcingaException('This function does nothing and will be removed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Split order field into its field and sort direction
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function splitOrder($field)
|
||||
{
|
||||
$fieldAndDirection = explode(' ', $field, 2);
|
||||
if (count($fieldAndDirection) === 1) {
|
||||
$direction = null;
|
||||
} else {
|
||||
$field = $fieldAndDirection[0];
|
||||
$direction = (strtoupper(trim($fieldAndDirection[1])) === 'DESC') ?
|
||||
Sortable::SORT_DESC : Sortable::SORT_ASC;
|
||||
}
|
||||
return array($field, $direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort result set by the given field (and direction)
|
||||
*
|
||||
|
@ -172,18 +192,14 @@ class SimpleQuery implements QueryInterface, Queryable
|
|||
* @param string $field
|
||||
* @param string $direction
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function order($field, $direction = null)
|
||||
{
|
||||
if ($direction === null) {
|
||||
$fieldAndDirection = explode(' ', $field, 2);
|
||||
if (count($fieldAndDirection) === 1) {
|
||||
$direction = self::SORT_ASC;
|
||||
} else {
|
||||
$field = $fieldAndDirection[0];
|
||||
$direction = (strtoupper(trim($fieldAndDirection[1])) === 'DESC') ?
|
||||
Sortable::SORT_DESC : Sortable::SORT_ASC;
|
||||
list($field, $direction) = $this->splitOrder($field);
|
||||
if ($direction === null) {
|
||||
$direction = Sortable::SORT_ASC;
|
||||
}
|
||||
} else {
|
||||
switch (($direction = strtoupper($direction))) {
|
||||
|
@ -254,7 +270,7 @@ class SimpleQuery implements QueryInterface, Queryable
|
|||
* @param int $count Number of rows to return
|
||||
* @param int $offset Start returning after this many rows
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function limit($count = null, $offset = null)
|
||||
{
|
||||
|
@ -401,7 +417,7 @@ class SimpleQuery implements QueryInterface, Queryable
|
|||
*
|
||||
* @param array $columns
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function columns(array $columns)
|
||||
{
|
||||
|
|
|
@ -14,14 +14,14 @@ class SimpleTree implements IteratorAggregate
|
|||
/**
|
||||
* Root node
|
||||
*
|
||||
* @type TreeNode
|
||||
* @var TreeNode
|
||||
*/
|
||||
protected $sentinel;
|
||||
|
||||
/**
|
||||
* Nodes
|
||||
*
|
||||
* @type array
|
||||
* @var array
|
||||
*/
|
||||
protected $nodes = array();
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ class TreeNode implements Identifiable
|
|||
/**
|
||||
* The node's ID
|
||||
*
|
||||
* @type mixed
|
||||
* @var mixed
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
|
@ -24,7 +24,7 @@ class TreeNode implements Identifiable
|
|||
/**
|
||||
* The node's children
|
||||
*
|
||||
* @type array
|
||||
* @var array
|
||||
*/
|
||||
protected $children = array();
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class TreeNodeIterator implements RecursiveIterator
|
|||
/**
|
||||
* The node's children
|
||||
*
|
||||
* @type array
|
||||
* @var array
|
||||
*/
|
||||
protected $children;
|
||||
|
||||
|
|
|
@ -4,9 +4,37 @@
|
|||
namespace Icinga\Exception;
|
||||
|
||||
/**
|
||||
* Class MissingParameterException
|
||||
* @package Icinga\Exception
|
||||
* Exception thrown if a mandatory parameter was not given
|
||||
*/
|
||||
class MissingParameterException extends IcingaException
|
||||
{
|
||||
/**
|
||||
* Name of the missing parameter
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $parameter;
|
||||
|
||||
/**
|
||||
* Get the name of the missing parameter
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getParameter()
|
||||
{
|
||||
return $this->parameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the missing parameter
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setParameter($name)
|
||||
{
|
||||
$this->parameter = (string) $name;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ class FileExtensionFilterIterator extends FilterIterator
|
|||
/**
|
||||
* The extension to filter for
|
||||
*
|
||||
* @type string
|
||||
* @var string
|
||||
*/
|
||||
protected $extension;
|
||||
|
||||
|
@ -58,7 +58,7 @@ class FileExtensionFilterIterator extends FilterIterator
|
|||
public function accept()
|
||||
{
|
||||
$current = $this->current();
|
||||
/** @type $current \SplFileInfo */
|
||||
/** @var $current \SplFileInfo */
|
||||
if (! $current->isFile()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class NonEmptyFileIterator extends FilterIterator
|
|||
public function accept()
|
||||
{
|
||||
$current = $this->current();
|
||||
/** @type $current \SplFileInfo */
|
||||
/** @var $current \SplFileInfo */
|
||||
if (! $current->isFile()
|
||||
|| $current->getSize() === 0
|
||||
) {
|
||||
|
|
|
@ -26,6 +26,13 @@ class FileReader implements Selectable, Countable
|
|||
*/
|
||||
protected $filename;
|
||||
|
||||
/**
|
||||
* Cache for static::count()
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $count = null;
|
||||
|
||||
/**
|
||||
* Create a new reader
|
||||
*
|
||||
|
@ -51,7 +58,7 @@ class FileReader implements Selectable, Countable
|
|||
*/
|
||||
public function iterate()
|
||||
{
|
||||
return new FileIterator($this->filename, $this->fields);
|
||||
return new LogFileIterator($this->filename, $this->fields);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,7 +78,10 @@ class FileReader implements Selectable, Countable
|
|||
*/
|
||||
public function count()
|
||||
{
|
||||
return iterator_count($this->iterate());
|
||||
if ($this->count === null) {
|
||||
$this->count = iterator_count($this->iterate());
|
||||
}
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Protocol\File;
|
||||
|
||||
use Icinga\Exception\IcingaException;
|
||||
use SplFileObject;
|
||||
use Iterator;
|
||||
|
||||
/**
|
||||
* Iterate over a log file, yielding the regex fields of the log messages
|
||||
*/
|
||||
class LogFileIterator implements Iterator
|
||||
{
|
||||
/**
|
||||
* Log file
|
||||
*
|
||||
* @var SplFileObject
|
||||
*/
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* A PCRE string with the fields to extract
|
||||
* from the log messages as named subpatterns
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fields;
|
||||
|
||||
/**
|
||||
* Value for static::current()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $current;
|
||||
|
||||
/**
|
||||
* Index for static::key()
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $index;
|
||||
|
||||
/**
|
||||
* Value for static::valid()
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $valid;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $next = null;
|
||||
|
||||
/**
|
||||
* @param string $filename The log file's name
|
||||
* @param string $fields A PCRE string with the fields to extract
|
||||
* from the log messages as named subpatterns
|
||||
*/
|
||||
public function __construct($filename, $fields)
|
||||
{
|
||||
$this->file = new SplFileObject($filename);
|
||||
$this->file->setFlags(
|
||||
SplFileObject::DROP_NEW_LINE |
|
||||
SplFileObject::READ_AHEAD
|
||||
);
|
||||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
$this->file->rewind();
|
||||
$this->index = 0;
|
||||
$this->nextMessage();
|
||||
}
|
||||
|
||||
public function next()
|
||||
{
|
||||
$this->file->next();
|
||||
++$this->index;
|
||||
$this->nextMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->valid;
|
||||
}
|
||||
|
||||
protected function nextMessage()
|
||||
{
|
||||
$message = $this->next === null ? array() : array($this->next);
|
||||
$this->valid = null;
|
||||
while ($this->file->valid()) {
|
||||
if (false === ($res = preg_match(
|
||||
$this->fields, $current = $this->file->current()
|
||||
))) {
|
||||
throw new IcingaException('Failed at preg_match()');
|
||||
}
|
||||
if (empty($message)) {
|
||||
if ($res === 1) {
|
||||
$message[] = $current;
|
||||
}
|
||||
} else if ($res === 1) {
|
||||
$this->next = $current;
|
||||
$this->valid = true;
|
||||
break;
|
||||
} else {
|
||||
$message[] = $current;
|
||||
}
|
||||
|
||||
$this->file->next();
|
||||
}
|
||||
if ($this->valid === null) {
|
||||
$this->next = null;
|
||||
$this->valid = ! empty($message);
|
||||
}
|
||||
|
||||
if ($this->valid) {
|
||||
while (! empty($message)) {
|
||||
$matches = array();
|
||||
if (false === ($res = preg_match(
|
||||
$this->fields, implode(PHP_EOL, $message), $matches
|
||||
))) {
|
||||
throw new IcingaException('Failed at preg_match()');
|
||||
}
|
||||
if ($res === 1) {
|
||||
$this->current = $matches;
|
||||
return;
|
||||
}
|
||||
array_pop($message);
|
||||
}
|
||||
$this->valid = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -121,7 +121,7 @@ class Capability
|
|||
*
|
||||
* @return bool Whether StartTLS is supported
|
||||
*/
|
||||
public function hasStartTLS()
|
||||
public function hasStartTls()
|
||||
{
|
||||
return isset($this->oids[self::LDAP_SERVER_START_TLS_OID]);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
namespace Icinga\Protocol\Ldap;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Protocol\Ldap\Exception as LdapException;
|
||||
use Icinga\Application\Platform;
|
||||
|
@ -24,10 +23,6 @@ use Icinga\Data\ConfigObject;
|
|||
* 'bind_pw' => '***'
|
||||
* ));
|
||||
* </code>
|
||||
*
|
||||
* @copyright Copyright (c) 2013 Icinga-Web Team <info@icinga.org>
|
||||
* @author Icinga-Web Team <info@icinga.org>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
|
||||
*/
|
||||
class Connection
|
||||
{
|
||||
|
@ -36,6 +31,27 @@ class Connection
|
|||
const LDAP_ADMINLIMIT_EXCEEDED = 11;
|
||||
const PAGE_SIZE = 1000;
|
||||
|
||||
/**
|
||||
* Encrypt connection using STARTTLS (upgrading a plain text connection)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const STARTTLS = 'starttls';
|
||||
|
||||
/**
|
||||
* Encrypt connection using LDAP over SSL (using a separate port)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const LDAPS = 'ldaps';
|
||||
|
||||
/**
|
||||
* Encryption for the connection if any
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $encryption;
|
||||
|
||||
protected $ds;
|
||||
protected $hostname;
|
||||
protected $port = 389;
|
||||
|
@ -43,6 +59,7 @@ class Connection
|
|||
protected $bind_pw;
|
||||
protected $root_dn;
|
||||
protected $count;
|
||||
protected $reqCert = true;
|
||||
|
||||
/**
|
||||
* Whether the bind on this connection was already performed
|
||||
|
@ -66,8 +83,6 @@ class Connection
|
|||
/**
|
||||
* Constructor
|
||||
*
|
||||
* TODO: Allow to pass port and SSL options
|
||||
*
|
||||
* @param ConfigObject $config
|
||||
*/
|
||||
public function __construct(ConfigObject $config)
|
||||
|
@ -77,6 +92,11 @@ class Connection
|
|||
$this->bind_pw = $config->bind_pw;
|
||||
$this->root_dn = $config->root_dn;
|
||||
$this->port = $config->get('port', $this->port);
|
||||
$this->encryption = $config->get('encryption');
|
||||
if ($this->encryption !== null) {
|
||||
$this->encryption = strtolower($this->encryption);
|
||||
}
|
||||
$this->reqCert = (bool) $config->get('reqcert', $this->reqCert);
|
||||
}
|
||||
|
||||
public function getHostname()
|
||||
|
@ -470,59 +490,52 @@ class Connection
|
|||
*/
|
||||
protected function prepareNewConnection()
|
||||
{
|
||||
$use_tls = false;
|
||||
$force_tls = false;
|
||||
|
||||
if ($use_tls) {
|
||||
if ($this->encryption === static::STARTTLS || $this->encryption === static::LDAPS) {
|
||||
$this->prepareTlsEnvironment();
|
||||
}
|
||||
|
||||
$ds = ldap_connect($this->hostname, $this->port);
|
||||
$hostname = $this->hostname;
|
||||
if ($this->encryption === static::LDAPS) {
|
||||
$hostname = 'ldaps://' . $hostname;
|
||||
}
|
||||
|
||||
$ds = ldap_connect($hostname, $this->port);
|
||||
try {
|
||||
$this->capabilities = $this->discoverCapabilities($ds);
|
||||
$this->discoverySuccess = true;
|
||||
|
||||
} catch (LdapException $e) {
|
||||
|
||||
// create empty default capabilities
|
||||
Logger::debug($e);
|
||||
Logger::warning('LADP discovery failed, assuming default LDAP settings.');
|
||||
$this->capabilities = new Capability();
|
||||
$this->capabilities = new Capability(); // create empty default capabilities
|
||||
}
|
||||
|
||||
if ($use_tls) {
|
||||
if ($this->capabilities->hasStartTLS()) {
|
||||
if ($this->encryption === static::STARTTLS) {
|
||||
$force_tls = false;
|
||||
if ($this->capabilities->hasStartTls()) {
|
||||
if (@ldap_start_tls($ds)) {
|
||||
Logger::debug('LDAP STARTTLS succeeded');
|
||||
} else {
|
||||
Logger::debug('LDAP STARTTLS failed: %s', ldap_error($ds));
|
||||
throw new LdapException(
|
||||
'LDAP STARTTLS failed: %s',
|
||||
ldap_error($ds)
|
||||
);
|
||||
Logger::error('LDAP STARTTLS failed: %s', ldap_error($ds));
|
||||
throw new LdapException('LDAP STARTTLS failed: %s', ldap_error($ds));
|
||||
}
|
||||
} elseif ($force_tls) {
|
||||
throw new LdapException(
|
||||
'TLS is required but not announced by %s',
|
||||
$this->hostname
|
||||
);
|
||||
throw new LdapException('STARTTLS is required but not announced by %s', $this->hostname);
|
||||
} else {
|
||||
Logger::warning('LDAP TLS enabled but not announced');
|
||||
Logger::warning('LDAP STARTTLS enabled but not announced');
|
||||
}
|
||||
}
|
||||
|
||||
// ldap_rename requires LDAPv3:
|
||||
if ($this->capabilities->hasLdapV3()) {
|
||||
if (! ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3)) {
|
||||
throw new LdapException('LDAPv3 is required');
|
||||
}
|
||||
} else {
|
||||
|
||||
// TODO: remove this -> FORCING v3 for now
|
||||
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
Logger::warning('No LDAPv3 support detected');
|
||||
}
|
||||
|
||||
// Not setting this results in "Operations error" on AD when using the
|
||||
// whole domain as search base:
|
||||
// Not setting this results in "Operations error" on AD when using the whole domain as search base
|
||||
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
|
||||
// ldap_set_option($ds, LDAP_OPT_DEREF, LDAP_DEREF_NEVER);
|
||||
return $ds;
|
||||
|
@ -530,17 +543,16 @@ class Connection
|
|||
|
||||
protected function prepareTlsEnvironment()
|
||||
{
|
||||
$strict_tls = true;
|
||||
// TODO: allow variable known CA location (system VS Icinga)
|
||||
if (Platform::isWindows()) {
|
||||
// putenv('LDAP...')
|
||||
putenv('LDAPTLS_REQCERT=never');
|
||||
} else {
|
||||
if ($strict_tls) {
|
||||
if ($this->reqCert) {
|
||||
$ldap_conf = $this->getConfigDir('ldap_ca.conf');
|
||||
} else {
|
||||
$ldap_conf = $this->getConfigDir('ldap_nocert.conf');
|
||||
}
|
||||
putenv('LDAPRC=' . $ldap_conf);
|
||||
putenv('LDAPRC=' . $ldap_conf); // TODO: Does not have any effect
|
||||
if (getenv('LDAPRC') !== $ldap_conf) {
|
||||
throw new LdapException('putenv failed');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Protocol\Ldap;
|
||||
|
||||
class Expression
|
||||
{
|
||||
protected $value;
|
||||
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->getValue();
|
||||
}
|
||||
}
|
|
@ -306,6 +306,19 @@ class Query
|
|||
return $paginator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a filter expression to this query
|
||||
*
|
||||
* @param Expression $expression
|
||||
*
|
||||
* @return Query
|
||||
*/
|
||||
public function addFilter(Expression $expression)
|
||||
{
|
||||
$this->filters[] = $expression;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP filter that will be applied
|
||||
*
|
||||
|
@ -318,11 +331,15 @@ class Query
|
|||
throw new Exception('Object class is mandatory');
|
||||
}
|
||||
foreach ($this->filters as $key => $value) {
|
||||
$parts[] = sprintf(
|
||||
'%s=%s',
|
||||
LdapUtils::quoteForSearch($key),
|
||||
LdapUtils::quoteForSearch($value, true)
|
||||
);
|
||||
if ($value instanceof Expression) {
|
||||
$parts[] = (string) $value;
|
||||
} else {
|
||||
$parts[] = sprintf(
|
||||
'%s=%s',
|
||||
LdapUtils::quoteForSearch($key),
|
||||
LdapUtils::quoteForSearch($value, true)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (count($parts) > 1) {
|
||||
return '(&(' . implode(')(', $parts) . '))';
|
||||
|
@ -331,6 +348,11 @@ class Query
|
|||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Descructor
|
||||
*/
|
||||
|
|
|
@ -416,7 +416,7 @@ if ($col > $size - 1) return $res;
|
|||
/**
|
||||
* Disconnect in case we are connected to a Livestatus socket
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
|
|
|
@ -413,22 +413,30 @@ class User
|
|||
/**
|
||||
* Whether the user has a given permission
|
||||
*
|
||||
* @param string $permission
|
||||
* @param string $requiredPermission
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can($permission)
|
||||
public function can($requiredPermission)
|
||||
{
|
||||
if (isset($this->permissions['*']) || isset($this->permissions[$permission])) {
|
||||
if (isset($this->permissions['*']) || isset($this->permissions[$requiredPermission])) {
|
||||
return true;
|
||||
}
|
||||
foreach ($this->permissions as $permitted) {
|
||||
$wildcard = strpos($permitted, '*');
|
||||
// If the permission to check contains a wildcard, grant the permission if any permit related to the permission
|
||||
// matches
|
||||
$any = strpos($requiredPermission, '*');
|
||||
foreach ($this->permissions as $grantedPermission) {
|
||||
if ($any !== false && strpos($grantedPermission, '*') === false) {
|
||||
$wildcard = $any;
|
||||
} else {
|
||||
// If the permit contains a wildcard, grant the permission if it's related to the permit
|
||||
$wildcard = strpos($grantedPermission, '*');
|
||||
}
|
||||
if ($wildcard !== false) {
|
||||
if (substr($permission, 0, $wildcard) === substr($permitted, 0, $wildcard)) {
|
||||
if (substr($requiredPermission, 0, $wildcard) === substr($grantedPermission, 0, $wildcard)) {
|
||||
return true;
|
||||
}
|
||||
} elseif ($permission === $permitted) {
|
||||
} elseif ($requiredPermission === $grantedPermission) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,12 +203,14 @@ class DbStore extends PreferencesStore
|
|||
foreach ($preferences as $key => $value) {
|
||||
$db->update(
|
||||
$this->table,
|
||||
array(self::COLUMN_VALUE => $value),
|
||||
array(
|
||||
self::COLUMN_VALUE => $value,
|
||||
self::COLUMN_MODIFIED_TIME => new Zend_Db_Expr('NOW()')
|
||||
),
|
||||
array(
|
||||
self::COLUMN_USERNAME . '=?' => $this->getUser()->getUsername(),
|
||||
$db->quoteIdentifier(self::COLUMN_SECTION) . '=?' => $section,
|
||||
$db->quoteIdentifier(self::COLUMN_PREFERENCE) . '=?' => $key,
|
||||
self::COLUMN_MODIFIED_TIME => new Zend_Db_Expr('NOW()')
|
||||
$db->quoteIdentifier(self::COLUMN_PREFERENCE) . '=?' => $key
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
|
||||
namespace Icinga\Web;
|
||||
|
||||
use Zend_Paginator;
|
||||
use Icinga\Web\Controller\ModuleActionController;
|
||||
use Icinga\Web\Widget\SortBox;
|
||||
use Icinga\Web\Widget\Limiter;
|
||||
|
||||
/**
|
||||
* This is the controller all modules should inherit from
|
||||
|
@ -12,4 +15,78 @@ use Icinga\Web\Controller\ModuleActionController;
|
|||
*/
|
||||
class Controller extends ModuleActionController
|
||||
{
|
||||
/**
|
||||
* Create a SortBox widget at the `sortBox' view property
|
||||
*
|
||||
* In case the current view has been requested as compact this method does nothing.
|
||||
*
|
||||
* @param array $columns An array containing the sort columns, with the
|
||||
* submit value as the key and the label as the value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupSortControl(array $columns)
|
||||
{
|
||||
if (! $this->view->compact) {
|
||||
$req = $this->getRequest();
|
||||
$this->view->sortBox = SortBox::create(
|
||||
'sortbox-' . $req->getActionName(),
|
||||
$columns
|
||||
)->applyRequest($req);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Limiter widget at the `limiter' view property
|
||||
*
|
||||
* In case the current view has been requested as compact this method does nothing.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupLimitControl()
|
||||
{
|
||||
if (! $this->view->compact) {
|
||||
$this->view->limiter = new Limiter();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the view property `paginator' to the given Zend_Paginator
|
||||
*
|
||||
* In case the current view has been requested as compact this method does nothing.
|
||||
*
|
||||
* @param Zend_Paginator $paginator The Zend_Paginator for which to show a pagination control
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupPaginationControl(Zend_Paginator $paginator)
|
||||
{
|
||||
if (! $this->view->compact) {
|
||||
$this->view->paginator = $paginator;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the view property `filterEditor' to the given FilterEditor
|
||||
*
|
||||
* In case the current view has been requested as compact this method does nothing.
|
||||
*
|
||||
* @param Form $editor The FilterEditor
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupFilterControl($editor)
|
||||
{
|
||||
if (! $this->view->compact) {
|
||||
$this->view->filterEditor = $editor;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,10 +51,15 @@ class ActionController extends Zend_Controller_Action
|
|||
/**
|
||||
* Authentication manager
|
||||
*
|
||||
* @type Manager|null
|
||||
* @var Manager|null
|
||||
*/
|
||||
private $auth;
|
||||
|
||||
/**
|
||||
* URL parameters
|
||||
*
|
||||
* @var UrlParams
|
||||
*/
|
||||
protected $params;
|
||||
|
||||
/**
|
||||
|
@ -82,6 +87,7 @@ class ActionController extends Zend_Controller_Action
|
|||
$this->_helper->layout()->isIframe = $request->getUrl()->shift('isIframe');
|
||||
$this->_helper->layout()->moduleName = false;
|
||||
|
||||
$this->view->compact = $request->getParam('view') === 'compact';
|
||||
if ($this->rerenderLayout = $request->getUrl()->shift('renderLayout')) {
|
||||
$this->xhrLayout = 'body';
|
||||
}
|
||||
|
@ -293,34 +299,36 @@ class ActionController extends Zend_Controller_Action
|
|||
}
|
||||
|
||||
/**
|
||||
* Redirect to the login path
|
||||
* Redirect to login
|
||||
*
|
||||
* @param Url $afterLogin The action to call when the login was successful. Defaults to '/index/welcome'
|
||||
* XHR will always redirect to __SELF__ if an URL to redirect to after successful login is set. __SELF__ instructs
|
||||
* JavaScript to redirect to the current window's URL if it's an auto-refresh request or to redirect to the URL
|
||||
* which required login if it's not an auto-refreshing one.
|
||||
*
|
||||
* @throws \Exception
|
||||
* XHR will respond with HTTP status code 403 Forbidden.
|
||||
*
|
||||
* @param Url|string $redirect URL to redirect to after successful login
|
||||
*/
|
||||
protected function redirectToLogin($afterLogin = null)
|
||||
protected function redirectToLogin($redirect = null)
|
||||
{
|
||||
$redir = null;
|
||||
if ($afterLogin !== null) {
|
||||
if (! $afterLogin instanceof Url) {
|
||||
$afterLogin = Url::fromPath($afterLogin);
|
||||
$login = Url::fromPath('authentication/login');
|
||||
if ($this->isXhr()) {
|
||||
if ($redirect !== null) {
|
||||
$login->setParam('redirect', '__SELF__');
|
||||
}
|
||||
if ($this->isXhr()) {
|
||||
$redir = '__SELF__';
|
||||
} else {
|
||||
// TODO: Ignore /?
|
||||
$redir = $afterLogin->getRelativeUrl();
|
||||
|
||||
$this->_response->setHttpResponseCode(403);
|
||||
} elseif ($redirect !== null) {
|
||||
if (! $redirect instanceof Url) {
|
||||
$redirect = Url::fromPath($redirect);
|
||||
}
|
||||
|
||||
if (($relativeUrl = $redirect->getRelativeUrl())) {
|
||||
$login->setParam('redirect', $relativeUrl);
|
||||
}
|
||||
}
|
||||
|
||||
$url = Url::fromPath('authentication/login');
|
||||
|
||||
if ($redir) {
|
||||
$url->setParam('redirect', $redir);
|
||||
}
|
||||
|
||||
$this->rerenderLayout()->redirectNow($url);
|
||||
$this->rerenderLayout()->redirectNow($login);
|
||||
}
|
||||
|
||||
protected function rerenderLayout()
|
||||
|
|
|
@ -27,7 +27,7 @@ class BasePreferenceController extends ActionController
|
|||
}
|
||||
|
||||
/**
|
||||
* Initialize the controller and collect all tabs for it from the application and it's modules
|
||||
* Initialize the controller and collect all tabs for it from the application and its modules
|
||||
*
|
||||
* @see ActionController::init()
|
||||
*/
|
||||
|
|
|
@ -33,7 +33,7 @@ class DomNodeIterator implements RecursiveIterator
|
|||
/**
|
||||
* The node's children
|
||||
*
|
||||
* @type IteratorIterator
|
||||
* @var IteratorIterator
|
||||
*/
|
||||
protected $children;
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ use Icinga\Web\Form\Element\CsrfCounterMeasure;
|
|||
*/
|
||||
class Form extends Zend_Form
|
||||
{
|
||||
/**
|
||||
* The suffix to append to a field's hidden default field name
|
||||
*/
|
||||
const DEFAULT_SUFFIX = '_default';
|
||||
|
||||
/**
|
||||
* Whether this form has been created
|
||||
*
|
||||
|
@ -145,7 +150,7 @@ class Form extends Zend_Form
|
|||
/**
|
||||
* Authentication manager
|
||||
*
|
||||
* @type Manager|null
|
||||
* @var Manager|null
|
||||
*/
|
||||
private $auth;
|
||||
|
||||
|
@ -157,7 +162,7 @@ class Form extends Zend_Form
|
|||
public static $defaultElementDecorators = array(
|
||||
array('ViewHelper', array('separator' => '')),
|
||||
array('Errors', array('separator' => '')),
|
||||
array('Help'),
|
||||
array('Help', array('placement' => 'PREPEND')),
|
||||
array('Label', array('separator' => '')),
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'element'))
|
||||
);
|
||||
|
@ -211,7 +216,7 @@ class Form extends Zend_Form
|
|||
*
|
||||
* @param string $label The label to use for the submit button
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setSubmitLabel($label)
|
||||
{
|
||||
|
@ -234,7 +239,7 @@ class Form extends Zend_Form
|
|||
*
|
||||
* @param string|Url $url The url to redirect to
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setRedirectUrl($url)
|
||||
{
|
||||
|
@ -263,7 +268,7 @@ class Form extends Zend_Form
|
|||
*
|
||||
* @param string $viewScript The view script to use
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setViewScript($viewScript)
|
||||
{
|
||||
|
@ -286,7 +291,7 @@ class Form extends Zend_Form
|
|||
*
|
||||
* @param bool $disabled Set true in order to disable CSRF protection for this form, otherwise false
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setTokenDisabled($disabled = true)
|
||||
{
|
||||
|
@ -314,7 +319,7 @@ class Form extends Zend_Form
|
|||
*
|
||||
* @param string $name The name to set
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setTokenElementName($name)
|
||||
{
|
||||
|
@ -337,7 +342,7 @@ class Form extends Zend_Form
|
|||
*
|
||||
* @param bool $disabled Set true in order to disable identification for this form, otherwise false
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setUidDisabled($disabled = true)
|
||||
{
|
||||
|
@ -365,7 +370,7 @@ class Form extends Zend_Form
|
|||
*
|
||||
* @param string $name The name to set
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setUidElementName($name)
|
||||
{
|
||||
|
@ -388,7 +393,7 @@ class Form extends Zend_Form
|
|||
*
|
||||
* @param bool $state
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setValidatePartial($state)
|
||||
{
|
||||
|
@ -525,7 +530,7 @@ class Form extends Zend_Form
|
|||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function create(array $formData = array())
|
||||
{
|
||||
|
@ -535,7 +540,13 @@ class Form extends Zend_Form
|
|||
->addCsrfCounterMeasure()
|
||||
->addSubmitButton();
|
||||
|
||||
if ($this->getAction() === '') {
|
||||
if ($this->getAttrib('action') === null) {
|
||||
// Use Form::getAttrib() instead of Form::getAction() here because we want to explicitly check against
|
||||
// null. Form::getAction() would return the empty string '' if the action is not set.
|
||||
// For not setting the action attribute use Form::setAction(''). This is required for for the
|
||||
// accessibility's enable/disable auto-refresh mechanic
|
||||
|
||||
// TODO(el): Re-evalute this necessity. JavaScript could use the container's URL if there's no action set.
|
||||
// We MUST set an action as JS gets confused otherwise, if
|
||||
// this form is being displayed in an additional column
|
||||
$this->setAction(Url::fromRequest()->without(array_keys($this->getElements())));
|
||||
|
@ -587,7 +598,7 @@ class Form extends Zend_Form
|
|||
* Uses the label previously set with Form::setSubmitLabel(). Overwrite this
|
||||
* method in order to add multiple submit buttons or one with a custom name.
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function addSubmitButton()
|
||||
{
|
||||
|
@ -622,7 +633,7 @@ class Form extends Zend_Form
|
|||
public function addSubForm(Zend_Form $form, $name = null, $order = null)
|
||||
{
|
||||
if ($form instanceof self) {
|
||||
$form->removeDecorator('Form');
|
||||
$form->setDecorators(array('FormElements')); // TODO: Makes it difficult to customise subform decorators..
|
||||
$form->setSubmitLabel('');
|
||||
$form->setTokenDisabled();
|
||||
$form->setUidDisabled();
|
||||
|
@ -725,6 +736,20 @@ class Form extends Zend_Form
|
|||
unset($el->autosubmit);
|
||||
}
|
||||
|
||||
if ($el->getAttrib('preserveDefault')) {
|
||||
$el->addDecorator(
|
||||
array('preserveDefault' => 'HtmlTag'),
|
||||
array(
|
||||
'tag' => 'input',
|
||||
'type' => 'hidden',
|
||||
'name' => $name . static::DEFAULT_SUFFIX,
|
||||
'value' => $el->getValue()
|
||||
)
|
||||
);
|
||||
|
||||
unset($el->preserveDefault);
|
||||
}
|
||||
|
||||
return $this->ensureElementAccessibility($el);
|
||||
}
|
||||
|
||||
|
@ -743,7 +768,7 @@ class Form extends Zend_Form
|
|||
if (($cue = $this->getRequiredCue()) !== null && ($label = $element->getDecorator('label')) !== false) {
|
||||
$element->setLabel($this->getView()->escape($element->getLabel()));
|
||||
$label->setOption('escape', false);
|
||||
$label->setOption('requiredSuffix', sprintf(' <span aria-hidden="true">%s</span>', $cue));
|
||||
$label->setRequiredSuffix(sprintf(' <span aria-hidden="true">%s</span>', $cue));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -767,7 +792,7 @@ class Form extends Zend_Form
|
|||
/**
|
||||
* Add a field with a unique and form specific ID
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function addFormIdentification()
|
||||
{
|
||||
|
@ -789,7 +814,7 @@ class Form extends Zend_Form
|
|||
/**
|
||||
* Add CSRF counter measure field to this form
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function addCsrfCounterMeasure()
|
||||
{
|
||||
|
@ -808,6 +833,17 @@ class Form extends Zend_Form
|
|||
public function populate(array $defaults)
|
||||
{
|
||||
$this->create($defaults);
|
||||
|
||||
foreach ($this->getElements() as $name => $_) {
|
||||
if (
|
||||
array_key_exists($name, $defaults)
|
||||
&& array_key_exists($name . static::DEFAULT_SUFFIX, $defaults)
|
||||
&& $defaults[$name] === $defaults[$name . static::DEFAULT_SUFFIX]
|
||||
) {
|
||||
unset($defaults[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::populate($defaults);
|
||||
}
|
||||
|
||||
|
@ -894,10 +930,18 @@ class Form extends Zend_Form
|
|||
{
|
||||
$this->create($formData);
|
||||
|
||||
// Ensure that disabled elements are not overwritten (http://www.zendframework.com/issues/browse/ZF-6909)
|
||||
foreach ($this->getElements() as $name => $element) {
|
||||
if ($element->getAttrib('disabled')) {
|
||||
$formData[$name] = $element->getValue();
|
||||
if (array_key_exists($name, $formData)) {
|
||||
if ($element->getAttrib('disabled')) {
|
||||
// Ensure that disabled elements are not overwritten
|
||||
// (http://www.zendframework.com/issues/browse/ZF-6909)
|
||||
$formData[$name] = $element->getValue();
|
||||
} elseif (
|
||||
array_key_exists($name . static::DEFAULT_SUFFIX, $formData)
|
||||
&& $formData[$name] === $formData[$name . static::DEFAULT_SUFFIX]
|
||||
) {
|
||||
unset($formData[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -942,7 +986,7 @@ class Form extends Zend_Form
|
|||
* Overwrites Zend_Form::loadDefaultDecorators to avoid having
|
||||
* the HtmlTag-Decorator added and to provide viewscript usage
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function loadDefaultDecorators()
|
||||
{
|
||||
|
@ -1071,10 +1115,11 @@ class Form extends Zend_Form
|
|||
protected function getTranslationDomain()
|
||||
{
|
||||
$parts = explode('\\', get_called_class());
|
||||
if ($parts[1] === 'Module') {
|
||||
if (count($parts) > 1 && $parts[1] === 'Module') {
|
||||
// Assume format Icinga\Module\ModuleName\Forms\...
|
||||
return strtolower($parts[2]);
|
||||
}
|
||||
|
||||
return 'icinga';
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,29 @@ use Icinga\Web\Form;
|
|||
*/
|
||||
class FormDescriptions extends Zend_Form_Decorator_Abstract
|
||||
{
|
||||
/**
|
||||
* A list of element class names to be ignored when detecting which message to use to describe required elements
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $blacklist;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($options = null)
|
||||
{
|
||||
parent::__construct($options);
|
||||
$this->blacklist = array(
|
||||
'Zend_Form_Element_Hidden',
|
||||
'Zend_Form_Element_Submit',
|
||||
'Zend_Form_Element_Button',
|
||||
'Icinga\Web\Form\Element\Note',
|
||||
'Icinga\Web\Form\Element\Button',
|
||||
'Icinga\Web\Form\Element\CsrfCounterMeasure'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render form descriptions
|
||||
*
|
||||
|
@ -32,9 +55,16 @@ class FormDescriptions extends Zend_Form_Decorator_Abstract
|
|||
return $content;
|
||||
}
|
||||
|
||||
$descriptions = $form->getDescriptions();
|
||||
if (($requiredDesc = $this->getRequiredDescription($form)) !== null) {
|
||||
$descriptions[] = $requiredDesc;
|
||||
$descriptions = $this->recurseForm($form, $entirelyRequired);
|
||||
if ($entirelyRequired) {
|
||||
$descriptions[] = $form->getView()->translate(
|
||||
'All fields are required and must be filled in to complete the form.'
|
||||
);
|
||||
} elseif ($entirelyRequired === false) {
|
||||
$descriptions[] = $form->getView()->translate(sprintf(
|
||||
'Required fields are marked with %s and must be filled in to complete the form.',
|
||||
$form->getRequiredCue()
|
||||
));
|
||||
}
|
||||
|
||||
if (empty($descriptions)) {
|
||||
|
@ -60,53 +90,57 @@ class FormDescriptions extends Zend_Form_Decorator_Abstract
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the description for the given form's required elements
|
||||
* Recurse the given form and return the descriptions for it and all of its subforms
|
||||
*
|
||||
* @param Form $form
|
||||
* @param Form $form The form to recurse
|
||||
* @param mixed $entirelyRequired Set by reference, true means all elements in the hierarchy are
|
||||
* required, false only a partial subset and null none at all
|
||||
* @param bool $elementsPassed Whether there were any elements passed during the recursion until now
|
||||
*
|
||||
* @return string|null
|
||||
* @return array
|
||||
*/
|
||||
protected function getRequiredDescription(Form $form)
|
||||
protected function recurseForm(Form $form, & $entirelyRequired = null, $elementsPassed = false)
|
||||
{
|
||||
if (($cue = $form->getRequiredCue()) === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$requiredLabels = array();
|
||||
$entirelyRequired = true;
|
||||
$partiallyRequired = false;
|
||||
$blacklist = array(
|
||||
'Zend_Form_Element_Hidden',
|
||||
'Zend_Form_Element_Submit',
|
||||
'Zend_Form_Element_Button',
|
||||
'Icinga\Web\Form\Element\Note',
|
||||
'Icinga\Web\Form\Element\Button',
|
||||
'Icinga\Web\Form\Element\CsrfCounterMeasure'
|
||||
);
|
||||
foreach ($form->getElements() as $element) {
|
||||
if (! in_array($element->getType(), $blacklist)) {
|
||||
if (! $element->isRequired()) {
|
||||
$entirelyRequired = false;
|
||||
} else {
|
||||
$partiallyRequired = true;
|
||||
if (($label = $element->getDecorator('label')) !== false) {
|
||||
$requiredLabels[] = $label;
|
||||
if ($form->getRequiredCue() !== null) {
|
||||
$partiallyRequired = $partiallyOptional = false;
|
||||
foreach ($form->getElements() as $element) {
|
||||
if (! in_array($element->getType(), $this->blacklist)) {
|
||||
if (! $element->isRequired()) {
|
||||
$partiallyOptional = true;
|
||||
if ($entirelyRequired) {
|
||||
$entirelyRequired = false;
|
||||
}
|
||||
} else {
|
||||
$partiallyRequired = true;
|
||||
if (($label = $element->getDecorator('label')) !== false) {
|
||||
$requiredLabels[] = $label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! $elementsPassed) {
|
||||
$elementsPassed = $partiallyRequired || $partiallyOptional;
|
||||
if ($entirelyRequired === null && $partiallyRequired) {
|
||||
$entirelyRequired = ! $partiallyOptional;
|
||||
}
|
||||
} elseif ($entirelyRequired === null && $partiallyRequired) {
|
||||
$entirelyRequired = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($entirelyRequired && $partiallyRequired) {
|
||||
$descriptions = array($form->getDescriptions());
|
||||
foreach ($form->getSubForms() as $subForm) {
|
||||
$descriptions[] = $this->recurseForm($subForm, $entirelyRequired, $elementsPassed);
|
||||
}
|
||||
|
||||
if ($entirelyRequired) {
|
||||
foreach ($requiredLabels as $label) {
|
||||
$label->setRequiredSuffix('');
|
||||
}
|
||||
|
||||
return $form->getView()->translate('All fields are required and must be filled in to complete the form.');
|
||||
} elseif ($partiallyRequired) {
|
||||
return $form->getView()->translate(sprintf(
|
||||
'Required fields are marked with %s and must be filled in to complete the form.',
|
||||
$cue
|
||||
));
|
||||
}
|
||||
|
||||
return call_user_func_array('array_merge', $descriptions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,18 +76,35 @@ class Help extends Zend_Form_Decorator_Abstract
|
|||
*/
|
||||
public function render($content = '')
|
||||
{
|
||||
if ($content && ($description = $this->getElement()->getDescription()) !== null) {
|
||||
$element = $this->getElement();
|
||||
$description = $element->getDescription();
|
||||
$requirement = $element->getAttrib('requirement');
|
||||
unset($element->requirement);
|
||||
|
||||
$helpContent = '';
|
||||
if ($description || $requirement) {
|
||||
if ($this->accessible) {
|
||||
$content = '<span id="'
|
||||
$helpContent = '<span id="'
|
||||
. $this->getDescriptionId()
|
||||
. '" class="sr-only">'
|
||||
. $description
|
||||
. '</span>' . $content;
|
||||
. ($description && $requirement ? ' ' : '')
|
||||
. $requirement
|
||||
. '</span>';
|
||||
}
|
||||
|
||||
$content = $this->getView()->icon('help', $description, array('aria-hidden' => 'true')) . $content;
|
||||
$helpContent = $this->getView()->icon(
|
||||
'help',
|
||||
$description . ($description && $requirement ? ' ' : '') . $requirement,
|
||||
array('aria-hidden' => $this->accessible ? 'true' : 'false')
|
||||
) . $helpContent;
|
||||
}
|
||||
|
||||
return $content;
|
||||
switch ($this->getPlacement()) {
|
||||
case self::APPEND:
|
||||
return $content . $helpContent;
|
||||
case self::PREPEND:
|
||||
return $helpContent . $content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ class Menu implements RecursiveIterator
|
|||
/**
|
||||
* The id of this menu
|
||||
*
|
||||
* @type string
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
|
@ -27,7 +27,7 @@ class Menu implements RecursiveIterator
|
|||
*
|
||||
* Used for sorting when priority is unset or equal to other items
|
||||
*
|
||||
* @type string
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
|
@ -36,45 +36,56 @@ class Menu implements RecursiveIterator
|
|||
*
|
||||
* Used for sorting
|
||||
*
|
||||
* @type int
|
||||
* @var int
|
||||
*/
|
||||
protected $priority = 100;
|
||||
|
||||
/**
|
||||
* The url of this menu
|
||||
*
|
||||
* @type string
|
||||
* @var string
|
||||
*/
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* The path to the icon of this menu
|
||||
*
|
||||
* @type string
|
||||
* @var string
|
||||
*/
|
||||
protected $icon;
|
||||
|
||||
/**
|
||||
* The sub menus of this menu
|
||||
*
|
||||
* @type array
|
||||
* @var array
|
||||
*/
|
||||
protected $subMenus = array();
|
||||
|
||||
/**
|
||||
* A custom item renderer used instead of the default rendering logic
|
||||
*
|
||||
* @type MenuItemRenderer
|
||||
* @var MenuItemRenderer
|
||||
*/
|
||||
protected $itemRenderer = null;
|
||||
|
||||
/*
|
||||
* Parent menu
|
||||
*
|
||||
* @type Menu
|
||||
* @var Menu
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Permission a user is required to have granted to display the menu item
|
||||
*
|
||||
* If a permission is set, authentication is of course required.
|
||||
*
|
||||
* Note that only one required permission can be set yet.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $permission;
|
||||
|
||||
/**
|
||||
* Create a new menu
|
||||
*
|
||||
|
@ -106,13 +117,18 @@ class Menu implements RecursiveIterator
|
|||
foreach ($props as $key => $value) {
|
||||
$method = 'set' . implode('', array_map('ucfirst', explode('_', strtolower($key))));
|
||||
if ($key === 'renderer') {
|
||||
$class = '\Icinga\Web\Menu\\' . $value;
|
||||
if (!class_exists($class)) {
|
||||
throw new ConfigurationError(
|
||||
sprintf('ItemRenderer with class "%s" does not exist', $class)
|
||||
);
|
||||
$value = '\\' . ltrim($value, '\\');
|
||||
if (class_exists($value)) {
|
||||
$value = new $value;
|
||||
} else {
|
||||
$class = '\Icinga\Web\Menu' . $value;
|
||||
if (!class_exists($class)) {
|
||||
throw new ConfigurationError(
|
||||
sprintf('ItemRenderer with class "%s" does not exist', $class)
|
||||
);
|
||||
}
|
||||
$value = new $class;
|
||||
}
|
||||
$value = new $class;
|
||||
}
|
||||
if (method_exists($this, $method)) {
|
||||
$this->{$method}($value);
|
||||
|
@ -218,15 +234,18 @@ class Menu implements RecursiveIterator
|
|||
|
||||
$section = $this->add(t('System'), array(
|
||||
'icon' => 'wrench',
|
||||
'priority' => 200
|
||||
'priority' => 200,
|
||||
'renderer' => 'ProblemMenuItemRenderer'
|
||||
));
|
||||
$section->add(t('Configuration'), array(
|
||||
'url' => 'config',
|
||||
'priority' => 300
|
||||
'url' => 'config',
|
||||
'permission' => 'config/application/*',
|
||||
'priority' => 300
|
||||
));
|
||||
$section->add(t('Modules'), array(
|
||||
'url' => 'config/modules',
|
||||
'priority' => 400
|
||||
'url' => 'config/modules',
|
||||
'permission' => 'config/modules',
|
||||
'priority' => 400
|
||||
));
|
||||
|
||||
if (Logger::writesToFile()) {
|
||||
|
@ -442,15 +461,47 @@ class Menu implements RecursiveIterator
|
|||
}
|
||||
|
||||
/**
|
||||
* Set required Permissions
|
||||
* Get the permission a user is required to have granted to display the menu item
|
||||
*
|
||||
* @param $permission
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPermission()
|
||||
{
|
||||
return $this->permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parent menu
|
||||
*
|
||||
* @return \Icinga\Web\Menu
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get submenus
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSubMenus()
|
||||
{
|
||||
return $this->subMenus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set permission a user is required to have granted to display the menu item
|
||||
*
|
||||
* If a permission is set, authentication is of course required.
|
||||
*
|
||||
* @param string $permission
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function requirePermission($permission)
|
||||
public function setPermission($permission)
|
||||
{
|
||||
// Not implemented yet
|
||||
$this->permission = (string) $permission;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -614,7 +665,7 @@ class Menu implements RecursiveIterator
|
|||
*
|
||||
* @param array $menus The menus to load, as key-value array
|
||||
*
|
||||
* @return static
|
||||
* @return $this
|
||||
*/
|
||||
protected function loadSubMenus(array $menus)
|
||||
{
|
||||
|
|
|
@ -9,15 +9,9 @@ use Icinga\Web\Url;
|
|||
/**
|
||||
* A menu item with a link that surpasses the regular navigation link behavior
|
||||
*/
|
||||
class ForeignMenuItemRenderer implements MenuItemRenderer {
|
||||
|
||||
public function render(Menu $menu)
|
||||
{
|
||||
return sprintf(
|
||||
'<a href="%s" target="_self">%s%s<span></span></a>',
|
||||
$menu->getUrl() ?: '#',
|
||||
$menu->getIcon() ? '<img aria-hidden="true" src="' . Url::fromPath($menu->getIcon()) . '" class="icon" /> ' : '',
|
||||
htmlspecialchars($menu->getTitle())
|
||||
);
|
||||
}
|
||||
class ForeignMenuItemRenderer extends MenuItemRenderer
|
||||
{
|
||||
protected $attributes = array(
|
||||
'target' => '_self'
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,11 +3,108 @@
|
|||
|
||||
namespace Icinga\Web\Menu;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Web\Menu;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\View;
|
||||
|
||||
/**
|
||||
* Renders the html content of a single menu item
|
||||
* Default MenuItemRenderer class
|
||||
*/
|
||||
interface MenuItemRenderer {
|
||||
public function render(Menu $menu);
|
||||
class MenuItemRenderer
|
||||
{
|
||||
/**
|
||||
* Contains <a> element specific attributes
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = array();
|
||||
|
||||
/**
|
||||
* View
|
||||
*
|
||||
* @var View|null
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* Set the view
|
||||
*
|
||||
* @param View $view
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setView(View $view)
|
||||
{
|
||||
$this->view = $view;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function getView()
|
||||
{
|
||||
if ($this->view === null) {
|
||||
$this->view = Icinga::app()->getViewRenderer()->view;
|
||||
}
|
||||
return $this->view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the html content of a single menu item
|
||||
*
|
||||
* @param Menu $menu
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(Menu $menu)
|
||||
{
|
||||
return $this->createLink($menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a menu item link element
|
||||
*
|
||||
* @param Menu $menu
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function createLink(Menu $menu)
|
||||
{
|
||||
if ($menu->getIcon() && strpos($menu->getIcon(), '.') === false) {
|
||||
return sprintf(
|
||||
'<a href="%s"%s><i aria-hidden="true" class="icon-%s"></i>%s</a>',
|
||||
$menu->getUrl() ? : '#',
|
||||
$this->getAttributes(),
|
||||
$menu->getIcon(),
|
||||
$this->getView()->escape($menu->getTitle())
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<a href="%s"%s>%s%s<span></span></a>',
|
||||
$menu->getUrl() ? : '#',
|
||||
$this->getAttributes(),
|
||||
$menu->getIcon() ? '<img aria-hidden="true" src="' . Url::fromPath($menu->getIcon()) . '" class="icon" /> ' : '',
|
||||
$this->getView()->escape($menu->getTitle())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <a> element specific attributes if present
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAttributes()
|
||||
{
|
||||
$attributes = '';
|
||||
$view = $this->getView();
|
||||
foreach ($this->attributes as $attribute => $value) {
|
||||
$attributes .= ' ' . $view->escape($attribute) . '="' . $view->escape($value) . '"';
|
||||
}
|
||||
return $attributes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Web\Menu;
|
||||
|
||||
use RecursiveFilterIterator;
|
||||
use Icinga\Authentication\Manager;
|
||||
use Icinga\Web\Menu;
|
||||
|
||||
class PermittedMenuItemFilter extends RecursiveFilterIterator
|
||||
{
|
||||
/**
|
||||
* Accept menu items that are permitted to the user
|
||||
*
|
||||
* @return bool Whether the user has the required permission granted to display the menu item
|
||||
*/
|
||||
public function accept()
|
||||
{
|
||||
$item = $this->current();
|
||||
/** @var Menu $item */
|
||||
if (($permission = $item->getPermission()) !== null) {
|
||||
$auth = Manager::getInstance();
|
||||
if (! $auth->isAuthenticated()) {
|
||||
// Don't accept menu item because user is not authenticated and the menu item requires a permission
|
||||
return false;
|
||||
}
|
||||
if (! $auth->getUser()->can($permission)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Accept menu item if it does not require a permission
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -3,10 +3,62 @@
|
|||
|
||||
namespace Icinga\Web\Menu;
|
||||
|
||||
class ProblemMenuItemRenderer extends MonitoringMenuItemRenderer
|
||||
use Icinga\Web\Menu;
|
||||
|
||||
class ProblemMenuItemRenderer extends MenuItemRenderer
|
||||
{
|
||||
protected $columns = array(
|
||||
'hosts_down_unhandled',
|
||||
'services_critical_unhandled'
|
||||
);
|
||||
/**
|
||||
* Set of summarized problems from submenus
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $summary = array();
|
||||
|
||||
/**
|
||||
* Renders the html content of a single menu item and summarizes submenu problems
|
||||
*
|
||||
* @param Menu $menu
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(Menu $menu)
|
||||
{
|
||||
if ($menu->getParent() !== null && $menu->hasSubMenus()) {
|
||||
/** @var $submenu Menu */
|
||||
foreach ($menu->getSubMenus() as $submenu) {
|
||||
$renderer = $submenu->getRenderer();
|
||||
if (method_exists($renderer, 'getSummary')) {
|
||||
if ($renderer->getSummary() !== null) {
|
||||
$this->summary[] = $renderer->getSummary();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->getBadge() . $this->createLink($menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the problem badge
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getBadge()
|
||||
{
|
||||
if (count($this->summary) > 0) {
|
||||
$problems = 0;
|
||||
$titles = array();
|
||||
|
||||
foreach ($this->summary as $summary) {
|
||||
$problems += $summary['problems'];
|
||||
$titles[] = $summary['title'];
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<div title="%s" class="badge-container"><span class="badge badge-critical">%s</span></div>',
|
||||
implode(', ', $titles),
|
||||
$problems
|
||||
);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
namespace Icinga\Web;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Web\Menu\MenuItemRenderer;
|
||||
use RecursiveIteratorIterator;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Web\Menu\PermittedMenuItemFilter;
|
||||
|
||||
/**
|
||||
* A renderer to draw a menu with its sub-menus using an unordered html list
|
||||
|
@ -31,6 +33,11 @@ class MenuRenderer extends RecursiveIteratorIterator
|
|||
*/
|
||||
protected $useCustomRenderer = false;
|
||||
|
||||
/**
|
||||
* @var MenuItemRenderer
|
||||
*/
|
||||
protected $defaultRenderer;
|
||||
|
||||
/**
|
||||
* Create a new MenuRenderer
|
||||
*
|
||||
|
@ -44,7 +51,8 @@ class MenuRenderer extends RecursiveIteratorIterator
|
|||
} else {
|
||||
$this->url = Url::fromPath($url);
|
||||
}
|
||||
parent::__construct($menu, RecursiveIteratorIterator::CHILD_FIRST);
|
||||
$this->defaultRenderer = new MenuItemRenderer();
|
||||
parent::__construct(new PermittedMenuItemFilter($menu), RecursiveIteratorIterator::CHILD_FIRST);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,22 +121,8 @@ class MenuRenderer extends RecursiveIteratorIterator
|
|||
Logger::error('Could not invoke custom renderer. Exception: '. $e->getMessage());
|
||||
}
|
||||
}
|
||||
if ($child->getIcon() && strpos($child->getIcon(), '.') === false) {
|
||||
return sprintf(
|
||||
'<a href="%s"><i aria-hidden="true" class="icon-%s"></i>%s</a>',
|
||||
$child->getUrl() ?: '#',
|
||||
$child->getIcon(),
|
||||
htmlspecialchars($child->getTitle())
|
||||
);
|
||||
}
|
||||
return sprintf(
|
||||
'<a href="%s">%s%s</a>',
|
||||
$child->getUrl() ?: '#',
|
||||
$child->getIcon()
|
||||
? '<img aria-hidden="true" src="' . Url::fromPath($child->getIcon()) . '" class="icon" /> '
|
||||
: '',
|
||||
htmlspecialchars($child->getTitle())
|
||||
);
|
||||
|
||||
return $this->defaultRenderer->render($child);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,8 +18,13 @@ use Icinga\Web\Session;
|
|||
class Notification
|
||||
{
|
||||
protected static $instance;
|
||||
|
||||
protected $isCli = false;
|
||||
|
||||
protected $session;
|
||||
|
||||
protected $messages = array();
|
||||
|
||||
public static function info($msg)
|
||||
{
|
||||
self::getInstance()->addMessage($msg, 'info');
|
||||
|
@ -74,8 +79,7 @@ class Notification
|
|||
return;
|
||||
}
|
||||
|
||||
$messages = & Session::getSession()->getByRef('messages');
|
||||
$messages[] = (object) array(
|
||||
$this->messages[] = (object) array(
|
||||
'type' => $type,
|
||||
'message' => $message,
|
||||
);
|
||||
|
@ -83,30 +87,30 @@ class Notification
|
|||
|
||||
public function hasMessages()
|
||||
{
|
||||
$session = Session::getSession();
|
||||
return false === empty($session->messages);
|
||||
return false === empty($this->messages);
|
||||
}
|
||||
|
||||
public function getMessages()
|
||||
{
|
||||
$session = Session::getSession();
|
||||
$messages = $session->messages;
|
||||
if (false === empty($messages)) {
|
||||
$session->messages = array();
|
||||
}
|
||||
|
||||
$messages = $this->messages;
|
||||
$this->messages = array();
|
||||
return $messages;
|
||||
}
|
||||
|
||||
final private function __construct()
|
||||
{
|
||||
$session = Session::getSession();
|
||||
if (!is_array($session->get('messages'))) {
|
||||
$session->messages = array();
|
||||
if (Platform::isCli()) {
|
||||
$this->isCli = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Platform::isCli()) {
|
||||
$this->is_cli = true;
|
||||
$this->session = Session::getSession();
|
||||
|
||||
$stored = $this->session->get('messages');
|
||||
if (is_array($stored)) {
|
||||
$this->messages = $stored;
|
||||
$this->session->set('messages', array());
|
||||
$this->session->write();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,4 +121,17 @@ class Notification
|
|||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
final public function __destruct()
|
||||
{
|
||||
if ($this->isCli) {
|
||||
return;
|
||||
}
|
||||
if ($this->session->get('messages') !== $this->messages) {
|
||||
$this->session->set('messages', $this->messages);
|
||||
}
|
||||
$this->session->write();
|
||||
|
||||
unset($this->session);
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue