Merge branch 'master' into feature/custom-menu-items-5600
Conflicts: modules/monitoring/application/views/scripts/list/comments.phtml modules/monitoring/application/views/scripts/list/downtimes.phtml
This commit is contained in:
commit
a55cced039
|
@ -33,7 +33,23 @@ class DbResourceForm extends Form
|
|||
if (Platform::hasPostgresqlSupport()) {
|
||||
$dbChoices['pgsql'] = 'PostgreSQL';
|
||||
}
|
||||
|
||||
if (Platform::hasMssqlSupport()) {
|
||||
$dbChoices['mssql'] = 'MSSQL';
|
||||
}
|
||||
if (Platform::hasOracleSupport()) {
|
||||
$dbChoices['oracle'] = 'Oracle';
|
||||
}
|
||||
if (Platform::hasOciSupport()) {
|
||||
$dbChoices['oci'] = 'Oracle (OCI8)';
|
||||
}
|
||||
$offerPostgres = false;
|
||||
if (isset($formData['db'])) {
|
||||
if ($formData['db'] === 'pgsql') {
|
||||
$offerPostgres = true;
|
||||
}
|
||||
} elseif (key($dbChoices) === 'pgsql') {
|
||||
$offerPostgres = true;
|
||||
}
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
|
@ -68,11 +84,11 @@ class DbResourceForm extends Form
|
|||
'number',
|
||||
'port',
|
||||
array(
|
||||
'required' => true,
|
||||
'preserveDefault' => true,
|
||||
'label' => $this->translate('Port'),
|
||||
'description' => $this->translate('The port to use'),
|
||||
'value' => ! array_key_exists('db', $formData) || $formData['db'] === 'mysql' ? 3306 : 5432
|
||||
'label' => $this->translate('Port'),
|
||||
'preserveDefault' => true,
|
||||
'required' => $offerPostgres,
|
||||
'value' => $offerPostgres ? 5432 : null
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -103,6 +119,17 @@ class DbResourceForm extends Form
|
|||
'description' => $this->translate('The password to use for authentication')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'persistent',
|
||||
array(
|
||||
'description' => $this->translate(
|
||||
'Check this box for persistent database connections. Persistent connections are not closed at the'
|
||||
. ' end of a request, but are cached and re-used. This is experimental'
|
||||
),
|
||||
'label' => $this->translate('Persistent')
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
@ -236,10 +236,10 @@ class ResourceConfigForm extends ConfigForm
|
|||
'livestatus' => 'Livestatus',
|
||||
'ssh' => $this->translate('SSH Identity'),
|
||||
);
|
||||
if ($resourceType === 'ldap' || Platform::extensionLoaded('ldap')) {
|
||||
if ($resourceType === 'ldap' || Platform::hasLdapSupport()) {
|
||||
$resourceTypes['ldap'] = 'LDAP';
|
||||
}
|
||||
if ($resourceType === 'db' || Platform::hasMysqlSupport() || Platform::hasPostgresqlSupport()) {
|
||||
if ($resourceType === 'db' || Platform::hasDatabaseSupport()) {
|
||||
$resourceTypes['db'] = $this->translate('SQL Database');
|
||||
}
|
||||
|
||||
|
|
|
@ -53,20 +53,6 @@ class DbBackendForm extends Form
|
|||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -32,20 +32,6 @@ class ExternalBackendForm extends Form
|
|||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The backend name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -57,20 +57,6 @@ class LdapBackendForm extends Form
|
|||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others.'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -34,20 +34,6 @@ class DbUserGroupBackendForm extends Form
|
|||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this user group backend that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -39,20 +39,6 @@ class LdapUserGroupBackendForm extends Form
|
|||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this user group backend that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -77,21 +77,7 @@ class DashletForm extends Form
|
|||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Dashlet Title'),
|
||||
'description' => $this->translate('Enter a title for the dashlet.'),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\' or \']\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
'description' => $this->translate('Enter a title for the dashlet.')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
|
|
@ -12,6 +12,7 @@ use Icinga\Data\ConfigObject;
|
|||
use Icinga\Data\Selectable;
|
||||
use Icinga\Data\SimpleQuery;
|
||||
use Icinga\File\Ini\IniWriter;
|
||||
use Icinga\File\Ini\IniParser;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
|
||||
/**
|
||||
|
@ -313,9 +314,7 @@ class Config implements Countable, Iterator, Selectable
|
|||
if ($filepath === false) {
|
||||
$emptyConfig->setConfigFile($file);
|
||||
} elseif (is_readable($filepath)) {
|
||||
$config = new static(new ConfigObject(parse_ini_file($filepath, true)));
|
||||
$config->setConfigFile($filepath);
|
||||
return $config;
|
||||
return IniParser::parseIniFile($filepath);
|
||||
} elseif (@file_exists($filepath)) {
|
||||
throw new NotReadableError(t('Cannot read config file "%s". Permission denied'), $filepath);
|
||||
}
|
||||
|
|
|
@ -318,6 +318,41 @@ class Platform
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a LDAP server
|
||||
*
|
||||
* Checks whether the ldap extension is loaded
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasLdapSupport()
|
||||
{
|
||||
return static::extensionLoaded('ldap');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to any of the supported database servers
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasDatabaseSupport()
|
||||
{
|
||||
return static::hasMssqlSupport() || static::hasMysqlSupport() || static::hasOciSupport()
|
||||
|| static::hasOracleSupport() || static::hasPostgresqlSupport();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a MSSQL database
|
||||
*
|
||||
* Checks whether the mssql pdo extension has been loaded and Zend framework adapter for MSSQL is available
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasMssqlSupport()
|
||||
{
|
||||
return static::extensionLoaded('mssql') && static::classExists('Zend_Db_Adapter_Pdo_Mssql');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a MySQL database
|
||||
*
|
||||
|
@ -330,6 +365,30 @@ class Platform
|
|||
return static::extensionLoaded('mysql') && static::classExists('Zend_Db_Adapter_Pdo_Mysql');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a Oracle database using OCI8
|
||||
*
|
||||
* Checks whether the OCI8 extension has been loaded and the Zend framework adapter for Oracle is available
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasOciSupport()
|
||||
{
|
||||
return static::extensionLoaded('oci8') && static::classExists('Zend_Db_Adapter_Oracle');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a Oracle database using PDO_OCI
|
||||
*
|
||||
* Checks whether the OCI PDO extension has been loaded and the Zend framework adapter for Oci is available
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasOracleSupport()
|
||||
{
|
||||
return static::extensionLoaded('pdo_oci') && static::classExists('Zend_Db_Adapter_Pdo_Mysql');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether it's possible to connect to a PostgreSQL database
|
||||
*
|
||||
|
|
|
@ -364,7 +364,12 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
|
|||
return false;
|
||||
}
|
||||
|
||||
return $this->ds->testCredentials($userDn, $password);
|
||||
$testCredentialsResult = $this->ds->testCredentials($userDn, $password);
|
||||
if ($testCredentialsResult) {
|
||||
$user->setAdditional('ldap_dn', $userDn);
|
||||
}
|
||||
|
||||
return $testCredentialsResult;
|
||||
} catch (LdapException $e) {
|
||||
throw new AuthenticationException(
|
||||
'Failed to authenticate user "%s" against backend "%s". An exception was thrown:',
|
||||
|
|
|
@ -12,6 +12,7 @@ use Icinga\Protocol\Ldap\Expression;
|
|||
use Icinga\Repository\LdapRepository;
|
||||
use Icinga\Repository\RepositoryQuery;
|
||||
use Icinga\User;
|
||||
use Icinga\Application\Logger;
|
||||
|
||||
class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBackendInterface
|
||||
{
|
||||
|
@ -532,18 +533,26 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||
*/
|
||||
public function getMemberships(User $user)
|
||||
{
|
||||
$userQuery = $this->ds
|
||||
->select()
|
||||
->from($this->userClass)
|
||||
->where($this->userNameAttribute, $user->getUsername())
|
||||
->setBase($this->userBaseDn)
|
||||
->setUsePagedResults(false);
|
||||
if ($this->userFilter) {
|
||||
$userQuery->where(new Expression($this->userFilter));
|
||||
}
|
||||
if ($this->groupClass === 'posixGroup') {
|
||||
// Posix group only uses simple user name
|
||||
$userDn = $user->getUsername();
|
||||
} else {
|
||||
// LDAP groups use the complete DN
|
||||
if (($userDn = $user->getAdditional('ldap_dn')) === null) {
|
||||
$userQuery = $this->ds
|
||||
->select()
|
||||
->from($this->userClass)
|
||||
->where($this->userNameAttribute, $user->getUsername())
|
||||
->setBase($this->userBaseDn)
|
||||
->setUsePagedResults(false);
|
||||
if ($this->userFilter) {
|
||||
$userQuery->where(new Expression($this->userFilter));
|
||||
}
|
||||
|
||||
if (($userDn = $userQuery->fetchDn()) === null) {
|
||||
return array();
|
||||
if (($userDn = $userQuery->fetchDn()) === null) {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$groupQuery = $this->ds
|
||||
|
@ -555,10 +564,12 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||
$groupQuery->where(new Expression($this->groupFilter));
|
||||
}
|
||||
|
||||
Logger::debug('Fetching groups for user %s using filter %s.', $user->getUsername(), $groupQuery->__toString());
|
||||
$groups = array();
|
||||
foreach ($groupQuery as $row) {
|
||||
$groups[] = $row->{$this->groupNameAttribute};
|
||||
}
|
||||
Logger::debug('Fetched %d groups: %s.', count($groups), join(', ', $groups));
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
|
|
@ -62,8 +62,7 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp
|
|||
private static $driverOptions = array(
|
||||
PDO::ATTR_TIMEOUT => 10,
|
||||
PDO::ATTR_CASE => PDO::CASE_LOWER,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
// TODO: allow configurable PDO::ATTR_PERSISTENT => true
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -131,11 +130,16 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp
|
|||
'username' => $this->config->username,
|
||||
'password' => $this->config->password,
|
||||
'dbname' => $this->config->dbname,
|
||||
'persistent' => (bool) $this->config->get('persistent', false),
|
||||
'options' => & $genericAdapterOptions,
|
||||
'driver_options' => & $driverOptions
|
||||
);
|
||||
$this->dbType = strtolower($this->config->get('db', 'mysql'));
|
||||
switch ($this->dbType) {
|
||||
case 'mssql':
|
||||
$adapter = 'Pdo_Mssql';
|
||||
$adapterParamaters['pdoType'] = $this->config->get('pdoType', 'dblib');
|
||||
break;
|
||||
case 'mysql':
|
||||
$adapter = 'Pdo_Mysql';
|
||||
/*
|
||||
|
@ -150,19 +154,21 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp
|
|||
. 'NO_AUTO_CREATE_USER,ANSI_QUOTES,PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION\';';
|
||||
$adapterParamaters['port'] = $this->config->get('port', 3306);
|
||||
break;
|
||||
case 'oci':
|
||||
$adapter = 'Oracle';
|
||||
unset($adapterParamaters['options']);
|
||||
unset($adapterParamaters['driver_options']);
|
||||
$adapterParamaters['driver_options'] = array(
|
||||
'lob_as_string' => true
|
||||
);
|
||||
break;
|
||||
case 'oracle':
|
||||
$adapter = 'Pdo_Oci';
|
||||
break;
|
||||
case 'pgsql':
|
||||
$adapter = 'Pdo_Pgsql';
|
||||
$adapterParamaters['port'] = $this->config->get('port', 5432);
|
||||
break;
|
||||
/*case 'oracle':
|
||||
if ($this->dbtype === 'oracle') {
|
||||
$attributes['persistent'] = true;
|
||||
}
|
||||
$this->db = ZfDb::factory($adapter, $attributes);
|
||||
if ($adapter === 'Oracle') {
|
||||
$this->db->setLobAsString(false);
|
||||
}
|
||||
break;*/
|
||||
default:
|
||||
throw new ConfigurationError(
|
||||
'Backend "%s" is not supported',
|
||||
|
|
|
@ -115,4 +115,18 @@ class Document
|
|||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert $this to an array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$a = array();
|
||||
foreach ($this->sections as $section) {
|
||||
$a[$section->getName()] = $section->toArray();
|
||||
}
|
||||
return $a;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,4 +169,18 @@ class Section
|
|||
$str = str_replace(';', '\\;', $str);
|
||||
return str_replace(PHP_EOL, ' ', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert $this to an array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$a = array();
|
||||
foreach ($this->directives as $directive) {
|
||||
$a[$directive->getKey()] = $directive->getValue();
|
||||
}
|
||||
return $a;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ use Icinga\File\Ini\Dom\Document;
|
|||
use Icinga\File\Ini\Dom\Directive;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
use Icinga\Application\Config;
|
||||
|
||||
class IniParser
|
||||
{
|
||||
|
@ -239,4 +241,25 @@ class IniParser
|
|||
}
|
||||
return $doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the ini file and parse it with ::parseIni()
|
||||
*
|
||||
* @param string $file The ini file to read
|
||||
*
|
||||
* @return Config
|
||||
* @throws NotReadableError When the file cannot be read
|
||||
*/
|
||||
public static function parseIniFile($file)
|
||||
{
|
||||
if (($path = realpath($file)) === false) {
|
||||
throw new NotReadableError('Couldn\'t compute the absolute path of `%s\'', $file);
|
||||
}
|
||||
|
||||
if (($content = file_get_contents($path)) === false) {
|
||||
throw new NotReadableError('Couldn\'t read the file `%s\'', $path);
|
||||
}
|
||||
|
||||
return Config::fromArray(self::parseIni($content)->toArray())->setConfigFile($file);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -667,17 +667,20 @@ class LdapConnection implements Selectable, Inspectable
|
|||
$ds = $this->getConnection();
|
||||
|
||||
$serverSorting = $this->getCapabilities()->hasOid(LdapCapabilities::LDAP_SERVER_SORT_OID);
|
||||
if ($serverSorting && $query->hasOrder()) {
|
||||
ldap_set_option($ds, LDAP_OPT_SERVER_CONTROLS, array(
|
||||
array(
|
||||
'oid' => LdapCapabilities::LDAP_SERVER_SORT_OID,
|
||||
'value' => $this->encodeSortRules($query->getOrder())
|
||||
)
|
||||
));
|
||||
} elseif ($query->hasOrder()) {
|
||||
foreach ($query->getOrder() as $rule) {
|
||||
if (! in_array($rule[0], $fields)) {
|
||||
$fields[] = $rule[0];
|
||||
|
||||
if ($query->hasOrder()) {
|
||||
if ($serverSorting) {
|
||||
ldap_set_option($ds, LDAP_OPT_SERVER_CONTROLS, array(
|
||||
array(
|
||||
'oid' => LdapCapabilities::LDAP_SERVER_SORT_OID,
|
||||
'value' => $this->encodeSortRules($query->getOrder())
|
||||
)
|
||||
));
|
||||
} else {
|
||||
foreach ($query->getOrder() as $rule) {
|
||||
if (! in_array($rule[0], $fields)) {
|
||||
$fields[] = $rule[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -778,7 +781,7 @@ class LdapConnection implements Selectable, Inspectable
|
|||
// server to return results even if the paged search request cannot be satisfied
|
||||
ldap_control_paged_result($ds, $pageSize, false, $cookie);
|
||||
|
||||
if ($serverSorting) {
|
||||
if ($serverSorting && $query->hasOrder()) {
|
||||
ldap_set_option($ds, LDAP_OPT_SERVER_CONTROLS, array(
|
||||
array(
|
||||
'oid' => LdapCapabilities::LDAP_SERVER_SORT_OID,
|
||||
|
|
|
@ -8,6 +8,7 @@ use Icinga\Exception\NotReadableError;
|
|||
use Icinga\Exception\NotWritableError;
|
||||
use Icinga\User\Preferences;
|
||||
use Icinga\User\Preferences\PreferencesStore;
|
||||
use Icinga\File\Ini\IniParser;
|
||||
|
||||
/**
|
||||
* Load and save user preferences from and to INI files
|
||||
|
@ -57,7 +58,7 @@ class IniStore extends PreferencesStore
|
|||
$this->getUser()->getUsername()
|
||||
);
|
||||
} else {
|
||||
$this->preferences = parse_ini_file($this->preferencesFile, true);
|
||||
$this->preferences = IniParser::parseIniFile($this->preferencesFile)->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -134,8 +134,8 @@ class Number extends FormElement
|
|||
{
|
||||
$this->setValue($value);
|
||||
$value = $this->getValue();
|
||||
if (! is_numeric($value)) {
|
||||
$this->addError(sprintf($this->translate('\'%s\' is not a valid number'), $value));
|
||||
if ($value !== '' && ! is_numeric($value)) {
|
||||
$this->addError(sprintf(t('\'%s\' is not a valid number'), $value));
|
||||
return false;
|
||||
}
|
||||
return parent::isValid($value, $context);
|
||||
|
|
|
@ -57,7 +57,9 @@ class AlertsummaryController extends Controller
|
|||
$this->view->title = $this->translate('Alert Summary');
|
||||
|
||||
$this->view->intervalBox = $this->createIntervalBox();
|
||||
$this->view->recentAlerts = $this->createRecentAlerts();
|
||||
list($recentAlerts, $recentAlertsUrl) = $this->createRecentAlerts();
|
||||
$this->view->recentAlerts = $recentAlerts;
|
||||
$this->view->recentAlertsUrl = $recentAlertsUrl;
|
||||
$this->view->interval = $this->getInterval();
|
||||
$this->view->defectChart = $this->createDefectImage();
|
||||
$this->view->healingChart = $this->createHealingChart();
|
||||
|
@ -80,6 +82,7 @@ class AlertsummaryController extends Controller
|
|||
);
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->view->notifications = $query;
|
||||
$this->view->notificationsUrl = 'monitoring/list/notifications';
|
||||
|
||||
$this->setupLimitControl();
|
||||
$this->setupPaginationControl($this->view->notifications);
|
||||
|
@ -487,7 +490,7 @@ class AlertsummaryController extends Controller
|
|||
/**
|
||||
* Top recent alerts
|
||||
*
|
||||
* @return mixed
|
||||
* @return array
|
||||
*/
|
||||
private function createRecentAlerts()
|
||||
{
|
||||
|
@ -508,7 +511,10 @@ class AlertsummaryController extends Controller
|
|||
|
||||
$query->order('notification_start_time', 'desc');
|
||||
|
||||
return $query->limit(5);
|
||||
return array(
|
||||
$query->limit(5),
|
||||
'monitoring/list/notifications?sort=notification_start_time&dir=desc'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -193,20 +193,6 @@ class BackendConfigForm extends ConfigForm
|
|||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this monitoring backend that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -217,20 +217,6 @@ class TransportConfigForm extends ConfigForm
|
|||
'label' => $this->translate('Transport Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this command transport that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -59,8 +59,9 @@
|
|||
<div class="alertsummary-flex-container">
|
||||
<div class="alertsummary-flex">
|
||||
<?= $this->partial('list/notifications.phtml', array(
|
||||
'notifications' => $this->recentAlerts,
|
||||
'compact' => true
|
||||
'notifications' => $this->recentAlerts,
|
||||
'compact' => true,
|
||||
'notificationsUrl' => $recentAlertsUrl
|
||||
)); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -70,8 +71,9 @@
|
|||
<div class="alertsummary-flex-container">
|
||||
<div class="alertsummary-flex">
|
||||
<?= $this->partial('list/notifications.phtml', array(
|
||||
'notifications' => $this->notifications,
|
||||
'compact' => true
|
||||
'notifications' => $this->notifications,
|
||||
'compact' => true,
|
||||
'notificationsUrl' => $notificationsUrl
|
||||
)); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<table data-base-target="_next"
|
||||
class="action comments multiselect"
|
||||
data-icinga-multiselect-url="<?= $this->href('monitoring/comments/show'); ?>"
|
||||
data-icinga-multiselect-related="<?= $this->href("monitoring/comments") ?>"
|
||||
data-icinga-multiselect-data="comment_id">
|
||||
<tbody>
|
||||
<?php foreach ($comments->peekAhead($this->compact) as $comment): ?>
|
||||
|
@ -46,7 +47,8 @@
|
|||
'title' => sprintf(
|
||||
$this->translate('Show detailed information for this comment about host %s'),
|
||||
$comment->host_display_name
|
||||
)
|
||||
),
|
||||
'class' => 'rowaction'
|
||||
)
|
||||
); ?>
|
||||
<?php endif ?>
|
||||
|
|
|
@ -21,6 +21,7 @@ if (! $this->compact): ?>
|
|||
<table data-base-target="_next"
|
||||
class="action multiselect"
|
||||
data-icinga-multiselect-url="<?= $this->href('monitoring/downtimes/show'); ?>"
|
||||
data-icinga-multiselect-controllers="<?= $this->href("monitoring/downtimes") ?>"
|
||||
data-icinga-multiselect-data="downtime_id">
|
||||
<tbody>
|
||||
<?php foreach ($downtimes as $downtime): ?>
|
||||
|
|
|
@ -23,6 +23,7 @@ if (! $this->compact): ?>
|
|||
data-base-target="_next"
|
||||
class="action multiselect"
|
||||
data-icinga-multiselect-url="<?= $this->href('monitoring/hosts/show') ?>"
|
||||
data-icinga-multiselect-controllers="<?= $this->href("monitoring/hosts") ?>"
|
||||
data-icinga-multiselect-data="host"
|
||||
>
|
||||
<tbody>
|
||||
|
|
|
@ -72,7 +72,7 @@ if (! $this->compact): ?>
|
|||
<?php elseif ($notifications->hasMore()): ?>
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url()->without(array('view', 'limit')),
|
||||
$this->url(isset($notificationsUrl) ? $notificationsUrl : null)->without(array('view', 'limit')),
|
||||
null,
|
||||
array(
|
||||
'data-base-target' => '_next',
|
||||
|
|
|
@ -24,6 +24,7 @@ if (! $this->compact): ?>
|
|||
<table data-base-target="_next"
|
||||
class="action multiselect <?php if ($this->compact): ?> compact<?php endif ?>" style="table-layout: auto;"
|
||||
data-icinga-multiselect-url="<?= $this->href("monitoring/services/show") ?>"
|
||||
data-icinga-multiselect-controllers="<?= $this->href("monitoring/services") ?>"
|
||||
data-icinga-multiselect-data="service,host">
|
||||
<tbody>
|
||||
<?php foreach ($services as $service):
|
||||
|
|
|
@ -181,6 +181,10 @@ class HostcommentQuery extends IdoQuery
|
|||
if ($this->hasJoinedVirtualTable('hoststatus')) {
|
||||
$group[] = 'hs.hoststatus_id';
|
||||
}
|
||||
|
||||
if ($this->hasJoinedVirtualTable('instances')) {
|
||||
$group[] = 'i.instance_id';
|
||||
}
|
||||
}
|
||||
|
||||
return $group;
|
||||
|
|
|
@ -187,6 +187,10 @@ class HostdowntimeQuery extends IdoQuery
|
|||
if ($this->hasJoinedVirtualTable('hoststatus')) {
|
||||
$group[] = 'hs.hoststatus_id';
|
||||
}
|
||||
|
||||
if ($this->hasJoinedVirtualTable('instances')) {
|
||||
$group[] = 'i.instance_id';
|
||||
}
|
||||
}
|
||||
|
||||
return $group;
|
||||
|
|
|
@ -265,6 +265,10 @@ class HostnotificationQuery extends IdoQuery
|
|||
if ($this->hasJoinedVirtualTable('acknowledgements')) {
|
||||
$group[] = 'a.acknowledgement_id';
|
||||
}
|
||||
|
||||
if ($this->hasJoinedVirtualTable('instances')) {
|
||||
$group[] = 'i.instance_id';
|
||||
}
|
||||
}
|
||||
|
||||
return $group;
|
||||
|
|
|
@ -289,26 +289,26 @@ class HoststatusQuery extends IdoQuery
|
|||
}
|
||||
$groupedTables = array();
|
||||
if ($this->hasJoinedVirtualTable('servicegroups')) {
|
||||
$group[] = 'ho.object_id';
|
||||
$group[] = 'h.host_id';
|
||||
$groupedTables['hosts'] = true;
|
||||
$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')) {
|
||||
if (! isset($groupedTables['hosts'])) {
|
||||
$group[] = 'ho.object_id';
|
||||
$group[] = 'h.host_id';
|
||||
$groupedTables['hosts'] = true;
|
||||
}
|
||||
$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;
|
||||
|
@ -336,6 +336,9 @@ class HoststatusQuery extends IdoQuery
|
|||
$group[] = 'so.object_id';
|
||||
$group[] = 's.service_id';
|
||||
break;
|
||||
case 'instances':
|
||||
$group[] = 'i.instance_id';
|
||||
break;
|
||||
default:
|
||||
continue 2;
|
||||
}
|
||||
|
|
|
@ -203,6 +203,10 @@ class ServicecommentQuery extends IdoQuery
|
|||
if ($this->hasJoinedVirtualTable('servicestatus')) {
|
||||
$group[] = 'ss.servicestatus_id';
|
||||
}
|
||||
|
||||
if ($this->hasJoinedVirtualTable('instances')) {
|
||||
$group[] = 'i.instance_id';
|
||||
}
|
||||
}
|
||||
|
||||
return $group;
|
||||
|
|
|
@ -210,6 +210,10 @@ class ServicedowntimeQuery extends IdoQuery
|
|||
if ($this->hasJoinedVirtualTable('servicestatus')) {
|
||||
$group[] = 'ss.servicestatus_id';
|
||||
}
|
||||
|
||||
if ($this->hasJoinedVirtualTable('instances')) {
|
||||
$group[] = 'i.instance_id';
|
||||
}
|
||||
}
|
||||
|
||||
return $group;
|
||||
|
|
|
@ -268,6 +268,10 @@ class ServicenotificationQuery extends IdoQuery
|
|||
if ($this->hasJoinedVirtualTable('acknowledgements')) {
|
||||
$group[] = 'a.acknowledgement_id';
|
||||
}
|
||||
|
||||
if ($this->hasJoinedVirtualTable('instances')) {
|
||||
$group[] = 'i.instance_id';
|
||||
}
|
||||
}
|
||||
|
||||
return $group;
|
||||
|
|
|
@ -409,26 +409,26 @@ class ServicestatusQuery extends IdoQuery
|
|||
}
|
||||
$groupedTables = array();
|
||||
if ($this->hasJoinedVirtualTable('servicegroups')) {
|
||||
$group[] = 'so.object_id';
|
||||
$group[] = 's.service_id';
|
||||
$groupedTables['services'] = true;
|
||||
$serviceGroupColumns = array_keys($this->columnMap['servicegroups']);
|
||||
$selectedServiceGroupColumns = array_intersect($serviceGroupColumns, array_keys($this->columns));
|
||||
if (! empty($selectedServiceGroupColumns)) {
|
||||
$group[] = 'so.object_id';
|
||||
$group[] = 's.service_id';
|
||||
$group[] = 'sgo.object_id';
|
||||
$group[] = 'sg.servicegroup_id';
|
||||
$groupedTables['services'] = true;
|
||||
$groupedTables['servicegroups'] = true;
|
||||
}
|
||||
}
|
||||
if ($this->hasJoinedVirtualTable('hostgroups')) {
|
||||
if (! isset($groupedTables['services'])) {
|
||||
$group[] = 'so.object_id';
|
||||
$group[] = 's.service_id';
|
||||
$groupedTables['services'] = true;
|
||||
}
|
||||
$hostGroupColumns = array_keys($this->columnMap['hostgroups']);
|
||||
$selectedHostGroupColumns = array_intersect($hostGroupColumns, array_keys($this->columns));
|
||||
if (! empty($selectedHostGroupColumns)) {
|
||||
if (! isset($groupedTables['services'])) {
|
||||
$group[] = 'so.object_id';
|
||||
$group[] = 's.service_id';
|
||||
$groupedTables['services'] = true;
|
||||
}
|
||||
$group[] = 'hgo.object_id';
|
||||
$group[] = 'hg.hostgroup_id';
|
||||
$groupedTables['hostgroups'] = true;
|
||||
|
@ -452,6 +452,9 @@ class ServicestatusQuery extends IdoQuery
|
|||
case 'hoststatus':
|
||||
$group[] = 'hs.hoststatus_id';
|
||||
break;
|
||||
case 'instances':
|
||||
$group[] = 'i.instance_id';
|
||||
break;
|
||||
case 'servicestatus':
|
||||
$group[] = 'ss.servicestatus_id';
|
||||
break;
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
var Selection = function(table, icinga) {
|
||||
this.$el = $(table);
|
||||
this.icinga = icinga;
|
||||
this.col = this.$el.closest('div.container').attr('id');
|
||||
|
||||
if (this.hasMultiselection()) {
|
||||
if (! this.getMultiselectionKeys().length) {
|
||||
|
@ -63,6 +64,11 @@
|
|||
|
||||
Selection.prototype = {
|
||||
|
||||
/**
|
||||
* The container id in which this selection happens
|
||||
*/
|
||||
col: null,
|
||||
|
||||
/**
|
||||
* Return all rows as jQuery selector
|
||||
*
|
||||
|
@ -110,7 +116,7 @@
|
|||
},
|
||||
|
||||
/**
|
||||
* Return the target URL that is used when multi selecting rows
|
||||
* Return the main target URL that is used when multi selecting rows
|
||||
*
|
||||
* This URL may differ from the url that is used when applying single rows
|
||||
*
|
||||
|
@ -120,6 +126,28 @@
|
|||
return this.$el.data('icinga-multiselect-url');
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether the given url is
|
||||
*
|
||||
* @param {String} url
|
||||
*/
|
||||
hasMultiselectionUrl: function(url) {
|
||||
var urls = this.$el.data('icinga-multiselect-url').split(' ');
|
||||
|
||||
var related = this.$el.data('icinga-multiselect-controllers');
|
||||
if (related && related.length) {
|
||||
urls = urls.concat(this.$el.data('icinga-multiselect-controllers').split(' '));
|
||||
}
|
||||
|
||||
var hasSelection = false;
|
||||
$.each(urls, function (i, object) {
|
||||
if (url.indexOf(object) === 0) {
|
||||
hasSelection = true;
|
||||
}
|
||||
});
|
||||
return hasSelection;
|
||||
},
|
||||
|
||||
/**
|
||||
* Read all filter data from the given row
|
||||
*
|
||||
|
@ -227,7 +255,17 @@
|
|||
* @param url {String} The target url
|
||||
*/
|
||||
selectUrl: function(url) {
|
||||
this.rows().filter('[href="' + url + '"]').addClass('active');
|
||||
var $row = this.rows().filter('[href="' + url + '"]');
|
||||
if ($row.length) {
|
||||
$row.addClass('active');
|
||||
} else {
|
||||
// rows sometimes need to be displayed as active when related actions
|
||||
// like command actions are being opened. Do not do this for col2, as it
|
||||
// would always select the opened URL itself.
|
||||
if (this.col !== 'col2') {
|
||||
this.rows().filter('[href$="' + icinga.utils.parseUrl(url).query + '"]').addClass('active');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -264,7 +302,7 @@
|
|||
var hash = icinga.history.getCol2State().replace(/^#!/, '');
|
||||
if (this.hasMultiselection()) {
|
||||
var query = parseSelectionQuery(hash);
|
||||
if (query.length > 1 && this.getMultiselectionUrl() === this.icinga.utils.parseUrl(hash).path) {
|
||||
if (query.length > 1 && this.hasMultiselectionUrl(this.icinga.utils.parseUrl(hash).path)) {
|
||||
// select all rows with matching filters
|
||||
var self = this;
|
||||
$.each(query, function(i, selection) {
|
||||
|
|
Loading…
Reference in New Issue