mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-04-08 17:15:08 +02:00
Merge branch 'master' into feature/namespaced-controllers-5786
This commit is contained in:
commit
4070f6c75b
@ -335,7 +335,7 @@ class ConfigController extends Controller
|
||||
public function resourceAction()
|
||||
{
|
||||
$this->assertPermission('config/application/resources');
|
||||
$this->view->resources = Config::app('resources', true)->keys();
|
||||
$this->view->resources = Config::app('resources', true);
|
||||
$this->createApplicationTabs()->activate('resource');
|
||||
}
|
||||
|
||||
|
@ -57,19 +57,12 @@ class GroupController extends AuthBackendController
|
||||
}
|
||||
|
||||
$query = $backend->select(array('group_name'));
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($query)
|
||||
->setSearchColumns(array('group', 'user'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$query->applyFilter($filterEditor->getFilter());
|
||||
$this->setupFilterControl($filterEditor);
|
||||
|
||||
$this->view->groups = $query;
|
||||
$this->view->backend = $backend;
|
||||
|
||||
$this->setupPaginationControl($query);
|
||||
$this->setupFilterControl($query);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
array(
|
||||
@ -104,15 +97,7 @@ class GroupController extends AuthBackendController
|
||||
->from('group_membership', array('user_name'))
|
||||
->where('group_name', $groupName);
|
||||
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($members)
|
||||
->setSearchColumns(array('user'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend', 'group')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$members->applyFilter($filterEditor->getFilter());
|
||||
|
||||
$this->setupFilterControl($filterEditor);
|
||||
$this->setupFilterControl($members, null, array('user'));
|
||||
$this->setupPaginationControl($members);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
@ -149,7 +134,7 @@ class GroupController extends AuthBackendController
|
||||
$removeForm->addElement('button', 'btn_submit', array(
|
||||
'escape' => false,
|
||||
'type' => 'submit',
|
||||
'class' => 'link-like',
|
||||
'class' => 'link-like spinner',
|
||||
'value' => 'btn_submit',
|
||||
'decorators' => array('ViewHelper'),
|
||||
'label' => $this->view->icon('trash'),
|
||||
|
@ -57,19 +57,12 @@ class UserController extends AuthBackendController
|
||||
}
|
||||
|
||||
$query = $backend->select(array('user_name'));
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($query)
|
||||
->setSearchColumns(array('user'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$query->applyFilter($filterEditor->getFilter());
|
||||
$this->setupFilterControl($filterEditor);
|
||||
|
||||
$this->view->users = $query;
|
||||
$this->view->backend = $backend;
|
||||
|
||||
$this->setupPaginationControl($query);
|
||||
$this->setupFilterControl($query);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
array(
|
||||
@ -103,15 +96,11 @@ class UserController extends AuthBackendController
|
||||
|
||||
$memberships = $this->loadMemberships(new User($userName))->select();
|
||||
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($memberships)
|
||||
->setSearchColumns(array('group_name'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend', 'user')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$memberships->applyFilter($filterEditor->getFilter());
|
||||
|
||||
$this->setupFilterControl($filterEditor);
|
||||
$this->setupFilterControl(
|
||||
$memberships,
|
||||
array('group_name' => t('User Group')),
|
||||
array('group_name')
|
||||
);
|
||||
$this->setupPaginationControl($memberships);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
@ -151,7 +140,7 @@ class UserController extends AuthBackendController
|
||||
$removeForm->addElement('button', 'btn_submit', array(
|
||||
'escape' => false,
|
||||
'type' => 'submit',
|
||||
'class' => 'link-like',
|
||||
'class' => 'link-like spinner',
|
||||
'value' => 'btn_submit',
|
||||
'decorators' => array('ViewHelper'),
|
||||
'label' => $this->view->icon('trash'),
|
||||
|
@ -37,7 +37,7 @@ class UsergroupbackendController extends Controller
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
$this->view->backendNames = Config::app('groups')->keys();
|
||||
$this->view->backendNames = Config::app('groups');
|
||||
$this->createListTabs()->activate('usergroupbackend');
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ class LoginForm extends Form
|
||||
$this->setRequiredCue(null);
|
||||
$this->setName('form_login');
|
||||
$this->setSubmitLabel($this->translate('Login'));
|
||||
$this->setProgressLabel($this->translate('Logging in'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,6 +25,20 @@ class ApplicationConfigForm extends Form
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'global_show_stacktraces',
|
||||
array(
|
||||
'required' => true,
|
||||
'value' => true,
|
||||
'label' => $this->translate('Show Stacktraces'),
|
||||
'description' => $this->translate(
|
||||
'Set whether to show an exception\'s stacktrace by default. This can also'
|
||||
. ' be set in a user\'s preferences with the appropriate permission.'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'global_module_path',
|
||||
|
@ -81,22 +81,6 @@ class LdapResourceForm extends Form
|
||||
)
|
||||
);
|
||||
|
||||
if (isset($formData['encryption']) && $formData['encryption'] !== 'none') {
|
||||
// TODO(jom): Do not show this checkbox unless the connection is actually failing due to certificate errors
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'reqcert',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Require Certificate'),
|
||||
'description' => $this->translate(
|
||||
'When checked, the LDAP server must provide a valid and known (trusted) certificate.'
|
||||
),
|
||||
'value' => 1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'root_dn',
|
||||
|
@ -344,9 +344,10 @@ class ResourceConfigForm extends ConfigForm
|
||||
'submit',
|
||||
'resource_validation',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'decorators' => array('ViewHelper')
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'data-progress-label' => $this->translate('Validation In Progress'),
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
$this->addDisplayGroup(
|
||||
|
@ -464,9 +464,10 @@ class UserBackendConfigForm extends ConfigForm
|
||||
'submit',
|
||||
'backend_validation',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'decorators' => array('ViewHelper')
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'data-progress-label' => $this->translate('Validation In Progress'),
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
$this->addDisplayGroup(
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
namespace Icinga\Forms\Config;
|
||||
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Web\Notification;
|
||||
@ -28,6 +29,16 @@ class UserBackendReorderForm extends ConfigForm
|
||||
return $this->config->keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ordered backend configuration
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form
|
||||
*
|
||||
|
@ -5,6 +5,7 @@ namespace Icinga\Forms;
|
||||
|
||||
use Exception;
|
||||
use DateTimeZone;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Authentication\Auth;
|
||||
use Icinga\User\Preferences;
|
||||
@ -178,6 +179,19 @@ class PreferenceForm extends Form
|
||||
)
|
||||
);
|
||||
|
||||
if (Auth::getInstance()->hasPermission('application/stacktraces')) {
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'show_stacktraces',
|
||||
array(
|
||||
'required' => true,
|
||||
'value' => $this->getDefaultShowStacktraces(),
|
||||
'label' => $this->translate('Show Stacktraces'),
|
||||
'description' => $this->translate('Set whether to show an exception\'s stacktrace.')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'show_benchmark',
|
||||
@ -220,8 +234,20 @@ class PreferenceForm extends Form
|
||||
)
|
||||
);
|
||||
|
||||
$this->setAttrib('data-progress-element', 'preferences-progress');
|
||||
$this->addElement(
|
||||
'note',
|
||||
'preferences-progress',
|
||||
array(
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('Spinner', array('id' => 'preferences-progress'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->addDisplayGroup(
|
||||
array('btn_submit_preferences', 'btn_submit_session'),
|
||||
array('btn_submit_preferences', 'btn_submit_session', 'preferences-progress'),
|
||||
'submit_buttons',
|
||||
array(
|
||||
'decorators' => array(
|
||||
@ -257,4 +283,14 @@ class PreferenceForm extends Form
|
||||
$locale = Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
||||
return $locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default global setting for show_stacktraces
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function getDefaultShowStacktraces()
|
||||
{
|
||||
return Config::app()->get('global', 'show_stacktraces', true);
|
||||
}
|
||||
}
|
||||
|
@ -21,35 +21,7 @@ class RoleForm extends ConfigForm
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $providedPermissions = array(
|
||||
'*' => 'Allow everything (*)',
|
||||
'config/*' => 'Allow config access (config/*)',
|
||||
/*
|
||||
// [tg] seems excessive for me, hidden for rc1, tbd
|
||||
'config/application/*' => 'config/application/*',
|
||||
'config/application/general' => 'config/application/general',
|
||||
'config/application/resources' => 'config/application/resources',
|
||||
'config/application/userbackend' => 'config/application/userbackend',
|
||||
'config/application/usergroupbackend' => 'config/application/usergroupbackend',
|
||||
'config/authentication/*' => 'config/authentication/*',
|
||||
'config/authentication/users/*' => 'config/authentication/users/*',
|
||||
'config/authentication/users/show' => 'config/authentication/users/show',
|
||||
'config/authentication/users/add' => 'config/authentication/users/add',
|
||||
'config/authentication/users/edit' => 'config/authentication/users/edit',
|
||||
'config/authentication/users/remove' => 'config/authentication/users/remove',
|
||||
'config/authentication/groups/*' => 'config/authentication/groups/*',
|
||||
'config/authentication/groups/show' => 'config/authentication/groups/show',
|
||||
'config/authentication/groups/add' => 'config/authentication/groups/add',
|
||||
'config/authentication/groups/edit' => 'config/authentication/groups/edit',
|
||||
'config/authentication/groups/remove' => 'config/authentication/groups/remove',
|
||||
'config/authentication/roles/*' => 'config/authentication/roles/*',
|
||||
'config/authentication/roles/show' => 'config/authentication/roles/show',
|
||||
'config/authentication/roles/add' => 'config/authentication/roles/add',
|
||||
'config/authentication/roles/edit' => 'config/authentication/roles/edit',
|
||||
'config/authentication/roles/remove' => 'config/authentication/roles/remove',
|
||||
'config/modules' => 'config/modules'
|
||||
*/
|
||||
);
|
||||
protected $providedPermissions;
|
||||
|
||||
/**
|
||||
* Provided restrictions by currently loaded modules
|
||||
@ -63,6 +35,40 @@ class RoleForm extends ConfigForm
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->providedPermissions = array(
|
||||
'*' => $this->translate('Allow everything') . ' (*)',
|
||||
'application/stacktraces' => $this->translate(
|
||||
'Allow to adjust in the preferences whether to show stacktraces'
|
||||
) . ' (application/stacktraces)',
|
||||
'config/*' => $this->translate('Allow config access') . ' (config/*)',
|
||||
/*
|
||||
// [tg] seems excessive for me, hidden for rc1, tbd
|
||||
'config/application/*' => 'config/application/*',
|
||||
'config/application/general' => 'config/application/general',
|
||||
'config/application/resources' => 'config/application/resources',
|
||||
'config/application/userbackend' => 'config/application/userbackend',
|
||||
'config/application/usergroupbackend' => 'config/application/usergroupbackend',
|
||||
'config/authentication/*' => 'config/authentication/*',
|
||||
'config/authentication/users/*' => 'config/authentication/users/*',
|
||||
'config/authentication/users/show' => 'config/authentication/users/show',
|
||||
'config/authentication/users/add' => 'config/authentication/users/add',
|
||||
'config/authentication/users/edit' => 'config/authentication/users/edit',
|
||||
'config/authentication/users/remove' => 'config/authentication/users/remove',
|
||||
'config/authentication/groups/*' => 'config/authentication/groups/*',
|
||||
'config/authentication/groups/show' => 'config/authentication/groups/show',
|
||||
'config/authentication/groups/add' => 'config/authentication/groups/add',
|
||||
'config/authentication/groups/edit' => 'config/authentication/groups/edit',
|
||||
'config/authentication/groups/remove' => 'config/authentication/groups/remove',
|
||||
'config/authentication/roles/*' => 'config/authentication/roles/*',
|
||||
'config/authentication/roles/show' => 'config/authentication/roles/show',
|
||||
'config/authentication/roles/add' => 'config/authentication/roles/add',
|
||||
'config/authentication/roles/edit' => 'config/authentication/roles/edit',
|
||||
'config/authentication/roles/remove' => 'config/authentication/roles/remove',
|
||||
'config/modules' => 'config/modules'
|
||||
*/
|
||||
);
|
||||
|
||||
|
||||
$helper = new Zend_Form_Element('bogus');
|
||||
$mm = Icinga::app()->getModuleManager();
|
||||
foreach ($mm->listInstalledModules() as $moduleName) {
|
||||
|
@ -5,7 +5,7 @@ use Icinga\Web\Notification;
|
||||
use Icinga\Authentication\Auth;
|
||||
|
||||
$moduleName = $this->layout()->moduleName;
|
||||
if ($moduleName) {
|
||||
if ($moduleName !== 'default') {
|
||||
$moduleClass = ' icinga-module module-' . $moduleName;
|
||||
} else {
|
||||
$moduleClass = '';
|
||||
|
@ -4,7 +4,7 @@ use Icinga\Web\StyleSheet;
|
||||
|
||||
|
||||
$moduleName = $this->layout()->moduleName;
|
||||
if ($moduleName) {
|
||||
if ($moduleName !== 'default') {
|
||||
$moduleClass = ' icinga-module module-' . $moduleName;
|
||||
} else {
|
||||
$moduleClass = '';
|
||||
|
@ -16,9 +16,9 @@
|
||||
<?php if ($module->enabled && $module->loaded) {
|
||||
echo $this->icon('thumbs-up', sprintf($this->translate('Module %s is enabled'), $module->name));
|
||||
} elseif (! $module->enabled) {
|
||||
echo $this->icon('thumbs-down', sprintf($this->translate('Module %s is disabled'), $module->name));
|
||||
echo $this->icon('block', sprintf($this->translate('Module %s is disabled'), $module->name));
|
||||
} else { // ! $module->loaded
|
||||
echo $this->icon('thumbs-down', sprintf($this->translate('Module %s has failed to load'), $module->name));
|
||||
echo $this->icon('block', sprintf($this->translate('Module %s has failed to load'), $module->name));
|
||||
}
|
||||
|
||||
echo $this->qlink(
|
||||
|
@ -11,15 +11,38 @@
|
||||
<th style="width: 5em"><?= $this->translate('Remove'); ?></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->resources as $name): ?>
|
||||
<?php foreach ($this->resources as $name => $value): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
switch ($value->type) {
|
||||
case 'db':
|
||||
$icon = 'database';
|
||||
break;
|
||||
case 'ldap':
|
||||
$icon = 'sitemap';
|
||||
break;
|
||||
case 'livestatus':
|
||||
$icon = 'flash';
|
||||
break;
|
||||
case 'ssh':
|
||||
$icon = 'user';
|
||||
break;
|
||||
case 'file':
|
||||
case 'ini':
|
||||
$icon = 'doc-text';
|
||||
break;
|
||||
default:
|
||||
$icon = 'edit';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
<?= $this->qlink(
|
||||
$name,
|
||||
'config/editresource',
|
||||
array('resource' => $name),
|
||||
array(
|
||||
'icon' => 'edit',
|
||||
'icon' => $icon,
|
||||
'title' => sprintf($this->translate('Edit resource %s'), $name)
|
||||
)
|
||||
); ?>
|
||||
|
@ -6,8 +6,12 @@
|
||||
<th style="width: 5em"><?= $this->translate('Order'); ?></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $backendNames = $form->getBackendOrder(); ?>
|
||||
<?php for ($i = 0; $i < count($backendNames); $i++): ?>
|
||||
<?php
|
||||
$backendNames = $form->getBackendOrder();
|
||||
$backendConfigs = $form->getConfig();
|
||||
for ($i = 0; $i < count($backendNames); $i++):
|
||||
$type = $backendConfigs->getSection($backendNames[$i])->get('backend');
|
||||
?>
|
||||
<tr>
|
||||
<td class="action">
|
||||
<?= $this->qlink(
|
||||
@ -15,7 +19,8 @@
|
||||
'config/edituserbackend',
|
||||
array('backend' => $backendNames[$i]),
|
||||
array(
|
||||
'icon' => 'edit',
|
||||
'icon' => $type === 'external' ?
|
||||
'magic' : ($type === 'ldap' || $type === 'msldap' ? 'sitemap' : 'database'),
|
||||
'class' => 'rowaction',
|
||||
'title' => sprintf($this->translate('rEdit user backend %s'), $backendNames[$i])
|
||||
)
|
||||
@ -34,7 +39,7 @@
|
||||
</td>
|
||||
<td data-base-target="_self">
|
||||
<?php if ($i > 0): ?>
|
||||
<button type="submit" name="backend_newpos" class="link-like icon-only" value="<?= sprintf(
|
||||
<button type="submit" name="backend_newpos" class="link-like icon-only animated move-up" value="<?= sprintf(
|
||||
'%s|%s',
|
||||
$backendNames[$i],
|
||||
$i - 1
|
||||
@ -48,7 +53,7 @@
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if ($i + 1 < count($backendNames)): ?>
|
||||
<button type="submit" name="backend_newpos" class="link-like icon-only" value="<?= sprintf(
|
||||
<button type="submit" name="backend_newpos" class="link-like icon-only animated move-down" value="<?= sprintf(
|
||||
'%s|%s',
|
||||
$backendNames[$i],
|
||||
$i + 1
|
||||
|
@ -19,14 +19,19 @@
|
||||
<tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($backendNames as $backendName): ?>
|
||||
<?php foreach ($backendNames as $backendName => $config):
|
||||
$type = $config->get('backend');
|
||||
?>
|
||||
<tr>
|
||||
<td class="backend-name">
|
||||
<?= $this->qlink(
|
||||
$backendName,
|
||||
'usergroupbackend/edit',
|
||||
array('backend' => $backendName),
|
||||
array('title' => sprintf($this->translate('Edit user group backend %s'), $backendName))
|
||||
array(
|
||||
'icon' => $type === 'external' ? 'magic' : ($type === 'ldap' || $type === 'msldap' ? 'sitemap' : 'database'),
|
||||
'title' => sprintf($this->translate('Edit user group backend %s'), $backendName)
|
||||
)
|
||||
); ?>
|
||||
</td>
|
||||
<td class="backend-remove"><?= $this->qlink(
|
||||
|
@ -62,14 +62,14 @@ with Icinga Web 2 (e.g. an alias) no matter what the primary user id might actua
|
||||
|
||||
Directive | Description
|
||||
------------------------|------------
|
||||
**backend** | `ad`
|
||||
**backend** | `msldap`
|
||||
**resource** | The name of the LDAP resource defined in [resources.ini](resources.md#resources).
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
[auth_ad]
|
||||
backend = ad
|
||||
backend = msldap
|
||||
resource = my_ad
|
||||
```
|
||||
|
||||
|
@ -4,10 +4,9 @@
|
||||
namespace Icinga\Application\Modules;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Web\Controller\Dispatcher;
|
||||
use Zend_Controller_Router_Route as Route;
|
||||
use Zend_Controller_Router_Route;
|
||||
use Zend_Controller_Router_Route_Abstract;
|
||||
use Zend_Controller_Router_Route_Regex as RegexRoute;
|
||||
use Zend_Controller_Router_Route_Regex;
|
||||
use Icinga\Application\ApplicationBootstrap;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
@ -18,6 +17,7 @@ use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Module\Setup\SetupWizard;
|
||||
use Icinga\Util\File;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Web\Controller\Dispatcher;
|
||||
use Icinga\Web\Hook;
|
||||
use Icinga\Web\Menu;
|
||||
use Icinga\Web\Widget;
|
||||
@ -189,7 +189,7 @@ class Module
|
||||
/**
|
||||
* A set of menu elements
|
||||
*
|
||||
* @var array
|
||||
* @var Menu[]
|
||||
*/
|
||||
protected $menuItems = array();
|
||||
|
||||
@ -771,6 +771,7 @@ class Module
|
||||
{
|
||||
$this->launchConfigScript();
|
||||
$tabs = Widget::create('tabs');
|
||||
/** @var \Icinga\Web\Widget\Tabs $tabs */
|
||||
$tabs->add('info', array(
|
||||
'url' => 'config/module',
|
||||
'urlParams' => array('name' => $this->getName()),
|
||||
@ -1045,12 +1046,13 @@ class Module
|
||||
protected function registerRoutes()
|
||||
{
|
||||
$router = $this->app->getFrontController()->getRouter();
|
||||
/** @var \Zend_Controller_Router_Rewrite $router */
|
||||
foreach ($this->routes as $name => $route) {
|
||||
$router->addRoute($name, $route);
|
||||
}
|
||||
$router->addRoute(
|
||||
$this->name . '_jsprovider',
|
||||
new Route(
|
||||
new Zend_Controller_Router_Route(
|
||||
'js/' . $this->name . '/:file',
|
||||
array(
|
||||
'controller' => 'static',
|
||||
@ -1061,7 +1063,7 @@ class Module
|
||||
);
|
||||
$router->addRoute(
|
||||
$this->name . '_img',
|
||||
new RegexRoute(
|
||||
new Zend_Controller_Router_Route_Regex(
|
||||
'img/' . $this->name . '/(.+)',
|
||||
array(
|
||||
'controller' => 'static',
|
||||
|
@ -214,9 +214,19 @@ class Web extends EmbeddedWeb
|
||||
$this->frontController->setDispatcher(new Dispatcher());
|
||||
$this->frontController->setRequest($this->getRequest());
|
||||
$this->frontController->setControllerDirectory($this->getApplicationDir('/controllers'));
|
||||
|
||||
$displayExceptions = $this->config->get('global', 'show_stacktraces', true);
|
||||
if ($this->user !== null && $this->user->can('application/stacktraces')) {
|
||||
$displayExceptions = $this->user->getPreferences()->getValue(
|
||||
'icingaweb',
|
||||
'show_stacktraces',
|
||||
$displayExceptions
|
||||
);
|
||||
}
|
||||
|
||||
$this->frontController->setParams(
|
||||
array(
|
||||
'displayExceptions' => true
|
||||
'displayExceptions' => $displayExceptions
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
|
@ -61,7 +61,14 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns = array('user');
|
||||
protected $blacklistedQueryColumns = array('user');
|
||||
|
||||
/**
|
||||
* The search columns being provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchColumns = array('user');
|
||||
|
||||
/**
|
||||
* The default sort rules to be applied on a query
|
||||
@ -98,6 +105,23 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's filter columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeFilterColumns()
|
||||
{
|
||||
$userLabel = t('Username') . ' ' . t('(Case insensitive)');
|
||||
return array(
|
||||
$userLabel => 'user',
|
||||
t('Username') => 'user_name',
|
||||
t('Active') => 'is_active',
|
||||
t('Created At') => 'created_at',
|
||||
t('Last Modified') => 'last_modified'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a table row with the given data
|
||||
*
|
||||
|
@ -50,7 +50,14 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns = array('user');
|
||||
protected $blacklistedQueryColumns = array('user');
|
||||
|
||||
/**
|
||||
* The search columns being provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchColumns = array('user');
|
||||
|
||||
/**
|
||||
* The default sort rules to be applied on a query
|
||||
@ -243,6 +250,21 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's filter columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeFilterColumns()
|
||||
{
|
||||
return array(
|
||||
t('Username') => 'user_name',
|
||||
t('Active') => 'is_active',
|
||||
t('Created At') => 'created_at',
|
||||
t('Last Modified') => 'last_modified'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's conversion rules
|
||||
*
|
||||
|
@ -71,7 +71,14 @@ class DbUserGroupBackend extends DbRepository implements UserGroupBackendInterfa
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns = array('group', 'user');
|
||||
protected $blacklistedQueryColumns = array('group', 'user');
|
||||
|
||||
/**
|
||||
* The search columns being provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchColumns = array('group', 'user');
|
||||
|
||||
/**
|
||||
* The value conversion rules to apply on a query or statement
|
||||
@ -97,6 +104,26 @@ class DbUserGroupBackend extends DbRepository implements UserGroupBackendInterfa
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's filter columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeFilterColumns()
|
||||
{
|
||||
$userLabel = t('Username') . ' ' . t('(Case insensitive)');
|
||||
$groupLabel = t('User Group') . ' ' . t('(Case insensitive)');
|
||||
return array(
|
||||
$userLabel => 'user',
|
||||
t('Username') => 'user_name',
|
||||
$groupLabel => 'group',
|
||||
t('User Group') => 'group_name',
|
||||
t('Parent') => 'parent',
|
||||
t('Created At') => 'created_at',
|
||||
t('Last Modified') => 'last_modified'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a table row with the given data
|
||||
*
|
||||
|
@ -32,7 +32,14 @@ class IniUserGroupBackend extends IniRepository implements UserGroupBackendInter
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns = array('group');
|
||||
protected $blacklistedQueryColumns = array('group');
|
||||
|
||||
/**
|
||||
* The search columns being provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchColumns = array('group');
|
||||
|
||||
/**
|
||||
* The value conversion rules to apply on a query or statement
|
||||
@ -55,6 +62,21 @@ class IniUserGroupBackend extends IniRepository implements UserGroupBackendInter
|
||||
$this->ds->getConfigObject()->setKeyColumn('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's filter columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeFilterColumns()
|
||||
{
|
||||
return array(
|
||||
t('User Group') => 'group',
|
||||
t('Parent') => 'parent',
|
||||
t('Created At') => 'created_at',
|
||||
t('Last Modified') => 'last_modified'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new group to this backend
|
||||
*
|
||||
|
@ -83,7 +83,14 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns = array('group', 'user');
|
||||
protected $blacklistedQueryColumns = array('group', 'user');
|
||||
|
||||
/**
|
||||
* The search columns being provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchColumns = array('group', 'user');
|
||||
|
||||
/**
|
||||
* The default sort rules to be applied on a query
|
||||
@ -457,6 +464,21 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
||||
return array('group' => $columns, 'group_membership' => $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's filter columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeFilterColumns()
|
||||
{
|
||||
return array(
|
||||
t('Username') => 'user',
|
||||
t('User Group') => 'group_name',
|
||||
t('Created At') => 'created_at',
|
||||
t('Last Modified') => 'last_modified'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this repository's conversion rules
|
||||
*
|
||||
|
@ -273,30 +273,10 @@ class Loader
|
||||
|
||||
protected function searchMatch($needle, $haystack)
|
||||
{
|
||||
$stack = $haystack;
|
||||
$search = $needle;
|
||||
$this->lastSuggestions = array();
|
||||
while (strlen($search) > 0) {
|
||||
$len = strlen($search);
|
||||
foreach ($stack as & $s) {
|
||||
$s = substr($s, 0, $len);
|
||||
}
|
||||
|
||||
$res = array_keys($stack, $search, true);
|
||||
if (count($res) === 1) {
|
||||
$found = $haystack[$res[0]];
|
||||
if (substr($found, 0, strlen($needle)) === $needle) {
|
||||
return $found;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} elseif (count($res) > 1) {
|
||||
foreach ($res as $key) {
|
||||
$this->lastSuggestions[] = $haystack[$key];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$search = substr($search, 0, -1);
|
||||
$this->lastSuggestions = preg_grep(sprintf('/^%s.*$/', preg_quote($needle, '/')), $haystack);
|
||||
$match = array_search($needle, $haystack, true);
|
||||
if (false !== $match) {
|
||||
return $haystack[$match];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
21
library/Icinga/Data/FilterColumns.php
Normal file
21
library/Icinga/Data/FilterColumns.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Data;
|
||||
|
||||
interface FilterColumns
|
||||
{
|
||||
/**
|
||||
* Return a filterable's filter columns with their optional label as key
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFilterColumns();
|
||||
|
||||
/**
|
||||
* Return a filterable's search columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSearchColumns();
|
||||
}
|
@ -4,12 +4,11 @@
|
||||
namespace Icinga\Data;
|
||||
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\SimpleQuery;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Web\Paginator\Adapter\QueryAdapter;
|
||||
use Zend_Paginator;
|
||||
|
||||
class PivotTable
|
||||
class PivotTable implements Sortable
|
||||
{
|
||||
/**
|
||||
* The query to fetch as pivot table
|
||||
@ -19,53 +18,74 @@ class PivotTable
|
||||
protected $baseQuery;
|
||||
|
||||
/**
|
||||
* The query to fetch the x axis labels
|
||||
*
|
||||
* @var SimpleQuery
|
||||
*/
|
||||
protected $xAxisQuery;
|
||||
|
||||
/**
|
||||
* The query to fetch the y axis labels
|
||||
*
|
||||
* @var SimpleQuery
|
||||
*/
|
||||
protected $yAxisQuery;
|
||||
|
||||
/**
|
||||
* The column that contains the labels for the x axis
|
||||
* X-axis pivot column
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $xAxisColumn;
|
||||
|
||||
/**
|
||||
* The column that contains the labels for the y axis
|
||||
* Y-axis pivot column
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $yAxisColumn;
|
||||
|
||||
/**
|
||||
* The filter being applied on the query for the x axis
|
||||
* Column for sorting the result set
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $order = array();
|
||||
|
||||
/**
|
||||
* The filter being applied on the query for the x-axis
|
||||
*
|
||||
* @var Filter
|
||||
*/
|
||||
protected $xAxisFilter;
|
||||
|
||||
/**
|
||||
* The filter being applied on the query for the y axis
|
||||
* The filter being applied on the query for the y-axis
|
||||
*
|
||||
* @var Filter
|
||||
*/
|
||||
protected $yAxisFilter;
|
||||
|
||||
/**
|
||||
* The query to fetch the leading x-axis rows and their headers
|
||||
*
|
||||
* @var SimpleQuery
|
||||
*/
|
||||
protected $xAxisQuery;
|
||||
|
||||
/**
|
||||
* The query to fetch the leading y-axis rows and their headers
|
||||
*
|
||||
* @var SimpleQuery
|
||||
*/
|
||||
protected $yAxisQuery;
|
||||
|
||||
/**
|
||||
* X-axis header column
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $xAxisHeader;
|
||||
|
||||
/**
|
||||
* Y-axis header column
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $yAxisHeader;
|
||||
|
||||
/**
|
||||
* Create a new pivot table
|
||||
*
|
||||
* @param SimpleQuery $query The query to fetch as pivot table
|
||||
* @param string $xAxisColumn The column that contains the labels for the x axis
|
||||
* @param string $yAxisColumn The column that contains the labels for the y axis
|
||||
* @param SimpleQuery $query The query to fetch as pivot table
|
||||
* @param string $xAxisColumn X-axis pivot column
|
||||
* @param string $yAxisColumn Y-axis pivot column
|
||||
*/
|
||||
public function __construct(SimpleQuery $query, $xAxisColumn, $yAxisColumn)
|
||||
{
|
||||
@ -75,7 +95,32 @@ class PivotTable
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter to apply on the query for the x axis
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasOrder()
|
||||
{
|
||||
return ! empty($this->order);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function order($field, $direction = null)
|
||||
{
|
||||
$this->order[$field] = $direction;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter to apply on the query for the x-axis
|
||||
*
|
||||
* @param Filter $filter
|
||||
*
|
||||
@ -88,7 +133,7 @@ class PivotTable
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter to apply on the query for the y axis
|
||||
* Set the filter to apply on the query for the y-axis
|
||||
*
|
||||
* @param Filter $filter
|
||||
*
|
||||
@ -100,6 +145,56 @@ class PivotTable
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the x-axis header
|
||||
*
|
||||
* Defaults to {@link $xAxisColumn} in case no x-axis header has been set using {@link setXAxisHeader()}
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getXAxisHeader()
|
||||
{
|
||||
return $this->xAxisHeader !== null ? $this->xAxisHeader : $this->xAxisColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the x-axis header
|
||||
*
|
||||
* @param string $xAxisHeader
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setXAxisHeader($xAxisHeader)
|
||||
{
|
||||
$this->xAxisHeader = (string) $xAxisHeader;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the y-axis header
|
||||
*
|
||||
* Defaults to {@link $yAxisColumn} in case no x-axis header has been set using {@link setYAxisHeader()}
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getYAxisHeader()
|
||||
{
|
||||
return $this->yAxisHeader !== null ? $this->yAxisHeader : $this->yAxisColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the y-axis header
|
||||
*
|
||||
* @param string $yAxisHeader
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setYAxisHeader($yAxisHeader)
|
||||
{
|
||||
$this->yAxisHeader = (string) $yAxisHeader;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value for the given request parameter
|
||||
*
|
||||
@ -107,7 +202,7 @@ class PivotTable
|
||||
* @param string $param The parameter name to return
|
||||
* @param int $default The default value to return
|
||||
*
|
||||
* @return int
|
||||
* @return int
|
||||
*/
|
||||
protected function getPaginationParameter($axis, $param, $default = null)
|
||||
{
|
||||
@ -125,23 +220,25 @@ class PivotTable
|
||||
/**
|
||||
* Query horizontal (x) axis
|
||||
*
|
||||
* @return SimpleQuery
|
||||
* @return SimpleQuery
|
||||
*/
|
||||
protected function queryXAxis()
|
||||
{
|
||||
if ($this->xAxisQuery === null) {
|
||||
$this->xAxisQuery = clone $this->baseQuery;
|
||||
$this->xAxisQuery->group($this->xAxisColumn);
|
||||
$this->xAxisQuery->columns(array($this->xAxisColumn));
|
||||
$this->xAxisQuery->setUseSubqueryCount();
|
||||
$xAxisHeader = $this->getXAxisHeader();
|
||||
$columns = array($this->xAxisColumn, $xAxisHeader);
|
||||
$this->xAxisQuery->group(array_unique($columns)); // xAxisColumn and header may be the same column
|
||||
$this->xAxisQuery->columns($columns);
|
||||
|
||||
if ($this->xAxisFilter !== null) {
|
||||
$this->xAxisQuery->addFilter($this->xAxisFilter);
|
||||
}
|
||||
|
||||
if (! $this->xAxisQuery->hasOrder($this->xAxisColumn)) {
|
||||
$this->xAxisQuery->order($this->xAxisColumn, 'asc');
|
||||
}
|
||||
$this->xAxisQuery->order(
|
||||
$xAxisHeader,
|
||||
isset($this->order[$xAxisHeader]) ? $this->order[$xAxisHeader] : self::SORT_ASC
|
||||
);
|
||||
}
|
||||
|
||||
return $this->xAxisQuery;
|
||||
@ -150,30 +247,31 @@ class PivotTable
|
||||
/**
|
||||
* Query vertical (y) axis
|
||||
*
|
||||
* @return SimpleQuery
|
||||
* @return SimpleQuery
|
||||
*/
|
||||
protected function queryYAxis()
|
||||
{
|
||||
if ($this->yAxisQuery === null) {
|
||||
$this->yAxisQuery = clone $this->baseQuery;
|
||||
$this->yAxisQuery->group($this->yAxisColumn);
|
||||
$this->yAxisQuery->columns(array($this->yAxisColumn));
|
||||
$this->yAxisQuery->setUseSubqueryCount();
|
||||
$yAxisHeader = $this->getYAxisHeader();
|
||||
$columns = array($this->yAxisColumn, $yAxisHeader);
|
||||
$this->yAxisQuery->group(array_unique($columns)); // yAxisColumn and header may be the same column
|
||||
$this->yAxisQuery->columns($columns);
|
||||
|
||||
if ($this->yAxisFilter !== null) {
|
||||
$this->yAxisQuery->addFilter($this->yAxisFilter);
|
||||
}
|
||||
|
||||
if (! $this->yAxisQuery->hasOrder($this->yAxisColumn)) {
|
||||
$this->yAxisQuery->order($this->yAxisColumn, 'asc');
|
||||
}
|
||||
$this->yAxisQuery->order(
|
||||
$yAxisHeader,
|
||||
isset($this->order[$yAxisHeader]) ? $this->order[$yAxisHeader] : self::SORT_ASC
|
||||
);
|
||||
}
|
||||
|
||||
return $this->yAxisQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pagination adapter for the x axis query
|
||||
* Return a pagination adapter for the x-axis query
|
||||
*
|
||||
* $limit and $page are taken from the current request if not given.
|
||||
*
|
||||
@ -204,7 +302,7 @@ class PivotTable
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pagination adapter for the y axis query
|
||||
* Return a pagination adapter for the y-axis query
|
||||
*
|
||||
* $limit and $page are taken from the current request if not given.
|
||||
*
|
||||
@ -235,9 +333,9 @@ class PivotTable
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pivot table as array
|
||||
* Return the pivot table as an array of pivot data and pivot header
|
||||
*
|
||||
* @return array
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
@ -245,33 +343,39 @@ class PivotTable
|
||||
($this->xAxisFilter === null && $this->yAxisFilter === null)
|
||||
|| ($this->xAxisFilter !== null && $this->yAxisFilter !== null)
|
||||
) {
|
||||
$xAxis = $this->queryXAxis()->fetchColumn();
|
||||
$yAxis = $this->queryYAxis()->fetchColumn();
|
||||
$xAxis = $this->queryXAxis()->fetchPairs();
|
||||
$yAxis = $this->queryYAxis()->fetchPairs();
|
||||
} else {
|
||||
if ($this->xAxisFilter !== null) {
|
||||
$xAxis = $this->queryXAxis()->fetchColumn();
|
||||
$yAxis = $this->queryYAxis()->where($this->xAxisColumn, $xAxis)->fetchColumn();
|
||||
$xAxis = $this->queryXAxis()->fetchPairs();
|
||||
$yAxis = $this->queryYAxis()->where($this->xAxisColumn, $xAxis)->fetchPairs();
|
||||
} else { // $this->yAxisFilter !== null
|
||||
$yAxis = $this->queryYAxis()->fetchColumn();
|
||||
$xAxis = $this->queryXAxis()->where($this->yAxisColumn, $yAxis)->fetchColumn();
|
||||
$yAxis = $this->queryYAxis()->fetchPairs();
|
||||
$xAxis = $this->queryXAxis()->where($this->yAxisColumn, $yAxis)->fetchPairs();
|
||||
}
|
||||
}
|
||||
$pivotData = array();
|
||||
$pivotHeader = array(
|
||||
'cols' => $xAxis,
|
||||
'rows' => $yAxis
|
||||
);
|
||||
if (! empty($xAxis) && ! empty($yAxis)) {
|
||||
$xAxisKeys = array_keys($xAxis);
|
||||
$yAxisKeys = array_keys($yAxis);
|
||||
$this->baseQuery
|
||||
->where($this->xAxisColumn, $xAxisKeys)
|
||||
->where($this->yAxisColumn, $yAxisKeys);
|
||||
|
||||
$pivot = array();
|
||||
if (!empty($xAxis) && !empty($yAxis)) {
|
||||
$this->baseQuery->where($this->xAxisColumn, $xAxis)->where($this->yAxisColumn, $yAxis);
|
||||
|
||||
foreach ($yAxis as $yLabel) {
|
||||
foreach ($xAxis as $xLabel) {
|
||||
$pivot[$yLabel][$xLabel] = null;
|
||||
foreach ($yAxisKeys as $yAxisKey) {
|
||||
foreach ($xAxisKeys as $xAxisKey) {
|
||||
$pivotData[$yAxisKey][$xAxisKey] = null;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->baseQuery as $row) {
|
||||
$pivot[$row->{$this->yAxisColumn}][$row->{$this->xAxisColumn}] = $row;
|
||||
$pivotData[$row->{$this->yAxisColumn}][$row->{$this->xAxisColumn}] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
return $pivot;
|
||||
return array($pivotData, $pivotHeader);
|
||||
}
|
||||
}
|
||||
|
@ -122,13 +122,6 @@ class LdapConnection implements Selectable, Inspectable
|
||||
*/
|
||||
protected $rootDn;
|
||||
|
||||
/**
|
||||
* Whether to load the configuration for strict certificate validation or the one for non-strict validation
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $validateCertificate;
|
||||
|
||||
/**
|
||||
* Whether the bind on this connection has already been performed
|
||||
*
|
||||
@ -176,7 +169,6 @@ class LdapConnection implements Selectable, Inspectable
|
||||
$this->bindPw = $config->bind_pw;
|
||||
$this->rootDn = $config->root_dn;
|
||||
$this->port = $config->get('port', 389);
|
||||
$this->validateCertificate = (bool) $config->get('reqcert', true);
|
||||
|
||||
$this->encryption = $config->encryption;
|
||||
if ($this->encryption !== null) {
|
||||
@ -957,16 +949,9 @@ class LdapConnection implements Selectable, Inspectable
|
||||
$info = new Inspection('');
|
||||
}
|
||||
|
||||
if ($this->encryption === static::STARTTLS || $this->encryption === static::LDAPS) {
|
||||
$this->prepareTlsEnvironment();
|
||||
}
|
||||
|
||||
$hostname = $this->hostname;
|
||||
if ($this->encryption === static::LDAPS) {
|
||||
$info->write('Connect using LDAPS');
|
||||
if (! $this->validateCertificate) {
|
||||
$info->write('Skip certificate validation');
|
||||
}
|
||||
$hostname = 'ldaps://' . $hostname;
|
||||
}
|
||||
|
||||
@ -983,9 +968,6 @@ class LdapConnection implements Selectable, Inspectable
|
||||
if ($this->encryption === static::STARTTLS) {
|
||||
$this->encrypted = true;
|
||||
$info->write('Connect using STARTTLS');
|
||||
if (! $this->validateCertificate) {
|
||||
$info->write('Skip certificate validation');
|
||||
}
|
||||
if (! ldap_start_tls($ds)) {
|
||||
throw new LdapException('LDAP STARTTLS failed: %s', ldap_error($ds));
|
||||
}
|
||||
@ -998,30 +980,6 @@ class LdapConnection implements Selectable, Inspectable
|
||||
return $ds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up how to handle StartTLS connections
|
||||
*
|
||||
* @throws LdapException In case the LDAPRC environment variable cannot be set
|
||||
*/
|
||||
protected function prepareTlsEnvironment()
|
||||
{
|
||||
// TODO: allow variable known CA location (system VS Icinga)
|
||||
if (Platform::isWindows()) {
|
||||
putenv('LDAPTLS_REQCERT=never');
|
||||
} else {
|
||||
if ($this->validateCertificate) {
|
||||
$ldap_conf = $this->getConfigDir('ldap_ca.conf');
|
||||
} else {
|
||||
$ldap_conf = $this->getConfigDir('ldap_nocert.conf');
|
||||
}
|
||||
|
||||
putenv('LDAPRC=' . $ldap_conf); // TODO: Does not have any effect
|
||||
if (getenv('LDAPRC') !== $ldap_conf) {
|
||||
throw new LdapException('putenv failed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an LDAP entry
|
||||
*
|
||||
@ -1103,6 +1061,13 @@ class LdapConnection implements Selectable, Inspectable
|
||||
try {
|
||||
$ds = $this->prepareNewConnection($insp);
|
||||
} catch (Exception $e) {
|
||||
if ($this->encryption === 'starttls') {
|
||||
// The Exception does not return any proper error messages in case of certificate errors. Connecting
|
||||
// by STARTTLS will usually fail at this point when the certificate is unknown,
|
||||
// so at least try to give some hints.
|
||||
$insp->write('NOTE: There might be an issue with the chosen encryption. Ensure that the LDAP-Server ' .
|
||||
'supports STARTTLS and that the LDAP-Client is configured to accept its certificate.');
|
||||
}
|
||||
return $insp->error($e->getMessage());
|
||||
}
|
||||
|
||||
@ -1116,6 +1081,13 @@ class LdapConnection implements Selectable, Inspectable
|
||||
'***' /* $this->bindPw */
|
||||
);
|
||||
if (! $success) {
|
||||
// ldap_error does not return any proper error messages in case of certificate errors. Connecting
|
||||
// by LDAPS will usually fail at this point when the certificate is unknown, so at least try to give
|
||||
// some hints.
|
||||
if ($this->encryption === 'ldaps') {
|
||||
$insp->write('NOTE: There might be an issue with the chosen encryption. Ensure that the LDAP-Server ' .
|
||||
' supports LDAPS and that the LDAP-Client is configured to accept its certificate.');
|
||||
}
|
||||
return $insp->error(sprintf('%s failed: %s', $msg, ldap_error($ds)));
|
||||
}
|
||||
$insp->write(sprintf($msg . ' successful'));
|
||||
@ -1137,12 +1109,4 @@ class LdapConnection implements Selectable, Inspectable
|
||||
}
|
||||
return $insp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the environment variables set by self::prepareTlsEnvironment()
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
putenv('LDAPRC');
|
||||
}
|
||||
}
|
||||
|
@ -64,19 +64,43 @@ abstract class Repository implements Selectable
|
||||
* 'alias2' => 'column3'
|
||||
* )
|
||||
* )
|
||||
* <pre><code>
|
||||
* </code></pre>
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $queryColumns;
|
||||
|
||||
/**
|
||||
* The columns (or aliases) which are not permitted to be queried. (by design)
|
||||
* The columns (or aliases) which are not permitted to be queried
|
||||
*
|
||||
* Blacklisted query columns can still occur in a filter expression or sort rule.
|
||||
*
|
||||
* @var array An array of strings
|
||||
*/
|
||||
protected $blacklistedQueryColumns;
|
||||
|
||||
/**
|
||||
* The filter columns being provided
|
||||
*
|
||||
* This may be intialized by concrete repository implementations, in the following format
|
||||
* <pre><code>
|
||||
* array(
|
||||
* 'alias_or_column_name',
|
||||
* 'label_to_show_in_the_filter_editor' => 'alias_or_column_name'
|
||||
* )
|
||||
* </code></pre>
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filterColumns;
|
||||
|
||||
/**
|
||||
* The search columns (or aliases) being provided
|
||||
*
|
||||
* @var array An array of strings
|
||||
*/
|
||||
protected $searchColumns;
|
||||
|
||||
/**
|
||||
* The sort rules to be applied on a query
|
||||
*
|
||||
@ -98,7 +122,7 @@ abstract class Repository implements Selectable
|
||||
* // Ascendant sort by default
|
||||
* )
|
||||
* )
|
||||
* <pre><code>
|
||||
* </code></pre>
|
||||
* Note that it's mandatory to supply the alias name in case there is one.
|
||||
*
|
||||
* @var array
|
||||
@ -260,6 +284,33 @@ abstract class Repository implements Selectable
|
||||
/**
|
||||
* Return the columns (or aliases) which are not permitted to be queried
|
||||
*
|
||||
* Calls $this->initializeBlacklistedQueryColumns() in case $this->blacklistedQueryColumns is null.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getBlacklistedQueryColumns()
|
||||
{
|
||||
if ($this->blacklistedQueryColumns === null) {
|
||||
$this->blacklistedQueryColumns = $this->initializeBlacklistedQueryColumns();
|
||||
}
|
||||
|
||||
return $this->blacklistedQueryColumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite this in your repository implementation in case you
|
||||
* need to initialize the blacklisted query columns lazily
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeBlacklistedQueryColumns()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filter columns being provided
|
||||
*
|
||||
* Calls $this->initializeFilterColumns() in case $this->filterColumns is null.
|
||||
*
|
||||
* @return array
|
||||
@ -283,6 +334,32 @@ abstract class Repository implements Selectable
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the search columns being provided
|
||||
*
|
||||
* Calls $this->initializeSearchColumns() in case $this->searchColumns is null.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSearchColumns()
|
||||
{
|
||||
if ($this->searchColumns === null) {
|
||||
$this->searchColumns = $this->initializeSearchColumns();
|
||||
}
|
||||
|
||||
return $this->searchColumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite this in your repository implementation in case you need to initialize the search columns lazily
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initializeSearchColumns()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sort rules to be applied on a query
|
||||
*
|
||||
@ -781,10 +858,10 @@ abstract class Repository implements Selectable
|
||||
throw new ProgrammingError('Table name "%s" not found', $table);
|
||||
}
|
||||
|
||||
$filterColumns = $this->getFilterColumns();
|
||||
$blacklist = $this->getBlacklistedQueryColumns();
|
||||
$columns = array();
|
||||
foreach ($queryColumns[$table] as $alias => $column) {
|
||||
if (! in_array(is_string($alias) ? $alias : $column, $filterColumns)) {
|
||||
if (! in_array(is_string($alias) ? $alias : $column, $blacklist)) {
|
||||
$columns[$alias] = $column;
|
||||
}
|
||||
}
|
||||
@ -874,7 +951,8 @@ abstract class Repository implements Selectable
|
||||
return false;
|
||||
}
|
||||
|
||||
return !in_array($alias, $this->getFilterColumns()) && $this->validateQueryColumnAssociation($table, $name);
|
||||
return !in_array($alias, $this->getBlacklistedQueryColumns())
|
||||
&& $this->validateQueryColumnAssociation($table, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -898,8 +976,8 @@ abstract class Repository implements Selectable
|
||||
throw new QueryException(t('Query column "%s" not found'), $name);
|
||||
}
|
||||
|
||||
if (in_array($alias, $this->getFilterColumns())) {
|
||||
throw new QueryException(t('Filter column "%s" cannot be queried'), $name);
|
||||
if (in_array($alias, $this->getBlacklistedQueryColumns())) {
|
||||
throw new QueryException(t('Column "%s" cannot be queried'), $name);
|
||||
}
|
||||
|
||||
if (! $this->validateQueryColumnAssociation($table, $alias)) {
|
||||
@ -985,8 +1063,8 @@ abstract class Repository implements Selectable
|
||||
throw new StatementException('Statement column "%s" not found', $name);
|
||||
}
|
||||
|
||||
if (in_array($alias, $this->getFilterColumns())) {
|
||||
throw new StatementException('Filter column "%s" cannot be referenced in a statement', $name);
|
||||
if (in_array($alias, $this->getBlacklistedQueryColumns())) {
|
||||
throw new StatementException('Column "%s" cannot be referenced in a statement', $name);
|
||||
}
|
||||
|
||||
if (! $this->validateQueryColumnAssociation($table, $alias)) {
|
||||
|
@ -10,13 +10,14 @@ use Icinga\Application\Benchmark;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\QueryInterface;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\FilterColumns;
|
||||
use Icinga\Data\SortRules;
|
||||
use Icinga\Exception\QueryException;
|
||||
|
||||
/**
|
||||
* Query class supposed to mediate between a repository and its datasource's query
|
||||
*/
|
||||
class RepositoryQuery implements QueryInterface, SortRules, Iterator
|
||||
class RepositoryQuery implements QueryInterface, SortRules, FilterColumns, Iterator
|
||||
{
|
||||
/**
|
||||
* The repository being used
|
||||
@ -141,6 +142,26 @@ class RepositoryQuery implements QueryInterface, SortRules, Iterator
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this query's available filter columns with their optional label as key
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFilterColumns()
|
||||
{
|
||||
return $this->repository->getFilterColumns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this query's available search columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSearchColumns()
|
||||
{
|
||||
return $this->repository->getSearchColumns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter this query using the given column and value
|
||||
*
|
||||
|
@ -452,16 +452,19 @@ class User
|
||||
if (isset($this->permissions['*']) || isset($this->permissions[$requiredPermission])) {
|
||||
return true;
|
||||
}
|
||||
// If the permission to check contains a wildcard, grant the permission if any permit related to the permission
|
||||
// matches
|
||||
$any = strpos($requiredPermission, '*');
|
||||
|
||||
$requiredWildcard = strpos($requiredPermission, '*');
|
||||
foreach ($this->permissions as $grantedPermission) {
|
||||
if ($any !== false) {
|
||||
$wildcard = $any;
|
||||
if ($requiredWildcard !== false) {
|
||||
if (($grantedWildcard = strpos($grantedPermission, '*')) !== false) {
|
||||
$wildcard = min($requiredWildcard, $grantedWildcard);
|
||||
} else {
|
||||
$wildcard = $requiredWildcard;
|
||||
}
|
||||
} 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($requiredPermission, 0, $wildcard) === substr($grantedPermission, 0, $wildcard)) {
|
||||
return true;
|
||||
@ -470,6 +473,7 @@ class User
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
namespace Icinga\Util;
|
||||
|
||||
/**
|
||||
* Common string helper
|
||||
* Common string functions
|
||||
*/
|
||||
class String
|
||||
{
|
||||
@ -103,8 +103,8 @@ class String
|
||||
/**
|
||||
* Check if a string ends with a different string
|
||||
*
|
||||
* @param $haystack The string to search for matches
|
||||
* @param $needle The string to match at the start of the haystack
|
||||
* @param $haystack string The string to search for matches
|
||||
* @param $needle string The string to match at the start of the haystack
|
||||
*
|
||||
* @return bool Whether or not needle is at the beginning of haystack
|
||||
*/
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
namespace Icinga\Web;
|
||||
|
||||
use Icinga\Data\Filterable;
|
||||
use Icinga\Data\Sortable;
|
||||
use Icinga\Data\QueryInterface;
|
||||
use Icinga\Exception\Http\HttpNotFoundException;
|
||||
@ -140,16 +141,51 @@ class Controller extends ModuleActionController
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the view property `filterEditor' to the given FilterEditor
|
||||
* Create a FilterEditor widget and apply the user's chosen filter options on the given filterable
|
||||
*
|
||||
* In case the current view has been requested as compact this method does nothing.
|
||||
* The widget is set on the `filterEditor' view property only if the current view has not been requested as compact.
|
||||
* The optional $filterColumns parameter should be an array of key-value pairs where the key is the name of the
|
||||
* column and the value the label to show to the user. The optional $searchColumns parameter should be an array
|
||||
* of column names to be used to handle quick searches.
|
||||
*
|
||||
* @param Form $editor The FilterEditor
|
||||
* If the given filterable is an instance of Icinga\Data\FilterColumns, $filterable->getFilterColumns() and
|
||||
* $filterable->getSearchColumns() is called to provide the respective columns if $filterColumns or $searchColumns
|
||||
* is not given.
|
||||
*
|
||||
* @param Filterable $filterable The filterable to create a filter editor for
|
||||
* @param array $filterColumns The filter columns to offer to the user
|
||||
* @param array $searchColumns The search columns to utilize for quick searches
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @todo Preserving and ignoring parameters should be configurable (another two method params? property magic?)
|
||||
*/
|
||||
protected function setupFilterControl($editor)
|
||||
{
|
||||
protected function setupFilterControl(
|
||||
Filterable $filterable,
|
||||
array $filterColumns = null,
|
||||
array $searchColumns = null
|
||||
) {
|
||||
$editor = Widget::create('filterEditor')
|
||||
->setQuery($filterable)
|
||||
->preserveParams(
|
||||
'limit',
|
||||
'sort',
|
||||
'dir',
|
||||
'format',
|
||||
'view',
|
||||
'user',
|
||||
'group',
|
||||
'backend',
|
||||
'stateType',
|
||||
'addColumns',
|
||||
'problems',
|
||||
'_dev'
|
||||
)
|
||||
->ignoreParams('page')
|
||||
->setColumns($filterColumns)
|
||||
->setSearchColumns($searchColumns)
|
||||
->handleRequest($this->getRequest());
|
||||
|
||||
if (! $this->view->compact) {
|
||||
$this->view->filterEditor = $editor;
|
||||
}
|
||||
|
@ -38,6 +38,13 @@ class ActionController extends Zend_Controller_Action
|
||||
*/
|
||||
protected $requiresAuthentication = true;
|
||||
|
||||
/**
|
||||
* The current module's name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $moduleName;
|
||||
|
||||
private $autorefreshInterval;
|
||||
|
||||
private $reloadCss = false;
|
||||
@ -90,10 +97,11 @@ class ActionController extends Zend_Controller_Action
|
||||
$this->_helper = new ActionHelperBroker($this);
|
||||
|
||||
$this->handlerBrowserWindows();
|
||||
$this->view->translationDomain = 'icinga';
|
||||
$moduleName = $this->getModuleName();
|
||||
$this->view->translationDomain = $moduleName !== 'default' ? $moduleName : 'icinga';
|
||||
$this->_helper->layout()->isIframe = $request->getUrl()->shift('isIframe');
|
||||
$this->_helper->layout()->showFullscreen = $request->getUrl()->shift('showFullscreen');
|
||||
$this->_helper->layout()->moduleName = false;
|
||||
$this->_helper->layout()->moduleName = $moduleName;
|
||||
|
||||
$this->view->compact = $request->getParam('view') === 'compact';
|
||||
if ($request->getUrl()->shift('showCompact')) {
|
||||
@ -166,6 +174,20 @@ class ActionController extends Zend_Controller_Action
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current module's name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getModuleName()
|
||||
{
|
||||
if ($this->moduleName === null) {
|
||||
$this->moduleName = $this->getRequest()->getModuleName();
|
||||
}
|
||||
|
||||
return $this->moduleName;
|
||||
}
|
||||
|
||||
public function Config($file = null)
|
||||
{
|
||||
if ($file === null) {
|
||||
|
@ -6,6 +6,7 @@ namespace Icinga\Web\Controller;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Modules\Manager;
|
||||
use Icinga\Application\Modules\Module;
|
||||
|
||||
/**
|
||||
* Base class for module action controllers
|
||||
@ -18,25 +19,15 @@ class ModuleActionController extends ActionController
|
||||
|
||||
private $module;
|
||||
|
||||
/**
|
||||
* Module name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $moduleName;
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Controller\ActionController For the method documentation.
|
||||
*/
|
||||
protected function prepareInit()
|
||||
{
|
||||
$this->moduleName = $this->_request->getModuleName();
|
||||
$this->_helper->layout()->moduleName = $this->moduleName;
|
||||
$this->view->translationDomain = $this->moduleName;
|
||||
$this->moduleInit();
|
||||
if ($this->getFrontController()->getDefaultModule() !== $this->moduleName) {
|
||||
$this->assertPermission(Manager::MODULE_PERMISSION_NS . $this->moduleName);
|
||||
if ($this->getFrontController()->getDefaultModule() !== $this->getModuleName()) {
|
||||
$this->assertPermission(Manager::MODULE_PERMISSION_NS . $this->getModuleName());
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,22 +42,28 @@ class ModuleActionController extends ActionController
|
||||
{
|
||||
if ($file === null) {
|
||||
if ($this->config === null) {
|
||||
$this->config = Config::module($this->moduleName);
|
||||
$this->config = Config::module($this->getModuleName());
|
||||
}
|
||||
return $this->config;
|
||||
} else {
|
||||
if (! array_key_exists($file, $this->configs)) {
|
||||
$this->configs[$file] = Config::module($this->moduleName, $file);
|
||||
$this->configs[$file] = Config::module($this->getModuleName(), $file);
|
||||
}
|
||||
return $this->configs[$file];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this controller's module
|
||||
*
|
||||
* @return Module
|
||||
*/
|
||||
public function Module()
|
||||
{
|
||||
if ($this->module === null) {
|
||||
$this->module = Icinga::app()->getModuleManager()->getModule($this->moduleName);
|
||||
$this->module = Icinga::app()->getModuleManager()->getModule($this->getModuleName());
|
||||
}
|
||||
|
||||
return $this->module;
|
||||
}
|
||||
|
||||
@ -77,6 +74,6 @@ class ModuleActionController extends ActionController
|
||||
public function postDispatchXhr()
|
||||
{
|
||||
parent::postDispatchXhr();
|
||||
$this->getResponse()->setHeader('X-Icinga-Module', $this->moduleName, true);
|
||||
$this->getResponse()->setHeader('X-Icinga-Module', $this->getModuleName(), true);
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +81,13 @@ class Form extends Zend_Form
|
||||
*/
|
||||
protected $submitLabel;
|
||||
|
||||
/**
|
||||
* Label to use for showing the user an activity indicator when submitting the form
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $progressLabel;
|
||||
|
||||
/**
|
||||
* The url to redirect to upon success
|
||||
*
|
||||
@ -263,6 +270,29 @@ class Form extends Zend_Form
|
||||
return $this->submitLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the label to use for showing the user an activity indicator when submitting the form
|
||||
*
|
||||
* @param string $label
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProgressLabel($label)
|
||||
{
|
||||
$this->progressLabel = $label;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the label to use for showing the user an activity indicator when submitting the form
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getProgressLabel()
|
||||
{
|
||||
return $this->progressLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the url to redirect to upon success
|
||||
*
|
||||
@ -638,6 +668,12 @@ class Form extends Zend_Form
|
||||
public function setUseFormAutosubmit($state = true)
|
||||
{
|
||||
$this->useFormAutosubmit = (bool) $state;
|
||||
if ($this->useFormAutosubmit) {
|
||||
$this->setAttrib('data-progress-element', 'header-' . $this->getId());
|
||||
} else {
|
||||
$this->removeAttrib('data-progress-element');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -738,11 +774,13 @@ class Form extends Zend_Form
|
||||
'submit',
|
||||
'btn_submit',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $submitLabel,
|
||||
'decorators' => array(
|
||||
'ignore' => true,
|
||||
'label' => $submitLabel,
|
||||
'data-progress-label' => $this->getProgressLabel(),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'div'))
|
||||
array('Spinner', array('separator' => '')),
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'buttons'))
|
||||
)
|
||||
)
|
||||
);
|
||||
@ -801,9 +839,17 @@ class Form extends Zend_Form
|
||||
&& ! array_key_exists('disabledLoadDefaultDecorators', $options)
|
||||
) {
|
||||
$options['decorators'] = static::$defaultElementDecorators;
|
||||
if (! isset($options['data-progress-label']) && ($type === 'submit'
|
||||
|| ($type === 'button' && isset($options['type']) && $options['type'] === 'submit'))
|
||||
) {
|
||||
array_splice($options['decorators'], 1, 0, array(array('Spinner', array('separator' => ''))));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$options = array('decorators' => static::$defaultElementDecorators);
|
||||
if ($type === 'submit') {
|
||||
array_splice($options['decorators'], 1, 0, array(array('Spinner', array('separator' => ''))));
|
||||
}
|
||||
}
|
||||
|
||||
$el = parent::createElement($type, $name, $options);
|
||||
@ -1162,8 +1208,15 @@ class Form extends Zend_Form
|
||||
} else {
|
||||
$this->addDecorator('Description', array('tag' => 'h1'));
|
||||
if ($this->getUseFormAutosubmit()) {
|
||||
$this->addDecorator('Autosubmit', array('accessible' => true))
|
||||
->addDecorator('HtmlTag', array('tag' => 'div', 'class' => 'header'));
|
||||
$this->getDecorator('Description')->setEscape(false);
|
||||
$this->addDecorator(
|
||||
'HtmlTag',
|
||||
array(
|
||||
'tag' => 'div',
|
||||
'class' => 'header',
|
||||
'id' => 'header-' . $this->getId()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->addDecorator('FormDescriptions')
|
||||
@ -1210,6 +1263,25 @@ class Form extends Zend_Form
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve form description
|
||||
*
|
||||
* This will return the escaped description with the autosubmit warning icon if form autosubmit is enabled.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
$description = parent::getDescription();
|
||||
if ($description && $this->getUseFormAutosubmit()) {
|
||||
$autosubmit = $this->_getDecorator('Autosubmit', array('accessible' => true));
|
||||
$autosubmit->setElement($this);
|
||||
$description = $autosubmit->render($this->getView()->escape($description));
|
||||
}
|
||||
|
||||
return $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action to submit this form against
|
||||
*
|
||||
|
@ -96,7 +96,10 @@ class Help extends Zend_Form_Decorator_Abstract
|
||||
$helpContent = $this->getView()->icon(
|
||||
'help',
|
||||
$description . ($description && $requirement ? ' ' : '') . $requirement,
|
||||
array('aria-hidden' => $this->accessible ? 'true' : 'false')
|
||||
array(
|
||||
'class' => 'help',
|
||||
'aria-hidden' => $this->accessible ? 'true' : 'false'
|
||||
)
|
||||
) . $helpContent;
|
||||
}
|
||||
|
||||
|
48
library/Icinga/Web/Form/Decorator/Spinner.php
Normal file
48
library/Icinga/Web/Form/Decorator/Spinner.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Form\Decorator;
|
||||
|
||||
use Zend_Form_Decorator_Abstract;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Web\View;
|
||||
|
||||
/**
|
||||
* Decorator to add a spinner next to an element
|
||||
*/
|
||||
class Spinner extends Zend_Form_Decorator_Abstract
|
||||
{
|
||||
/**
|
||||
* Return the current view
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
protected function getView()
|
||||
{
|
||||
return Icinga::app()->getViewRenderer()->view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a spinner icon to a form element
|
||||
*
|
||||
* @param string $content The html rendered so far
|
||||
*
|
||||
* @return string The updated html
|
||||
*/
|
||||
public function render($content = '')
|
||||
{
|
||||
$spinner = '<div '
|
||||
. ($this->getOption('id') !== null ? ' id="' . $this->getOption('id') . '"' : '')
|
||||
. 'class="spinner ' . ($this->getOption('class') ?: '') . '"'
|
||||
. '>'
|
||||
. $this->getView()->icon('spin6')
|
||||
. '</div>';
|
||||
|
||||
switch ($this->getPlacement()) {
|
||||
case self::APPEND:
|
||||
return $content . $spinner;
|
||||
case self::PREPEND:
|
||||
return $spinner . $content;
|
||||
}
|
||||
}
|
||||
}
|
@ -117,9 +117,19 @@ class Menu implements RecursiveIterator
|
||||
foreach ($props as $key => $value) {
|
||||
$method = 'set' . implode('', array_map('ucfirst', explode('_', strtolower($key))));
|
||||
if ($key === 'renderer') {
|
||||
// nested configuration is used to pass multiple arguments to the item renderer
|
||||
if ($value instanceof ConfigObject) {
|
||||
$args = $value;
|
||||
$value = $value->get('0');
|
||||
}
|
||||
|
||||
$value = '\\' . ltrim($value, '\\');
|
||||
if (class_exists($value)) {
|
||||
$value = new $value;
|
||||
if (isset($args)) {
|
||||
$value = new $value($args);
|
||||
} else {
|
||||
$value = new $value;
|
||||
}
|
||||
} else {
|
||||
$class = '\Icinga\Web\Menu' . $value;
|
||||
if (!class_exists($class)) {
|
||||
@ -127,7 +137,11 @@ class Menu implements RecursiveIterator
|
||||
sprintf('ItemRenderer with class "%s" does not exist', $class)
|
||||
);
|
||||
}
|
||||
$value = new $class;
|
||||
if (isset($args)) {
|
||||
$value = new $class($args);
|
||||
} else {
|
||||
$value = new $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (method_exists($this, $method)) {
|
||||
@ -226,7 +240,6 @@ class Menu implements RecursiveIterator
|
||||
$auth = Auth::getInstance();
|
||||
|
||||
if ($auth->isAuthenticated()) {
|
||||
|
||||
$this->add(t('Dashboard'), array(
|
||||
'url' => 'dashboard',
|
||||
'icon' => 'dashboard',
|
||||
@ -236,7 +249,10 @@ class Menu implements RecursiveIterator
|
||||
$section = $this->add(t('System'), array(
|
||||
'icon' => 'services',
|
||||
'priority' => 700,
|
||||
'renderer' => 'ProblemMenuItemRenderer'
|
||||
'renderer' => array(
|
||||
'SummaryMenuItemRenderer',
|
||||
'state' => 'critical'
|
||||
)
|
||||
));
|
||||
$section->add(t('About'), array(
|
||||
'url' => 'about',
|
||||
@ -255,7 +271,7 @@ class Menu implements RecursiveIterator
|
||||
'priority' => 800
|
||||
));
|
||||
$section->add(t('Application'), array(
|
||||
'url' => 'config',
|
||||
'url' => 'config/general',
|
||||
'permission' => 'config/application/*',
|
||||
'priority' => 810
|
||||
));
|
||||
@ -297,7 +313,10 @@ class Menu implements RecursiveIterator
|
||||
$section->add(t('Logout'), array(
|
||||
'url' => 'authentication/logout',
|
||||
'priority' => 990,
|
||||
'renderer' => 'ForeignMenuItemRenderer'
|
||||
'renderer' => array(
|
||||
'MenuItemRenderer',
|
||||
'target' => '_self'
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
65
library/Icinga/Web/Menu/BadgeMenuItemRenderer.php
Normal file
65
library/Icinga/Web/Menu/BadgeMenuItemRenderer.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Web\Menu;
|
||||
|
||||
use Icinga\Web\Menu;
|
||||
|
||||
abstract class BadgeMenuItemRenderer extends MenuItemRenderer
|
||||
{
|
||||
const STATE_OK = 'ok';
|
||||
const STATE_CRITICAL = 'critical';
|
||||
const STATE_WARNING = 'warning';
|
||||
const STATE_PENDING = 'pending';
|
||||
const STATE_UNKNOWN = 'unknown';
|
||||
|
||||
/**
|
||||
* Defines the color of the badge
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getState();
|
||||
|
||||
/**
|
||||
* The amount of items to display in the badge
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getCount();
|
||||
|
||||
/**
|
||||
* The tooltip title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getTitle();
|
||||
|
||||
/**
|
||||
* Renders the html content of a single menu item
|
||||
*
|
||||
* @param Menu $menu
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(Menu $menu)
|
||||
{
|
||||
return $this->renderBadge() . $this->createLink($menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the badge
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function renderBadge()
|
||||
{
|
||||
if ($count = $this->getCount()) {
|
||||
return sprintf(
|
||||
'<div title="%s" class="badge-container"><span class="badge badge-%s">%s</span></div>',
|
||||
$this->getView()->escape($this->getTitle()),
|
||||
$this->getView()->escape($this->getState()),
|
||||
$count
|
||||
);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Menu;
|
||||
|
||||
use Icinga\Web\Menu;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
* A menu item with a link that surpasses the regular navigation link behavior
|
||||
*/
|
||||
class ForeignMenuItemRenderer extends MenuItemRenderer
|
||||
{
|
||||
protected $attributes = array(
|
||||
'target' => '_self'
|
||||
);
|
||||
}
|
@ -7,6 +7,7 @@ use Icinga\Application\Icinga;
|
||||
use Icinga\Web\Menu;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\View;
|
||||
use Icinga\Data\ConfigObject;
|
||||
|
||||
/**
|
||||
* Default MenuItemRenderer class
|
||||
@ -14,38 +15,39 @@ use Icinga\Web\View;
|
||||
class MenuItemRenderer
|
||||
{
|
||||
/**
|
||||
* Contains <a> element specific attributes
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = array();
|
||||
|
||||
/**
|
||||
* View
|
||||
* The view this menu item is being rendered to
|
||||
*
|
||||
* @var View|null
|
||||
*/
|
||||
protected $view;
|
||||
protected $view = null;
|
||||
|
||||
/**
|
||||
* Set the view
|
||||
* The link target
|
||||
*
|
||||
* @param View $view
|
||||
*
|
||||
* @return $this
|
||||
* @var string
|
||||
*/
|
||||
public function setView(View $view)
|
||||
protected $target = null;
|
||||
|
||||
/**
|
||||
* Create a new instance of MenuItemRenderer
|
||||
*
|
||||
* Is is possible to configure the link target using the option 'target'
|
||||
*
|
||||
* @param ConfigObject|null $configuration
|
||||
*/
|
||||
public function __construct(ConfigObject $configuration = null)
|
||||
{
|
||||
$this->view = $view;
|
||||
return $this;
|
||||
if ($configuration !== null) {
|
||||
$this->target = $configuration->get('target', null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view
|
||||
* Get the view this menu item is being rendered to
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function getView()
|
||||
protected function getView()
|
||||
{
|
||||
if ($this->view === null) {
|
||||
$this->view = Icinga::app()->getViewRenderer()->view;
|
||||
@ -53,6 +55,36 @@ class MenuItemRenderer
|
||||
return $this->view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a menu item link element
|
||||
*
|
||||
* @param Menu $menu
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function createLink(Menu $menu)
|
||||
{
|
||||
$attributes = isset($this->target) ? sprintf(' target="%s"', $this->getView()->escape($this->target)) : '';
|
||||
|
||||
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() ? : '#',
|
||||
$attributes,
|
||||
$menu->getIcon(),
|
||||
$this->getView()->escape($menu->getTitle())
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<a href="%s"%s>%s%s<span></span></a>',
|
||||
$menu->getUrl() ? : '#',
|
||||
$attributes,
|
||||
$menu->getIcon() ? '<img aria-hidden="true" src="' . Url::fromPath($menu->getIcon()) . '" class="icon" /> ' : '',
|
||||
$this->getView()->escape($menu->getTitle())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the html content of a single menu item
|
||||
*
|
||||
@ -64,47 +96,4 @@ class MenuItemRenderer
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Menu;
|
||||
|
||||
use Icinga\Web\Menu;
|
||||
|
||||
class ProblemMenuItemRenderer extends MenuItemRenderer
|
||||
{
|
||||
/**
|
||||
* 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 '';
|
||||
}
|
||||
}
|
94
library/Icinga/Web/Menu/SummaryMenuItemRenderer.php
Normal file
94
library/Icinga/Web/Menu/SummaryMenuItemRenderer.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Menu;
|
||||
|
||||
use Icinga\Web\Menu;
|
||||
use Icinga\Data\ConfigObject;
|
||||
|
||||
/**
|
||||
* Summary badge adding up all badges in the sub-menus that have the same state
|
||||
*/
|
||||
class SummaryMenuItemRenderer extends BadgeMenuItemRenderer
|
||||
{
|
||||
/**
|
||||
* Set of summarized problems from submenus
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $titles = array();
|
||||
|
||||
/**
|
||||
* The amount of problems
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $count = 0;
|
||||
|
||||
/**
|
||||
* The state that should be summarized
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The amount of problems
|
||||
*/
|
||||
public function __construct(ConfigObject $configuration)
|
||||
{
|
||||
$this->state = $configuration->get('state', self::STATE_CRITICAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the html content of a single menu item and summarized sub-menus
|
||||
*
|
||||
* @param Menu $menu
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(Menu $menu)
|
||||
{
|
||||
/** @var $submenu Menu */
|
||||
foreach ($menu->getSubMenus() as $submenu) {
|
||||
$renderer = $submenu->getRenderer();
|
||||
if ($renderer instanceof BadgeMenuItemRenderer) {
|
||||
if ($renderer->getState() === $this->state) {
|
||||
$this->titles[] = $renderer->getTitle();
|
||||
$this->count += $renderer->getCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->renderBadge() . $this->createLink($menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount of items to display in the badge
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCount()
|
||||
{
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the color of the badge
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* The tooltip title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return implode(', ', $this->titles);
|
||||
}
|
||||
}
|
@ -119,6 +119,11 @@ class Request extends Zend_Controller_Request_Http
|
||||
return $id . '-' . $this->uniqueId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect whether cookies are enabled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasCookieSupport()
|
||||
{
|
||||
$cookie = new Cookie($this);
|
||||
|
@ -12,6 +12,7 @@ class StyleSheet
|
||||
protected static $lessFiles = array(
|
||||
'../application/fonts/fontello-ifont/css/ifont-embedded.css',
|
||||
'css/vendor/tipsy.css',
|
||||
'css/icinga/mixins.less',
|
||||
'css/icinga/defaults.less',
|
||||
'css/icinga/animation.less',
|
||||
'css/icinga/layout-colors.less',
|
||||
|
@ -3,8 +3,6 @@
|
||||
|
||||
namespace Icinga\Web\Widget\Dashboard;
|
||||
|
||||
use Zend_Form_Element_Button;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Exception\IcingaException;
|
||||
@ -43,6 +41,13 @@ class Dashlet extends UserWidget
|
||||
*/
|
||||
private $disabled = false;
|
||||
|
||||
/**
|
||||
* The progress label being used
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $progressLabel;
|
||||
|
||||
/**
|
||||
* The template string used for rendering this widget
|
||||
*
|
||||
@ -52,6 +57,7 @@ class Dashlet extends UserWidget
|
||||
|
||||
<div class="container" data-icinga-url="{URL}">
|
||||
<h1><a href="{FULL_URL}" aria-label="{TOOLTIP}" title="{TOOLTIP}" data-base-target="col1">{TITLE}</a></h1>
|
||||
<p class="progress-label">{PROGRESS_LABEL}<span>.</span><span>.</span><span>.</span></p>
|
||||
<noscript>
|
||||
<iframe
|
||||
src="{IFRAME_URL}"
|
||||
@ -147,6 +153,33 @@ EOD;
|
||||
return $this->disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the progress label to use
|
||||
*
|
||||
* @param string $label
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProgressLabel($label)
|
||||
{
|
||||
$this->progressLabel = $label;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the progress label to use
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getProgressLabe()
|
||||
{
|
||||
if ($this->progressLabel === null) {
|
||||
return $this->view()->translate('Loading');
|
||||
}
|
||||
|
||||
return $this->progressLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this dashlet's structure as array
|
||||
*
|
||||
@ -185,7 +218,8 @@ EOD;
|
||||
'{FULL_URL}',
|
||||
'{TOOLTIP}',
|
||||
'{TITLE}',
|
||||
'{TITLE_PREFIX}'
|
||||
'{TITLE_PREFIX}',
|
||||
'{PROGRESS_LABEL}'
|
||||
);
|
||||
|
||||
$replaceTokens = array(
|
||||
@ -194,7 +228,8 @@ EOD;
|
||||
$url->getUrlWithout(array('view', 'limit')),
|
||||
sprintf($view->translate('Show %s', 'dashboard.dashlet.tooltip'), $view->escape($this->getTitle())),
|
||||
$view->escape($this->getTitle()),
|
||||
$view->translate('Dashlet') . ': '
|
||||
$view->translate('Dashlet') . ': ',
|
||||
$this->getProgressLabe()
|
||||
);
|
||||
|
||||
return str_replace($searchTokens, $replaceTokens, $this->template);
|
||||
|
@ -191,6 +191,21 @@ class Pane extends UserWidget
|
||||
return implode("\n", $dashlets) . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create, add and return a new dashlet
|
||||
*
|
||||
* @param string $title
|
||||
* @param string $url
|
||||
*
|
||||
* @return Dashlet
|
||||
*/
|
||||
public function createDashlet($title, $url = null)
|
||||
{
|
||||
$dashlet = new Dashlet($title, $url, $this);
|
||||
$this->addDashlet($dashlet);
|
||||
return $dashlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a dashlet to this pane, optionally creating it if $dashlet is a string
|
||||
*
|
||||
@ -206,7 +221,7 @@ class Pane extends UserWidget
|
||||
if ($dashlet instanceof Dashlet) {
|
||||
$this->dashlets[$dashlet->getTitle()] = $dashlet;
|
||||
} elseif (is_string($dashlet) && $url !== null) {
|
||||
$this->dashlets[$dashlet] = new Dashlet($dashlet, $url, $this);
|
||||
$this->createDashlet($dashlet, $url);
|
||||
} else {
|
||||
throw new ConfigurationError('Invalid dashlet added: %s', $dashlet);
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
namespace Icinga\Web\Widget;
|
||||
|
||||
use Icinga\Data\Filterable;
|
||||
use Icinga\Data\FilterColumns;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\Filter\FilterExpression;
|
||||
use Icinga\Data\Filter\FilterChain;
|
||||
@ -25,6 +27,11 @@ class FilterEditor extends AbstractWidget
|
||||
*/
|
||||
private $filter;
|
||||
|
||||
/**
|
||||
* The query to filter
|
||||
*
|
||||
* @var Filterable
|
||||
*/
|
||||
protected $query;
|
||||
|
||||
protected $url;
|
||||
@ -41,7 +48,7 @@ class FilterEditor extends AbstractWidget
|
||||
|
||||
protected $ignoreParams = array();
|
||||
|
||||
protected $searchColumns = null;
|
||||
protected $searchColumns;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
@ -84,7 +91,7 @@ class FilterEditor extends AbstractWidget
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSearchColumns(array $searchColumns)
|
||||
public function setSearchColumns(array $searchColumns = null)
|
||||
{
|
||||
$this->searchColumns = $searchColumns;
|
||||
return $this;
|
||||
@ -112,7 +119,14 @@ class FilterEditor extends AbstractWidget
|
||||
return $this->preservedUrl;
|
||||
}
|
||||
|
||||
public function setQuery($query)
|
||||
/**
|
||||
* Set the query to filter
|
||||
*
|
||||
* @param Filterable $query
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setQuery(Filterable $query)
|
||||
{
|
||||
$this->query = $query;
|
||||
return $this;
|
||||
@ -219,19 +233,25 @@ class FilterEditor extends AbstractWidget
|
||||
if (strpos($search, '=') !== false) {
|
||||
list($k, $v) = preg_split('/=/', $search);
|
||||
$filter = $this->mergeRootExpression($filter, trim($k), '=', ltrim($v));
|
||||
} elseif (! empty($this->searchColumns)) {
|
||||
if (! $this->resetSearchColumns($filter)) {
|
||||
$filter = Filter::matchAll();
|
||||
}
|
||||
$filters = array();
|
||||
$search = ltrim($search);
|
||||
foreach ($this->searchColumns as $searchColumn) {
|
||||
$filters[] = Filter::expression($searchColumn, '=', "*$search*");
|
||||
}
|
||||
$filter = $filter->andFilter(new FilterOr($filters));
|
||||
} else {
|
||||
Notification::error(mt('monitoring', 'Cannot search here'));
|
||||
return $this;
|
||||
if ($this->searchColumns === null && $this->query instanceof FilterColumns) {
|
||||
$this->searchColumns = $this->query->getSearchColumns();
|
||||
}
|
||||
|
||||
if (! empty($this->searchColumns)) {
|
||||
if (! $this->resetSearchColumns($filter)) {
|
||||
$filter = Filter::matchAll();
|
||||
}
|
||||
$filters = array();
|
||||
$search = ltrim($search);
|
||||
foreach ($this->searchColumns as $searchColumn) {
|
||||
$filters[] = Filter::expression($searchColumn, '=', "*$search*");
|
||||
}
|
||||
$filter = $filter->andFilter(new FilterOr($filters));
|
||||
} else {
|
||||
Notification::error(mt('monitoring', 'Cannot search here'));
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
$url = $this->url()->setQueryString(
|
||||
@ -284,6 +304,11 @@ class FilterEditor extends AbstractWidget
|
||||
if ($add) {
|
||||
$this->addFilterToId($add);
|
||||
}
|
||||
|
||||
if ($this->query !== null && $request->isGet()) {
|
||||
$this->query->applyFilter($this->getFilter());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -482,12 +507,14 @@ class FilterEditor extends AbstractWidget
|
||||
);
|
||||
}
|
||||
|
||||
protected function arrayForSelect($array)
|
||||
protected function arrayForSelect($array, $flip = false)
|
||||
{
|
||||
$res = array();
|
||||
foreach ($array as $k => $v) {
|
||||
if (is_int($k)) {
|
||||
$res[$v] = $v;
|
||||
$res[$v] = ucwords(str_replace('_', ' ', $v));
|
||||
} elseif ($flip) {
|
||||
$res[$v] = $k;
|
||||
} else {
|
||||
$res[$k] = $v;
|
||||
}
|
||||
@ -540,9 +567,9 @@ class FilterEditor extends AbstractWidget
|
||||
);
|
||||
}
|
||||
|
||||
public function setColumns(array $columns)
|
||||
public function setColumns(array $columns = null)
|
||||
{
|
||||
$this->cachedColumnSelect = $this->arrayForSelect($columns);
|
||||
$this->cachedColumnSelect = $columns ? $this->arrayForSelect($columns) : null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -558,20 +585,15 @@ class FilterEditor extends AbstractWidget
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->cachedColumnSelect === null) {
|
||||
$this->cachedColumnSelect = $this->arrayForSelect($this->query->getColumns());
|
||||
if ($this->cachedColumnSelect === null && $this->query instanceof FilterColumns) {
|
||||
$this->cachedColumnSelect = $this->arrayForSelect($this->query->getFilterColumns(), true);
|
||||
asort($this->cachedColumnSelect);
|
||||
}
|
||||
$cols = $this->cachedColumnSelect;
|
||||
$seen = false;
|
||||
foreach ($cols as $k => & $v) {
|
||||
$v = str_replace('_', ' ', ucfirst($v));
|
||||
if ($k === $active) {
|
||||
$seen = true;
|
||||
}
|
||||
} elseif ($this->cachedColumnSelect === null) {
|
||||
throw new ProgrammingError('No columns set nor does the query provide any');
|
||||
}
|
||||
|
||||
if (!$seen) {
|
||||
$cols = $this->cachedColumnSelect;
|
||||
if ($active && !isset($cols[$active])) {
|
||||
$cols[$active] = str_replace('_', ' ', ucfirst(ltrim($active, '_')));
|
||||
}
|
||||
|
||||
|
@ -69,10 +69,10 @@ class SearchDashboard extends Dashboard
|
||||
usort($searchUrls, array($this, 'compareSearchUrls'));
|
||||
|
||||
foreach (array_reverse($searchUrls) as $searchUrl) {
|
||||
$pane->addDashlet(
|
||||
$pane->createDashlet(
|
||||
$searchUrl->title . ': ' . $searchString,
|
||||
Url::fromPath($searchUrl->url, array('q' => $searchString))
|
||||
);
|
||||
)->setProgressLabel(t('Searching'));
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -118,12 +118,12 @@ class SortBox extends AbstractWidget
|
||||
if ($request === null) {
|
||||
$request = Icinga::app()->getRequest();
|
||||
}
|
||||
|
||||
if (($sort = $request->getParam('sort'))) {
|
||||
$this->query->order($sort, $request->getParam('dir'));
|
||||
} elseif (($dir = $request->getParam('dir'))) {
|
||||
$this->query->order(null, $dir);
|
||||
if (null === $sort = $request->getParam('sort')) {
|
||||
list($sort, $dir) = $this->getSortDefaults();
|
||||
} else {
|
||||
list($_, $dir) = $this->getSortDefaults($sort);
|
||||
}
|
||||
$this->query->order($sort, $request->getParam('dir', $dir));
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -148,8 +148,10 @@ class SortBox extends AbstractWidget
|
||||
if ($column !== null && isset($sortRules[$column]['order'])) {
|
||||
$direction = strtoupper($sortRules[$column]['order']) === Sortable::SORT_DESC ? 'desc' : 'asc';
|
||||
}
|
||||
} elseif ($column === null) {
|
||||
reset($this->sortFields);
|
||||
$column = key($this->sortFields);
|
||||
}
|
||||
|
||||
return array($column, $direction);
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,11 @@ class Wizard
|
||||
*/
|
||||
const BTN_PREV = 'btn_prev';
|
||||
|
||||
/**
|
||||
* The name and id of the element for showing the user an activity indicator when advancing the wizard
|
||||
*/
|
||||
const PROGRESS_ELEMENT = 'wizard_progress';
|
||||
|
||||
/**
|
||||
* This wizard's parent
|
||||
*
|
||||
@ -606,7 +611,7 @@ class Wizard
|
||||
'type' => 'submit',
|
||||
'value' => $pages[1]->getName(),
|
||||
'label' => t('Next'),
|
||||
'decorators' => array('ViewHelper')
|
||||
'decorators' => array('ViewHelper', 'Spinner')
|
||||
)
|
||||
);
|
||||
} elseif ($index < count($pages) - 1) {
|
||||
@ -655,8 +660,21 @@ class Wizard
|
||||
);
|
||||
}
|
||||
|
||||
$page->setAttrib('data-progress-element', static::PROGRESS_ELEMENT);
|
||||
$page->addElement(
|
||||
'note',
|
||||
static::PROGRESS_ELEMENT,
|
||||
array(
|
||||
'order' => 99, // Ensures that it's shown on the right even if a sub-class adds another button
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('Spinner', array('id' => static::PROGRESS_ELEMENT))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$page->addDisplayGroup(
|
||||
array(static::BTN_PREV, static::BTN_NEXT),
|
||||
array(static::BTN_PREV, static::BTN_NEXT, static::PROGRESS_ELEMENT),
|
||||
'buttons',
|
||||
array(
|
||||
'decorators' => array(
|
||||
|
@ -10,7 +10,6 @@ use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||
use Icinga\Web\Widget\Tabs;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Web\Widget;
|
||||
use Icinga\Module\Monitoring\Forms\StatehistoryForm;
|
||||
use Icinga\Module\Monitoring\DataView\DataView;
|
||||
|
||||
@ -25,24 +24,6 @@ class Monitoring_ListController extends Controller
|
||||
$this->createTabs();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated DO NOT USE. THIS IS A HACK. This is removed once we fix the eventhistory action w/ filters.
|
||||
*/
|
||||
protected function applyFilter($query)
|
||||
{
|
||||
$params = clone $this->params;
|
||||
$params->shift('format');
|
||||
$params->shift('limit');
|
||||
$params->shift('page');
|
||||
$params->shift('view');
|
||||
if ($sort = $params->shift('sort')) {
|
||||
$query->order($sort, $params->shift('dir'));
|
||||
}
|
||||
$query->applyFilter(Filter::fromQuerystring((string) $params));
|
||||
$this->handleFormatRequest($query);
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite the backend to use (used for testing)
|
||||
*
|
||||
@ -92,8 +73,8 @@ class Monitoring_ListController extends Controller
|
||||
'host_current_check_attempt',
|
||||
'host_max_check_attempts'
|
||||
), $this->addColumns()));
|
||||
$this->filterQuery($query);
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->view->hosts = $query;
|
||||
$stats = $this->backend->select()->from('hoststatussummary', array(
|
||||
'hosts_total',
|
||||
@ -178,8 +159,8 @@ class Monitoring_ListController extends Controller
|
||||
'max_check_attempts' => 'service_max_check_attempts'
|
||||
), $this->addColumns());
|
||||
$query = $this->backend->select()->from('servicestatus', $columns);
|
||||
$this->filterQuery($query);
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->view->services = $query;
|
||||
|
||||
$this->setupLimitControl();
|
||||
@ -243,9 +224,8 @@ class Monitoring_ListController extends Controller
|
||||
'host_display_name',
|
||||
'service_display_name'
|
||||
));
|
||||
$this->filterQuery($query);
|
||||
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
|
||||
$this->view->downtimes = $query;
|
||||
|
||||
@ -292,8 +272,8 @@ class Monitoring_ListController extends Controller
|
||||
'host_display_name',
|
||||
'service_display_name'
|
||||
));
|
||||
$this->filterQuery($query);
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->view->notifications = $query;
|
||||
|
||||
$this->setupLimitControl();
|
||||
@ -315,8 +295,8 @@ class Monitoring_ListController extends Controller
|
||||
'contact_notify_service_timeperiod',
|
||||
'contact_notify_host_timeperiod'
|
||||
));
|
||||
$this->filterQuery($query);
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->view->contacts = $query;
|
||||
|
||||
$this->setupLimitControl();
|
||||
@ -387,8 +367,8 @@ class Monitoring_ListController extends Controller
|
||||
'contact_email',
|
||||
'contact_pager'
|
||||
));
|
||||
$this->filterQuery($query);
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
|
||||
$this->setupSortControl(array(
|
||||
'contactgroup_name' => $this->translate('Contactgroup Name'),
|
||||
@ -431,10 +411,8 @@ class Monitoring_ListController extends Controller
|
||||
'host_display_name',
|
||||
'service_display_name'
|
||||
));
|
||||
$this->filterQuery($query);
|
||||
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
|
||||
$this->filterQuery($query);
|
||||
$this->view->comments = $query;
|
||||
|
||||
$this->setupLimitControl();
|
||||
@ -486,10 +464,8 @@ class Monitoring_ListController extends Controller
|
||||
'services_warning_last_state_change_unhandled' => 'services_warning_unhandled_last_state_change',
|
||||
'services_warning_unhandled'
|
||||
));
|
||||
$this->filterQuery($query);
|
||||
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
|
||||
$this->filterQuery($query);
|
||||
$this->view->servicegroups = $query;
|
||||
|
||||
$this->setupLimitControl();
|
||||
@ -532,10 +508,8 @@ class Monitoring_ListController extends Controller
|
||||
'services_warning_handled',
|
||||
'services_warning_unhandled'
|
||||
));
|
||||
$this->filterQuery($query);
|
||||
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
|
||||
$this->filterQuery($query);
|
||||
$this->view->hostgroups = $query;
|
||||
|
||||
$this->setupLimitControl();
|
||||
@ -582,29 +556,36 @@ class Monitoring_ListController extends Controller
|
||||
{
|
||||
$this->addTitleTab('servicegrid', $this->translate('Service Grid'), $this->translate('Show the Service Grid'));
|
||||
$this->setAutorefreshInterval(15);
|
||||
$problems = (bool) $this->params->shift('problems', 0);
|
||||
$query = $this->backend->select()->from('servicestatus', array(
|
||||
'host_display_name',
|
||||
'host_name',
|
||||
'service_description',
|
||||
'service_state',
|
||||
'service_display_name',
|
||||
'service_handled',
|
||||
'service_output',
|
||||
'service_handled'
|
||||
'service_state'
|
||||
));
|
||||
$this->filterQuery($query);
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$filter = (bool) $this->params->shift('problems', false) ? Filter::where('service_problem', 1) : null;
|
||||
$pivot = $query
|
||||
->pivot(
|
||||
'service_description',
|
||||
'host_name',
|
||||
$filter,
|
||||
$filter ? clone $filter : null
|
||||
)
|
||||
->setXAxisHeader('service_display_name')
|
||||
->setYAxisHeader('host_display_name');
|
||||
$this->setupSortControl(array(
|
||||
'host_name' => $this->translate('Hostname'),
|
||||
'service_description' => $this->translate('Service description')
|
||||
), $query);
|
||||
$pivot = $query->pivot(
|
||||
'service_description',
|
||||
'host_name',
|
||||
$problems ? Filter::where('service_problem', 1) : null,
|
||||
$problems ? Filter::where('service_problem', 1) : null
|
||||
);
|
||||
$this->view->pivot = $pivot;
|
||||
'host_display_name' => $this->translate('Hostname'),
|
||||
'service_display_name' => $this->translate('Service Name')
|
||||
), $pivot);
|
||||
$this->view->horizontalPaginator = $pivot->paginateXAxis();
|
||||
$this->view->verticalPaginator = $pivot->paginateYAxis();
|
||||
$this->view->verticalPaginator = $pivot->paginateYAxis();
|
||||
list($pivotData, $pivotHeader) = $pivot->toArray();
|
||||
$this->view->pivotData = $pivotData;
|
||||
$this->view->pivotHeader = $pivotHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -616,20 +597,7 @@ class Monitoring_ListController extends Controller
|
||||
*/
|
||||
protected function filterQuery(DataView $dataView)
|
||||
{
|
||||
$editor = Widget::create('filterEditor')
|
||||
->setQuery($dataView)
|
||||
->preserveParams(
|
||||
'limit', 'sort', 'dir', 'format', 'view', 'backend',
|
||||
'stateType', 'addColumns', '_dev', 'problems'
|
||||
)
|
||||
->ignoreParams('page')
|
||||
->setSearchColumns($dataView->getSearchColumns())
|
||||
->handleRequest($this->getRequest());
|
||||
$dataView->applyFilter($editor->getFilter());
|
||||
|
||||
$this->setupFilterControl($editor);
|
||||
$this->view->filter = $editor->getFilter();
|
||||
|
||||
$this->setupFilterControl($dataView);
|
||||
$this->handleFormatRequest($dataView);
|
||||
return $dataView;
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ class DeleteCommentCommandForm extends CommandForm
|
||||
'ignore' => true,
|
||||
'escape' => false,
|
||||
'type' => 'submit',
|
||||
'class' => 'link-like',
|
||||
'class' => 'link-like spinner',
|
||||
'label' => $this->getView()->icon('trash'),
|
||||
'title' => $this->translate('Delete this comment'),
|
||||
'decorators' => array('ViewHelper')
|
||||
|
@ -68,7 +68,7 @@ class DeleteDowntimeCommandForm extends CommandForm
|
||||
'ignore' => true,
|
||||
'escape' => false,
|
||||
'type' => 'submit',
|
||||
'class' => 'link-like',
|
||||
'class' => 'link-like spinner',
|
||||
'label' => $this->getView()->icon('trash'),
|
||||
'title' => $this->translate('Delete this downtime'),
|
||||
'decorators' => array('ViewHelper')
|
||||
|
@ -8,6 +8,7 @@ use Icinga\Forms\Config\ResourceConfigForm;
|
||||
use Icinga\Forms\Config\Resource\DbResourceForm;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Module\Monitoring\Forms\Config\BackendConfigForm;
|
||||
use Icinga\Module\Setup\Utils\DbTool;
|
||||
|
||||
class IdoResourcePage extends Form
|
||||
{
|
||||
@ -73,23 +74,8 @@ class IdoResourcePage extends Form
|
||||
}
|
||||
|
||||
if (! isset($formData['skip_validation']) || !$formData['skip_validation']) {
|
||||
$inspection = ResourceConfigForm::inspectResource($this);
|
||||
if ($inspection !== null && $inspection->hasError()) {
|
||||
$this->error($inspection->getError());
|
||||
$this->addSkipValidationCheckbox($this->translate(
|
||||
'Check this to not to validate connectivity with the given database server.'
|
||||
));
|
||||
return false;
|
||||
}
|
||||
|
||||
$configObject = new ConfigObject($this->getValues());
|
||||
if (
|
||||
! BackendConfigForm::isValidIdoSchema($this, $configObject)
|
||||
|| !BackendConfigForm::isValidIdoInstance($this, $configObject)
|
||||
) {
|
||||
$this->addSkipValidationCheckbox($this->translate(
|
||||
'Check this to not to validate the IDO schema in the given database.'
|
||||
));
|
||||
if (! $this->validateConfiguration()) {
|
||||
$this->addSkipValidationCheckbox();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -109,8 +95,31 @@ class IdoResourcePage extends Form
|
||||
public function isValidPartial(array $formData)
|
||||
{
|
||||
if (isset($formData['backend_validation']) && parent::isValid($formData)) {
|
||||
$inspection = ResourceConfigForm::inspectResource($this);
|
||||
if ($inspection !== null) {
|
||||
if (! $this->validateConfiguration(true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->info($this->translate('The configuration has been successfully validated.'));
|
||||
} elseif (! isset($formData['backend_validation'])) {
|
||||
// This is usually done by isValid(Partial), but as we're not calling any of these...
|
||||
$this->populate($formData);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the configuration is valid
|
||||
*
|
||||
* @param bool $showLog Whether to show the validation log
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function validateConfiguration($showLog = false)
|
||||
{
|
||||
$inspection = ResourceConfigForm::inspectResource($this);
|
||||
if ($inspection !== null) {
|
||||
if ($showLog) {
|
||||
$join = function ($e) use (& $join) {
|
||||
return is_string($e) ? $e : join("\n", array_map($join, $e));
|
||||
};
|
||||
@ -127,45 +136,53 @@ class IdoResourcePage extends Form
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ($inspection->hasError()) {
|
||||
$this->warning(sprintf(
|
||||
$this->translate('Failed to successfully validate the configuration: %s'),
|
||||
$inspection->getError()
|
||||
));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info($this->translate('The configuration has been successfully validated.'));
|
||||
} elseif (! isset($formData['backend_validation'])) {
|
||||
// This is usually done by isValid(Partial), but as we're not calling any of these...
|
||||
$this->populate($formData);
|
||||
if ($inspection->hasError()) {
|
||||
$this->error(sprintf(
|
||||
$this->translate('Failed to successfully validate the configuration: %s'),
|
||||
$inspection->getError()
|
||||
));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$configObject = new ConfigObject($this->getValues());
|
||||
if (
|
||||
! BackendConfigForm::isValidIdoSchema($this, $configObject)
|
||||
|| !BackendConfigForm::isValidIdoInstance($this, $configObject)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getValue('db') === 'pgsql') {
|
||||
$db = new DbTool($this->getValues());
|
||||
$version = $db->connectToDb()->getServerVersion();
|
||||
if (version_compare($version, '9.1', '<')) {
|
||||
$this->error($this->translate(sprintf(
|
||||
'The server\'s version %s is too old. The minimum required version is %s.',
|
||||
$version,
|
||||
'9.1'
|
||||
)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a checkbox to the form by which the user can skip the resource validation
|
||||
*
|
||||
* @param string $description
|
||||
* Add a checkbox to the form by which the user can skip the configuration validation
|
||||
*/
|
||||
protected function addSkipValidationCheckbox($description = null)
|
||||
protected function addSkipValidationCheckbox()
|
||||
{
|
||||
if (empty($description)) {
|
||||
$description = $this->translate(
|
||||
'Proceed without any further (custom) validation.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'skip_validation',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Skip Validation'),
|
||||
'description' => $description
|
||||
'description' => $this->translate('Check this to not to validate the configuration')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ class Zend_View_Helper_IconImage extends Zend_View_Helper_Abstract
|
||||
public function host($object)
|
||||
{
|
||||
if ($object->host_icon_image && ! preg_match('/[\'"]/', $object->host_icon_image)) {
|
||||
return $this->view->img(
|
||||
'img/icons/' . Macro::resolveMacros($object->host_icon_image, $object),
|
||||
return $this->view->icon(
|
||||
Macro::resolveMacros($object->host_icon_image, $object),
|
||||
null,
|
||||
array(
|
||||
'alt' => $object->host_icon_image_alt,
|
||||
@ -49,8 +49,8 @@ class Zend_View_Helper_IconImage extends Zend_View_Helper_Abstract
|
||||
public function service($object)
|
||||
{
|
||||
if ($object->service_icon_image && ! preg_match('/[\'"]/', $object->service_icon_image)) {
|
||||
return $this->view->img(
|
||||
'img/icons/' . Macro::resolveMacros($object->service_icon_image, $object),
|
||||
return $this->view->icon(
|
||||
Macro::resolveMacros($object->service_icon_image, $object),
|
||||
null,
|
||||
array(
|
||||
'alt' => $object->service_icon_image_alt,
|
||||
|
@ -67,7 +67,7 @@
|
||||
) : $this->translate('This comment does not expire.'); ?>
|
||||
</td>
|
||||
<?php if (isset($delCommentForm)): // Form is unset if the current user lacks the respective permission ?>
|
||||
<td style="width: 2em" data-base-target="self">
|
||||
<td style="width: 2em" data-base-target="_self">
|
||||
<?php
|
||||
$delCommentForm = clone $delCommentForm;
|
||||
$delCommentForm->populate(
|
||||
|
@ -126,7 +126,7 @@ if (! $this->compact): ?>
|
||||
</small>
|
||||
</td>
|
||||
<?php if (isset($delDowntimeForm)): // Form is unset if the current user lacks the respective permission ?>
|
||||
<td style="width: 2em" data-base-target="self">
|
||||
<td style="width: 2em" data-base-target="_self">
|
||||
<?php
|
||||
$delDowntimeForm = clone $delDowntimeForm;
|
||||
$delDowntimeForm->populate(
|
||||
|
@ -68,7 +68,7 @@ foreach ($summary as $entry) {
|
||||
Filter::expression('timestamp', '<', strtotime($day . ' 23:59:59')),
|
||||
Filter::expression('timestamp', '>', strtotime($day . ' 00:00:00')),
|
||||
$form->getFilter(),
|
||||
$filter
|
||||
Filter::fromQueryString($this->url()->getParams()->toString())
|
||||
);
|
||||
$data[$day] = array(
|
||||
'value' => $value,
|
||||
|
@ -36,7 +36,8 @@ if (! $this->compact): ?>
|
||||
$notification->service_description,
|
||||
$notification->service_display_name,
|
||||
$notification->host_name,
|
||||
$notification->host_display_name
|
||||
$notification->host_display_name,
|
||||
'rowaction'
|
||||
) ?>
|
||||
<?php else: ?>
|
||||
<?= $this->icon('host', $this->translate('Host')); ?>
|
||||
|
@ -12,97 +12,84 @@ if (! $this->compact): ?>
|
||||
<?php endif ?>
|
||||
<div class="content" data-base-target="_next">
|
||||
<?php
|
||||
|
||||
$hasHeader = false;
|
||||
$pivotData = $this->pivot->toArray();
|
||||
if (count($pivotData) === 0) {
|
||||
if (empty($pivotData)) {
|
||||
echo $this->translate('No services found matching the filter') . '</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
$hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ')';
|
||||
?>
|
||||
<table class="pivot servicestates">
|
||||
<?php foreach ($pivotData as $host_name => $serviceStates): ?>
|
||||
<?php if (!$hasHeader): ?>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?= $this->partial(
|
||||
'joystickPagination.phtml',
|
||||
'default',
|
||||
array(
|
||||
'xAxisPaginator' => $horizontalPaginator,
|
||||
'yAxisPaginator' => $verticalPaginator
|
||||
)
|
||||
); ?></th>
|
||||
<th colspan="<?= count($serviceStates); ?>">
|
||||
<div>
|
||||
<?php
|
||||
$serviceDescriptions = array_keys($serviceStates);
|
||||
$serviceFilter = '(service_description=' . implode('|service_description=', $serviceDescriptions) . ')';
|
||||
|
||||
foreach ($serviceDescriptions as $service_description): ?>
|
||||
<span>
|
||||
<?= $this->qlink(
|
||||
'<abbr>' . (strlen($service_description) > 18 ? substr($service_description, 0, 18) . '...' : $service_description) . '</abbr>',
|
||||
<table class="service-grid-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?= $this->partial(
|
||||
'joystickPagination.phtml',
|
||||
'default',
|
||||
array(
|
||||
'xAxisPaginator' => $horizontalPaginator,
|
||||
'yAxisPaginator' => $verticalPaginator
|
||||
)
|
||||
); ?></th>
|
||||
<?php foreach ($pivotHeader['cols'] as $serviceDescription => $serviceDisplayName): ?>
|
||||
<th class="rotate-45"><div><span><?= $this->qlink(
|
||||
$this->ellipsis($serviceDisplayName, 18),
|
||||
'monitoring/list/services?' . $hostFilter,
|
||||
array(
|
||||
'service_description' => $service_description
|
||||
),
|
||||
array(
|
||||
'title' => sprintf($this->translate('List all services with the name "%s" on all reported hosts'), $service_description)
|
||||
),
|
||||
array('service_description' => $serviceDescription),
|
||||
array('title' => sprintf(
|
||||
$this->translate('List all services with the name "%s" on all reported hosts'),
|
||||
$serviceDisplayName
|
||||
)),
|
||||
false
|
||||
); ?>
|
||||
</span>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
) ?></span></div></th>
|
||||
<?php endforeach ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $hasHeader = true; ?>
|
||||
<?php endif ?>
|
||||
<tr>
|
||||
<th>
|
||||
<?= $this->qlink(
|
||||
$host_name,
|
||||
'monitoring/list/services?' . $serviceFilter,
|
||||
array('host' => $host_name),
|
||||
array('title' => sprintf($this->translate('List all reported services on host %s'), $host_name))
|
||||
); ?>
|
||||
</th>
|
||||
<?php foreach (array_values($serviceStates) as $service): ?>
|
||||
<?php if ($service !== null): ?>
|
||||
<td>
|
||||
<span class="sr-only" id="<?= $service->host_name . '_' . $service->service_description . '_desc'; ?>">
|
||||
<?= $this->escape($service->service_output); ?>
|
||||
</span>
|
||||
<?= $this->qlink(
|
||||
'',
|
||||
'monitoring/show/service',
|
||||
array(
|
||||
'host' => $service->host_name,
|
||||
'service' => $service->service_description
|
||||
),
|
||||
array(
|
||||
'aria-describedby' => $service->host_name . '_' . $service->service_description . '_desc',
|
||||
'class' => 'state_' . Service::getStateText($service->service_state). ($service->service_handled ? ' handled' : ''),
|
||||
'title' => $this->escape($service->service_output),
|
||||
'aria-label' => sprintf(
|
||||
$this->translate('Show detailed information for service %s on host %s'),
|
||||
$service->service_description,
|
||||
$service->host_name
|
||||
)
|
||||
)
|
||||
); ?>
|
||||
</td>
|
||||
<?php else: ?>
|
||||
<td><span aria-hidden="true">·</span></td>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
<?php foreach ($pivotHeader['rows'] as $hostName => $hostDisplayName): ?>
|
||||
<tr>
|
||||
<th><?php
|
||||
$services = $pivotData[$hostName];
|
||||
$serviceFilter = '(service_description=' . implode('|service_description=', array_keys($services)) . ')';
|
||||
echo $this->qlink(
|
||||
$hostDisplayName,
|
||||
'monitoring/list/services?' . $serviceFilter,
|
||||
array('host_name' => $hostName),
|
||||
array('title' => sprintf($this->translate('List all reported services on host %s'), $hostDisplayName))
|
||||
);
|
||||
?></th>
|
||||
<?php foreach (array_keys($pivotHeader['cols']) as $serviceDescription): ?>
|
||||
<td>
|
||||
<?php
|
||||
$service = $pivotData[$hostName][$serviceDescription];
|
||||
if ($service === null): ?>
|
||||
<span aria-hidden="true">·</span>
|
||||
<?php continue; endif ?>
|
||||
<?php $ariaDescribedById = $this->protectId($service->host_name . '_' . $service->service_description . '_desc') ?>
|
||||
<span class="sr-only" id="<?= $ariaDescribedById ?>">
|
||||
<?= $this->escape($service->service_output) ?>
|
||||
</span>
|
||||
<?= $this->qlink(
|
||||
'',
|
||||
'monitoring/show/service',
|
||||
array(
|
||||
'host' => $hostName,
|
||||
'service' => $serviceDescription
|
||||
),
|
||||
array(
|
||||
'aria-describedby' => $ariaDescribedById,
|
||||
'class' => 'bg-state-' . Service::getStateText($service->service_state) . ($service->service_handled ? ' handled' : ''),
|
||||
'title' => $this->escape($service->service_output),
|
||||
'aria-label' => sprintf(
|
||||
$this->translate('Show detailed information for service %s on host %s'),
|
||||
$service->service_display_name,
|
||||
$service->host_display_name
|
||||
)
|
||||
)
|
||||
); ?>
|
||||
</td>
|
||||
<?php endforeach ?>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -5,6 +5,12 @@ $command = array_shift($parts);
|
||||
|
||||
?>
|
||||
|
||||
<?php if ($showInstance): ?>
|
||||
<tr class="newsection">
|
||||
<th><?= $this->translate('Instance'); ?></th>
|
||||
<td><?= $this->escape($object->instance_name); ?></td>
|
||||
</tr>
|
||||
<?php endif ?>
|
||||
<tr class="newsection">
|
||||
<th><?= $this->translate('Command'); ?></th>
|
||||
<td>
|
||||
|
@ -89,17 +89,34 @@ $this->provideSearchUrl($this->translate('Servicegroups'), 'monitoring/list/serv
|
||||
* Problems Section
|
||||
*/
|
||||
$section = $this->menuSection($this->translate('Problems'), array(
|
||||
'renderer' => 'Icinga\Module\Monitoring\Web\Menu\ProblemMenuItemRenderer',
|
||||
'renderer' => array(
|
||||
'SummaryMenuItemRenderer',
|
||||
'state' => 'critical'
|
||||
),
|
||||
'icon' => 'block',
|
||||
'priority' => 20
|
||||
));
|
||||
$section->add($this->translate('Unhandled Hosts'), array(
|
||||
'renderer' => 'Icinga\Module\Monitoring\Web\Menu\UnhandledHostMenuItemRenderer',
|
||||
'renderer' => array(
|
||||
'Icinga\Module\Monitoring\Web\Menu\MonitoringBadgeMenuItemRenderer',
|
||||
'columns' => array(
|
||||
'hosts_down_unhandled' => $this->translate('%d unhandled hosts down')
|
||||
),
|
||||
'state' => 'critical',
|
||||
'dataView' => 'statussummary'
|
||||
),
|
||||
'url' => 'monitoring/list/hosts?host_problem=1&host_handled=0',
|
||||
'priority' => 30
|
||||
));
|
||||
$section->add($this->translate('Unhandled Services'), array(
|
||||
'renderer' => 'Icinga\Module\Monitoring\Web\Menu\UnhandledServiceMenuItemRenderer',
|
||||
'renderer' => array(
|
||||
'Icinga\Module\Monitoring\Web\Menu\MonitoringBadgeMenuItemRenderer',
|
||||
'columns' => array(
|
||||
'services_critical_unhandled' => $this->translate('%d unhandled services critical')
|
||||
),
|
||||
'state' => 'critical',
|
||||
'dataView' => 'statussummary'
|
||||
),
|
||||
'url' => 'monitoring/list/services?service_problem=1&service_handled=0&sort=service_severity',
|
||||
'priority' => 40
|
||||
));
|
||||
@ -204,7 +221,7 @@ $section = $this->menuSection($this->translate('System'));
|
||||
$section->add($this->translate('Monitoring Health'), array(
|
||||
'url' => 'monitoring/process/info',
|
||||
'priority' => 720,
|
||||
'renderer' => 'Icinga\Module\Monitoring\Web\Menu\BackendAvailabilityMenuItemRenderer'
|
||||
'renderer' => 'Icinga\Module\Monitoring\Web\Menu\BackendAvailabilityMenuItemRenderer'
|
||||
));
|
||||
|
||||
/*
|
||||
@ -223,3 +240,9 @@ $dashboard->add(
|
||||
$this->translate('Host Problems'),
|
||||
'monitoring/list/hosts?host_problem=1&sort=host_severity'
|
||||
);
|
||||
|
||||
/*
|
||||
* CSS
|
||||
*/
|
||||
$this->provideCssFile('colors.less');
|
||||
$this->provideCssFile('service-grid.less');
|
||||
|
@ -25,7 +25,8 @@ class CommentQuery extends IdoQuery
|
||||
'comment_is_persistent' => 'c.comment_is_persistent',
|
||||
'comment_timestamp' => 'c.comment_timestamp',
|
||||
'comment_type' => 'c.comment_type',
|
||||
'object_type' => 'c.object_type'
|
||||
'object_type' => 'c.object_type',
|
||||
'instance_name' => 'c.instance_name'
|
||||
),
|
||||
'hosts' => array(
|
||||
'host_display_name' => 'c.host_display_name',
|
||||
@ -54,6 +55,20 @@ class CommentQuery extends IdoQuery
|
||||
*/
|
||||
protected $subQueries = array();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
foreach ($this->subQueries as $query) {
|
||||
if (! $query->allowsCustomVars()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -58,6 +58,20 @@ class CommentdeletionhistoryQuery extends IdoQuery
|
||||
*/
|
||||
protected $fetchHistoryColumns = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
foreach ($this->subQueries as $query) {
|
||||
if (! $query->allowsCustomVars()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -58,6 +58,20 @@ class CommenthistoryQuery extends IdoQuery
|
||||
*/
|
||||
protected $fetchHistoryColumns = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
foreach ($this->subQueries as $query) {
|
||||
if (! $query->allowsCustomVars()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,6 +17,9 @@ class ContactQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'contacts' => array(
|
||||
'contact_id' => 'c.contact_id',
|
||||
'contact' => 'co.name1 COLLATE latin1_general_ci',
|
||||
@ -183,6 +186,18 @@ class ContactQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = c.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,6 +17,9 @@ class ContactgroupQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'contactgroups' => array(
|
||||
'contactgroup' => 'cgo.name1 COLLATE latin1_general_ci',
|
||||
'contactgroup_name' => 'cgo.name1',
|
||||
@ -187,6 +190,18 @@ class ContactgroupQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = cg.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -6,7 +6,10 @@ namespace Icinga\Module\Monitoring\Backend\Ido\Query;
|
||||
class CustomvarQuery extends IdoQuery
|
||||
{
|
||||
protected $columnMap = array(
|
||||
'customvars' => array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'customvariablestatus' => array(
|
||||
'varname' => 'cvs.varname',
|
||||
'varvalue' => 'cvs.varvalue',
|
||||
'is_json' => 'cvs.is_json',
|
||||
@ -38,7 +41,7 @@ class CustomvarQuery extends IdoQuery
|
||||
protected function joinBaseTables()
|
||||
{
|
||||
if (version_compare($this->getIdoVersion(), '1.12.0', '<')) {
|
||||
$this->columnMap['customvars']['is_json'] = '(0)';
|
||||
$this->columnMap['customvariablestatus']['is_json'] = '(0)';
|
||||
}
|
||||
|
||||
$this->select->from(
|
||||
@ -50,8 +53,41 @@ class CustomvarQuery extends IdoQuery
|
||||
array()
|
||||
);
|
||||
$this->joinedVirtualTables = array(
|
||||
'customvars' => true,
|
||||
'objects' => true
|
||||
'customvariablestatus' => true,
|
||||
'objects' => true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = cvs.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getGroup()
|
||||
{
|
||||
$group = parent::getGroup();
|
||||
if (! empty($group) && $this->ds->getDbType() === 'pgsql') {
|
||||
foreach ($this->columnMap as $table => $columns) {
|
||||
$pk = ($table === 'objects' ? 'cvo.' : 'cvs.') . $this->getPrimaryKeyColumn($table);
|
||||
foreach ($columns as $alias => $_) {
|
||||
if (! in_array($pk, $group, true) && in_array($alias, $group, true)) {
|
||||
$group[] = $pk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,8 @@ class DowntimeQuery extends IdoQuery
|
||||
'downtime_scheduled_end' => 'd.downtime_scheduled_end',
|
||||
'downtime_scheduled_start' => 'd.downtime_scheduled_start',
|
||||
'downtime_start' => 'd.downtime_start',
|
||||
'object_type' => 'd.object_type'
|
||||
'object_type' => 'd.object_type',
|
||||
'instance_name' => 'd.instance_name'
|
||||
),
|
||||
'hosts' => array(
|
||||
'host_display_name' => 'd.host_display_name',
|
||||
@ -59,6 +60,20 @@ class DowntimeQuery extends IdoQuery
|
||||
*/
|
||||
protected $subQueries = array();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
foreach ($this->subQueries as $query) {
|
||||
if (! $query->allowsCustomVars()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -58,6 +58,20 @@ class DowntimeendhistoryQuery extends IdoQuery
|
||||
*/
|
||||
protected $fetchHistoryColumns = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
foreach ($this->subQueries as $query) {
|
||||
if (! $query->allowsCustomVars()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -58,6 +58,20 @@ class DowntimestarthistoryQuery extends IdoQuery
|
||||
*/
|
||||
protected $fetchHistoryColumns = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
foreach ($this->subQueries as $query) {
|
||||
if (! $query->allowsCustomVars()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -9,7 +9,7 @@ use Icinga\Data\Filter\Filter;
|
||||
/**
|
||||
* Query for event history records
|
||||
*/
|
||||
class EventHistoryQuery extends IdoQuery
|
||||
class EventhistoryQuery extends IdoQuery
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@ -75,6 +75,20 @@ class EventHistoryQuery extends IdoQuery
|
||||
$this->joinedVirtualTables['eventhistory'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
foreach ($this->subQueries as $query) {
|
||||
if (! $query->allowsCustomVars()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@ use Zend_Db_Select;
|
||||
/**
|
||||
* Query for host and service group summaries
|
||||
*/
|
||||
class GroupSummaryQuery extends IdoQuery
|
||||
class GroupsummaryQuery extends IdoQuery
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -17,6 +17,9 @@ class HostcommentQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'comments' => array(
|
||||
'comment_author' => 'c.author_name COLLATE latin1_general_ci',
|
||||
'comment_author_name' => 'c.author_name',
|
||||
@ -151,6 +154,18 @@ class HostcommentQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = c.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,6 +17,9 @@ class HostcommenthistoryQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'commenthistory' => array(
|
||||
'host' => 'ho.name1 COLLATE latin1_general_ci',
|
||||
'host_name' => 'ho.name1',
|
||||
@ -149,6 +152,18 @@ class HostcommenthistoryQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = hch.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,6 +17,9 @@ class HostdowntimeQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'downtimes' => array(
|
||||
'downtime_author' => 'sd.author_name COLLATE latin1_general_ci',
|
||||
'downtime_author_name' => 'sd.author_name',
|
||||
@ -157,6 +160,18 @@ class HostdowntimeQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = sd.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,6 +17,9 @@ class HostdowntimestarthistoryQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'downtimehistory' => array(
|
||||
'host' => 'ho.name1 COLLATE latin1_general_ci',
|
||||
'host_name' => 'ho.name1',
|
||||
@ -158,6 +161,18 @@ class HostdowntimestarthistoryQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = hdh.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,6 +17,9 @@ class HostgroupQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'hostgroups' => array(
|
||||
'hostgroup' => 'hgo.name1 COLLATE latin1_general_ci',
|
||||
'hostgroup_alias' => 'hg.alias COLLATE latin1_general_ci',
|
||||
@ -126,6 +129,18 @@ class HostgroupQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = hg.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -66,6 +66,20 @@ class HostgroupsummaryQuery extends IdoQuery
|
||||
*/
|
||||
protected $subQueries = array();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
foreach ($this->subQueries as $query) {
|
||||
if (! $query->allowsCustomVars()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,6 +17,9 @@ class HostnotificationQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'notifications' => array(
|
||||
'notification_output' => 'hn.output',
|
||||
'notification_start_time' => 'UNIX_TIMESTAMP(hn.start_time)',
|
||||
@ -224,6 +227,18 @@ class HostnotificationQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = hn.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -21,6 +21,9 @@ class HostserviceproblemsummaryQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'services' => array(
|
||||
'host_name' => 'so.name1',
|
||||
'service_description' => 'so.name2'
|
||||
@ -76,6 +79,18 @@ class HostserviceproblemsummaryQuery extends IdoQuery
|
||||
$this->joinedVirtualTables['services'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = so.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join host groups
|
||||
*/
|
||||
|
@ -27,6 +27,9 @@ class HoststatehistoryQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'statehistory' => array(
|
||||
'host' => 'ho.name1 COLLATE latin1_general_ci',
|
||||
'host_name' => 'ho.name1',
|
||||
@ -165,6 +168,18 @@ class HoststatehistoryQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = hh.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -16,6 +16,9 @@ class HoststatusQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'hostgroups' => array(
|
||||
'hostgroup' => 'hgo.name1 COLLATE latin1_general_ci',
|
||||
'hostgroup_alias' => 'hg.alias COLLATE latin1_general_ci',
|
||||
@ -237,67 +240,82 @@ class HoststatusQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = ho.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getGroup()
|
||||
{
|
||||
$group = array();
|
||||
if ($this->hasJoinedVirtualTable('hostgroups') || $this->hasJoinedVirtualTable('services')) {
|
||||
$group = array('h.host_id', 'ho.object_id');
|
||||
if ($this->hasJoinedVirtualTable('hoststatus')) {
|
||||
$group[] = 'hs.hoststatus_id';
|
||||
}
|
||||
|
||||
if ($this->hasJoinedVirtualTable('serviceproblemsummary')) {
|
||||
$group[] = 'sps.unhandled_services_count';
|
||||
}
|
||||
|
||||
if ($this->hasJoinedVirtualTable('hostgroups')) {
|
||||
$selected = false;
|
||||
foreach ($this->columns as $alias => $column) {
|
||||
if ($column instanceof Zend_Db_Expr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$table = $this->aliasToTableName(
|
||||
$this->hasAliasName($alias) ? $alias : $this->customAliasToAlias($alias)
|
||||
);
|
||||
if ($table === 'hostgroups') {
|
||||
$selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($selected) {
|
||||
$group[] = 'hg.hostgroup_id';
|
||||
$group[] = 'hgo.object_id';
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->hasJoinedVirtualTable('servicegroups')) {
|
||||
$selected = false;
|
||||
foreach ($this->columns as $alias => $column) {
|
||||
if ($column instanceof Zend_Db_Expr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$table = $this->aliasToTableName(
|
||||
$this->hasAliasName($alias) ? $alias : $this->customAliasToAlias($alias)
|
||||
);
|
||||
if ($table === 'servicegroups') {
|
||||
$selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($selected) {
|
||||
$group[] = 'sg.servicegroup_id';
|
||||
$group[] = 'sgo.object_id';
|
||||
}
|
||||
$group = parent::getGroup() ?: array();
|
||||
if (! is_array($group)) {
|
||||
$group = array($group);
|
||||
}
|
||||
$groupedTables = array();
|
||||
if ($this->hasJoinedVirtualTable('servicegroups')) {
|
||||
$serviceGroupColumns = array_keys($this->columnMap['servicegroups']);
|
||||
$selectedServiceGroupColumns = array_intersect($serviceGroupColumns, array_keys($this->columns));
|
||||
if (! empty($selectedServiceGroupColumns)) {
|
||||
$group[] = 'ho.object_id';
|
||||
$group[] = 'h.host_id';
|
||||
$group[] = 'sgo.object_id';
|
||||
$group[] = 'sg.servicegroup_id';
|
||||
$groupedTables['hosts'] = true;
|
||||
$groupedTables['servicegroups'] = true;
|
||||
}
|
||||
}
|
||||
if ($this->hasJoinedVirtualTable('hostgroups')) {
|
||||
$hostGroupColumns = array_keys($this->columnMap['hostgroups']);
|
||||
$selectedHostGroupColumns = array_intersect($hostGroupColumns, array_keys($this->columns));
|
||||
if (! empty($selectedHostGroupColumns)) {
|
||||
if (! isset($groupedTables['hosts'])) {
|
||||
$group[] = 'ho.object_id';
|
||||
$group[] = 'h.host_id';
|
||||
$groupedTables['hosts'] = true;
|
||||
}
|
||||
$group[] = 'hgo.object_id';
|
||||
$group[] = 'hg.hostgroup_id';
|
||||
$groupedTables['hostgroups'] = true;
|
||||
}
|
||||
}
|
||||
if (! empty($groupedTables)) {
|
||||
foreach ($this->columns as $alias => $column) {
|
||||
if ($column instanceof Zend_Db_Expr || $column === '(NULL)') {
|
||||
continue;
|
||||
}
|
||||
$tableName = $this->aliasToTableName(
|
||||
$this->hasAliasName($alias) ? $alias : $this->customAliasToAlias($alias)
|
||||
);
|
||||
if (isset($groupedTables[$tableName])) {
|
||||
continue;
|
||||
}
|
||||
switch ($tableName) {
|
||||
case 'hoststatus':
|
||||
$group[] = 'hs.hoststatus_id';
|
||||
break;
|
||||
case 'serviceproblemsummary':
|
||||
$group[] = 'sps.unhandled_services_count';
|
||||
break;
|
||||
case 'services':
|
||||
$group[] = 'so.object_id';
|
||||
$group[] = 's.service_id';
|
||||
break;
|
||||
default:
|
||||
continue 2;
|
||||
}
|
||||
$groupedTables[$tableName] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,14 @@ class HoststatussummaryQuery extends IdoQuery
|
||||
*/
|
||||
protected $subSelect;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
return $this->subSelect->allowsCustomVars();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -461,17 +461,23 @@ abstract class IdoQuery extends DbQuery
|
||||
if ($filter->getExpression() === '*') {
|
||||
return; // Wildcard only filters are ignored so stop early here to avoid joining a table for nothing
|
||||
}
|
||||
|
||||
$col = $filter->getColumn();
|
||||
$this->requireColumn($col);
|
||||
|
||||
if ($this->isCustomvar($col)) {
|
||||
$col = $this->getCustomvarColumnName($col);
|
||||
$alias = $filter->getColumn();
|
||||
$this->requireColumn($alias);
|
||||
if ($this->isCustomvar($alias)) {
|
||||
$column = $this->getCustomvarColumnName($alias);
|
||||
} else {
|
||||
$col = $this->aliasToColumnName($col);
|
||||
$column = $this->aliasToColumnName($alias);
|
||||
}
|
||||
if (isset($this->columnsWithoutCollation[$alias])) {
|
||||
$expression = $filter->getExpression();
|
||||
if (is_array($expression)) {
|
||||
$filter->setExpression(array_map('strtolower', $expression));
|
||||
} else {
|
||||
$filter->setExpression(strtolower($expression));
|
||||
|
||||
$filter->setColumn($col);
|
||||
}
|
||||
}
|
||||
$filter->setColumn($column);
|
||||
} else {
|
||||
foreach ($filter->filters() as $filter) {
|
||||
$this->requireFilterColumns($filter);
|
||||
@ -479,54 +485,21 @@ abstract class IdoQuery extends DbQuery
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addFilter(Filter $filter)
|
||||
{
|
||||
$filter = clone $filter;
|
||||
$this->requireFilterColumns($filter);
|
||||
return parent::addFilter($filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recurse the given filter and ensure that any string conversion is case-insensitive
|
||||
*
|
||||
* @param Filter $filter
|
||||
*/
|
||||
protected function lowerColumnsWithoutCollation(Filter $filter)
|
||||
{
|
||||
if ($filter instanceof FilterExpression) {
|
||||
if (
|
||||
in_array($filter->getColumn(), $this->columnsWithoutCollation)
|
||||
&& strpos($filter->getColumn(), 'LOWER') !== 0
|
||||
) {
|
||||
$filter->setColumn('LOWER(' . $filter->getColumn() . ')');
|
||||
$expression = $filter->getExpression();
|
||||
if (is_array($expression)) {
|
||||
$filter->setExpression(array_map('strtolower', $expression));
|
||||
} else {
|
||||
$filter->setExpression(strtolower($expression));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($filter->filters() as $chainedFilter) {
|
||||
$this->lowerColumnsWithoutCollation($chainedFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyFilterSql($select)
|
||||
{
|
||||
if (! empty($this->columnsWithoutCollation)) {
|
||||
$this->lowerColumnsWithoutCollation($this->filter);
|
||||
}
|
||||
|
||||
parent::applyFilterSql($select);
|
||||
}
|
||||
|
||||
public function where($condition, $value = null)
|
||||
{
|
||||
if ($value === '*') {
|
||||
return $this; // Wildcard only filters are ignored so stop early here to avoid joining a table for nothing
|
||||
}
|
||||
|
||||
$this->requireColumn($condition);
|
||||
$col = $this->getMappedField($condition);
|
||||
if ($col === null) {
|
||||
@ -553,6 +526,30 @@ abstract class IdoQuery extends DbQuery
|
||||
return stripos($mapped, 'UNIX_TIMESTAMP') !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given alias or column name provides case insensitive value comparison
|
||||
*
|
||||
* @param string $aliasOrColumn
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isCaseInsensitive($aliasOrColumn)
|
||||
{
|
||||
if ($this->isCustomVar($aliasOrColumn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$column = $this->getMappedField($aliasOrColumn) ?: $aliasOrColumn;
|
||||
if (! $column) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! empty($this->columnsWithoutCollation)) {
|
||||
return in_array($column, $this->columnsWithoutCollation) || strpos($column, 'LOWER') !== 0;
|
||||
}
|
||||
return preg_match('/ COLLATE .+$/', $column) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply oracle specific query initialization
|
||||
*/
|
||||
@ -574,27 +571,27 @@ abstract class IdoQuery extends DbQuery
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply postgresql specific query initialization
|
||||
* Apply PostgreSQL specific query initialization
|
||||
*/
|
||||
private function initializeForPostgres()
|
||||
{
|
||||
$this->customVarsJoinTemplate =
|
||||
'%1$s = %2$s.object_id AND LOWER(%2$s.varname) = %3$s';
|
||||
foreach ($this->columnMap as $table => & $columns) {
|
||||
foreach ($columns as $key => & $value) {
|
||||
$value = preg_replace('/ COLLATE .+$/', '', $value, -1, $count);
|
||||
if ($count > 0) {
|
||||
$this->columnsWithoutCollation[] = $this->getMappedField($key);
|
||||
foreach ($this->columnMap as $table => &$columns) {
|
||||
foreach ($columns as $alias => &$column) {
|
||||
if (false !== $pos = strpos($column, ' COLLATE')) {
|
||||
$column = 'LOWER(' . substr($column, 0, $pos) . ')';
|
||||
$this->columnsWithoutCollation[$alias] = true;
|
||||
}
|
||||
$value = preg_replace(
|
||||
$column = preg_replace(
|
||||
'/inet_aton\(([[:word:].]+)\)/i',
|
||||
'(CASE WHEN $1 ~ \'(?:[0-9]{1,3}\\\\.){3}[0-9]{1,3}\' THEN $1::inet - \'0.0.0.0\' ELSE NULL END)',
|
||||
$value
|
||||
$column
|
||||
);
|
||||
$value = preg_replace(
|
||||
$column = preg_replace(
|
||||
'/UNIX_TIMESTAMP(\((?>[^()]|(?-1))*\))/i',
|
||||
'CASE WHEN ($1 < \'1970-01-03 00:00:00+00\'::timestamp with time zone) THEN 0 ELSE UNIX_TIMESTAMP($1) END',
|
||||
$value
|
||||
$column
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -795,6 +792,16 @@ abstract class IdoQuery extends DbQuery
|
||||
return isset($this->idxAliasTable[$alias]) ? $this->idxAliasTable[$alias] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this query allows to join custom variables
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
return $this->allowCustomVars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given alias denotes a custom variable
|
||||
*
|
||||
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
|
||||
|
||||
class InstanceQuery extends IdoQuery
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_id' => 'i.instance_id',
|
||||
'instance_name' => 'i.instance_name'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function joinBaseTables()
|
||||
{
|
||||
$this->select()->from(array('i' => $this->prefix . 'instances'), array());
|
||||
$this->joinedVirtualTables['instances'] = true;
|
||||
}
|
||||
}
|
@ -26,7 +26,8 @@ class NotificationQuery extends IdoQuery
|
||||
'acknowledgement_entry_time' => 'n.acknowledgement_entry_time',
|
||||
'acknowledgement_author_name' => 'n.acknowledgement_author_name',
|
||||
'acknowledgement_comment_data' => 'n.acknowledgement_comment_data',
|
||||
'object_type' => 'n.object_type'
|
||||
'object_type' => 'n.object_type',
|
||||
'instance_name' => 'n.instance_name'
|
||||
),
|
||||
'history' => array(
|
||||
'type' => 'n.type',
|
||||
@ -128,6 +129,20 @@ class NotificationQuery extends IdoQuery
|
||||
$this->notificationQuery->union(array($services), Zend_Db_Select::SQL_UNION_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
foreach ($this->subQueries as $query) {
|
||||
if (! $query->allowsCustomVars()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -4,10 +4,13 @@
|
||||
namespace Icinga\Module\Monitoring\Backend\Ido\Query;
|
||||
|
||||
/**
|
||||
* Query program status out of database
|
||||
* Program status query
|
||||
*/
|
||||
class ProgramstatusQuery extends IdoQuery
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'programstatus' => array(
|
||||
'id' => 'programstatus_id',
|
||||
@ -15,16 +18,11 @@ class ProgramstatusQuery extends IdoQuery
|
||||
'program_version' => 'program_version',
|
||||
'program_start_time' => 'UNIX_TIMESTAMP(programstatus.program_start_time)',
|
||||
'program_end_time' => 'UNIX_TIMESTAMP(programstatus.program_end_time)',
|
||||
'is_currently_running' => 'CASE WHEN (programstatus.is_currently_running = 0)
|
||||
'is_currently_running' => 'CASE WHEN (UNIX_TIMESTAMP(programstatus.status_update_time) + 60 > UNIX_TIMESTAMP(NOW()))
|
||||
THEN
|
||||
0
|
||||
1
|
||||
ELSE
|
||||
CASE WHEN (UNIX_TIMESTAMP(programstatus.status_update_time) + 60 > UNIX_TIMESTAMP(NOW()))
|
||||
THEN
|
||||
1
|
||||
ELSE
|
||||
0
|
||||
END
|
||||
0
|
||||
END',
|
||||
'process_id' => 'process_id',
|
||||
'endpoint_name' => 'endpoint_name',
|
||||
@ -50,6 +48,9 @@ class ProgramstatusQuery extends IdoQuery
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function joinBaseTables()
|
||||
{
|
||||
parent::joinBaseTables();
|
||||
|
@ -17,6 +17,9 @@ class ServicecommentQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'comments' => array(
|
||||
'comment_author' => 'c.author_name COLLATE latin1_general_ci',
|
||||
'comment_author_name' => 'c.author_name',
|
||||
@ -165,6 +168,18 @@ class ServicecommentQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = c.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,6 +17,9 @@ class ServicecommenthistoryQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'commenthistory' => array(
|
||||
'host' => 'so.name1 COLLATE latin1_general_ci',
|
||||
'host_name' => 'so.name1',
|
||||
@ -147,6 +150,18 @@ class ServicecommenthistoryQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = sch.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,6 +17,9 @@ class ServicedowntimeQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'downtimes' => array(
|
||||
'downtime_author' => 'sd.author_name COLLATE latin1_general_ci',
|
||||
'downtime_author_name' => 'sd.author_name',
|
||||
@ -171,6 +174,18 @@ class ServicedowntimeQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = sd.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,6 +17,9 @@ class ServicedowntimestarthistoryQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'downtimehistory' => array(
|
||||
'host' => 'so.name1 COLLATE latin1_general_ci',
|
||||
'host_name' => 'so.name1',
|
||||
@ -156,6 +159,18 @@ class ServicedowntimestarthistoryQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = sdh.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -14,6 +14,9 @@ class ServicegroupQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'hostgroups' => array(
|
||||
'hostgroup' => 'hgo.name1 COLLATE latin1_general_ci',
|
||||
'hostgroup_alias' => 'hg.alias COLLATE latin1_general_ci',
|
||||
@ -118,6 +121,18 @@ class ServicegroupQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = sg.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -58,6 +58,20 @@ class ServicegroupsummaryQuery extends IdoQuery
|
||||
*/
|
||||
protected $subQueries = array();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allowsCustomVars()
|
||||
{
|
||||
foreach ($this->subQueries as $query) {
|
||||
if (! $query->allowsCustomVars()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,6 +17,9 @@ class ServicenotificationQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'notifications' => array(
|
||||
'notification_output' => 'sn.output',
|
||||
'notification_start_time' => 'UNIX_TIMESTAMP(sn.start_time)',
|
||||
@ -222,6 +225,18 @@ class ServicenotificationQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = sn.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -27,6 +27,9 @@ class ServicestatehistoryQuery extends IdoQuery
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnMap = array(
|
||||
'instances' => array(
|
||||
'instance_name' => 'i.instance_name'
|
||||
),
|
||||
'statehistory' => array(
|
||||
'host' => 'so.name1 COLLATE latin1_general_ci',
|
||||
'host_name' => 'so.name1',
|
||||
@ -163,6 +166,18 @@ class ServicestatehistoryQuery extends IdoQuery
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join instances
|
||||
*/
|
||||
protected function joinInstances()
|
||||
{
|
||||
$this->select->join(
|
||||
array('i' => $this->prefix . 'instances'),
|
||||
'i.instance_id = sh.instance_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user