From 1f7a4a170ff989247e6600def3a5fd3dbcc0b103 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Sat, 27 Feb 2016 18:00:50 +0100 Subject: [PATCH 001/109] Add zero width space characters to plugin output where appropriate This helps browsers to break lines if the plugin output is missing whitespaces. Alternatively we could set word-break: break-all but that may produce ugly results. refs #10820 --- .../monitoring/application/views/helpers/PluginOutput.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/monitoring/application/views/helpers/PluginOutput.php b/modules/monitoring/application/views/helpers/PluginOutput.php index f5c73ee21..ba3013a3a 100644 --- a/modules/monitoring/application/views/helpers/PluginOutput.php +++ b/modules/monitoring/application/views/helpers/PluginOutput.php @@ -51,6 +51,14 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract $isHtml = false; } $output = $this->fixLinks($output); + // Help browsers to break words in plugin output + $output = trim($output); + // Add space after comma where missing + $output = preg_replace('/,[^\s]/', ', ', $output); + // Add zero width space after ')', ']', ':', '.', '_' and '-' if not surrounded by whitespaces + $output = preg_replace('/([^\s])([\\)\\]:._-])([^\s])/', '$1$2​$3', $output); + // Add zero width space before '(' and '[' if not surrounded by whitespaces + $output = preg_replace('/([^\s])([([])([^\s])/', '$1​$2$3', $output); if (! $raw) { if ($isHtml) { From bee0992fe478fade257b70b9957193cad8339469 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Sat, 27 Feb 2016 18:05:22 +0100 Subject: [PATCH 002/109] Use hyphens for word break in plugin output where supported Chrome, Opera and nearly all mobile browsers do not support hyphens (yet). refs #10820 --- modules/monitoring/public/css/tables.less | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/monitoring/public/css/tables.less b/modules/monitoring/public/css/tables.less index bb2027c95..93fa030f5 100644 --- a/modules/monitoring/public/css/tables.less +++ b/modules/monitoring/public/css/tables.less @@ -71,7 +71,20 @@ font-size: @font-size-small; } -// Plugin output in overviews +// Plugin output in detail views +.plugin-output, +// Plugin output in overvies +.overview-plugin-output { + -webkit-hyphens: auto; + -moz-hyphens: auto; + -ms-hyphens: auto; + hyphens: auto; + + overflow-wrap: break-word; + word-wrap: break-word; +} + +// Plugin output in overvies .overview-plugin-output { color: @text-color-light; font-family: @font-family-fixed; From d4dcdb96bd1705f1d48cb578fc74f692b9f0cfa3 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Sat, 27 Feb 2016 18:06:35 +0100 Subject: [PATCH 003/109] Force browsers to respect overflow of plugin output in tables refs #10820 --- modules/monitoring/public/css/tables.less | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/monitoring/public/css/tables.less b/modules/monitoring/public/css/tables.less index 93fa030f5..a0bdfa396 100644 --- a/modules/monitoring/public/css/tables.less +++ b/modules/monitoring/public/css/tables.less @@ -91,6 +91,12 @@ font-size: @font-size-small; margin: 0; white-space: pre-wrap; + // Long text in table cells overflows the table's width if the table's layout is not fixed. + // Thus overflow-wrap will not have any effect. But w/ the following we set a width of any value + // plus a min-width of 100% to consume the full width nonetheless which seems to always + // instruct browsers to not overflow the table. Ridiculous. + min-width: 100%; + width: 1em; } // Table for performance data in detail views From 2699d2c9ed8736c0e6bc090fcdfba7d6214f2d98 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 24 Mar 2016 15:28:21 +0100 Subject: [PATCH 004/109] lib: Rename AdmissionLoader::applyPerm... to applyRoles() refs #10887 --- library/Icinga/Authentication/AdmissionLoader.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/Icinga/Authentication/AdmissionLoader.php b/library/Icinga/Authentication/AdmissionLoader.php index 391622fb1..ca21913e3 100644 --- a/library/Icinga/Authentication/AdmissionLoader.php +++ b/library/Icinga/Authentication/AdmissionLoader.php @@ -45,11 +45,9 @@ class AdmissionLoader /** * Get user permissions and restrictions * - * @param User $user - * - * @return array + * @param User $user */ - public function getPermissionsAndRestrictions(User $user) + public function applyRoles(User $user) { $permissions = array(); $restrictions = array(); @@ -62,7 +60,7 @@ class AdmissionLoader $username, $e ); - return array($permissions, $restrictions); + return; } $userGroups = $user->getGroups(); foreach ($roles as $role) { @@ -83,6 +81,8 @@ class AdmissionLoader } } } - return array($permissions, $restrictions); + $user->setPermissions($permissions); + $user->setRestrictions($restrictions); +// $user->setRoles($roles); } } From 6ec18789770429bd76aa4dcdab1b6ea304ac1399 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 24 Mar 2016 15:29:39 +0100 Subject: [PATCH 005/109] lib: Add Authentication/Role refs #10887 --- library/Icinga/Authentication/Role.php | 113 +++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 library/Icinga/Authentication/Role.php diff --git a/library/Icinga/Authentication/Role.php b/library/Icinga/Authentication/Role.php new file mode 100644 index 000000000..5a8029e46 --- /dev/null +++ b/library/Icinga/Authentication/Role.php @@ -0,0 +1,113 @@ +name; + } + + /** + * Set the name of the role + * + * @param string $name + * + * @return $this + */ + public function setName($name) + { + $this->name = $name; + return $this; + } + + /** + * Add a permission to the role + * + * @param string $permission + * + * @return $this + */ + public function addPermission($permission) + { + $this->permissions[$permission] = $permission; + return $this; + } + + /** + * Get the permissions of the role + * + * @return string[] + */ + public function getPermissions() + { + return $this->permissions; + } + + /** + * Add a restriction to the role + * + * @param string $name + * @param string $restriction + * + * @return $this + */ + public function addRestriction($name, $restriction) + { + if (! isset($this->restrictions[$name])) { + $this->restrictions[$name] = array(); + } + $this->restrictions[$name][] = $restriction; + return $this; + } + + /** + * Get the restrictions of the role + * + * @param string $name Optional name of the restriction + * + * @return string[]|null + */ + public function getRestrictions($name = null) + { + $restrictions = $this->restrictions; + + if ($name === null) { + return $restrictions; + } + + if (isset($restrictions[$name])) { + return $restrictions[$name]; + } + + return null; + } +} From 1aa42bdaf62acf45e1e215e83c8f80a421b4c889 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 24 Mar 2016 15:30:07 +0100 Subject: [PATCH 006/109] lib: Add User::getRoles() and ::setRoles() refs #10887 --- library/Icinga/User.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/Icinga/User.php b/library/Icinga/User.php index cbd8c4743..6ec266685 100644 --- a/library/Icinga/User.php +++ b/library/Icinga/User.php @@ -6,6 +6,7 @@ namespace Icinga; use DateTimeZone; use InvalidArgumentException; use Icinga\Application\Config; +use Icinga\Authentication\Role; use Icinga\User\Preferences; use Icinga\Web\Navigation\Navigation; @@ -238,6 +239,29 @@ class User $this->restrictions = $restrictions; } + /** + * Get the roles of the user + * + * @return Role[] + */ + public function getRoles() + { + return $this->roles; + } + + /** + * Set the roles of the user + * + * @param Role[] $roles + * + * @return $this + */ + public function setRoles(array $roles) + { + $this->roles = $roles; + return $this; + } + /** * Getter for username * From f1f4cdc3cb8f1d0e2d433dfba8308ee88956ef0a Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 24 Mar 2016 15:30:30 +0100 Subject: [PATCH 007/109] lib: Use AdmissionLoader::applyRoles() in Auth refs #10887 --- library/Icinga/Authentication/Auth.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/Icinga/Authentication/Auth.php b/library/Icinga/Authentication/Auth.php index 9fb43922c..392a59d71 100644 --- a/library/Icinga/Authentication/Auth.php +++ b/library/Icinga/Authentication/Auth.php @@ -160,9 +160,7 @@ class Auth } $user->setGroups($groups); $admissionLoader = new AdmissionLoader(); - list($permissions, $restrictions) = $admissionLoader->getPermissionsAndRestrictions($user); - $user->setPermissions($permissions); - $user->setRestrictions($restrictions); + $admissionLoader->applyRoles($user); $this->user = $user; if ($persist) { $this->persistCurrentUser(); From 57ce39834d8928368bfb8fa07aaa67e443d9e9ec Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 24 Mar 2016 16:11:31 +0100 Subject: [PATCH 008/109] Role: implement setPermissions() and setRestrictions() refs #10887 --- library/Icinga/Authentication/Role.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/library/Icinga/Authentication/Role.php b/library/Icinga/Authentication/Role.php index 5a8029e46..a032e7957 100644 --- a/library/Icinga/Authentication/Role.php +++ b/library/Icinga/Authentication/Role.php @@ -62,6 +62,19 @@ class Role return $this; } + /** + * Set permissions of the role + * + * @param string[] $permissions + * + * @return $this + */ + public function setPermissions(array $permissions) + { + $this->permissions = $permissions; + return $this; + } + /** * Get the permissions of the role * @@ -89,6 +102,19 @@ class Role return $this; } + /** + * Set restrictions of the role + * + * @param string[] $restrictions + * + * @return $this + */ + public function setRestrictions(array $restrictions) + { + $this->restrictions = $restrictions; + return $this; + } + /** * Get the restrictions of the role * From df0d3aaf1ea9b9d1dc7d4a5f4ec73b24630090ec Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 24 Mar 2016 16:24:24 +0100 Subject: [PATCH 009/109] AdmissionLoader: set the roles of the user refs #10887 --- library/Icinga/Authentication/AdmissionLoader.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/library/Icinga/Authentication/AdmissionLoader.php b/library/Icinga/Authentication/AdmissionLoader.php index ca21913e3..6d0df9f65 100644 --- a/library/Icinga/Authentication/AdmissionLoader.php +++ b/library/Icinga/Authentication/AdmissionLoader.php @@ -5,6 +5,7 @@ namespace Icinga\Authentication; use Icinga\Application\Config; use Icinga\Application\Logger; +use Icinga\Authentication\Role; use Icinga\Exception\NotReadableError; use Icinga\Data\ConfigObject; use Icinga\User; @@ -63,11 +64,13 @@ class AdmissionLoader return; } $userGroups = $user->getGroups(); - foreach ($roles as $role) { + $roleObjs = array(); + foreach ($roles as $roleName => $role) { if ($this->match($username, $userGroups, $role)) { + $permissionsFromRole = StringHelper::trimSplit($role->permissions); $permissions = array_merge( $permissions, - array_diff(StringHelper::trimSplit($role->permissions), $permissions) + array_diff($permissionsFromRole, $permissions) ); $restrictionsFromRole = $role->toArray(); unset($restrictionsFromRole['users']); @@ -79,10 +82,16 @@ class AdmissionLoader } $restrictions[$name][] = $restriction; } + + $roleObj = new Role(); + $roleObjs[] = $roleObj + ->setName($roleName) + ->setPermissions($permissionsFromRole) + ->setRestrictions($restrictionsFromRole); } } $user->setPermissions($permissions); $user->setRestrictions($restrictions); -// $user->setRoles($roles); + $user->setRoles($roleObjs); } } From c6eb3cd2c7f7d36acc0ddccfd6ba8881225304c9 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 24 Mar 2016 16:34:32 +0100 Subject: [PATCH 010/109] Add missing User::$roles definition refs #10887 --- library/Icinga/User.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/Icinga/User.php b/library/Icinga/User.php index 6ec266685..da5c37390 100644 --- a/library/Icinga/User.php +++ b/library/Icinga/User.php @@ -92,6 +92,13 @@ class User */ protected $groups = array(); + /** + * Roles of this user + * + * @var Role[] + */ + protected $roles = array(); + /** * Preferences object * From ea871ea032c78f58fa43bd672b96c5a66339fcf3 Mon Sep 17 00:00:00 2001 From: Raphael Bicker Date: Thu, 24 Mar 2016 17:53:55 +0100 Subject: [PATCH 011/109] Fix Cannot execute queries while other unbuffered queries are active fixes #11264 Signed-off-by: Eric Lippmann --- library/Icinga/Data/Db/DbConnection.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/Icinga/Data/Db/DbConnection.php b/library/Icinga/Data/Db/DbConnection.php index f643d4849..e9d3bd5f0 100644 --- a/library/Icinga/Data/Db/DbConnection.php +++ b/library/Icinga/Data/Db/DbConnection.php @@ -152,11 +152,12 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp */ $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET SESSION SQL_MODE=\'STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,' - . 'NO_AUTO_CREATE_USER,ANSI_QUOTES,PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION\';'; + . 'NO_AUTO_CREATE_USER,ANSI_QUOTES,PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION\''; if (array_key_exists('charset', $adapterParamaters) && $adapterParamaters['charset']) { - $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .= 'SET NAMES ' . $adapterParamaters['charset']. ';'; + $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .= ', NAMES ' . $adapterParamaters['charset']; unset($adapterParamaters['charset']); } + $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .=';'; $adapterParamaters['port'] = $this->config->get('port', 3306); break; From 98934e9c5f0928367fad8dd53c74470025b84ae7 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 24 Mar 2016 17:55:30 +0100 Subject: [PATCH 012/109] lib/DbConnection: Use isset for charset check --- library/Icinga/Data/Db/DbConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Icinga/Data/Db/DbConnection.php b/library/Icinga/Data/Db/DbConnection.php index e9d3bd5f0..81afb2c3d 100644 --- a/library/Icinga/Data/Db/DbConnection.php +++ b/library/Icinga/Data/Db/DbConnection.php @@ -153,7 +153,7 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET SESSION SQL_MODE=\'STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,' . 'NO_AUTO_CREATE_USER,ANSI_QUOTES,PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION\''; - if (array_key_exists('charset', $adapterParamaters) && $adapterParamaters['charset']) { + if (isset($adapterParamaters['charset'])) { $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .= ', NAMES ' . $adapterParamaters['charset']; unset($adapterParamaters['charset']); } From 3d6ae6ac26022049ef4ed82714b968fd5a627d20 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 29 Mar 2016 11:18:36 +0200 Subject: [PATCH 013/109] Fix PHPDoc of User::setRestrictions() refs #10887 --- library/Icinga/User.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/Icinga/User.php b/library/Icinga/User.php index da5c37390..738df109e 100644 --- a/library/Icinga/User.php +++ b/library/Icinga/User.php @@ -237,13 +237,16 @@ class User } /** - * Settter for restrictions + * Set the user's restrictions * - * @param array $restrictions + * @param string[] $restrictions + * + * @return $this */ public function setRestrictions(array $restrictions) { $this->restrictions = $restrictions; + return $this; } /** From 08b70267cda211d84f561f2a20cf50b473fec8d4 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 29 Mar 2016 11:19:03 +0200 Subject: [PATCH 014/109] Move setters after getter in Role.php refs #10887 --- library/Icinga/Authentication/Role.php | 48 +++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/library/Icinga/Authentication/Role.php b/library/Icinga/Authentication/Role.php index a032e7957..28a32d235 100644 --- a/library/Icinga/Authentication/Role.php +++ b/library/Icinga/Authentication/Role.php @@ -63,7 +63,17 @@ class Role } /** - * Set permissions of the role + * Get the permissions of the role + * + * @return string[] + */ + public function getPermissions() + { + return $this->permissions; + } + + /** + * Set the permissions of the role * * @param string[] $permissions * @@ -75,16 +85,6 @@ class Role return $this; } - /** - * Get the permissions of the role - * - * @return string[] - */ - public function getPermissions() - { - return $this->permissions; - } - /** * Add a restriction to the role * @@ -102,19 +102,6 @@ class Role return $this; } - /** - * Set restrictions of the role - * - * @param string[] $restrictions - * - * @return $this - */ - public function setRestrictions(array $restrictions) - { - $this->restrictions = $restrictions; - return $this; - } - /** * Get the restrictions of the role * @@ -136,4 +123,17 @@ class Role return null; } + + /** + * Set the restrictions of the role + * + * @param string[] $restrictions + * + * @return $this + */ + public function setRestrictions(array $restrictions) + { + $this->restrictions = $restrictions; + return $this; + } } From 123488cfc0e740efd82faea095a0f3693612117f Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 29 Mar 2016 11:19:30 +0200 Subject: [PATCH 015/109] Remove Role::addRestriction() Method is not used. refs #10887 --- library/Icinga/Authentication/Role.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/library/Icinga/Authentication/Role.php b/library/Icinga/Authentication/Role.php index 28a32d235..afb27392f 100644 --- a/library/Icinga/Authentication/Role.php +++ b/library/Icinga/Authentication/Role.php @@ -85,23 +85,6 @@ class Role return $this; } - /** - * Add a restriction to the role - * - * @param string $name - * @param string $restriction - * - * @return $this - */ - public function addRestriction($name, $restriction) - { - if (! isset($this->restrictions[$name])) { - $this->restrictions[$name] = array(); - } - $this->restrictions[$name][] = $restriction; - return $this; - } - /** * Get the restrictions of the role * From 32c6a0300018758879cc85745eff9eb2a5474df2 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 29 Mar 2016 11:20:15 +0200 Subject: [PATCH 016/109] Remove Role::addPermission() Method is not used. refs #10887 --- library/Icinga/Authentication/Role.php | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/library/Icinga/Authentication/Role.php b/library/Icinga/Authentication/Role.php index afb27392f..f00d063e2 100644 --- a/library/Icinga/Authentication/Role.php +++ b/library/Icinga/Authentication/Role.php @@ -49,19 +49,6 @@ class Role return $this; } - /** - * Add a permission to the role - * - * @param string $permission - * - * @return $this - */ - public function addPermission($permission) - { - $this->permissions[$permission] = $permission; - return $this; - } - /** * Get the permissions of the role * From 5b5978787bd57445f3168b28b2b04a9616cbf230 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 29 Mar 2016 11:23:18 +0200 Subject: [PATCH 017/109] Move permission and restriction initialization in AdmissionLoader refs #10887 --- library/Icinga/Authentication/AdmissionLoader.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/Icinga/Authentication/AdmissionLoader.php b/library/Icinga/Authentication/AdmissionLoader.php index 6d0df9f65..f0e5c7783 100644 --- a/library/Icinga/Authentication/AdmissionLoader.php +++ b/library/Icinga/Authentication/AdmissionLoader.php @@ -50,8 +50,6 @@ class AdmissionLoader */ public function applyRoles(User $user) { - $permissions = array(); - $restrictions = array(); $username = $user->getUsername(); try { $roles = Config::app('roles'); @@ -64,6 +62,8 @@ class AdmissionLoader return; } $userGroups = $user->getGroups(); + $permissions = array(); + $restrictions = array(); $roleObjs = array(); foreach ($roles as $roleName => $role) { if ($this->match($username, $userGroups, $role)) { From e0781cf8b52ce40919621bfe91f010b42ecfcd91 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 29 Mar 2016 11:24:58 +0200 Subject: [PATCH 018/109] Fix PHPDoc of AdmissionLoader::applyRoles() refs #10887 --- library/Icinga/Authentication/AdmissionLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Icinga/Authentication/AdmissionLoader.php b/library/Icinga/Authentication/AdmissionLoader.php index f0e5c7783..0a80be127 100644 --- a/library/Icinga/Authentication/AdmissionLoader.php +++ b/library/Icinga/Authentication/AdmissionLoader.php @@ -44,7 +44,7 @@ class AdmissionLoader } /** - * Get user permissions and restrictions + * Apply permissions, restrictions and roles to the given user * * @param User $user */ From c7aec8ae64c9255a0d129b08313440730ed9f3eb Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 29 Mar 2016 11:39:41 +0200 Subject: [PATCH 019/109] Respect module stylesheets again when generating the ETag fixes #11465 --- library/Icinga/Web/LessCompiler.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/library/Icinga/Web/LessCompiler.php b/library/Icinga/Web/LessCompiler.php index acf616d18..7ec34a143 100644 --- a/library/Icinga/Web/LessCompiler.php +++ b/library/Icinga/Web/LessCompiler.php @@ -70,7 +70,7 @@ class LessCompiler */ public function addLessFile($lessFile) { - $this->lessFiles[] = $lessFile; + $this->lessFiles[] = realpath($lessFile); return $this; } @@ -87,7 +87,7 @@ class LessCompiler if (! isset($this->moduleLessFiles[$moduleName])) { $this->moduleLessFiles[$moduleName] = array(); } - $this->moduleLessFiles[$moduleName][] = $lessFile; + $this->moduleLessFiles[$moduleName][] = realpath($lessFile); return $this; } @@ -98,9 +98,12 @@ class LessCompiler */ public function getLessFiles() { - $lessFiles = iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator( - $this->lessFiles + $this->moduleLessFiles - ))); + $lessFiles = $this->lessFiles; + + foreach ($this->moduleLessFiles as $moduleLessFiles) { + $lessFiles = array_merge($lessFiles, $moduleLessFiles); + } + if ($this->theme !== null) { $lessFiles[] = $this->theme; } From 03e4d626f1d6fb213685b3db7f77ccd508756dc7 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 29 Mar 2016 13:41:38 +0200 Subject: [PATCH 020/109] RPM: Install public/font fixes #11171 --- icingaweb2.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icingaweb2.spec b/icingaweb2.spec index f284df23b..91862e0ee 100644 --- a/icingaweb2.spec +++ b/icingaweb2.spec @@ -190,7 +190,7 @@ cp -pv etc/bash_completion.d/icingacli %{buildroot}/%{_sysconfdir}/bash_completi cp -prv modules/{monitoring,setup,doc,translation} %{buildroot}/%{basedir}/modules cp -prv library/Icinga %{buildroot}/%{phpdir} cp -prv library/vendor/{dompdf,HTMLPurifier*,JShrink,lessphp,Parsedown,Zend} %{buildroot}/%{basedir}/library/vendor -cp -prv public/{css,img,js,error_norewrite.html} %{buildroot}/%{basedir}/public +cp -prv public/{css,font,img,js,error_norewrite.html} %{buildroot}/%{basedir}/public cp -pv packages/files/apache/icingaweb2.conf %{buildroot}/%{wwwconfigdir}/icingaweb2.conf cp -pv packages/files/bin/icingacli %{buildroot}/%{bindir} cp -pv packages/files/public/index.php %{buildroot}/%{basedir}/public From 528be1ee796d25fa50c2f736fd57302d24945893 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 30 Mar 2016 15:26:24 +0200 Subject: [PATCH 021/109] doc: Iterate files alphabetically and directories last --- library/Icinga/Util/DirectoryIterator.php | 100 +++++++++++++++------- 1 file changed, 70 insertions(+), 30 deletions(-) diff --git a/library/Icinga/Util/DirectoryIterator.php b/library/Icinga/Util/DirectoryIterator.php index 3addbd2bb..472899b2f 100644 --- a/library/Icinga/Util/DirectoryIterator.php +++ b/library/Icinga/Util/DirectoryIterator.php @@ -3,14 +3,22 @@ namespace Icinga\Util; +use ArrayIterator; use InvalidArgumentException; -use Iterator; +use RecursiveIterator; /** * Iterator for traversing a directory */ -class DirectoryIterator implements Iterator +class DirectoryIterator implements RecursiveIterator { + /** + * Iterate files first + * + * @var int + */ + const FILES_FIRST = 1; + /** * Current directory item * @@ -26,11 +34,18 @@ class DirectoryIterator implements Iterator protected $extension; /** - * Directory handle + * Scanned files * - * @var resource + * @var ArrayIterator */ - private $handle; + private $files; + + /** + * Iterator flags + * + * @var int + */ + protected $flags; /** * Current key @@ -46,6 +61,13 @@ class DirectoryIterator implements Iterator */ protected $path; + /** + * Directory queue if FILES_FIRST flag is set + * + * @var array + */ + private $queue; + /** * Whether to skip empty files * @@ -72,8 +94,9 @@ class DirectoryIterator implements Iterator * * @param string $path The path of the directory to traverse * @param string $extension The file extension to filter for. A leading dot is optional + * @param int $flags Iterator flags */ - public function __construct($path, $extension = null) + public function __construct($path, $extension = null, $flags = null) { if (empty($path)) { throw new InvalidArgumentException('The path can\'t be empty'); @@ -82,6 +105,9 @@ class DirectoryIterator implements Iterator if (! empty($extension)) { $this->extension = '.' . ltrim($extension, '.'); } + if ($flags !== null) { + $this->flags = $flags; + } } /** @@ -96,6 +122,23 @@ class DirectoryIterator implements Iterator return is_dir($path) && is_readable($path); } + /** + * {@inheritdoc} + */ + public function hasChildren() + { + return static::isReadable($this->current); + } + + /** + * {@inheritdoc} + */ + public function getChildren() + { + return new static($this->current, $this->extension, $this->flags); + } + + /** * {@inheritdoc} */ @@ -110,12 +153,14 @@ class DirectoryIterator implements Iterator public function next() { do { - $file = readdir($this->handle); - if ($file === false) { - $key = false; + $this->files->next(); + $skip = false; + if (! $this->files->valid()) { + $file = false; + $path = false; break; } else { - $skip = false; + $file = $this->files->current(); do { if ($this->skipHidden && $file[0] === '.') { $skip = true; @@ -125,7 +170,10 @@ class DirectoryIterator implements Iterator $path = $this->path . '/' . $file; if (is_dir($path)) { - $skip = true; + if ($this->flags & static::FILES_FIRST === static::FILES_FIRST) { + $this->queue[] = array($path, $file); + $skip = true; + } break; } @@ -138,16 +186,18 @@ class DirectoryIterator implements Iterator $skip = true; break; } - - $key = $file; - $file = $path; } while (0); } } while ($skip); - $this->current = $file; /** @noinspection PhpUndefinedVariableInspection */ - $this->key = $key; + + if ($path === false && ! empty($this->queue)) { + list($path, $file) = array_shift($this->queue); + } + + $this->current = $path; + $this->key = $file; } /** @@ -171,21 +221,11 @@ class DirectoryIterator implements Iterator */ public function rewind() { - if ($this->handle === null) { - $this->handle = opendir($this->path); - } else { - rewinddir($this->handle); + if ($this->files === null) { + $this->files = new ArrayIterator(scandir($this->path)); } + $this->files->rewind(); + $this->queue = array(); $this->next(); } - - /** - * Close directory handle if created - */ - public function __destruct() - { - if ($this->handle !== null) { - closedir($this->handle); - } - } } From a5119a7a2e418c2491bd6ebe0a3b6aae32c51c15 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 30 Mar 2016 15:27:34 +0200 Subject: [PATCH 022/109] Fix TreeNodeIterator::isEmpty() --- library/Icinga/Data/Tree/TreeNodeIterator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Icinga/Data/Tree/TreeNodeIterator.php b/library/Icinga/Data/Tree/TreeNodeIterator.php index dcba0f1e9..839b1a1d0 100644 --- a/library/Icinga/Data/Tree/TreeNodeIterator.php +++ b/library/Icinga/Data/Tree/TreeNodeIterator.php @@ -92,6 +92,6 @@ class TreeNodeIterator implements RecursiveIterator */ public function isEmpty() { - return empty($this->children); + return ! $this->children->count(); } } From 2667457eecfaeceb0b327804abd1181631b30ea5 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 30 Mar 2016 15:29:50 +0200 Subject: [PATCH 023/109] doc: Don't fail on duplicate IDs --- modules/doc/library/Doc/DocParser.php | 42 +++++++++++++++++++++------ 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/modules/doc/library/Doc/DocParser.php b/modules/doc/library/Doc/DocParser.php index 6d52665c7..5b4986b45 100644 --- a/modules/doc/library/Doc/DocParser.php +++ b/modules/doc/library/Doc/DocParser.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Doc; use CachingIterator; +use RecursiveIteratorIterator; use SplFileObject; use SplStack; use Icinga\Data\Tree\SimpleTree; @@ -61,7 +62,7 @@ class DocParser ); } $this->path = $path; - $this->docIterator = new DirectoryIterator($path, 'md'); + $this->docIterator = new DirectoryIterator($path, 'md', DirectoryIterator::FILES_FIRST); } /** @@ -117,9 +118,35 @@ class DocParser } else { $id = null; } + /** @noinspection PhpUndefinedVariableInspection */ return array($header, $id, $level, $headerStyle); } + /** + * Generate unique section ID + * + * @param string $id + * @param string $filename + * @param SimpleTree $tree + * + * @return string + */ + protected function uuid($id, $filename, SimpleTree $tree) + { + if ($tree->getNode($id) !== null) { + $id = $id . '-' . md5($filename); + } + $offset = 0; + while ($tree->getNode($id)) { + if ($offset++ === 0) { + $id .= '-' . $offset; + } else { + $id = substr($id, 0, -1) . $offset; + } + } + return $id; + } + /** * Get the documentation tree * @@ -128,7 +155,7 @@ class DocParser public function getDocTree() { $tree = new SimpleTree(); - foreach ($this->docIterator as $filename) { + foreach (new RecursiveIteratorIterator($this->docIterator) as $filename) { $file = new SplFileObject($filename); $lastLine = null; $stack = new SplStack(); @@ -154,9 +181,9 @@ class DocParser } else { $noFollow = false; } - if ($tree->getNode($id) !== null) { - $id = uniqid($id); - } + + $id = $this->uuid($id, $filename, $tree); + $section = new DocSection(); $section ->setId($id) @@ -178,10 +205,7 @@ class DocParser } else { if ($stack->isEmpty()) { $title = ucfirst($file->getBasename('.' . pathinfo($file->getFilename(), PATHINFO_EXTENSION))); - $id = $title; - if ($tree->getNode($id) !== null) { - $id = uniqid($id); - } + $id = $this->uuid($title, $filename, $tree); $section = new DocSection(); $section ->setId($id) From fde78cdeb82c4c85ba9eb86d5107cd5aba997870 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 30 Mar 2016 15:40:56 +0200 Subject: [PATCH 024/109] doc: Improve order of chapters refs #9386 --- doc/{about.md => 01-About.md} | 0 doc/{installation.md => 02-Installation.md} | 0 doc/{configuration.md => 03-Configuration.md} | 0 doc/{resources.md => 04-Resources.md} | 0 doc/{authentication.md => 05-Authentication.md} | 0 doc/{security.md => 06-Security.md} | 0 doc/{preferences.md => 07-Preferences.md} | 0 doc/{vagrant.md => 99-Vagrant.md} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename doc/{about.md => 01-About.md} (100%) rename doc/{installation.md => 02-Installation.md} (100%) rename doc/{configuration.md => 03-Configuration.md} (100%) rename doc/{resources.md => 04-Resources.md} (100%) rename doc/{authentication.md => 05-Authentication.md} (100%) rename doc/{security.md => 06-Security.md} (100%) rename doc/{preferences.md => 07-Preferences.md} (100%) rename doc/{vagrant.md => 99-Vagrant.md} (100%) diff --git a/doc/about.md b/doc/01-About.md similarity index 100% rename from doc/about.md rename to doc/01-About.md diff --git a/doc/installation.md b/doc/02-Installation.md similarity index 100% rename from doc/installation.md rename to doc/02-Installation.md diff --git a/doc/configuration.md b/doc/03-Configuration.md similarity index 100% rename from doc/configuration.md rename to doc/03-Configuration.md diff --git a/doc/resources.md b/doc/04-Resources.md similarity index 100% rename from doc/resources.md rename to doc/04-Resources.md diff --git a/doc/authentication.md b/doc/05-Authentication.md similarity index 100% rename from doc/authentication.md rename to doc/05-Authentication.md diff --git a/doc/security.md b/doc/06-Security.md similarity index 100% rename from doc/security.md rename to doc/06-Security.md diff --git a/doc/preferences.md b/doc/07-Preferences.md similarity index 100% rename from doc/preferences.md rename to doc/07-Preferences.md diff --git a/doc/vagrant.md b/doc/99-Vagrant.md similarity index 100% rename from doc/vagrant.md rename to doc/99-Vagrant.md From aefb5cfe08242d0a848b4fea19a6e004208641c7 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 30 Mar 2016 16:03:53 +0200 Subject: [PATCH 025/109] doc: Remove external_authentication.md fixes #9386 --- doc/05-Authentication.md | 61 ++++++++++++++++++------ doc/external_authentication.md | 86 ---------------------------------- 2 files changed, 46 insertions(+), 101 deletions(-) delete mode 100644 doc/external_authentication.md diff --git a/doc/05-Authentication.md b/doc/05-Authentication.md index 21f5a8b9f..a1455e203 100644 --- a/doc/05-Authentication.md +++ b/doc/05-Authentication.md @@ -18,24 +18,55 @@ The order of entries in the authentication configuration determines the order of If the current authentication method errors or if the current authentication method does not know the account being authenticated, the next authentication method will be used. -### External Authentication +## External Authentication For delegating authentication to the web server simply add `autologin` to your authentication configuration: -```` +``` [autologin] backend = external -```` +``` -If your web server is not configured for authentication though the `autologin` section has no effect. +If your web server is not configured for authentication though, the `autologin` section has no effect. -### Active Directory or LDAP Authentication +### Example Configuration for Apache and Basic Authentication + +The following example will show you how to enable external authentication in Apache +using **Basic access authentication**. + +**Creating Users** + +To create users for **basic access authentication** you can use the tool `htpasswd`. In this example **.http-users** is +the name of the file containing the user credentials. + +The following command creates a new file with the user **icingaadmin**. `htpasswd` will prompt you for a password. +If you want to add more users to the file you have to omit the `-c` switch to not overwrite the file. + +``` +sudo htpasswd -c /etc/icingaweb2/.http-users icingaadmin +``` + +**Configuring the Web Server** + +Add the following configuration to the **<Directory> Directive** in the **icingaweb.conf** web server +configuration file. + +``` +AuthType Basic +AuthName "Icinga Web 2" +AuthUserFile /etc/icingaweb2/.http-users +Require valid-user +``` + +Restart your web server to apply the changes. + +## Active Directory or LDAP Authentication If you want to authenticate against Active Directory or LDAP, you have to define a -[LDAP resource](resources.md#resources-configuration-ldap) which will be referenced as data source for the Active Directory -or LDAP configuration method. +[LDAP resource](resources.md#resources-configuration-ldap) which will be referenced as data source for the +Active Directory or LDAP configuration method. -#### LDAP +### LDAP Directive | Description ------------------------|------------ @@ -60,7 +91,7 @@ Note that in case the set *user_name_attribute* holds multiple values it is requ values are unique. Additionally, a user will be logged in using the exact user id used to authenticate with Icinga Web 2 (e.g. an alias) no matter what the primary user id might actually be. -#### Active Directory +### Active Directory Directive | Description ------------------------|------------ @@ -75,7 +106,7 @@ backend = msldap resource = my_ad ``` -### Database Authentication +## Database Authentication If you want to authenticate against a MySQL or a PostgreSQL database, you have to define a [database resource](resources.md#resources-configuration-database) which will be referenced as data source for the database @@ -94,7 +125,7 @@ backend = db resource = icingaweb-mysql ``` -#### Database Setup +### Database Setup For authenticating against a database, you have to import one of the following database schemas: @@ -108,14 +139,14 @@ After that you have to define the [database resource](resources.md#resources-con Icinga Web 2 uses the MD5 based BSD password algorithm. For generating a password hash, please use the following command: -```` +``` openssl passwd -1 password -```` +``` > Note: The switch to `openssl passwd` is the **number one** (`-1`) for using the MD5 based BSD password algorithm. Insert the user into the database using the generated password hash: -```` +``` INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, 'hash from openssl'); -```` +``` diff --git a/doc/external_authentication.md b/doc/external_authentication.md deleted file mode 100644 index 05225fb82..000000000 --- a/doc/external_authentication.md +++ /dev/null @@ -1,86 +0,0 @@ -# External Authentication - -It is possible to utilize the authentication mechanism of the webserver instead -of the internal authentication of Icinga Web 2 to authenticate users. This might -be useful if you only have very few users and user management over **.htaccess** -is not sufficient or if you are required to use some other authentication -mechanism that is only available by utilizing the webserver. - -Icinga Web 2 will entrust the complete authentication process to the -authentication provider of the webserver, if external authentication is used. -So it is very important that the webserver's authentication is configured -correctly as wrong configuration might lead to unauthorized access or a -malfunction in the login-process. - -## Using External Authentication - -External authentication in Icinga Web 2 requires the following preparations: - -1. The external authentication must be set up properly to correctly - authenticate users -2. Icinga Web 2 must be configured to use external authentication - -### Preparing the External Authentication Provider - -This step depends heavily on the used webserver and authentication mechanism you -want to use. It is not possible to cover all possibillities and you should -probably read the documentation for your webserver to get detailed instructions -on how to set up authentication properly. - -In general you need to make sure that: - -- All routes require authentication -- Only permitted users are allowed to authenticate - -#### Example Configuration for Apache and HTTPDigestAuthentication - -The following example will show how to enable external authentication in Apache -using *HTTP Digest Authentication*. - -##### Creating users - -To create users for digest authentication you can use the tool *htdigest*. In -this example **.icingawebdigest** is the name of the file containing the user -credentials. - -This command creates a new file with the user *jdoe*. *htdigest* will prompt -you for a password. If you want to add more users to the file you need to omit -the *-c* parameter in all following commands to not to overwrite the file. - -```` -sudo htdigest -c /etc/icingaweb2/.icingawebdigest "Icinga Web 2" jdoe -```` - -##### Configuring the Webserver - -The webserver should require authentication for all public Icinga Web 2 files. - -```` - - AuthType digest - AuthName "Icinga Web 2" - AuthDigestProvider file - AuthUserFile /etc/icingaweb2/.icingawebdigest - Require valid-user - -```` - -To get these changes to work, make sure to enable the module for -HTTPDigestAuthentication and restart the webserver. - -### Preparing Icinga Web 2 - -Once external authentication is set up correctly you need to configure Icinga -Web 2. In case you already completed the setup wizard it is likely that you are -now finished. - -To get Icinga Web 2 to use external authentication the file -**config/authentication.ini** is required. Just add the following section -called "autologin", or any name of your choice, and save your changes: - -```` -[autologin] -backend = external -```` - -Congratulations! You are now logged in when visiting Icinga Web 2. \ No newline at end of file From 975230d1166c13f713f80ba0fabf0e15e33decc6 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 30 Mar 2016 18:02:40 +0200 Subject: [PATCH 026/109] monitoring: Use descriptive variable names in commentsAction() --- .../controllers/ListController.php | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 35ce34797..efde0a749 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -385,12 +385,20 @@ class ListController extends Controller $this->view->groupData = $groupData; } + /** + * List all comments + */ public function commentsAction() { - $this->addTitleTab('comments', $this->translate('Comments'), $this->translate('List comments')); + $this->addTitleTab( + 'comments', + $this->translate('Comments'), + $this->translate('List comments') + ); + $this->setAutorefreshInterval(12); - $query = $this->backend->select()->from('comment', array( + $comments = $this->backend->select()->from('comment', array( 'id' => 'comment_internal_id', 'objecttype' => 'object_type', 'comment' => 'comment_data', @@ -404,12 +412,11 @@ class ListController extends Controller 'host_display_name', 'service_display_name' )); - $this->applyRestriction('monitoring/filter/objects', $query); - $this->filterQuery($query); - $this->view->comments = $query; + $this->applyRestriction('monitoring/filter/objects', $comments); + $this->filterQuery($comments); + $this->setupPaginationControl($comments); $this->setupLimitControl(); - $this->setupPaginationControl($this->view->comments); $this->setupSortControl( array( 'comment_timestamp' => $this->translate('Comment Timestamp'), @@ -418,9 +425,11 @@ class ListController extends Controller 'comment_type' => $this->translate('Comment Type'), 'comment_expiration' => $this->translate('Expiration') ), - $query + $comments ); + $this->view->comments = $comments; + if ($this->Auth()->hasPermission('monitoring/command/comment/delete')) { $this->view->delCommentForm = new DeleteCommentCommandForm(); $this->view->delCommentForm->handleRequest(); From 7481e3af43086cf717ee067bbdc09b952178dcc4 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 30 Mar 2016 18:03:37 +0200 Subject: [PATCH 027/109] monitoring: Update controls markup in comments refs #11145 --- .../application/views/scripts/list/comments.phtml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/comments.phtml b/modules/monitoring/application/views/scripts/list/comments.phtml index 0801a7e4d..4941922a9 100644 --- a/modules/monitoring/application/views/scripts/list/comments.phtml +++ b/modules/monitoring/application/views/scripts/list/comments.phtml @@ -1,11 +1,11 @@ compact): ?>
- + tabs ?> render('list/components/selectioninfo.phtml') ?> -
- sortBox ?> + paginator ?> +
limiter ?> - paginator ?> + sortBox ?>
filterEditor ?>
From a2ff8c9778d49d322050aa79bcd8fbc157ccac5c Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:14:15 +0200 Subject: [PATCH 028/109] monitoring: No longer provide contact columns in the contact group query Contacts query w/ filter for contact group should be used instead. --- .../controllers/ListController.php | 36 ++++------- .../views/scripts/list/contactgroups.phtml | 61 +++++++++---------- .../Backend/Ido/Query/ContactgroupQuery.php | 38 +++--------- .../Monitoring/DataView/Contactgroup.php | 27 +------- 4 files changed, 50 insertions(+), 112 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index efde0a749..d1fba8a72 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -342,6 +342,9 @@ class ListController extends Controller $this->view->orientation = $orientation; } + /** + * List contact groups + */ public function contactgroupsAction() { $this->addTitleTab( @@ -350,39 +353,22 @@ class ListController extends Controller $this->translate('List contact groups') ); - $query = $this->backend->select()->from('contactgroup', array( + $contactGroups = $this->backend->select()->from('contactgroup', array( 'contactgroup_name', 'contactgroup_alias', - 'contact_name', - 'contact_alias', - 'contact_email', - 'contact_pager' + 'contact_count' )); - $this->applyRestriction('monitoring/filter/objects', $query); - $this->filterQuery($query); + $this->applyRestriction('monitoring/filter/objects', $contactGroups); + $this->filterQuery($contactGroups); + $this->setupPaginationControl($contactGroups); + $this->setupLimitControl(); $this->setupSortControl(array( 'contactgroup_name' => $this->translate('Contactgroup Name'), 'contactgroup_alias' => $this->translate('Contactgroup Alias') - ), $query); + ), $contactGroups); - // Fetch and prepare all contact groups: - $contactgroups = $query->getQuery()->fetchAll(); - $groupData = array(); - foreach ($contactgroups as $c) { - if (!array_key_exists($c->contactgroup_name, $groupData)) { - $groupData[$c->contactgroup_name] = array( - 'alias' => $c->contactgroup_alias, - 'contacts' => array() - ); - } - if (isset ($c->contact_name)) { - $groupData[$c->contactgroup_name]['contacts'][] = $c; - } - } - - // TODO: Find a better naming - $this->view->groupData = $groupData; + $this->view->contactGroups = $contactGroups; } /** diff --git a/modules/monitoring/application/views/scripts/list/contactgroups.phtml b/modules/monitoring/application/views/scripts/list/contactgroups.phtml index eea6302b1..7deb4e6fb 100644 --- a/modules/monitoring/application/views/scripts/list/contactgroups.phtml +++ b/modules/monitoring/application/views/scripts/list/contactgroups.phtml @@ -12,42 +12,39 @@ if (! $this->compact): ?>
-translate('No contactgroups found matching the filter') . '
'; - return; -} -?> - +hasResult()): ?> +

translate('No contact groups found matching the filter') ?>

+ + +
- - - - - + + + + + - - $groupInfo): ?> - - + + + + - diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/ContactgroupQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/ContactgroupQuery.php index f0afc0768..c861d1fc9 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/ContactgroupQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/ContactgroupQuery.php @@ -16,12 +16,12 @@ class ContactgroupQuery extends IdoQuery /** * {@inheritdoc} */ - protected $groupBase = array('contactgroups' => array('cg.contactgroup_id', 'cgo.object_id')); + protected $groupBase = array('contactgroups' => array('cg.contactgroup_id')); /** * {@inheritdoc} */ - protected $groupOrigin = array('contacts', 'hosts', 'services'); + protected $groupOrigin = array('hosts', 'members', 'services'); /** * {@inheritdoc} @@ -32,28 +32,8 @@ class ContactgroupQuery extends IdoQuery 'contactgroup_name' => 'cgo.name1', 'contactgroup_alias' => 'cg.alias COLLATE latin1_general_ci' ), - 'contacts' => array( - 'contact_id' => 'c.contact_id', - 'contact' => 'co.name1 COLLATE latin1_general_ci', - 'contact_name' => 'co.name1', - 'contact_alias' => 'c.alias COLLATE latin1_general_ci', - 'contact_email' => 'c.email_address COLLATE latin1_general_ci', - 'contact_pager' => 'c.pager_address', - 'contact_object_id' => 'c.contact_object_id', - 'contact_has_host_notfications' => 'c.host_notifications_enabled', - 'contact_has_service_notfications' => 'c.service_notifications_enabled', - 'contact_can_submit_commands' => 'c.can_submit_commands', - 'contact_notify_service_recovery' => 'c.notify_service_recovery', - 'contact_notify_service_warning' => 'c.notify_service_warning', - 'contact_notify_service_critical' => 'c.notify_service_critical', - 'contact_notify_service_unknown' => 'c.notify_service_unknown', - 'contact_notify_service_flapping' => 'c.notify_service_flapping', - 'contact_notify_service_downtime' => 'c.notify_service_recovery', - 'contact_notify_host_recovery' => 'c.notify_host_recovery', - 'contact_notify_host_down' => 'c.notify_host_down', - 'contact_notify_host_unreachable' => 'c.notify_host_unreachable', - 'contact_notify_host_flapping' => 'c.notify_host_flapping', - 'contact_notify_host_downtime' => 'c.notify_host_downtime' + 'members' => array( + 'contact_count' => 'COUNT(cgm.contactgroup_member_id)' ), 'hostgroups' => array( 'hostgroup' => 'hgo.name1 COLLATE latin1_general_ci', @@ -99,22 +79,18 @@ class ContactgroupQuery extends IdoQuery } /** - * Join contacts + * Join contact group members */ - protected function joinContacts() + protected function joinMembers() { $this->select->joinLeft( array('cgm' => $this->prefix . 'contactgroup_members'), 'cgm.contactgroup_id = cg.contactgroup_id', array() - )->joinLeft( + )->join( array('co' => $this->prefix . 'objects'), 'co.object_id = cgm.contact_object_id AND co.is_active = 1 AND co.objecttype_id = 10', array() - )->joinLeft( - array('c' => $this->prefix . 'contacts'), - 'c.contact_object_id = co.object_id', - array() ); } diff --git a/modules/monitoring/library/Monitoring/DataView/Contactgroup.php b/modules/monitoring/library/Monitoring/DataView/Contactgroup.php index cb12b0e2f..84eecd101 100644 --- a/modules/monitoring/library/Monitoring/DataView/Contactgroup.php +++ b/modules/monitoring/library/Monitoring/DataView/Contactgroup.php @@ -11,31 +11,9 @@ class Contactgroup extends DataView public function getColumns() { return array( - 'instance_name', 'contactgroup_name', 'contactgroup_alias', - 'contact_object_id', - 'contact_id', - 'contact_name', - 'contact_alias', - 'contact_email', - 'contact_pager', - 'contact_has_host_notfications', - 'contact_has_service_notfications', - 'contact_can_submit_commands', - 'contact_notify_service_recovery', - 'contact_notify_service_warning', - 'contact_notify_service_critical', - 'contact_notify_service_unknown', - 'contact_notify_service_flapping', - 'contact_notify_service_downtime', - 'contact_notify_host_recovery', - 'contact_notify_host_down', - 'contact_notify_host_unreachable', - 'contact_notify_host_flapping', - 'contact_notify_host_downtime', - 'contact_notify_host_timeperiod', - 'contact_notify_service_timeperiod' + 'contact_count' ); } @@ -60,9 +38,10 @@ class Contactgroup extends DataView public function getStaticFilterColumns() { return array( - 'contactgroup', 'contact', + 'contactgroup', 'host', 'host_name', 'host_display_name', 'host_alias', 'hostgroup', 'hostgroup_alias', 'hostgroup_name', + 'instance_name', 'service', 'service_description', 'service_display_name', 'servicegroup', 'servicegroup_alias', 'servicegroup_name' ); From 6e287d7905f9ca7c9cea1ab4599e26ea87c91dfe Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:15:39 +0200 Subject: [PATCH 029/109] monitoring: Update controls markup in contact groups refs #11145 --- .../application/views/scripts/list/contactgroups.phtml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/contactgroups.phtml b/modules/monitoring/application/views/scripts/list/contactgroups.phtml index 7deb4e6fb..c0656471a 100644 --- a/modules/monitoring/application/views/scripts/list/contactgroups.phtml +++ b/modules/monitoring/application/views/scripts/list/contactgroups.phtml @@ -2,11 +2,11 @@ if (! $this->compact): ?>
- -
- sortBox ?> + tabs ?> + paginator ?> +
limiter ?> - paginator ?> + sortBox ?>
filterEditor ?>
From af2a26474e02f6c22347db347de3d0b5ca0bdeea Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:18:21 +0200 Subject: [PATCH 030/109] monitoring: Use descriptive variable names in contactsAction() --- .../controllers/ListController.php | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index d1fba8a72..ced141a74 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -274,11 +274,18 @@ class ListController extends Controller ), $query); } + /** + * List contacts + */ public function contactsAction() { - $this->addTitleTab('contacts', $this->translate('Contacts'), $this->translate('List contacts')); + $this->addTitleTab( + 'contacts', + $this->translate('Contacts'), + $this->translate('List contacts') + ); - $query = $this->backend->select()->from('contact', array( + $contacts = $this->backend->select()->from('contact', array( 'contact_name', 'contact_alias', 'contact_email', @@ -286,20 +293,21 @@ class ListController extends Controller 'contact_notify_service_timeperiod', 'contact_notify_host_timeperiod' )); - $this->applyRestriction('monitoring/filter/objects', $query); - $this->filterQuery($query); - $this->view->contacts = $query; + $this->applyRestriction('monitoring/filter/objects', $contacts); + $this->filterQuery($contacts); + $this->setupPaginationControl($contacts); $this->setupLimitControl(); - $this->setupPaginationControl($this->view->contacts); $this->setupSortControl(array( - 'contact_name' => $this->translate('Name'), + 'contact_name' => $this->translate('Name'), 'contact_alias' => $this->translate('Alias'), 'contact_email' => $this->translate('Email'), 'contact_pager' => $this->translate('Pager Address / Number'), 'contact_notify_service_timeperiod' => $this->translate('Service Notification Timeperiod'), 'contact_notify_host_timeperiod' => $this->translate('Host Notification Timeperiod') - ), $query); + ), $contacts); + + $this->view->contacts = $contacts; } public function eventgridAction() From bb565b28aa2056c9e3640bff9d8cb5f8b1924042 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:18:35 +0200 Subject: [PATCH 031/109] monitoring/contacts: Remove sort by time period --- modules/monitoring/application/controllers/ListController.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index ced141a74..f3c83d30e 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -302,9 +302,7 @@ class ListController extends Controller 'contact_name' => $this->translate('Name'), 'contact_alias' => $this->translate('Alias'), 'contact_email' => $this->translate('Email'), - 'contact_pager' => $this->translate('Pager Address / Number'), - 'contact_notify_service_timeperiod' => $this->translate('Service Notification Timeperiod'), - 'contact_notify_host_timeperiod' => $this->translate('Host Notification Timeperiod') + 'contact_pager' => $this->translate('Pager Address / Number') ), $contacts); $this->view->contacts = $contacts; From a2d067ba97064023627b31e118d5c02973d4c353 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:19:41 +0200 Subject: [PATCH 032/109] monitoring: Update controls markup in contacts refs #11145 --- .../application/views/scripts/list/contacts.phtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/contacts.phtml b/modules/monitoring/application/views/scripts/list/contacts.phtml index aca29d88e..f3ff3187c 100644 --- a/modules/monitoring/application/views/scripts/list/contacts.phtml +++ b/modules/monitoring/application/views/scripts/list/contacts.phtml @@ -1,10 +1,10 @@ compact): ?>
-
- sortBox ?> + paginator ?> +
limiter ?> - paginator ?> + sortBox ?>
filterEditor ?>
From 1da35eaad40ae19cdf63255c30dc99ac4151b4f4 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:24:31 +0200 Subject: [PATCH 033/109] monitoring/list: Update content markup in contacts --- .../views/scripts/list/contacts.phtml | 100 +++++++++--------- 1 file changed, 52 insertions(+), 48 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/contacts.phtml b/modules/monitoring/application/views/scripts/list/contacts.phtml index f3ff3187c..f712ada8a 100644 --- a/modules/monitoring/application/views/scripts/list/contacts.phtml +++ b/modules/monitoring/application/views/scripts/list/contacts.phtml @@ -1,6 +1,6 @@ compact): ?>
- + tabs ?> paginator ?>
limiter ?> @@ -10,70 +10,74 @@
-hasResult()): ?> -
translate('Contact Group ') ?>translate('Alias') ?>
translate('Contact Group ') ?>translate('Alias') ?>
- -
+ contact_count ?> + + qlink( + $contactGroup->contactgroup_name, + 'monitoring/list/contacts', + array('contactgroup_name' => $contactGroup->contactgroup_name), + array('title' => sprintf( + $this->translate('Show detailed information about %s'), + $contactGroup->contactgroup_name + )) + ) ?> + - qlink( - $groupName, - 'monitoring/list/contacts', - array('contactgroup_name' => $groupName), - array('title' => sprintf( - $this->translate('Show detailed information about %s'), - $groupName - )) - ) ?> - - - - + contactgroup_name !== $contactGroup->contactgroup_alias): ?> + contactgroup_alias ?> +
- +hasResult()): ?> +

translate('No contacts found matching the filter') ?>

+ + +
+ - - - peekAhead($this->compact) as $contact): ?> - - + peekAhead($this->compact) as $contact): ?> + + + ) + ) + ) ?> + + - - contact_notify_service_timeperiod): ?> - - + contact_notify_service_timeperiod): ?> + + - contact_notify_host_timeperiod): ?> - - - - - + contact_notify_host_timeperiod): ?> + + + + +
translate('Name') ?> translate('Email') ?> translate('Pager') ?>
- qlink( - $contact->contact_name, - 'monitoring/show/contact', - array('contact_name' => $contact->contact_name), - array('title' => sprintf( + +
+ qlink( + $contact->contact_name, + 'monitoring/show/contact', + array('contact_name' => $contact->contact_name), + array( + 'title' => sprintf( $this->translate('Show detailed information about %s'), $contact->contact_alias - ), 'class' => 'rowaction') - ); ?> - + translate('Email') ?>: + + escape($contact->contact_email) ?> + + - translate('Email') ?>: - - escape($contact->contact_email); ?> - + contact_pager): ?> + escape($contact->contact_pager) ?> + - contact_pager): ?> - escape($contact->contact_pager) ?> - - - escape($contact->contact_notify_service_timeperiod) ?> - + escape($contact->contact_notify_service_timeperiod) ?> + - escape($contact->contact_notify_host_timeperiod) ?> -
+ escape($contact->contact_notify_host_timeperiod) ?> +
- hasMore()): ?> +hasMore()): ?> + From 40e1c96df08dc6eda97370b339ae62cc83ee13cd Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:25:56 +0200 Subject: [PATCH 034/109] monitoring: Use descriptive variable names in downtimesAction() --- .../controllers/ListController.php | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index f3c83d30e..88cb5edd6 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -187,14 +187,19 @@ class ListController extends Controller } /** - * Fetch the current downtimes and put them into the view property `downtimes` + * List downtimes */ public function downtimesAction() { - $this->addTitleTab('downtimes', $this->translate('Downtimes'), $this->translate('List downtimes')); + $this->addTitleTab( + 'downtimes', + $this->translate('Downtimes'), + $this->translate('List downtimes') + ); + $this->setAutorefreshInterval(12); - $query = $this->backend->select()->from('downtime', array( + $downtimes = $this->backend->select()->from('downtime', array( 'id' => 'downtime_internal_id', 'objecttype' => 'object_type', 'comment' => 'downtime_comment', @@ -215,13 +220,11 @@ class ListController extends Controller 'host_display_name', 'service_display_name' )); - $this->applyRestriction('monitoring/filter/objects', $query); - $this->filterQuery($query); - - $this->view->downtimes = $query; + $this->applyRestriction('monitoring/filter/objects', $downtimes); + $this->filterQuery($downtimes); + $this->setupPaginationControl($downtimes); $this->setupLimitControl(); - $this->setupPaginationControl($this->view->downtimes); $this->setupSortControl(array( 'downtime_is_in_effect' => $this->translate('Is In Effect'), 'host_display_name' => $this->translate('Host'), @@ -233,7 +236,9 @@ class ListController extends Controller 'downtime_scheduled_start' => $this->translate('Scheduled Start'), 'downtime_scheduled_end' => $this->translate('Scheduled End'), 'downtime_duration' => $this->translate('Duration') - ), $query); + ), $downtimes); + + $this->view->downtimes = $downtimes; if ($this->Auth()->hasPermission('monitoring/command/downtime/delete')) { $this->view->delDowntimeForm = new DeleteDowntimeCommandForm(); From f135e4d0d26b4a3d77882535294c7b45061f3726 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:28:18 +0200 Subject: [PATCH 035/109] monitoring: Update controls markup in downtimes refs #11145 --- .../application/views/scripts/list/downtimes.phtml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/downtimes.phtml b/modules/monitoring/application/views/scripts/list/downtimes.phtml index 1033fdfe8..e0ac873d6 100644 --- a/modules/monitoring/application/views/scripts/list/downtimes.phtml +++ b/modules/monitoring/application/views/scripts/list/downtimes.phtml @@ -3,13 +3,13 @@ use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Service; if (! $this->compact): ?> -
+
render('list/components/selectioninfo.phtml') ?> -
- sortBox ?> + paginator ?> +
limiter ?> - paginator ?> + sortBox ?>
filterEditor ?>
From bd3d40d46dd285a1bfb3b9f6770d96b6028bcf6e Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:33:21 +0200 Subject: [PATCH 036/109] monitoring: Update content markup in downtimes --- .../views/scripts/list/downtimes.phtml | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/downtimes.phtml b/modules/monitoring/application/views/scripts/list/downtimes.phtml index e0ac873d6..cefddfa53 100644 --- a/modules/monitoring/application/views/scripts/list/downtimes.phtml +++ b/modules/monitoring/application/views/scripts/list/downtimes.phtml @@ -4,7 +4,7 @@ use Icinga\Module\Monitoring\Object\Service; if (! $this->compact): ?>
- + tabs ?> render('list/components/selectioninfo.phtml') ?> paginator ?>
@@ -15,39 +15,44 @@ if (! $this->compact): ?>
- " - data-icinga-multiselect-data="downtime_id"> +hasResult()): ?> +

translate('No downtimes found matching the filter.') ?>

+ + +
" + data-icinga-multiselect-data="downtime_id"> peekAhead($this->compact) as $downtime): - if (isset($downtime->service_description)) { - $this->isService = true; - $this->stateName = Service::getStateText($downtime->service_state); - } else { - $this->isService = false; - $this->stateName = Host::getStateText($downtime->host_state); - } - $this->downtime = $downtime; - ?> - - render('partials/downtime/downtime-header.phtml'); ?> - + if (isset($downtime->service_description)) { + $this->isService = true; + $this->stateName = Service::getStateText($downtime->service_state); + } else { + $this->isService = false; + $this->stateName = Host::getStateText($downtime->host_state); + } + // Set downtime for partials + $this->downtime = $downtime; + ?> + + render('partials/downtime/downtime-header.phtml') ?> + -
-hasResult()): ?> - translate('No downtimes found matching the filter, maybe the downtime already expired.'); ?> -hasMore()): ?> - qlink( - $this->translate('Show More'), - $this->url()->without(array('view', 'limit')), - null, - array( - 'data-base-target' => '_next', - 'class' => 'pull-right action-link' - ) - ); ?> + +hasMore()): ?> +
From c7249eab0c494f9341c7a9b7b9fecb756c2f915b Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:36:59 +0200 Subject: [PATCH 037/109] monitoring: Update controls markup in event views refs #11145 --- .../application/views/scripts/list/eventgrid.phtml | 8 ++------ .../application/views/scripts/list/eventhistory.phtml | 6 +++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/eventgrid.phtml b/modules/monitoring/application/views/scripts/list/eventgrid.phtml index 37024b841..aafa9b6b1 100644 --- a/modules/monitoring/application/views/scripts/list/eventgrid.phtml +++ b/modules/monitoring/application/views/scripts/list/eventgrid.phtml @@ -4,12 +4,8 @@ use Icinga\Web\Widget\Chart\HistoryColorGrid; if (! $this->compact): ?>
- tabs; ?> - sortBox; ?> - limiter; ?> - paginator; ?> - filterEditor; ?> - + tabs ?> + form ?>
diff --git a/modules/monitoring/application/views/scripts/list/eventhistory.phtml b/modules/monitoring/application/views/scripts/list/eventhistory.phtml index 32bb3d128..2ee788d60 100644 --- a/modules/monitoring/application/views/scripts/list/eventhistory.phtml +++ b/modules/monitoring/application/views/scripts/list/eventhistory.phtml @@ -3,11 +3,11 @@ if (! $this->compact): ?>
tabs ?> -
- sortBox ?> +
limiter ?> - filterEditor ?> + sortBox ?>
+ filterEditor ?>
partial( From 28e639bde1d678ecc31f1ebd19fea6e0a2da0738 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:38:02 +0200 Subject: [PATCH 038/109] monitoring: Use descriptive variable names in hostgroupsAction() --- .../controllers/ListController.php | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 88cb5edd6..e53f29417 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -470,10 +470,15 @@ class ListController extends Controller public function hostgroupsAction() { - $this->addTitleTab('hostgroups', $this->translate('Host Groups'), $this->translate('List host groups')); + $this->addTitleTab( + 'hostgroups', + $this->translate('Host Groups'), + $this->translate('List host groups') + ); + $this->setAutorefreshInterval(12); - $query = $this->backend->select()->from('hostgroupsummary', array( + $hostGroups = $this->backend->select()->from('hostgroupsummary', array( 'hostgroup_alias', 'hostgroup_name', 'hosts_down_handled', @@ -493,18 +498,19 @@ class ListController extends Controller 'services_warning_handled', 'services_warning_unhandled' )); - $this->applyRestriction('monitoring/filter/objects', $query); - $this->filterQuery($query); - $this->view->hostgroups = $query; + $this->applyRestriction('monitoring/filter/objects', $hostGroups); + $this->filterQuery($hostGroups); + $this->setupPaginationControl($hostGroups); $this->setupLimitControl(); - $this->setupPaginationControl($this->view->hostgroups); $this->setupSortControl(array( 'hosts_severity' => $this->translate('Severity'), 'hostgroup_alias' => $this->translate('Host Group Name'), 'hosts_total' => $this->translate('Total Hosts'), 'services_total' => $this->translate('Total Services') - ), $query); + ), $hostGroups); + + $this->view->hostgroups = $hostGroups; } public function eventhistoryAction() From 0551133291f53d520fb41c9489b3be5834a43fd1 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:40:54 +0200 Subject: [PATCH 039/109] monitoring: Update controls markup in host groups refs #11145 --- .../application/views/scripts/list/hostgroups.phtml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/hostgroups.phtml b/modules/monitoring/application/views/scripts/list/hostgroups.phtml index c39a80d33..848e2cd98 100644 --- a/modules/monitoring/application/views/scripts/list/hostgroups.phtml +++ b/modules/monitoring/application/views/scripts/list/hostgroups.phtml @@ -1,13 +1,13 @@ compact): ?>
- -
+ tabs ?> + paginator ?> +
sortBox ?> limiter ?> - paginator ?>
filterEditor ?>
From 7bc17aee74644e6acb5c27855a8768c3921f3824 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:44:48 +0200 Subject: [PATCH 040/109] monitoring: Update content markup in host groups --- .../controllers/ListController.php | 2 +- .../views/scripts/list/hostgroups.phtml | 516 +++++++++--------- 2 files changed, 260 insertions(+), 258 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index e53f29417..9e8a085cd 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -510,7 +510,7 @@ class ListController extends Controller 'services_total' => $this->translate('Total Services') ), $hostGroups); - $this->view->hostgroups = $hostGroups; + $this->view->hostGroups = $hostGroups; } public function eventhistoryAction() diff --git a/modules/monitoring/application/views/scripts/list/hostgroups.phtml b/modules/monitoring/application/views/scripts/list/hostgroups.phtml index 848e2cd98..2fbd9d4c5 100644 --- a/modules/monitoring/application/views/scripts/list/hostgroups.phtml +++ b/modules/monitoring/application/views/scripts/list/hostgroups.phtml @@ -6,273 +6,275 @@ if (! $this->compact): ?> tabs ?> paginator ?>
- sortBox ?> limiter ?> + sortBox ?>
filterEditor ?>
-hasResult()): ?> +hasResult()): ?>

translate('No host groups found matching the filter.') ?>

- - - - - - - - - - - -peekAhead($this->compact) as $hostgroup): ?> - - - - - - + + + +
translate('Host Group') ?>translate('Host States') ?>translate('Service States') ?>
- hosts_total ?> - - qlink( - $hostgroup->hostgroup_alias, - 'monitoring/list/hosts', - array('hostgroup_name' => $hostgroup->hostgroup_name), - array('title' => sprintf( - $this->translate('List all hosts in the group "%s"'), - $hostgroup->hostgroup_alias - )) - ) ?> - - setUrl('monitoring/list/hosts') - ->setBaseFilter($this->filterEditor->getFilter()) - ->add( - StateBadges::STATE_UP, - $hostgroup->hosts_up, - array( - 'host_state' => 0, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'host_severity' - ), - 'List %u host that is currently in state UP in the host group "%s"', - 'List %u hosts which are currently in state UP in the host group "%s"', - array($hostgroup->hosts_up, $hostgroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_DOWN, - $hostgroup->hosts_down_unhandled, - array( - 'host_state' => 1, - 'host_acknowledged' => 0, - 'host_in_downtime' => 0, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'host_severity' - ), - 'List %u host that is currently in state DOWN in the host group "%s"', - 'List %u hosts which are currently in state DOWN in the host group "%s"', - array($hostgroup->hosts_down_unhandled, $hostgroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_DOWN_HANDLED, - $hostgroup->hosts_down_handled, - array( - 'host_state' => 1, - 'host_handled' => 1, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'host_severity' - ), - 'List %u host that is currently in state DOWN (Acknowledged) in the host group "%s"', - 'List %u hosts which are currently in state DOWN (Acknowledged) in the host group "%s"', - array($hostgroup->hosts_down_handled, $hostgroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_UNREACHABLE, - $hostgroup->hosts_unreachable_unhandled, - array( - 'host_state' => 2, - 'host_acknowledged' => 0, - 'host_in_downtime' => 0, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'host_severity' - ), - 'List %u host that is currently in state UNREACHABLE in the host group "%s"', - 'List %u hosts which are currently in state UNREACHABLE in the host group "%s"', - array($hostgroup->hosts_unreachable_unhandled, $hostgroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_UNREACHABLE_HANDLED, - $hostgroup->hosts_unreachable_handled, - array( - 'host_state' => 2, - 'host_handled' => 1, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'host_severity' - ), - 'List %u host that is currently in state UNREACHABLE (Acknowledged) in the host group "%s"', - 'List %u hosts which are currently in state UNREACHABLE (Acknowledged) in the host group "%s"', - array($hostgroup->hosts_unreachable_handled, $hostgroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_PENDING, - $hostgroup->hosts_pending, - array( - 'host_state' => 99, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'host_severity' - ), - 'List %u host that is currently in state PENDING in the host group "%s"', - 'List %u hosts which are currently in state PENDING in the host group "%s"', - array($hostgroup->hosts_pending, $hostgroup->hostgroup_alias) - ); - echo $stateBadges->render(); - ?> - - qlink( - $hostgroup->services_total, - 'monitoring/list/services', - array('hostgroup_name' => $hostgroup->hostgroup_name), - array('title' => sprintf( - $this->translate('List all services of all hosts in host group "%s"'), - $hostgroup->hostgroup_alias - ), 'class' => 'badge') - ) ?> - - setUrl('monitoring/list/services') - ->add( - StateBadges::STATE_OK, - $hostgroup->services_ok, - array( - 'service_state' => 0, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'service_severity' - ), - 'List %u service that is currently in state OK on hosts in the host group "%s"', - 'List %u services which are currently in state OK on hosts in the host group "%s"', - array($hostgroup->services_ok, $hostgroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_CRITICAL, - $hostgroup->services_critical_unhandled, - array( - 'service_state' => 2, - 'service_acknowledged' => 0, - 'service_in_downtime' => 0, - 'host_problem' => 0, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'service_severity' - ), - 'List %u service that is currently in state CRITICAL on hosts in the host group "%s"', - 'List %u services which are currently in state CRITICAL on hosts in the host group "%s"', - array($hostgroup->services_critical_unhandled, $hostgroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_CRITICAL_HANDLED, - $hostgroup->services_critical_handled, - array( - 'service_state' => 2, - 'service_handled' => 1, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'service_severity' - ), - 'List %u service that is currently in state CRITICAL (Acknowledged) on hosts in the host group "%s"', - 'List %u services which are currently in state CRITICAL (Acknowledged) on hosts in the host group "%s"', - array($hostgroup->services_critical_unhandled, $hostgroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_UNKNOWN, - $hostgroup->services_unknown_unhandled, - array( - 'service_state' => 3, - 'service_acknowledged' => 0, - 'service_in_downtime' => 0, - 'host_problem' => 0, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'service_severity' - ), - 'List %u service that is currently in state UNKNOWN on hosts in the host group "%s"', - 'List %u services which are currently in state UNKNOWN on hosts in the host group "%s"', - array($hostgroup->services_unknown_unhandled, $hostgroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_UNKNOWN_HANDLED, - $hostgroup->services_unknown_handled, - array( - 'service_state' => 3, - 'service_handled' => 1, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'service_severity' - ), - 'List %u service that is currently in state UNKNOWN (Acknowledged) on hosts in the host group "%s"', - 'List %u services which are currently in state UNKNOWN (Acknowledged) on hosts in the host group "%s"', - array($hostgroup->services_unknown_handled, $hostgroup->hostgroup_alias) + + + + + + + + + + + + peekAhead($this->compact) as $hostGroup): ?> + + + + + + - - - -
translate('Host Group') ?>translate('Host States') ?>translate('Service States') ?>
+ hosts_total ?> + + qlink( + $hostGroup->hostgroup_alias, + 'monitoring/list/hosts', + array('hostgroup_name' => $hostGroup->hostgroup_name), + array('title' => sprintf( + $this->translate('List all hosts in the group "%s"'), + $hostGroup->hostgroup_alias + )) + ) ?> + + setUrl('monitoring/list/hosts') + ->setBaseFilter($this->filterEditor->getFilter()) + ->add( + StateBadges::STATE_UP, + $hostGroup->hosts_up, + array( + 'host_state' => 0, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'host_severity' + ), + 'List %u host that is currently in state UP in the host group "%s"', + 'List %u hosts which are currently in state UP in the host group "%s"', + array($hostGroup->hosts_up, $hostGroup->hostgroup_alias) + ) + ->add( + StateBadges::STATE_DOWN, + $hostGroup->hosts_down_unhandled, + array( + 'host_state' => 1, + 'host_acknowledged' => 0, + 'host_in_downtime' => 0, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'host_severity' + ), + 'List %u host that is currently in state DOWN in the host group "%s"', + 'List %u hosts which are currently in state DOWN in the host group "%s"', + array($hostGroup->hosts_down_unhandled, $hostGroup->hostgroup_alias) + ) + ->add( + StateBadges::STATE_DOWN_HANDLED, + $hostGroup->hosts_down_handled, + array( + 'host_state' => 1, + 'host_handled' => 1, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'host_severity' + ), + 'List %u host that is currently in state DOWN (Acknowledged) in the host group "%s"', + 'List %u hosts which are currently in state DOWN (Acknowledged) in the host group "%s"', + array($hostGroup->hosts_down_handled, $hostGroup->hostgroup_alias) + ) + ->add( + StateBadges::STATE_UNREACHABLE, + $hostGroup->hosts_unreachable_unhandled, + array( + 'host_state' => 2, + 'host_acknowledged' => 0, + 'host_in_downtime' => 0, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'host_severity' + ), + 'List %u host that is currently in state UNREACHABLE in the host group "%s"', + 'List %u hosts which are currently in state UNREACHABLE in the host group "%s"', + array($hostGroup->hosts_unreachable_unhandled, $hostGroup->hostgroup_alias) + ) + ->add( + StateBadges::STATE_UNREACHABLE_HANDLED, + $hostGroup->hosts_unreachable_handled, + array( + 'host_state' => 2, + 'host_handled' => 1, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'host_severity' + ), + 'List %u host that is currently in state UNREACHABLE (Acknowledged) in the host group "%s"', + 'List %u hosts which are currently in state UNREACHABLE (Acknowledged) in the host group "%s"', + array($hostGroup->hosts_unreachable_handled, $hostGroup->hostgroup_alias) + ) + ->add( + StateBadges::STATE_PENDING, + $hostGroup->hosts_pending, + array( + 'host_state' => 99, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'host_severity' + ), + 'List %u host that is currently in state PENDING in the host group "%s"', + 'List %u hosts which are currently in state PENDING in the host group "%s"', + array($hostGroup->hosts_pending, $hostGroup->hostgroup_alias) + ); + echo $stateBadges->render(); + ?> + + qlink( + $hostGroup->services_total, + 'monitoring/list/services', + array('hostgroup_name' => $hostGroup->hostgroup_name), + array('title' => sprintf( + $this->translate('List all services of all hosts in host group "%s"'), + $hostGroup->hostgroup_alias + ), 'class' => 'badge') + ) ?> + + setUrl('monitoring/list/services') + ->add( + StateBadges::STATE_OK, + $hostGroup->services_ok, + array( + 'service_state' => 0, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'service_severity' + ), + 'List %u service that is currently in state OK on hosts in the host group "%s"', + 'List %u services which are currently in state OK on hosts in the host group "%s"', + array($hostGroup->services_ok, $hostGroup->hostgroup_alias) + ) + ->add( + StateBadges::STATE_CRITICAL, + $hostGroup->services_critical_unhandled, + array( + 'service_state' => 2, + 'service_acknowledged' => 0, + 'service_in_downtime' => 0, + 'host_problem' => 0, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'service_severity' + ), + 'List %u service that is currently in state CRITICAL on hosts in the host group "%s"', + 'List %u services which are currently in state CRITICAL on hosts in the host group "%s"', + array($hostGroup->services_critical_unhandled, $hostGroup->hostgroup_alias) + ) + ->add( + StateBadges::STATE_CRITICAL_HANDLED, + $hostGroup->services_critical_handled, + array( + 'service_state' => 2, + 'service_handled' => 1, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'service_severity' + ), + 'List %u service that is currently in state CRITICAL (Acknowledged) on hosts in the host group "%s"', + 'List %u services which are currently in state CRITICAL (Acknowledged) on hosts in the host group "%s"', + array($hostGroup->services_critical_unhandled, $hostGroup->hostgroup_alias) + ) + ->add( + StateBadges::STATE_UNKNOWN, + $hostGroup->services_unknown_unhandled, + array( + 'service_state' => 3, + 'service_acknowledged' => 0, + 'service_in_downtime' => 0, + 'host_problem' => 0, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'service_severity' + ), + 'List %u service that is currently in state UNKNOWN on hosts in the host group "%s"', + 'List %u services which are currently in state UNKNOWN on hosts in the host group "%s"', + array($hostGroup->services_unknown_unhandled, $hostGroup->hostgroup_alias) + ) + ->add( + StateBadges::STATE_UNKNOWN_HANDLED, + $hostGroup->services_unknown_handled, + array( + 'service_state' => 3, + 'service_handled' => 1, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'service_severity' + ), + 'List %u service that is currently in state UNKNOWN (Acknowledged) on hosts in the host group "%s"', + 'List %u services which are currently in state UNKNOWN (Acknowledged) on hosts in the host group "%s"', + array($hostGroup->services_unknown_handled, $hostGroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_WARNING, - $hostgroup->services_warning_unhandled, - array( - 'service_state' => 1, - 'service_acknowledged' => 0, - 'service_in_downtime' => 0, - 'host_problem' => 0, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'service_severity' - ), - 'List %u service that is currently in state WARNING on hosts in the host group "%s"', - 'List %u services which are currently in state WARNING on hosts in the host group "%s"', - array($hostgroup->services_warning_unhandled, $hostgroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_WARNING_HANDLED, - $hostgroup->services_warning_handled, - array( - 'service_state' => 1, - 'service_handled' => 1, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'service_severity' - ), - 'List %u service that is currently in state WARNING (Acknowledged) on hosts in the host group "%s"', - 'List %u services which are currently in state WARNING (Acknowledged) on hosts in the host group "%s"', - array($hostgroup->services_warning_handled, $hostgroup->hostgroup_alias) - ) - ->add( - StateBadges::STATE_PENDING, - $hostgroup->services_pending, - array( - 'service_state' => 99, - 'hostgroup_name' => $hostgroup->hostgroup_name, - 'sort' => 'service_severity' - ), - 'List %u service that is currently in state PENDING on hosts in the host group "%s"', - 'List %u services which are currently in state PENDING on hosts in the host group "%s"', - array($hostgroup->services_pending, $hostgroup->hostgroup_alias) - ); - echo $stateBadges->render(); - ?> -
-hasMore()): ?> -qlink( - $this->translate('Show More'), - $this->url()->without(array('view', 'limit')), - null, - array( - 'data-base-target' => '_next', - 'class' => 'pull-right action-link' - ) -) ?> + ) + ->add( + StateBadges::STATE_WARNING, + $hostGroup->services_warning_unhandled, + array( + 'service_state' => 1, + 'service_acknowledged' => 0, + 'service_in_downtime' => 0, + 'host_problem' => 0, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'service_severity' + ), + 'List %u service that is currently in state WARNING on hosts in the host group "%s"', + 'List %u services which are currently in state WARNING on hosts in the host group "%s"', + array($hostGroup->services_warning_unhandled, $hostGroup->hostgroup_alias) + ) + ->add( + StateBadges::STATE_WARNING_HANDLED, + $hostGroup->services_warning_handled, + array( + 'service_state' => 1, + 'service_handled' => 1, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'service_severity' + ), + 'List %u service that is currently in state WARNING (Acknowledged) on hosts in the host group "%s"', + 'List %u services which are currently in state WARNING (Acknowledged) on hosts in the host group "%s"', + array($hostGroup->services_warning_handled, $hostGroup->hostgroup_alias) + ) + ->add( + StateBadges::STATE_PENDING, + $hostGroup->services_pending, + array( + 'service_state' => 99, + 'hostgroup_name' => $hostGroup->hostgroup_name, + 'sort' => 'service_severity' + ), + 'List %u service that is currently in state PENDING on hosts in the host group "%s"', + 'List %u services which are currently in state PENDING on hosts in the host group "%s"', + array($hostGroup->services_pending, $hostGroup->hostgroup_alias) + ); + echo $stateBadges->render(); + ?> +
+hasMore()): ?> +
From c1dce54b71d86d52d16441020b97b23d33b3b5ac Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:49:02 +0200 Subject: [PATCH 041/109] monitoring: Use descriptive variable names in hostsAction() --- .../controllers/ListController.php | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 9e8a085cd..5e1e678c5 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -39,10 +39,18 @@ class ListController extends Controller } /** - * Display host list + * List hosts */ public function hostsAction() { + $this->addTitleTab( + 'hosts', + $this->translate('Hosts'), + $this->translate('List hosts') + ); + + $this->setAutorefreshInterval(10); + // Handle soft and hard states if (strtolower($this->params->shift('stateType', 'soft')) === 'hard') { $stateColumn = 'host_hard_state'; @@ -51,9 +59,8 @@ class ListController extends Controller $stateColumn = 'host_state'; $stateChangeColumn = 'host_last_state_change'; } - $this->addTitleTab('hosts', $this->translate('Hosts'), $this->translate('List hosts')); - $this->setAutorefreshInterval(10); - $query = $this->backend->select()->from('hoststatus', array_merge(array( + + $hosts = $this->backend->select()->from('hoststatus', array_merge(array( 'host_icon_image', 'host_icon_image_alt', 'host_name', @@ -71,9 +78,20 @@ class ListController extends Controller 'host_active_checks_enabled', 'host_passive_checks_enabled' ), $this->addColumns())); - $this->applyRestriction('monitoring/filter/objects', $query); - $this->filterQuery($query); - $this->view->hosts = $query; + $this->applyRestriction('monitoring/filter/objects', $hosts); + $this->filterQuery($hosts); + + $this->setupPaginationControl($hosts); + $this->setupLimitControl(); + $this->setupSortControl(array( + 'host_severity' => $this->translate('Severity'), + 'host_state' => $this->translate('Current State'), + 'host_display_name' => $this->translate('Hostname'), + 'host_address' => $this->translate('Address'), + 'host_last_check' => $this->translate('Last Check'), + 'host_last_state_change' => $this->translate('Last State Change') + ), $hosts); + $stats = $this->backend->select()->from('hoststatussummary', array( 'hosts_total', 'hosts_up', @@ -86,20 +104,12 @@ class ListController extends Controller 'hosts_pending', )); $this->applyRestriction('monitoring/filter/objects', $stats); - $this->view->stats = $stats; - $this->setupLimitControl(); - $this->setupPaginationControl($this->view->hosts); - $this->setupSortControl(array( - 'host_severity' => $this->translate('Severity'), - 'host_state' => $this->translate('Current State'), - 'host_display_name' => $this->translate('Hostname'), - 'host_address' => $this->translate('Address'), - 'host_last_check' => $this->translate('Last Check'), - 'host_last_state_change' => $this->translate('Last State Change') - ), $query); - $summary = $query->getQuery()->queryServiceProblemSummary(); + $summary = $hosts->getQuery()->queryServiceProblemSummary(); $this->applyRestriction('monitoring/filter/objects', $summary); + + $this->view->hosts = $hosts; + $this->view->stats = $stats; $this->view->summary = $summary->fetchPairs(); } @@ -468,6 +478,9 @@ class ListController extends Controller ), $query); } + /** + * List host groups + */ public function hostgroupsAction() { $this->addTitleTab( From 107a06df4ea59a541e258391c3e93f2767fc4a01 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:49:25 +0200 Subject: [PATCH 042/109] monitoring: Update controls markup in hosts refs #11145 --- .../views/scripts/list/hosts.phtml | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/hosts.phtml b/modules/monitoring/application/views/scripts/list/hosts.phtml index f5ff2569a..6de773435 100644 --- a/modules/monitoring/application/views/scripts/list/hosts.phtml +++ b/modules/monitoring/application/views/scripts/list/hosts.phtml @@ -4,14 +4,12 @@ use Icinga\Module\Monitoring\Object\Host; if (! $this->compact): ?>
tabs ?> -
- render('list/components/hostssummary.phtml') ?> - render('list/components/selectioninfo.phtml') ?> -
-
- sortBox ?> + render('list/components/hostssummary.phtml') ?> + render('list/components/selectioninfo.phtml') ?> + paginator ?> +
limiter ?> - paginator ?> + sortBox ?>
filterEditor ?>
@@ -19,7 +17,7 @@ if (! $this->compact): ?>
hasResult()): ?>

translate('No hosts found matching the filter.') ?>

-
+
compact): ?>
hasMore()): ?> -
+ From 9e4d5387ab2a2cd3f5dc9021a3cac0ddbff304ef Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:52:11 +0200 Subject: [PATCH 043/109] monitoring: Use descriptive variable names in notificatiosnAction() --- .../application/controllers/ListController.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 5e1e678c5..7f5201d07 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -257,7 +257,7 @@ class ListController extends Controller } /** - * Display notification overview + * List notifications */ public function notificationsAction() { @@ -266,9 +266,10 @@ class ListController extends Controller $this->translate('Notifications'), $this->translate('List notifications') ); + $this->setAutorefreshInterval(15); - $query = $this->backend->select()->from('notification', array( + $notifications = $this->backend->select()->from('notification', array( 'host_name', 'service_description', 'notification_output', @@ -278,15 +279,16 @@ class ListController extends Controller 'host_display_name', 'service_display_name' )); - $this->applyRestriction('monitoring/filter/objects', $query); - $this->filterQuery($query); - $this->view->notifications = $query; + $this->applyRestriction('monitoring/filter/objects', $notifications); + $this->filterQuery($notifications); + $this->setupPaginationControl($notifications); $this->setupLimitControl(); - $this->setupPaginationControl($this->view->notifications); $this->setupSortControl(array( 'notification_start_time' => $this->translate('Notification Start') - ), $query); + ), $notifications); + + $this->view->notifications = $notifications; } /** From 09892d54901511defef595f33ffdca91f4e7b3c5 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 09:52:54 +0200 Subject: [PATCH 044/109] monitoring: Update controls markup in notifications refs #11145 --- .../application/views/scripts/list/notifications.phtml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/notifications.phtml b/modules/monitoring/application/views/scripts/list/notifications.phtml index 6428055cc..8316665d1 100644 --- a/modules/monitoring/application/views/scripts/list/notifications.phtml +++ b/modules/monitoring/application/views/scripts/list/notifications.phtml @@ -4,11 +4,11 @@ use Icinga\Module\Monitoring\Object\Service; if (! $this->compact): ?>
- -
- sortBox ?> + tabs ?> + paginator ?> +
limiter ?> - paginator ?> + sortBox ?>
filterEditor ?>
@@ -77,7 +77,7 @@ if (! $this->compact): ?> hasMore()): ?> -
+ From f50906dade99f3dd93d13825a045cd8bc49154b6 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 10:05:21 +0200 Subject: [PATCH 048/109] monitoring: Use descriptive variable names in servicesAction() --- .../controllers/ListController.php | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index f6209be15..8e493ed44 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -114,10 +114,16 @@ class ListController extends Controller } /** - * Display service list + * List services */ public function servicesAction() { + $this->addTitleTab( + 'services', + $this->translate('Services'), + $this->translate('List services') + ); + // Handle soft and hard states if (strtolower($this->params->shift('stateType', 'soft')) === 'hard') { $stateColumn = 'service_hard_state'; @@ -127,14 +133,9 @@ class ListController extends Controller $stateChangeColumn = 'service_last_state_change'; } - $this->addTitleTab('services', $this->translate('Services'), $this->translate('List services')); - $this->view->showHost = true; - if (strpos($this->params->get('host_name', '*'), '*') === false) { - $this->view->showHost = false; - } $this->setAutorefreshInterval(10); - $columns = array_merge(array( + $services = $this->backend->select()->from('servicestatus', array_merge(array( 'host_name', 'host_display_name', 'host_state', @@ -157,14 +158,12 @@ class ListController extends Controller 'service_notifications_enabled', 'service_active_checks_enabled', 'service_passive_checks_enabled' - ), $this->addColumns()); - $query = $this->backend->select()->from('servicestatus', $columns); - $this->applyRestriction('monitoring/filter/objects', $query); - $this->filterQuery($query); - $this->view->services = $query; + ), $this->addColumns())); + $this->applyRestriction('monitoring/filter/objects', $services); + $this->filterQuery($services); + $this->setupPaginationControl($services); $this->setupLimitControl(); - $this->setupPaginationControl($this->view->services); $this->setupSortControl(array( 'service_severity' => $this->translate('Service Severity'), 'service_state' => $this->translate('Current Service State'), @@ -176,7 +175,7 @@ class ListController extends Controller 'host_display_name' => $this->translate('Hostname'), 'host_address' => $this->translate('Host Address'), 'host_last_check' => $this->translate('Last Host Check') - ), $query); + ), $services); $stats = $this->backend->select()->from('servicestatussummary', array( 'services_critical', @@ -193,7 +192,14 @@ class ListController extends Controller 'services_warning_unhandled' )); $this->applyRestriction('monitoring/filter/objects', $stats); + + $this->view->services = $services; $this->view->stats = $stats; + if (strpos($this->params->get('host_name', '*'), '*') === false) { + $this->view->showHost = false; + } else { + $this->view->showHost = true; + } } /** From ad6d8dca2ee9f7c6bf79b0cda15a63e13de0db4d Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 10:05:53 +0200 Subject: [PATCH 049/109] monitoring: Update controls markup in services refs #11145 --- .../views/scripts/list/services.phtml | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/services.phtml b/modules/monitoring/application/views/scripts/list/services.phtml index 211347f53..d8fd5d4b5 100644 --- a/modules/monitoring/application/views/scripts/list/services.phtml +++ b/modules/monitoring/application/views/scripts/list/services.phtml @@ -5,14 +5,12 @@ use Icinga\Module\Monitoring\Object\Service; if (! $this->compact): ?>
tabs ?> -
- render('list/components/servicesummary.phtml') ?> - render('list/components/selectioninfo.phtml') ?> -
-
- sortBox ?> + render('list/components/servicesummary.phtml') ?> + render('list/components/selectioninfo.phtml') ?> + paginator ?> +
limiter ?> - paginator ?> + sortBox ?>
filterEditor ?>
@@ -101,16 +99,16 @@ if (! $this->compact): ?> hasMore()): ?> -
- qlink( - $this->translate('Show More'), - $this->url()->without(array('view', 'limit')), - null, - array( - 'data-base-target' => '_next', - 'class' => 'action-link' - ) - ) ?> -
+
From 6267001053be4e80eb5540b1cee05f748e1d921e Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Tue, 16 Feb 2016 14:32:38 +0100 Subject: [PATCH 050/109] monitoring: float state-summaries left refs #11145 --- modules/monitoring/public/css/module.less | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index c0c2fb023..87427fe9a 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -79,6 +79,11 @@ } } +.controls > .hosts-summary, +.controls > .services-summary { + float: left; +} + // State table in the host and service multi-selection and detail views .host-detail-state, .service-detail-state { From 13f8da254cf4d3b35dabeb39efde064e1a488021 Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Tue, 16 Feb 2016 14:35:00 +0100 Subject: [PATCH 051/109] CSS: Fix controls floating refs #11145 --- public/css/icinga/controls.less | 17 +++++++++++++++++ public/css/icinga/main.less | 3 --- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/public/css/icinga/controls.less b/public/css/icinga/controls.less index a4582a56d..b57293b17 100644 --- a/public/css/icinga/controls.less +++ b/public/css/icinga/controls.less @@ -1,5 +1,14 @@ /*! Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */ +.filter { + clear: both; +} + +.limiter-control, +.sort-control { + display: inline-block; +} + .limiter-control > .control-group { padding: 0; @@ -19,6 +28,9 @@ } .pagination-control { + clear: both; + float: left; + li { &.active { > a, @@ -78,6 +90,11 @@ } } +.sort-controls-container { + clear: right; + float: right; +} + html.no-js .sort-control form { display: table; margin-left: auto; diff --git a/public/css/icinga/main.less b/public/css/icinga/main.less index 61373e772..402c76f05 100644 --- a/public/css/icinga/main.less +++ b/public/css/icinga/main.less @@ -177,10 +177,8 @@ a:hover > .icon-cancel { width: @name-value-table-name-width; } -// TODO(el): Fix .controls { .limiter-control { - float: right; padding: @vertical-padding / 2 0; margin-bottom: 0.25em; } @@ -191,7 +189,6 @@ a:hover > .icon-cancel { } .sort-control { - float: right; padding: @vertical-padding / 2 0; margin-bottom: 0.25em; margin-left: 0.5em; From 4ea1e054e98f36399cc042f2a552126ab5c69517 Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Tue, 16 Feb 2016 15:59:07 +0100 Subject: [PATCH 052/109] Update user and group list controls markup refs #11145 --- application/views/scripts/group/list.phtml | 14 ++++++-------- application/views/scripts/user/list.phtml | 14 ++++++-------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/application/views/scripts/group/list.phtml b/application/views/scripts/group/list.phtml index cf0645633..b4e27d8a6 100644 --- a/application/views/scripts/group/list.phtml +++ b/application/views/scripts/group/list.phtml @@ -5,16 +5,14 @@ use Icinga\Data\Reducible; if (! $this->compact): ?>
- -
- sortBox ?> + tabs ?> + paginator ?> +
limiter ?> - paginator ?> -
-
- backendSelection; ?> - filterEditor; ?> + sortBox ?>
+ backendSelection ?> + filterEditor ?>
diff --git a/application/views/scripts/user/list.phtml b/application/views/scripts/user/list.phtml index 182e26e87..7e045d8a9 100644 --- a/application/views/scripts/user/list.phtml +++ b/application/views/scripts/user/list.phtml @@ -5,16 +5,14 @@ use Icinga\Data\Reducible; if (! $this->compact): ?>
- -
- sortBox ?> + tabs ?> + paginator ?> +
limiter ?> - paginator ?> -
-
- backendSelection ?> - filterEditor ?> + sortBox ?>
+ backendSelection ?> + filterEditor ?>
From a492839097ee18ee07338effbf7884f60602df13 Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Tue, 16 Feb 2016 15:59:49 +0100 Subject: [PATCH 053/109] CSS: add style for backend-selection refs #11145 --- public/css/icinga/controls.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/css/icinga/controls.less b/public/css/icinga/controls.less index b57293b17..325954877 100644 --- a/public/css/icinga/controls.less +++ b/public/css/icinga/controls.less @@ -1,5 +1,9 @@ /*! Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */ +.backend-selection { + float: left; +} + .filter { clear: both; } From 793acd8475694a0fb23040f14f6f778fffd7f9ce Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 12:38:25 +0200 Subject: [PATCH 054/109] CSS: Move styles related to controls to controls.less refs #11145 --- modules/monitoring/public/css/module.less | 11 ------ public/css/icinga/controls.less | 48 ++++++++++++++++++++--- public/css/icinga/main.less | 32 --------------- 3 files changed, 43 insertions(+), 48 deletions(-) diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 87427fe9a..2c0fe1a46 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -47,17 +47,6 @@ } } -// Multi-selection info -.selection-info { - float: right; - font-size: @font-size-small; - padding: @vertical-padding / 2 0; - - &:hover { - cursor: help; - } -} - // Performance data pie charts .sparkline { height: 1em; diff --git a/public/css/icinga/controls.less b/public/css/icinga/controls.less index 325954877..9bc611dcd 100644 --- a/public/css/icinga/controls.less +++ b/public/css/icinga/controls.less @@ -1,20 +1,34 @@ /*! Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */ +// TODO(el): Rename .filter to .filter-control + +// Backend selection control in user and group list views .backend-selection { float: left; } -.filter { - clear: both; +.backend-selection, +.pagination-control, +.selection-info, +.sort-controls-container { + margin-bottom: 0.5em; } -.limiter-control, -.sort-control { - display: inline-block; +.backend-selection, +.pagination-control, +.sort-controls-container { + // Select controls may not respect font-size thus leading to improperly vertical alignment w/o big enough line-height + line-height: 2em; +} + +.filter { + // Display filter control on a new line + clear: both; } .limiter-control > .control-group { padding: 0; + // Note that the sort-control form does not have padding as it's utilizing different decorators > .control-label-group { text-align: left; @@ -31,7 +45,14 @@ } } +.limiter-control, +.sort-control { + // Display limiter and sort control both on the same line; floating could be used here too to achieve the same + display: inline-block; +} + .pagination-control { + // Display the pagination-control on a new line clear: both; float: left; @@ -73,7 +94,19 @@ } } +// Multi-selection info +.selection-info { + float: right; + font-size: @font-size-small; + + &:hover { + cursor: help; + } +} + .sort-control { + margin-left: 0.25em; + label { width: auto; margin-right: 0.5em; @@ -99,6 +132,11 @@ float: right; } +.sort-direction-control { + margin-left: 0.25em; + width: 1em; +} + html.no-js .sort-control form { display: table; margin-left: auto; diff --git a/public/css/icinga/main.less b/public/css/icinga/main.less index 402c76f05..fa5066064 100644 --- a/public/css/icinga/main.less +++ b/public/css/icinga/main.less @@ -177,38 +177,6 @@ a:hover > .icon-cancel { width: @name-value-table-name-width; } -.controls { - .limiter-control { - padding: @vertical-padding / 2 0; - margin-bottom: 0.25em; - } - - .pagination-control { - padding: @vertical-padding / 2 0; - margin-bottom: 0.25em; - } - - .sort-control { - padding: @vertical-padding / 2 0; - margin-bottom: 0.25em; - margin-left: 0.5em; - } - - .sort-direction-control { - margin-bottom: 0.5em; - margin-left: 0.5em; - width: 1em; - } - - .filter { - margin-bottom: 0.5em; - } - - .selection-info { - margin-left: 0.5em; - } -} - /* Styles for centering content of unknown width and height both horizontally and vertically * * Example markup: From 9e0bee5006d0a92566e390b29eaa5c4a9e8f6aac Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Wed, 9 Mar 2016 13:45:26 +0100 Subject: [PATCH 055/109] Fix mispositioned mobile menu icon fixes #11099 --- public/css/icinga/layout.less | 17 ++++++++++++++++- public/js/icinga/ui.js | 21 ++++++++++----------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/public/css/icinga/layout.less b/public/css/icinga/layout.less index 9b155b9c1..ca090326e 100644 --- a/public/css/icinga/layout.less +++ b/public/css/icinga/layout.less @@ -76,7 +76,6 @@ @gutter: 1em; // x-column-layout - #main { .clearfix(); @@ -109,6 +108,22 @@ } } +// Mobile menu +#mobile-menu-toggle { + text-align: right; + + > button { + background: none; + border: none; + height: 2.5em; + + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + } +} + #sidebar { background-color: @gray-lighter; } diff --git a/public/js/icinga/ui.js b/public/js/icinga/ui.js index 09876e954..c5c90860e 100644 --- a/public/js/icinga/ui.js +++ b/public/js/icinga/ui.js @@ -587,7 +587,7 @@ }); if ($layout.hasClass('minimal-layout')) { - if (! this.mobileMenu) { + if (! this.mobileMenu && $sidebar.length) { $header.css({ top: $sidebar.outerHeight() + 'px' }); @@ -599,19 +599,18 @@ zIndex: 2 }); $sidebar + .on( + 'click', + this.toggleMobileMenu + ) + .prepend( + $('
') + ) .css({ - paddingBottom: 32, + paddingBottom: $('#mobile-menu-toggle').height(), top: 0, zIndex: 3 - }) - .on('click', this.toggleMobileMenu) - .prepend( - $('').css({ - cursor: 'pointer', - display: 'block', - height: '32px' - }) - ); + }); $search.on('keypress', this.closeMobileMenu); this.mobileMenu = true; From 862fddd705a38c24a413b74d41df019b932a2240 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 16:29:16 +0200 Subject: [PATCH 056/109] Reduce font-size in login --- public/css/icinga/login.less | 2 -- 1 file changed, 2 deletions(-) diff --git a/public/css/icinga/login.less b/public/css/icinga/login.less index 9c9a28a98..9a91a87ef 100644 --- a/public/css/icinga/login.less +++ b/public/css/icinga/login.less @@ -3,8 +3,6 @@ // Login page styles #login { - font-size: 1em; - #icinga-logo { .fadein(); } From f9b7c302fc1b291c9773ac072d673b970561ba76 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 31 Mar 2016 17:38:34 +0200 Subject: [PATCH 057/109] doc: Update bullets in toc --- modules/doc/public/css/module.less | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/doc/public/css/module.less b/modules/doc/public/css/module.less index 26dd18fd0..035c18278 100644 --- a/modules/doc/public/css/module.less +++ b/modules/doc/public/css/module.less @@ -60,14 +60,11 @@ pre > code { a { &:before { - .rounded-corners(); - - background-color: @icinga-blue; - color: @text-color-on-icinga-blue; - content: counter(li) "."; + color: @icinga-blue; + content: counters(li,".") " "; display: inline-block; font-size: small; - margin-right: 0.25em; + font-weight: @font-weight-bold; min-width: 1.5em; padding: 0.25em; text-align: center; From dc4bcdabb63416fa340e03b79e0f3e25b20dffe4 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 1 Apr 2016 14:19:20 +0200 Subject: [PATCH 058/109] Gettext: respect context while parsing mt(...) --- .../library/Translation/Util/GettextTranslationHelper.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/translation/library/Translation/Util/GettextTranslationHelper.php b/modules/translation/library/Translation/Util/GettextTranslationHelper.php index 49df57fb2..2178ca371 100644 --- a/modules/translation/library/Translation/Util/GettextTranslationHelper.php +++ b/modules/translation/library/Translation/Util/GettextTranslationHelper.php @@ -284,6 +284,7 @@ class GettextTranslationHelper '--keyword=translatePlural:1,2', '--keyword=translatePlural:1,2,4c', '--keyword=mt:2', + '--keyword=mt:2,3c', '--keyword=mtp:2,3', '--keyword=mtp:2,3,5c', '--keyword=t', From 38892a971f8668bd9aea435c23f672a661d24c2f Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 1 Apr 2016 14:32:33 +0200 Subject: [PATCH 059/109] doc: Support loading images beneath doc/ directories --- .../controllers/ModuleController.php | 57 +++++++++++++++ modules/doc/doc/1-module-documentation.md | 12 ++-- modules/doc/library/Doc/DocController.php | 11 ++- .../doc/library/Doc/Renderer/DocRenderer.php | 71 +++++++++++++------ .../Doc/Renderer/DocSectionRenderer.php | 15 +++- modules/doc/run.php | 15 ++++ 6 files changed, 151 insertions(+), 30 deletions(-) diff --git a/modules/doc/application/controllers/ModuleController.php b/modules/doc/application/controllers/ModuleController.php index b6b2d6375..5544dbce4 100644 --- a/modules/doc/application/controllers/ModuleController.php +++ b/modules/doc/application/controllers/ModuleController.php @@ -3,6 +3,8 @@ namespace Icinga\Module\Doc\Controllers; +use finfo; +use SplFileInfo; use Icinga\Application\Icinga; use Icinga\Module\Doc\DocController; use Icinga\Module\Doc\Exception\DocException; @@ -120,6 +122,7 @@ class ModuleController extends DocController $this->getPath($module, Icinga::app()->getModuleManager()->getModuleDir($module, '/doc')), $chapter, 'doc/module/chapter', + 'doc/module/img', array('moduleName' => $module) ); } catch (DocException $e) { @@ -127,6 +130,60 @@ class ModuleController extends DocController } } + /** + * Deliver images + */ + public function imageAction() + { + $module = $this->params->getRequired('moduleName'); + $image = $this->params->getRequired('image'); + $docPath = $this->getPath($module, Icinga::app()->getModuleManager()->getModuleDir($module, '/doc')); + $imagePath = realpath($docPath . '/' . $image); + if ($imagePath === false) { + $this->httpNotFound('%s does not exist', $image); + } + + $this->_helper->viewRenderer->setNoRender(true); + $this->_helper->layout()->disableLayout(); + + $imageInfo = new SplFileInfo($imagePath); + + $ETag = md5($imageInfo->getMTime() . $imagePath); + $lastModified = gmdate('D, d M Y H:i:s T', $imageInfo->getMTime()); + $match = false; + + if (isset($_SERER['HTTP_IF_NONE_MATCH'])) { + $ifNoneMatch = explode(', ', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])); + foreach ($ifNoneMatch as $tag) { + if ($tag === $ETag) { + $match = true; + break; + } + } + } elseif (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { + $lastModifiedSince = stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']); + if ($lastModifiedSince === $lastModified) { + $match = true; + } + } + + header('ETag: "' . $ETag . '"'); + header('Cache-Control: no-transform,public,max-age=3600'); + header('Last-Modified: ' . $lastModified); + // Set additional headers for compatibility reasons (Cache-Control should have precedence) in case + // session.cache_limiter is set to no cache + header('Pragma: cache'); + header('Expires: ' . gmdate('D, d M Y H:i:s T', time() + 3600)); + + if ($match) { + header('HTTP/1.1 304 Not Modified'); + } else { + $finfo = new finfo(); + header('Content-Type: ' . $finfo->file($imagePath, FILEINFO_MIME_TYPE)); + readfile($imagePath); + } + } + /** * View a module's documentation as PDF * diff --git a/modules/doc/doc/1-module-documentation.md b/modules/doc/doc/1-module-documentation.md index edf20aac2..2334324a9 100644 --- a/modules/doc/doc/1-module-documentation.md +++ b/modules/doc/doc/1-module-documentation.md @@ -1,6 +1,6 @@ # Writing Module Documentation -![Markdown](/img/doc/doc/markdown.png) +![Markdown](img/markdown.png) Icinga Web 2 is capable of viewing your module's documentation, if the documentation is written in [Markdown](http://en.wikipedia.org/wiki/Markdown). Please refer to @@ -50,13 +50,15 @@ This syntax is also supported in Icinga Web 2. ## Including Images -Images must placed in the `img` directory beneath your module's `public` directory, e.g.: +Images must placed in the `doc` directory beneath your module's root directory, e.g.: - example-module/public/img/doc + /path/to/icingaweb2/modules/example-module/doc/img/example.png + +Note that the `img` sub directory is not mandatory but good for organizing your directory structure. Module images can be accessed using the following URL: - {baseURL}/img/{moduleName}/{file} e.g. icingaweb/img/example-module/doc/example.png + {baseURL}/doc/module/{moduleName}/image/{image} e.g. icingaweb2/doc/module/example-module/image/img/example.png Markdown's image syntax is very similar to Markdown's link syntax, but prefixed with an exclamation mark, e.g.: @@ -64,4 +66,4 @@ Markdown's image syntax is very similar to Markdown's link syntax, but prefixed URLs to images inside your Markdown documentation files must be specified without the base URL, e.g.: - ![Example](/img/example-module/doc/example.png) + ![Example](img/example.png) diff --git a/modules/doc/library/Doc/DocController.php b/modules/doc/library/Doc/DocController.php index acd085d04..5f5438ed8 100644 --- a/modules/doc/library/Doc/DocController.php +++ b/modules/doc/library/Doc/DocController.php @@ -20,6 +20,9 @@ class DocController extends Controller if ($this->hasParam('chapter')) { $this->params->set('chapter', $this->getParam('chapter')); } + if ($this->hasParam('image')) { + $this->params->set('image', $this->getParam('image')); + } if ($this->hasParam('moduleName')) { $this->params->set('moduleName', $this->getParam('moduleName')); } @@ -31,16 +34,18 @@ class DocController extends Controller * @param string $path Path to the documentation * @param string $chapter ID of the chapter * @param string $url URL to replace links with + * @param string $imageUrl URL to images * @param array $urlParams Additional URL parameters */ - protected function renderChapter($path, $chapter, $url, array $urlParams = array()) + protected function renderChapter($path, $chapter, $url, $imageUrl = null, array $urlParams = array()) { $parser = new DocParser($path); $section = new DocSectionRenderer($parser->getDocTree(), DocSectionRenderer::decodeUrlParam($chapter)); $this->view->section = $section + ->setHighlightSearch($this->params->get('highlight-search')) + ->setImageUrl($imageUrl) ->setUrl($url) - ->setUrlParams($urlParams) - ->setHighlightSearch($this->params->get('highlight-search')); + ->setUrlParams($urlParams); $this->view->title = $chapter; $this->getTabs()->add('toc', array( 'active' => true, diff --git a/modules/doc/library/Doc/Renderer/DocRenderer.php b/modules/doc/library/Doc/Renderer/DocRenderer.php index feb420e91..3662fd574 100644 --- a/modules/doc/library/Doc/Renderer/DocRenderer.php +++ b/modules/doc/library/Doc/Renderer/DocRenderer.php @@ -13,6 +13,13 @@ use Icinga\Web\View; */ abstract class DocRenderer extends RecursiveIteratorIterator { + /** + * URL to images + * + * @var string + */ + protected $imageUrl; + /** * URL to replace links with * @@ -34,6 +41,38 @@ abstract class DocRenderer extends RecursiveIteratorIterator */ protected $view; + /** + * Get the URL to images + * + * @return string + */ + public function getImageUrl() + { + return $this->imageUrl; + } + + /** + * Set the URL to images + * + * @param string $imageUrl + * + * @return $this + */ + public function setImageUrl($imageUrl) + { + $this->imageUrl = (string) $imageUrl; + return $this; + } + /** + * Get the URL to replace links with + * + * @return string + */ + public function getUrl() + { + return $this->url; + } + /** * Set the URL to replace links with * @@ -48,13 +87,13 @@ abstract class DocRenderer extends RecursiveIteratorIterator } /** - * Get the URL to replace links with + * Get additional URL parameters * - * @return string + * @return array */ - public function getUrl() + public function getUrlParams() { - return $this->url; + return $this->urlParams; } /** @@ -71,13 +110,16 @@ abstract class DocRenderer extends RecursiveIteratorIterator } /** - * Get additional URL parameters + * Get the view * - * @return array + * @return View */ - public function getUrlParams() + public function getView() { - return $this->urlParams; + if ($this->view === null) { + $this->view = Icinga::app()->getViewRenderer()->view; + } + return $this->view; } /** @@ -93,19 +135,6 @@ abstract class DocRenderer extends RecursiveIteratorIterator return $this; } - /** - * Get the view - * - * @return View - */ - public function getView() - { - if ($this->view === null) { - $this->view = Icinga::app()->getViewRenderer()->view; - } - return $this->view; - } - /** * Encode an anchor identifier * diff --git a/modules/doc/library/Doc/Renderer/DocSectionRenderer.php b/modules/doc/library/Doc/Renderer/DocSectionRenderer.php index a39d24a77..9bc8bfee0 100644 --- a/modules/doc/library/Doc/Renderer/DocSectionRenderer.php +++ b/modules/doc/library/Doc/Renderer/DocSectionRenderer.php @@ -190,7 +190,20 @@ class DocSectionRenderer extends DocRenderer $xpath = new DOMXPath($doc); $img = $xpath->query('//img[1]')->item(0); /** @var \DOMElement $img */ - $img->setAttribute('src', Url::fromPath($img->getAttribute('src'))->getAbsoluteUrl()); + $path = $this->getView()->getHelper('Url')->url( + array_merge( + array( + 'image' => $img->getAttribute('src') + ), + $this->urlParams + ), + $this->imageUrl, + false, + false + ); + $url = $this->getView()->url($path); + /** @var \Icinga\Web\Url $url */ + $img->setAttribute('src', $url->getAbsoluteUrl()); return substr_replace($doc->saveXML($img), '', -2, 1); // Replace '/>' with '>' } diff --git a/modules/doc/run.php b/modules/doc/run.php index 9d49b89d4..df9dd0930 100644 --- a/modules/doc/run.php +++ b/modules/doc/run.php @@ -43,7 +43,22 @@ $docModulePdf = new Zend_Controller_Router_Route( ) ); +$docModuleImg = new Zend_Controller_Router_Route_Regex( + 'doc/module/([^/]+)/image/(.+)', + array( + 'controller' => 'module', + 'action' => 'image', + 'module' => 'doc' + ), + array( + 'moduleName' => 1, + 'image' => 2 + ), + 'doc/module/%s/image/%s' +); + $this->addRoute('doc/module/chapter', $docModuleChapter); $this->addRoute('doc/icingaweb/chapter', $docIcingaWebChapter); $this->addRoute('doc/module/toc', $docModuleToc); $this->addRoute('doc/module/pdf', $docModulePdf); +$this->addRoute('doc/module/img', $docModuleImg); From 3ecf390a4b35ec5d3eedefb37f7ea1ede0c032d2 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 1 Apr 2016 12:04:49 +0200 Subject: [PATCH 060/109] doc: Use module name for tab and window title --- modules/doc/application/controllers/ModuleController.php | 5 +++-- modules/doc/library/Doc/DocController.php | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/doc/application/controllers/ModuleController.php b/modules/doc/application/controllers/ModuleController.php index 5544dbce4..fafd94656 100644 --- a/modules/doc/application/controllers/ModuleController.php +++ b/modules/doc/application/controllers/ModuleController.php @@ -90,11 +90,12 @@ class ModuleController extends DocController { $module = $this->params->getRequired('moduleName'); $this->assertModuleInstalled($module); - $this->view->moduleName = $module; + $moduleManager = Icinga::app()->getModuleManager(); + $name = $moduleManager->getModule($module)->getTitle(); try { $this->renderToc( $this->getPath($module, Icinga::app()->getModuleManager()->getModuleDir($module, '/doc')), - $module, + $name, 'doc/module/chapter', array('moduleName' => $module) ); diff --git a/modules/doc/library/Doc/DocController.php b/modules/doc/library/Doc/DocController.php index 5f5438ed8..21c2173ce 100644 --- a/modules/doc/library/Doc/DocController.php +++ b/modules/doc/library/Doc/DocController.php @@ -71,10 +71,10 @@ class DocController extends Controller ->setUrl($url) ->setUrlParams($urlParams); $name = ucfirst($name); - $this->view->title = sprintf($this->translate('%s Documentation'), $name); + $title = sprintf($this->translate('%s Documentation'), $name); $this->getTabs()->add('toc', array( 'active' => true, - 'title' => $name, + 'title' => $title, 'url' => Url::fromRequest() )); $this->render('toc', null, true); From 48cd99aba3837e97171ad75fbbcae8b846ecf988 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 1 Apr 2016 14:38:23 +0200 Subject: [PATCH 061/109] doc: Render chapter tab titles human readable --- modules/doc/library/Doc/DocController.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/doc/library/Doc/DocController.php b/modules/doc/library/Doc/DocController.php index 21c2173ce..47c96b1a9 100644 --- a/modules/doc/library/Doc/DocController.php +++ b/modules/doc/library/Doc/DocController.php @@ -46,10 +46,15 @@ class DocController extends Controller ->setImageUrl($imageUrl) ->setUrl($url) ->setUrlParams($urlParams); - $this->view->title = $chapter; + $first = null; + foreach ($section as $first) { + break; + } + $title = $first === null ? ucfirst($chapter) : $first->getTitle(); + $this->view->title = $title; $this->getTabs()->add('toc', array( 'active' => true, - 'title' => ucfirst($chapter), + 'title' => $title, 'url' => Url::fromRequest() )); $this->render('chapter', null, true); From 0edd1b5a08cab7c5f7ece11351bf2a94237dcef3 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 1 Apr 2016 15:01:12 +0200 Subject: [PATCH 062/109] doc: natcasesort files --- library/Icinga/Util/DirectoryIterator.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/Icinga/Util/DirectoryIterator.php b/library/Icinga/Util/DirectoryIterator.php index 472899b2f..60368733e 100644 --- a/library/Icinga/Util/DirectoryIterator.php +++ b/library/Icinga/Util/DirectoryIterator.php @@ -222,7 +222,9 @@ class DirectoryIterator implements RecursiveIterator public function rewind() { if ($this->files === null) { - $this->files = new ArrayIterator(scandir($this->path)); + $files = scandir($this->path); + natcasesort($files); + $this->files = new ArrayIterator($files); } $this->files->rewind(); $this->queue = array(); From 0f538e7f06a683e615125a05bf17a92533b3d0c7 Mon Sep 17 00:00:00 2001 From: Markus Frosch Date: Thu, 31 Mar 2016 12:59:35 +0200 Subject: [PATCH 063/109] lib/LDAP: LdapUtils::explodeDN replace deprecated use of eval in preg_replace fixes #11490 --- library/Icinga/Protocol/Ldap/LdapUtils.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/Icinga/Protocol/Ldap/LdapUtils.php b/library/Icinga/Protocol/Ldap/LdapUtils.php index 68031fa57..3d86cf100 100644 --- a/library/Icinga/Protocol/Ldap/LdapUtils.php +++ b/library/Icinga/Protocol/Ldap/LdapUtils.php @@ -28,9 +28,11 @@ class LdapUtils $res = ldap_explode_dn($dn, $with_type ? 0 : 1); foreach ($res as $k => $v) { - $res[$k] = preg_replace( - '/\\\([0-9a-f]{2})/ei', - "chr(hexdec('\\1'))", + $res[$k] = preg_replace_callback( + '/\\\([0-9a-f]{2})/i', + function ($m) { + return chr(hexdec($m[1])); + }, $v ); } From 97bedfaa0814e8389dce3b80d57057d61a9ac770 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 6 Apr 2016 11:18:28 +0200 Subject: [PATCH 064/109] lib: Provide ticket pattern class for ticket hooks refs #10909 --- .../Application/Hook/Ticket/TicketPattern.php | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 library/Icinga/Application/Hook/Ticket/TicketPattern.php diff --git a/library/Icinga/Application/Hook/Ticket/TicketPattern.php b/library/Icinga/Application/Hook/Ticket/TicketPattern.php new file mode 100644 index 000000000..8116ca6be --- /dev/null +++ b/library/Icinga/Application/Hook/Ticket/TicketPattern.php @@ -0,0 +1,152 @@ +match[$offset]); + } + + /** + * {@inheritdoc} + */ + public function offsetGet($offset) + { + return array_key_exists($offset, $this->match) ? $this->match[$offset] : null; + } + + /** + * {@inheritdoc} + */ + public function offsetSet($offset, $value) + { + if ($offset === null) { + $this->match[] = $value; + } else { + $this->match[$offset] = $value; + } + } + + /** + * {@inheritdoc} + */ + public function offsetUnset($offset) + { + unset($this->match[$offset]); + } + + + /** + * Get the result of a performed ticket match + * + * @return array + */ + public function getMatch() + { + return $this->match; + } + + /** + * Set the result of a performed ticket match + * + * @param array $match + * + * @return $this + */ + public function setMatch(array $match) + { + $this->match = $match; + return $this; + } + + /** + * Get the name of the TTS integration + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Set the name of the TTS integration + * + * @param string $name + * + * @return $this + */ + public function setName($name) + { + $this->name = $name; + return $this; + } + + /** + * Get the ticket pattern + * + * @return string + */ + public function getPattern() + { + return $this->pattern; + } + + /** + * Set the ticket pattern + * + * @param string $pattern + * + * @return $this + */ + public function setPattern($pattern) + { + $this->pattern = $pattern; + return $this; + } + + /** + * Whether the integration is properly configured, i.e. the pattern and the URL are not empty + * + * @return bool + */ + public function isValid() + { + return ! empty($this->pattern); + } +} From 5b17a145f158568a59e3bf5da68c9dac907a9e1f Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 6 Apr 2016 11:28:41 +0200 Subject: [PATCH 065/109] Support multiple TTS integrations in the ticket hook refs #10909 --- .../Icinga/Application/Hook/TicketHook.php | 144 ++++++++++++++---- 1 file changed, 115 insertions(+), 29 deletions(-) diff --git a/library/Icinga/Application/Hook/TicketHook.php b/library/Icinga/Application/Hook/TicketHook.php index 72bb308ee..0cf106175 100644 --- a/library/Icinga/Application/Hook/TicketHook.php +++ b/library/Icinga/Application/Hook/TicketHook.php @@ -3,15 +3,17 @@ namespace Icinga\Application\Hook; +use ArrayIterator; use ErrorException; use Exception; +use Icinga\Application\Hook\Ticket\TicketPattern; use Icinga\Application\Logger; use Icinga\Exception\IcingaException; /** * Base class for ticket hooks * - * Extend this class if you want to integrate your ticketing solution Icinga Web 2 + * Extend this class if you want to integrate your ticketing solution into Icinga Web 2. */ abstract class TicketHook { @@ -39,6 +41,100 @@ abstract class TicketHook { } + /** + * Create a link for each matched element in the subject text + * + * @param array|TicketPattern $match Matched element according to {@link getPattern()} + * + * @return string Replacement string + */ + abstract public function createLink($match); + + /** + * Get the pattern(s) to search for + * + * Return an array of TicketPattern instances here to support multiple TTS integrations. + * + * @return string|TicketPattern[] + */ + abstract public function getPattern(); + + /** + * Apply ticket patterns to the given text + * + * @param string $text + * @param TicketPattern[] $ticketPatterns + * + * @return string + */ + private function applyTicketPatterns($text, array $ticketPatterns) + { + $out = ''; + $start = 0; + + $iterator = new ArrayIterator($ticketPatterns); + $iterator->rewind(); + + while ($iterator->valid()) { + $ticketPattern = $iterator->current(); + + try { + preg_match($ticketPattern->getPattern(), $text, $match, PREG_OFFSET_CAPTURE, $start); + } catch (ErrorException $e) { + $this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e)); + $iterator->next(); + continue; + } + + if (empty($match)) { + $iterator->next(); + continue; + } + + // Remove preg_offset from match for the ticket pattern + $carry = array(); + array_walk($match, function ($value, $key) use (&$carry) { + $carry[$key] = $value[0]; + }, $carry); + $ticketPattern->setMatch($carry); + + $offsetLeft = $match[0][1]; + $matchLength = strlen($match[0][0]); + + $out .= substr($text, $start, $offsetLeft - $start); + + try { + $out .= $this->createLink($ticketPattern); + } catch (Exception $e) { + $this->fail('Can\'t create ticket links: %s', IcingaException::describe($e)); + return $text; + } + + $start = $offsetLeft + $matchLength; + } + + $out .= substr($text, $start); + + return $out; + } + + /** + * Helper function to create a TicketPattern instance + * + * @param string $name Name of the TTS integration + * @param string $pattern Ticket pattern + * + * @return TicketPattern + */ + protected function createTicketPattern($name, $pattern) + { + $ticketPattern = new TicketPattern(); + $ticketPattern + ->setName($name) + ->setPattern($pattern); + return $ticketPattern; + } + /** * Set the hook as failed w/ the given message * @@ -63,22 +159,6 @@ abstract class TicketHook return $this->lastError; } - /** - * Get the pattern - * - * @return string - */ - abstract public function getPattern(); - - /** - * Create a link for each matched element in the subject text - * - * @param array $match Array of matched elements according to {@link getPattern()} - * - * @return string Replacement string - */ - abstract public function createLink($match); - /** * Create links w/ {@link createLink()} in the given text that matches to the subject from {@link getPattern()} * @@ -101,22 +181,28 @@ abstract class TicketHook $this->fail('Can\'t create ticket links: Retrieving the pattern failed: %s', IcingaException::describe($e)); return $text; } + if (empty($pattern)) { $this->fail('Can\'t create ticket links: Pattern is empty'); return $text; } - try { - $text = preg_replace_callback( - $pattern, - array($this, 'createLink'), - $text - ); - } catch (ErrorException $e) { - $this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e)); - return $text; - } catch (Exception $e) { - $this->fail('Can\'t create ticket links: %s', IcingaException::describe($e)); - return $text; + + if (is_array($pattern)) { + $text = $this->applyTicketPatterns($text, $pattern); + } else { + try { + $text = preg_replace_callback( + $pattern, + array($this, 'createLink'), + $text + ); + } catch (ErrorException $e) { + $this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e)); + return $text; + } catch (Exception $e) { + $this->fail('Can\'t create ticket links: %s', IcingaException::describe($e)); + return $text; + } } return $text; From 31adfb8a9f1357050b3e86ac00317bc7caf379dc Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 6 Apr 2016 12:09:49 +0200 Subject: [PATCH 066/109] Don't add the port twice when reloading CSS --- public/js/icinga/ui.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/public/js/icinga/ui.js b/public/js/icinga/ui.js index c5c90860e..af60a3ce9 100644 --- a/public/js/icinga/ui.js +++ b/public/js/icinga/ui.js @@ -100,9 +100,6 @@ var $oldLink = $(this); if ($oldLink.hasAttr('type') && $oldLink.attr('type').indexOf('css') > -1) { var base = location.protocol + '//' + location.host; - if (location.port) { - base += location.port; - } var url = icinga.utils.addUrlParams( $(this).attr('href'), { id: new Date().getTime() } From 9d87b469c7f176a44c088c2c7c887869dac90f1b Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Tue, 5 Apr 2016 14:12:15 +0200 Subject: [PATCH 067/109] Fix UserGroup authentication markup for empty state --- application/views/scripts/group/list.phtml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/application/views/scripts/group/list.phtml b/application/views/scripts/group/list.phtml index b4e27d8a6..36e59ceea 100644 --- a/application/views/scripts/group/list.phtml +++ b/application/views/scripts/group/list.phtml @@ -43,8 +43,7 @@ if (! isset($backend)) { hasResult()): ?>

translate('No user groups found matching the filter'); ?>

- - + From 73a80234cb29b9d966b57e027f2836437b8847cf Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Tue, 5 Apr 2016 14:13:24 +0200 Subject: [PATCH 068/109] Fix icon for remove action in the user group list --- application/views/scripts/group/list.phtml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/views/scripts/group/list.phtml b/application/views/scripts/group/list.phtml index 36e59ceea..84d75018c 100644 --- a/application/views/scripts/group/list.phtml +++ b/application/views/scripts/group/list.phtml @@ -82,8 +82,9 @@ if (! isset($backend)) { 'group' => $group->group_name ), array( + 'class' => 'action-link', 'title' => sprintf($this->translate('Remove user group %s'), $group->group_name), - 'icon' => 'trash' + 'icon' => 'cancel' ) ); ?> From ab626c211b03b748a23630d3b7f4aa3f1b74680c Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Tue, 5 Apr 2016 14:14:03 +0200 Subject: [PATCH 069/109] CSS: Fix alignment of action icon in tables --- public/css/icinga/main.less | 1 + 1 file changed, 1 insertion(+) diff --git a/public/css/icinga/main.less b/public/css/icinga/main.less index fa5066064..b7d2c7bb3 100644 --- a/public/css/icinga/main.less +++ b/public/css/icinga/main.less @@ -21,6 +21,7 @@ } .icon-col { + text-align: center; width: 1em; } From 0a9c0925cb187bc3dffa037f451308e44b9318ea Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Tue, 5 Apr 2016 14:15:08 +0200 Subject: [PATCH 070/109] CSS: Add space before the autosubmit info in forms --- library/Icinga/Web/Form/Decorator/Autosubmit.php | 2 +- public/css/icinga/forms.less | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/library/Icinga/Web/Form/Decorator/Autosubmit.php b/library/Icinga/Web/Form/Decorator/Autosubmit.php index e4392bbd9..f3ce02d53 100644 --- a/library/Icinga/Web/Form/Decorator/Autosubmit.php +++ b/library/Icinga/Web/Form/Decorator/Autosubmit.php @@ -100,7 +100,7 @@ class Autosubmit extends Zend_Form_Decorator_Abstract : t('Upon its value has changed, this field issues an automatic update of this page.'); $content .= $this->getView()->icon('cw', $warning, array( 'aria-hidden' => $isForm ? 'false' : 'true', - 'class' => 'spinner' + 'class' => 'spinner autosubmit-info' )); if (! $isForm && $this->getAccessible()) { $content = '' . $warning . '' . $content; diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index 25fd24265..e4cf350c3 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -83,6 +83,10 @@ form.inline { margin-left: 10em; } +.autosubmit-info { + margin-left: 0.5em; +} + button:hover .icon-cancel { color: @color-critical; } From 8792cfdf720937374c86ae51315c19da94cd1101 Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Wed, 6 Apr 2016 12:00:50 +0200 Subject: [PATCH 071/109] Fix alignment of backend selection in user and group lists --- public/css/icinga/controls.less | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/public/css/icinga/controls.less b/public/css/icinga/controls.less index 9bc611dcd..554be4048 100644 --- a/public/css/icinga/controls.less +++ b/public/css/icinga/controls.less @@ -2,9 +2,24 @@ // TODO(el): Rename .filter to .filter-control +// Hide auto sumbit info in controls but keep information for screen readers +.controls .autosubmit-info { + .sr-only(); +} + + // Backend selection control in user and group list views .backend-selection { float: left; + + > .control-group { + padding: 0; + + > .control-label-group { + text-align: left; + width: auto; + } + } } .backend-selection, @@ -121,10 +136,6 @@ width: 8em; margin-left: 0; } - - > form > i { - .sr-only(); - } } .sort-controls-container { From adeaf60aedcf4aa846165e7f6adec8f7c52b2f74 Mon Sep 17 00:00:00 2001 From: Markus Frosch Date: Thu, 31 Mar 2016 11:05:56 +0200 Subject: [PATCH 072/109] lib/LDAP: Do not explicitly set the fields list when ordering refs #11489 --- library/Icinga/Protocol/Ldap/LdapConnection.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/Icinga/Protocol/Ldap/LdapConnection.php b/library/Icinga/Protocol/Ldap/LdapConnection.php index 0729addfc..0f9d5a830 100644 --- a/library/Icinga/Protocol/Ldap/LdapConnection.php +++ b/library/Icinga/Protocol/Ldap/LdapConnection.php @@ -16,7 +16,6 @@ use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\FilterChain; use Icinga\Data\Filter\FilterExpression; use Icinga\Exception\ProgrammingError; -use Icinga\Protocol\Ldap\LdapException; /** * Encapsulate LDAP connections and query creation @@ -706,7 +705,7 @@ class LdapConnection implements Selectable, Inspectable 'value' => $this->encodeSortRules($query->getOrder()) ) )); - } else { + } elseif (! empty($fields)) { foreach ($query->getOrder() as $rule) { if (! in_array($rule[0], $fields, true)) { $fields[] = $rule[0]; @@ -825,7 +824,7 @@ class LdapConnection implements Selectable, Inspectable $ds = $this->getConnection(); $serverSorting = false;//$this->getCapabilities()->hasOid(LdapCapabilities::LDAP_SERVER_SORT_OID); - if (! $serverSorting && $query->hasOrder()) { + if (! $serverSorting && $query->hasOrder() && ! empty($fields)) { foreach ($query->getOrder() as $rule) { if (! in_array($rule[0], $fields, true)) { $fields[] = $rule[0]; From 202d61dd4e60f42c8f243366aa22621b4d7b9ff1 Mon Sep 17 00:00:00 2001 From: Markus Frosch Date: Tue, 5 Apr 2016 15:02:10 +0200 Subject: [PATCH 073/109] lib/LDAP: Add support for LDAP search scope Configurable on the LdapQuery, handled by LdapConnection::ldapSearch refs #11485 --- .../Icinga/Protocol/Ldap/LdapConnection.php | 23 ++++++- library/Icinga/Protocol/Ldap/LdapQuery.php | 68 +++++++++++++++++++ 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/library/Icinga/Protocol/Ldap/LdapConnection.php b/library/Icinga/Protocol/Ldap/LdapConnection.php index 0729addfc..2d9ee358a 100644 --- a/library/Icinga/Protocol/Ldap/LdapConnection.php +++ b/library/Icinga/Protocol/Ldap/LdapConnection.php @@ -4,6 +4,7 @@ namespace Icinga\Protocol\Ldap; use Exception; +use LogicException; use ArrayIterator; use Icinga\Application\Config; use Icinga\Application\Logger; @@ -1179,6 +1180,8 @@ class LdapConnection implements Selectable, Inspectable * @param int $deref * * @return resource|bool A search result identifier or false on error + * + * @throws LogicException If the LDAP query search scope is unsupported */ public function ldapSearch( LdapQuery $query, @@ -1190,6 +1193,7 @@ class LdapConnection implements Selectable, Inspectable ) { $queryString = (string) $query; $baseDn = $query->getBase() ?: $this->getDn(); + $scope = $query->getScope(); if (Logger::getInstance()->getLevel() === Logger::DEBUG) { // We're checking the level by ourself to avoid rendering the ldapsearch commandline for nothing @@ -1213,11 +1217,12 @@ class LdapConnection implements Selectable, Inspectable } Logger::debug("Issueing LDAP search. Use '%s' to reproduce.", sprintf( - 'ldapsearch -P 3%s -H "%s"%s -b "%s" -s "sub" -z %u -l %u -a "%s"%s%s%s', + 'ldapsearch -P 3%s -H "%s"%s -b "%s" -s "%s" -z %u -l %u -a "%s"%s%s%s', $starttlsParam, $ldapUrl, $bindParams, $baseDn, + $scope, $sizelimit, $timelimit, $derefName, @@ -1227,7 +1232,21 @@ class LdapConnection implements Selectable, Inspectable )); } - return @ldap_search( + switch($scope) { + case LdapQuery::SCOPE_SUB: + $function = 'ldap_search'; + break; + case LdapQuery::SCOPE_ONE: + $function = 'ldap_list'; + break; + case LdapQuery::SCOPE_BASE: + $function = 'ldap_read'; + break; + default: + throw new LogicException('LDAP scope %s not supported by ldapSearch', $scope); + } + + return @$function( $this->getConnection(), $baseDn, $queryString, diff --git a/library/Icinga/Protocol/Ldap/LdapQuery.php b/library/Icinga/Protocol/Ldap/LdapQuery.php index 1184765ba..7f31d32a0 100644 --- a/library/Icinga/Protocol/Ldap/LdapQuery.php +++ b/library/Icinga/Protocol/Ldap/LdapQuery.php @@ -3,6 +3,7 @@ namespace Icinga\Protocol\Ldap; +use LogicException; use Icinga\Data\SimpleQuery; /** @@ -38,6 +39,39 @@ class LdapQuery extends SimpleQuery */ protected $nativeFilter; + /** + * Only fetch the entry at the base of the search + */ + const SCOPE_BASE = 'base'; + + /** + * Fetch entries one below the base DN + */ + const SCOPE_ONE = 'one'; + + /** + * Fetch all entries below the base DN + */ + const SCOPE_SUB = 'sub'; + + /** + * All available scopes + * + * @var array + */ + public static $scopes = array( + LdapQuery::SCOPE_BASE, + LdapQuery::SCOPE_ONE, + LdapQuery::SCOPE_SUB + ); + + /** + * LDAP search scope (default: SCOPE_SUB) + * + * @var string + */ + protected $scope = LdapQuery::SCOPE_SUB; + /** * Initialize this query */ @@ -223,4 +257,38 @@ class LdapQuery extends SimpleQuery { return $this->renderFilter(); } + + /** + * Get LDAP search scope + * + * @return string + */ + public function getScope() + { + return $this->scope; + } + + /** + * Set LDAP search scope + * + * Valid: sub one base (Default: sub) + * + * @param string $scope + * + * @return LdapQuery + * + * @throws LogicException If scope value is invalid + */ + public function setScope($scope) + { + if (! in_array($scope, static::$scopes)) { + throw new LogicException( + 'Can\'t set scope %d, it is is invalid. Use one of %s or LdapQuery\'s constants.', + $scope, implode(', ', static::$scopes) + ); + } + $this->scope = $scope; + return $this; + } + } From 955a9482ada412d72a0febaebfce80232fbba339 Mon Sep 17 00:00:00 2001 From: Markus Frosch Date: Tue, 5 Apr 2016 15:05:58 +0200 Subject: [PATCH 074/109] lib/LDAP: Add fetchByDn for a base scope retrieval on an entry refs #11485 --- .../Icinga/Protocol/Ldap/LdapConnection.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/Icinga/Protocol/Ldap/LdapConnection.php b/library/Icinga/Protocol/Ldap/LdapConnection.php index 2d9ee358a..ffb8c3ed5 100644 --- a/library/Icinga/Protocol/Ldap/LdapConnection.php +++ b/library/Icinga/Protocol/Ldap/LdapConnection.php @@ -6,6 +6,7 @@ namespace Icinga\Protocol\Ldap; use Exception; use LogicException; use ArrayIterator; +use stdClass; use Icinga\Application\Config; use Icinga\Application\Logger; use Icinga\Data\ConfigObject; @@ -549,6 +550,23 @@ class LdapConnection implements Selectable, Inspectable return $pairs; } + /** + * Fetch an LDAP entry by its DN + * + * @param string $dn + * @param array|null $fields + * + * @return StdClass|bool + */ + public function fetchByDn($dn, array $fields = null) + { + return $this->select() + ->from('*', $fields) + ->setBase($dn) + ->setScope('base') + ->fetchRow(); + } + /** * Test the given LDAP credentials by establishing a connection and attempting a LDAP bind * From 1d1a4b4be3d47b9b9e982eefa902fe1dd42c3541 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 8 Apr 2016 12:58:30 +0200 Subject: [PATCH 075/109] Optimize imports in LdapConnection --- library/Icinga/Protocol/Ldap/LdapConnection.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Icinga/Protocol/Ldap/LdapConnection.php b/library/Icinga/Protocol/Ldap/LdapConnection.php index 0c2204143..e741e9678 100644 --- a/library/Icinga/Protocol/Ldap/LdapConnection.php +++ b/library/Icinga/Protocol/Ldap/LdapConnection.php @@ -3,20 +3,20 @@ namespace Icinga\Protocol\Ldap; +use ArrayIterator; use Exception; use LogicException; -use ArrayIterator; use stdClass; use Icinga\Application\Config; use Icinga\Application\Logger; use Icinga\Data\ConfigObject; +use Icinga\Data\Filter\Filter; +use Icinga\Data\Filter\FilterChain; +use Icinga\Data\Filter\FilterExpression; use Icinga\Data\Inspectable; use Icinga\Data\Inspection; use Icinga\Data\Selectable; use Icinga\Data\Sortable; -use Icinga\Data\Filter\Filter; -use Icinga\Data\Filter\FilterChain; -use Icinga\Data\Filter\FilterExpression; use Icinga\Exception\ProgrammingError; /** From de81eb7e936b751110297ac86ce7eb3623f17596 Mon Sep 17 00:00:00 2001 From: Ramy Talal Date: Fri, 8 Apr 2016 11:13:04 +0200 Subject: [PATCH 076/109] Fix installation URL in README.md Signed-off-by: Eric Lippmann --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 78aa4fe79..7705853d9 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Icinga Core and any other monitoring backend compatible with the IDO database. ## Installation -For installing Icinga Web 2 please read [doc/installation.md](doc/installation.md). +For installing Icinga Web 2 please read [doc/02-Installation.md](doc/02-Installation.md). ## Support From aced4f3b6e5f841e57f03d7dc36703ce1a7d1b43 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 10:27:28 +0200 Subject: [PATCH 077/109] lib: Reorder columns in Servicestatus --- .../Monitoring/DataView/Servicestatus.php | 133 +++++++++--------- 1 file changed, 65 insertions(+), 68 deletions(-) diff --git a/modules/monitoring/library/Monitoring/DataView/Servicestatus.php b/modules/monitoring/library/Monitoring/DataView/Servicestatus.php index 1b03bd8ec..e6f8baed0 100644 --- a/modules/monitoring/library/Monitoring/DataView/Servicestatus.php +++ b/modules/monitoring/library/Monitoring/DataView/Servicestatus.php @@ -11,93 +11,90 @@ class ServiceStatus extends DataView public function getColumns() { return array_merge($this->getHookedColumns(), array( - 'instance_name', - 'host_name', - 'host_display_name', - 'host_state', - 'host_hard_state', - 'host_state_type', - 'host_last_state_change', + 'host_acknowledged', + 'host_action_url', + 'host_active_checks_enabled', 'host_address', 'host_address6', - 'host_problem', + 'host_alias', + 'host_check_source', + 'host_display_name', 'host_handled', - 'service_description', - 'service_display_name', - 'service_state', - 'service_hard_state', - 'service_in_downtime', - 'service_acknowledged', - 'service_handled', - 'service_unhandled', - 'service_output', - 'service_last_state_change', - 'service_long_output', - 'service_is_flapping', - 'service_state_type', - 'service_severity', - 'service_last_check', - 'service_notifications_enabled', - 'service_notifications_enabled_changed', - 'service_action_url', - 'service_notes', - 'service_notes_url', - 'service_last_check', - 'service_next_check', - 'service_attempt', - 'service_last_notification', - 'service_check_command', - 'service_current_notification_number', - 'host_acknowledged', - 'host_output', - 'host_long_output', + 'host_hard_state', 'host_in_downtime', + 'host_ipv4', 'host_is_flapping', 'host_last_check', - 'host_notifications_enabled', - 'host_unhandled_service_count', - 'host_action_url', - 'host_notes_url', - 'host_display_name', - 'host_alias', - 'host_ipv4', - 'host_severity', - 'host_perfdata', - 'host_check_source', - 'host_active_checks_enabled', - 'host_passive_checks_enabled', 'host_last_hard_state', 'host_last_hard_state_change', - 'host_last_time_up', + 'host_last_state_change', 'host_last_time_down', 'host_last_time_unreachable', + 'host_last_time_up', + 'host_long_output', 'host_modified_host_attributes', - 'service_hard_state', - 'service_problem', - 'service_perfdata', - 'service_check_source', - 'service_check_timeperiod', + 'host_name', + 'host_notes_url', + 'host_notifications_enabled', + 'host_output', + 'host_passive_checks_enabled', + 'host_perfdata', + 'host_problem', + 'host_severity', + 'host_state', + 'host_state_type', + 'host_unhandled_service_count', + 'instance_name', + 'service_acknowledged', + 'service_acknowledgement_type', + 'service_action_url', 'service_active_checks_enabled', 'service_active_checks_enabled_changed', - 'service_passive_checks_enabled', - 'service_passive_checks_enabled_changed', - 'service_last_hard_state', - 'service_last_hard_state_change', - 'service_last_time_ok', - 'service_last_time_warning', - 'service_last_time_critical', - 'service_last_time_unknown', + 'service_attempt', + 'service_check_command', + 'service_check_source', + 'service_check_timeperiod', 'service_current_check_attempt', - 'service_max_check_attempts', - 'service_obsessing', - 'service_obsessing_changed', + 'service_current_notification_number', + 'service_description', + 'service_display_name', 'service_event_handler_enabled', 'service_event_handler_enabled_changed', 'service_flap_detection_enabled', 'service_flap_detection_enabled_changed', - 'service_modified_service_attributes', + 'service_handled', + 'service_hard_state', 'service_host_name', - 'service_acknowledgement_type', + 'service_in_downtime', + 'service_is_flapping', + 'service_last_check', + 'service_last_hard_state', + 'service_last_hard_state_change', + 'service_last_notification', + 'service_last_state_change', + 'service_last_time_critical', + 'service_last_time_ok', + 'service_last_time_unknown', + 'service_last_time_warning', + 'service_long_output', + 'service_max_check_attempts', + 'service_modified_service_attributes', + 'service_next_check', + 'service_notes', + 'service_notes_url', + 'service_notifications_enabled', + 'service_notifications_enabled_changed', + 'service_obsessing', + 'service_obsessing_changed', + 'service_output', + 'service_passive_checks_enabled', + 'service_passive_checks_enabled_changed', + 'service_perfdata', + 'service_problem', + 'service_severity', + 'service_state', + 'service_state_type', + 'service_unhandled' )); } From a824637c0ed0e20c624d5a0270d50fe096e0ec42 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 10:28:12 +0200 Subject: [PATCH 078/109] Add service_is_reachable column to the service status data view refs #11404 --- modules/monitoring/library/Monitoring/DataView/Servicestatus.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/monitoring/library/Monitoring/DataView/Servicestatus.php b/modules/monitoring/library/Monitoring/DataView/Servicestatus.php index e6f8baed0..be6aab849 100644 --- a/modules/monitoring/library/Monitoring/DataView/Servicestatus.php +++ b/modules/monitoring/library/Monitoring/DataView/Servicestatus.php @@ -67,6 +67,7 @@ class ServiceStatus extends DataView 'service_host_name', 'service_in_downtime', 'service_is_flapping', + 'service_is_reachable', 'service_last_check', 'service_last_hard_state', 'service_last_hard_state_change', From 750b8950b24de843bd894faf4fa50359333b0b86 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 10:29:08 +0200 Subject: [PATCH 079/109] lib: Reorder columns in Hoststatus --- .../Monitoring/DataView/Hoststatus.php | 81 +++++++++---------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/modules/monitoring/library/Monitoring/DataView/Hoststatus.php b/modules/monitoring/library/Monitoring/DataView/Hoststatus.php index 8484dd9cc..e96b2e089 100644 --- a/modules/monitoring/library/Monitoring/DataView/Hoststatus.php +++ b/modules/monitoring/library/Monitoring/DataView/Hoststatus.php @@ -11,58 +11,55 @@ class HostStatus extends DataView public function getColumns() { return array_merge($this->getHookedColumns(), array( - 'instance_name', - 'host_name', - 'host_display_name', - 'host_alias', + 'host_acknowledged', + 'host_acknowledgement_type', + 'host_action_url', + 'host_active_checks_enabled', + 'host_active_checks_enabled_changed', 'host_address', 'host_address6', - 'host_state', - 'host_hard_state', - 'host_state_type', - 'host_handled', - 'host_unhandled', - 'host_in_downtime', - 'host_acknowledged', - 'host_last_state_change', - 'host_last_state_change', - 'host_last_notification', - 'host_last_check', - 'host_next_check', + 'host_alias', + 'host_check_command', 'host_check_execution_time', 'host_check_latency', - 'host_output', - 'host_long_output', - 'host_check_command', - 'host_check_timeperiod', - 'host_perfdata', 'host_check_source', - 'host_passive_checks_enabled', - 'host_passive_checks_enabled_changed', - 'host_obsessing', - 'host_obsessing_changed', - 'host_notifications_enabled', - 'host_notifications_enabled_changed', + 'host_check_timeperiod', + 'host_current_check_attempt', + 'host_current_notification_number', + 'host_display_name', 'host_event_handler_enabled', 'host_event_handler_enabled_changed', 'host_flap_detection_enabled', 'host_flap_detection_enabled_changed', - 'host_active_checks_enabled', - 'host_active_checks_enabled_changed', - 'host_current_check_attempt', - 'host_max_check_attempts', - 'host_last_notification', - 'host_current_notification_number', - 'host_percent_state_change', - 'host_is_flapping', - 'host_action_url', - 'host_notes_url', - 'host_percent_state_change', - 'host_modified_host_attributes', - 'host_severity', - 'host_problem', + 'host_handled', + 'host_hard_state', + 'host_in_downtime', 'host_ipv4', - 'host_acknowledgement_type' + 'host_is_flapping', + 'host_last_check', + 'host_last_notification', + 'host_last_state_change', + 'host_long_output', + 'host_max_check_attempts', + 'host_modified_host_attributes', + 'host_name', + 'host_next_check', + 'host_notes_url', + 'host_notifications_enabled', + 'host_notifications_enabled_changed', + 'host_obsessing', + 'host_obsessing_changed', + 'host_output', + 'host_passive_checks_enabled', + 'host_passive_checks_enabled_changed', + 'host_percent_state_change', + 'host_perfdata', + 'host_problem', + 'host_severity', + 'host_state', + 'host_state_type', + 'host_unhandled', + 'instance_name' )); } From 4cc4657ee915b4eb63b709a3ef2bff47facf03b5 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 10:29:26 +0200 Subject: [PATCH 080/109] Add host_is_reachable column to the host status data view refs #11404 --- modules/monitoring/library/Monitoring/DataView/Hoststatus.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/monitoring/library/Monitoring/DataView/Hoststatus.php b/modules/monitoring/library/Monitoring/DataView/Hoststatus.php index e96b2e089..8f02b70ac 100644 --- a/modules/monitoring/library/Monitoring/DataView/Hoststatus.php +++ b/modules/monitoring/library/Monitoring/DataView/Hoststatus.php @@ -36,6 +36,7 @@ class HostStatus extends DataView 'host_in_downtime', 'host_ipv4', 'host_is_flapping', + 'host_is_reachable', 'host_last_check', 'host_last_notification', 'host_last_state_change', From b783b0c44c3f0eb1dc138eda4d37bad51ee6748c Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 10:41:22 +0200 Subject: [PATCH 081/109] monitoring: Use icon view helper instead for icon images fixes #11299 --- modules/monitoring/application/views/helpers/IconImage.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/monitoring/application/views/helpers/IconImage.php b/modules/monitoring/application/views/helpers/IconImage.php index 3fee8e3a7..8ae72d83e 100644 --- a/modules/monitoring/application/views/helpers/IconImage.php +++ b/modules/monitoring/application/views/helpers/IconImage.php @@ -27,7 +27,7 @@ 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( + return $this->view->icon( Macro::resolveMacros($object->host_icon_image, $object), null, array( @@ -50,7 +50,7 @@ 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( + return $this->view->icon( Macro::resolveMacros($object->service_icon_image, $object), null, array( From 05f752ecd8f61e0f8342bc77511544eaa7d025a3 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 10:51:37 +0200 Subject: [PATCH 082/109] Don't offer disable notifications w/ expire time if backend is Icinga 2 resolves #11529 --- .../ToggleInstanceFeaturesCommandForm.php | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php index ed50466fe..dbd786d5e 100644 --- a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php +++ b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php @@ -58,24 +58,27 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm */ public function createElements(array $formData = array()) { - if ((bool) $this->status->notifications_enabled) { - if ($this->hasPermission('monitoring/command/feature/instance')) { + $notificationDescription = null; + $isIcinga2 = $this->getBackend()->isIcinga2($this->status->program_version); + + if (! $isIcinga2) { + if ((bool) $this->status->notifications_enabled) { + if ($this->hasPermission('monitoring/command/feature/instance')) { + $notificationDescription = sprintf( + '%3$s', + $this->translate('Disable notifications for a specific time on a program-wide basis'), + $this->getView()->href('monitoring/health/disable-notifications'), + $this->translate('Disable temporarily') + ); + } else { + $notificationDescription = null; + } + } elseif ($this->status->disable_notif_expire_time) { $notificationDescription = sprintf( - '%3$s', - $this->translate('Disable notifications for a specific time on a program-wide basis'), - $this->getView()->href('monitoring/health/disable-notifications'), - $this->translate('Disable temporarily') + $this->translate('Notifications will be re-enabled in %s'), + $this->getView()->timeUntil($this->status->disable_notif_expire_time) ); - } else { - $notificationDescription = null; } - } elseif ($this->status->disable_notif_expire_time) { - $notificationDescription = sprintf( - $this->translate('Notifications will be re-enabled in %s'), - $this->getView()->timeUntil($this->status->disable_notif_expire_time) - ); - } else { - $notificationDescription = null; } $toggleDisabled = $this->hasPermission('monitoring/command/feature/instance') ? null : ''; @@ -138,7 +141,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm ) ); - if (! $this->getBackend()->isIcinga2($this->status->program_version)) { + if (! $isIcinga2) { $this->addElement( 'checkbox', ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING, From c803ec64c555428f2bd3b5e8b48fdb5c8c139574 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 10:57:01 +0200 Subject: [PATCH 083/109] lib: Move getters before setters in ExternalBackend --- library/Icinga/Authentication/User/ExternalBackend.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/Icinga/Authentication/User/ExternalBackend.php b/library/Icinga/Authentication/User/ExternalBackend.php index db3212499..e2cb44716 100644 --- a/library/Icinga/Authentication/User/ExternalBackend.php +++ b/library/Icinga/Authentication/User/ExternalBackend.php @@ -38,18 +38,18 @@ class ExternalBackend implements UserBackendInterface /** * {@inheritdoc} */ - public function setName($name) + public function getName() { - $this->name = $name; - return $this; + return $this->name; } /** * {@inheritdoc} */ - public function getName() + public function setName($name) { - return $this->name; + $this->name = $name; + return $this; } From 2ac54d7c3e309ef44cdaa5e7490697fffda81e8f Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 14:01:36 +0200 Subject: [PATCH 084/109] lib: Add ExternalBackend::getRemoteUser() If the user is authenticated via the web server, this method should be used to retrieve the user because it supports both reading the user from the environment or from the $_SERVER variable as fallback. refs #11391 --- .../Authentication/User/ExternalBackend.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/Icinga/Authentication/User/ExternalBackend.php b/library/Icinga/Authentication/User/ExternalBackend.php index e2cb44716..616f2371e 100644 --- a/library/Icinga/Authentication/User/ExternalBackend.php +++ b/library/Icinga/Authentication/User/ExternalBackend.php @@ -52,6 +52,25 @@ class ExternalBackend implements UserBackendInterface return $this; } + /** + * Get the remote user from environment or $_SERVER, if any + * + * @param string $variable The name variable where to read the user from + * + * @return string|null + */ + public static function getRemoteUser($variable = 'REMOTE_USER') + { + $username = getenv($variable); + if ($username !== false) { + return $username; + } + if (array_key_exists($variable, $_SERVER)) { + return $_SERVER[$variable]; + } + return null; + } + /** * {@inheritdoc} From 99d08bf03b6be08eebfa5575d88bf35ae12ac467 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 14:07:44 +0200 Subject: [PATCH 085/109] Get remote user from $_SERVER if env does not have it in external auth refs #11391 --- library/Icinga/Authentication/Auth.php | 6 +++--- library/Icinga/Authentication/User/ExternalBackend.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/Icinga/Authentication/Auth.php b/library/Icinga/Authentication/Auth.php index 392a59d71..814f1366e 100644 --- a/library/Icinga/Authentication/Auth.php +++ b/library/Icinga/Authentication/Auth.php @@ -240,10 +240,10 @@ class Auth public function authenticateFromSession() { $this->user = Session::getSession()->get('user'); - if ($this->user !== null && $this->user->isExternalUser() === true) { + if ($this->user !== null && $this->user->isExternalUser()) { list($originUsername, $field) = $this->user->getExternalUserInformation(); - $username = getenv($field); // usually REMOTE_USER here - if ( !$username || $username !== $originUsername) { + $username = ExternalBackend::getRemoteUser($field); + if ($username === null || $username !== $originUsername) { $this->removeAuthorization(); } } diff --git a/library/Icinga/Authentication/User/ExternalBackend.php b/library/Icinga/Authentication/User/ExternalBackend.php index 616f2371e..3baf1c8e0 100644 --- a/library/Icinga/Authentication/User/ExternalBackend.php +++ b/library/Icinga/Authentication/User/ExternalBackend.php @@ -77,8 +77,8 @@ class ExternalBackend implements UserBackendInterface */ public function authenticate(User $user, $password = null) { - $username = getenv('REMOTE_USER'); - if ($username !== false) { + $username = static::getRemoteUser(); + if ($username !== null) { $user->setExternalUserInformation($username, 'REMOTE_USER'); if ($this->stripUsernameRegexp) { From 7ea9ae83057fba85e0161d09df004f81dbff93ee Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 14:11:49 +0200 Subject: [PATCH 086/109] CSS: Remove redundant hover styles for a --- modules/monitoring/public/css/module.less | 10 ---------- public/css/icinga/tabs.less | 4 ---- 2 files changed, 14 deletions(-) diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 2c0fe1a46..d803f41a5 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -88,10 +88,6 @@ /* Generic box element */ -.boxview a { - text-decoration: none; -} - .boxview > div.box { text-align: center; vertical-align: top; @@ -364,13 +360,7 @@ div.timeline { a { font-weight: bold; - text-decoration: none; white-space: nowrap; - - &:hover { - text-decoration: underline; - - } } } diff --git a/public/css/icinga/tabs.less b/public/css/icinga/tabs.less index 4ab8ace23..d1cf11e74 100644 --- a/public/css/icinga/tabs.less +++ b/public/css/icinga/tabs.less @@ -29,10 +29,6 @@ > a { color: @body-bg-color; - - &:hover { - text-decoration: underline; - } } &.active > a, From 25a85ca36b6899e93af34a17d473a0d1ac071e1b Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 14:13:37 +0200 Subject: [PATCH 087/109] Help IE to outline the focus --- public/css/icinga/base.less | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/public/css/icinga/base.less b/public/css/icinga/base.less index f3c3328fa..4aea04fb6 100644 --- a/public/css/icinga/base.less +++ b/public/css/icinga/base.less @@ -80,15 +80,19 @@ a { color: inherit; text-decoration: none; - &:focus { - outline-color: @icinga-blue; - } - &:hover { text-decoration: underline; } } +a:focus, +button:focus, +input[type="checkbox"]:focus { + outline-color: @icinga-blue; + outline-style: solid; // IE + outline-style: auto; +} + // Default margin for block text blockquote, p, pre { margin: 0 0 1em 0; From 93b50fe484ea5828babd79b4a924aff15935bb5d Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 11 Apr 2016 14:24:23 +0200 Subject: [PATCH 088/109] Refresh menu but keep search text if not focused fixes #11128 --- public/js/icinga/behavior/form.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/public/js/icinga/behavior/form.js b/public/js/icinga/behavior/form.js index 063df5093..750f02223 100644 --- a/public/js/icinga/behavior/form.js +++ b/public/js/icinga/behavior/form.js @@ -55,6 +55,20 @@ * @returns {string|NULL} The content to be rendered, or NULL, when nothing should be changed */ Form.prototype.renderHook = function(content, $container, action, autorefresh) { + if ($container.attr('id') === 'menu') { + var $search = $container.find('#search'); + if ($search[0] === document.activeElement) { + return null; + } + var search = $container.find('#search').val(); + if (search.length) { + var $content = $('
').append(content); + $content.find('#search').attr('value', search).addClass('active'); + return $content.html(); + } + return content; + } + var origFocus = document.activeElement; var containerId = $container.attr('id'); var icinga = this.icinga; From e298ee8e3dd582e700912cc5543236c4c39d9f9f Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Mon, 11 Apr 2016 16:30:35 +0200 Subject: [PATCH 089/109] Docs: Fix global permission table formatting '<' and '>' must be escaped using html-tags in tables. refs #11568 --- doc/06-Security.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/06-Security.md b/doc/06-Security.md index 3b8731a7d..c39b508de 100644 --- a/doc/06-Security.md +++ b/doc/06-Security.md @@ -157,12 +157,12 @@ through a group) all permissions are added together to get the users actual perm ### Global Permissions -Name | Permits ---------------- ----|-------------------------------------------------------- -* | Allow everything, including module-specific permissions -config/* | Allow all configuration actions -config/modules | Allow enabling or disabling modules -module/ | Allow access to module +Name | Permits +--------------------------|-------------------------------------------------------- +* | Allow everything, including module-specific permissions +config/* | Allow all configuration actions +config/modules | Allow enabling or disabling modules +module/<moduleName> | Allow access to module <moduleName> ### Monitoring Module Permissions From fb07b9aa83b72cf73042fe5f5680d9d84f3c3e64 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 12 Apr 2016 10:51:54 +0200 Subject: [PATCH 090/109] vendor: Upgrade Parsedown to version 1.6.0 fixes #11558 --- library/vendor/Parsedown/Parsedown.php | 71 ++++++++++++-------------- library/vendor/Parsedown/SOURCE | 2 +- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/library/vendor/Parsedown/Parsedown.php b/library/vendor/Parsedown/Parsedown.php index 71a033e2e..c8c92a392 100644 --- a/library/vendor/Parsedown/Parsedown.php +++ b/library/vendor/Parsedown/Parsedown.php @@ -17,7 +17,7 @@ class Parsedown { # ~ - const version = '1.5.0'; + const version = '1.6.0'; # ~ @@ -107,12 +107,6 @@ class Parsedown # ~ - protected $DefinitionTypes = array( - '[' => array('Reference'), - ); - - # ~ - protected $unmarkedBlockTypes = array( 'Code', ); @@ -169,7 +163,7 @@ class Parsedown # ~ - if (isset($CurrentBlock['incomplete'])) + if (isset($CurrentBlock['continuable'])) { $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); @@ -185,8 +179,6 @@ class Parsedown { $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); } - - unset($CurrentBlock['incomplete']); } } @@ -226,7 +218,7 @@ class Parsedown if (method_exists($this, 'block'.$blockType.'Continue')) { - $Block['incomplete'] = true; + $Block['continuable'] = true; } $CurrentBlock = $Block; @@ -253,7 +245,7 @@ class Parsedown # ~ - if (isset($CurrentBlock['incomplete']) and method_exists($this, 'block'.$CurrentBlock['type'].'Complete')) + if (isset($CurrentBlock['continuable']) and method_exists($this, 'block'.$CurrentBlock['type'].'Complete')) { $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); } @@ -394,16 +386,16 @@ class Parsedown protected function blockFencedCode($Line) { - if (preg_match('/^(['.$Line['text'][0].']{3,})[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches)) + if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches)) { $Element = array( 'name' => 'code', 'text' => '', ); - if (isset($matches[2])) + if (isset($matches[1])) { - $class = 'language-'.$matches[2]; + $class = 'language-'.$matches[1]; $Element['attributes'] = array( 'class' => $class, @@ -673,7 +665,9 @@ class Parsedown if (preg_match('/^<(\w*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches)) { - if (in_array($matches[1], $this->textLevelElements)) + $element = strtolower($matches[1]); + + if (in_array($element, $this->textLevelElements)) { return; } @@ -736,8 +730,6 @@ class Parsedown { $Block['closed'] = true; } - - $Block['markup'] .= $matches[1]; } if (isset($Block['interrupted'])) @@ -989,15 +981,13 @@ class Parsedown { $markup = ''; - $unexaminedText = $text; + # $excerpt is based on the first occurrence of a marker - $markerPosition = 0; - - while ($excerpt = strpbrk($unexaminedText, $this->inlineMarkerList)) + while ($excerpt = strpbrk($text, $this->inlineMarkerList)) { $marker = $excerpt[0]; - $markerPosition += strpos($unexaminedText, $marker); + $markerPosition = strpos($text, $marker); $Excerpt = array('text' => $excerpt, 'context' => $text); @@ -1010,34 +1000,42 @@ class Parsedown continue; } - if (isset($Inline['position']) and $Inline['position'] > $markerPosition) # position is ahead of marker + # makes sure that the inline belongs to "our" marker + + if (isset($Inline['position']) and $Inline['position'] > $markerPosition) { continue; } + # sets a default inline position + if ( ! isset($Inline['position'])) { $Inline['position'] = $markerPosition; } + # the text that comes before the inline $unmarkedText = substr($text, 0, $Inline['position']); + # compile the unmarked text $markup .= $this->unmarkedText($unmarkedText); + # compile the inline $markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']); + # remove the examined text $text = substr($text, $Inline['position'] + $Inline['extent']); - $unexaminedText = $text; - - $markerPosition = 0; - continue 2; } - $unexaminedText = substr($excerpt, 1); + # the marker does not belong to an inline - $markerPosition ++; + $unmarkedText = substr($text, 0, $markerPosition + 1); + + $markup .= $this->unmarkedText($unmarkedText); + + $text = substr($text, $markerPosition + 1); } $markup .= $this->unmarkedText($text); @@ -1199,7 +1197,7 @@ class Parsedown return; } - if (preg_match('/^[(]((?:[^ (]|[(][^ )]+[)])+)(?:[ ]+("[^"]+"|\'[^\']+\'))?[)]/', $remainder, $matches)) + if (preg_match('/^[(]((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+("[^"]*"|\'[^\']*\'))?[)]/', $remainder, $matches)) { $Element['attributes']['href'] = $matches[1]; @@ -1214,7 +1212,7 @@ class Parsedown { if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) { - $definition = $matches[1] ? $matches[1] : $Element['text']; + $definition = strlen($matches[1]) ? $matches[1] : $Element['text']; $definition = strtolower($definition); $extent += strlen($matches[0]); @@ -1360,11 +1358,6 @@ class Parsedown } } - # - # ~ - - protected $unmarkedInlineTypes = array("\n" => 'Break', '://' => 'Url'); - # ~ protected function unmarkedText($text) @@ -1409,7 +1402,7 @@ class Parsedown if (isset($Element['handler'])) { - $markup .= $this->$Element['handler']($Element['text']); + $markup .= $this->{$Element['handler']}($Element['text']); } else { @@ -1483,7 +1476,7 @@ class Parsedown return self::$instances[$name]; } - $instance = new self(); + $instance = new static(); self::$instances[$name] = $instance; diff --git a/library/vendor/Parsedown/SOURCE b/library/vendor/Parsedown/SOURCE index cbbe887be..38fc9f5bf 100644 --- a/library/vendor/Parsedown/SOURCE +++ b/library/vendor/Parsedown/SOURCE @@ -1,4 +1,4 @@ -RELEASE=1.5.0 +RELEASE=1.6.0 PARSEDOWN=parsedown-$RELEASE curl https://codeload.github.com/erusev/parsedown/tar.gz/${RELEASE} -o ${PARSEDOWN}.tar.gz tar xfz ${PARSEDOWN}.tar.gz --strip-components 1 ${PARSEDOWN}/Parsedown.php ${PARSEDOWN}/LICENSE.txt From b0e3dd438f665f90c8ea793449d1f6606692f5ba Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 12 Apr 2016 11:11:41 +0200 Subject: [PATCH 091/109] Doc: Fix too greedy regex for matching blockquotes --- modules/doc/library/Doc/Renderer/DocSectionRenderer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/doc/library/Doc/Renderer/DocSectionRenderer.php b/modules/doc/library/Doc/Renderer/DocSectionRenderer.php index 9bc8bfee0..113f707c5 100644 --- a/modules/doc/library/Doc/Renderer/DocSectionRenderer.php +++ b/modules/doc/library/Doc/Renderer/DocSectionRenderer.php @@ -287,7 +287,7 @@ class DocSectionRenderer extends DocRenderer $html ); $html = preg_replace_callback( - '#
.+
#ms', + '#
.+?
#ms', array($this, 'markupNotes'), $html ); From 5afc54d973a5a9b8217ba23a9a2db767638130f1 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 12 Apr 2016 13:23:13 +0200 Subject: [PATCH 092/109] monitoring: Select instance_name in multi-select views Before, if all command transports are configured to filter for a specific instance, no command would have been sent to Icinga. --- modules/monitoring/application/controllers/HostsController.php | 3 ++- .../monitoring/application/controllers/ServicesController.php | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/monitoring/application/controllers/HostsController.php b/modules/monitoring/application/controllers/HostsController.php index 12017657c..17969df8d 100644 --- a/modules/monitoring/application/controllers/HostsController.php +++ b/modules/monitoring/application/controllers/HostsController.php @@ -49,7 +49,8 @@ class HostsController extends Controller 'host_obsessing', 'host_passive_checks_enabled', 'host_problem', - 'host_state' + 'host_state', + 'instance_name' )); $this->view->baseFilter = $this->hostList->getFilter(); $this->getTabs()->add( diff --git a/modules/monitoring/application/controllers/ServicesController.php b/modules/monitoring/application/controllers/ServicesController.php index 53312ae48..17e82124b 100644 --- a/modules/monitoring/application/controllers/ServicesController.php +++ b/modules/monitoring/application/controllers/ServicesController.php @@ -41,6 +41,7 @@ class ServicesController extends Controller 'host_name', 'host_problem', 'host_state', + 'instance_name', 'service_acknowledged', 'service_active_checks_enabled', 'service_description', From 9082a5204e85254b0a666329a61b7b4175c1f62e Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 13 Apr 2016 11:04:23 +0200 Subject: [PATCH 093/109] Fix tab order of refresh and close container controls --- library/Icinga/Web/Widget/Tabs.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/Icinga/Web/Widget/Tabs.php b/library/Icinga/Web/Widget/Tabs.php index b8c058604..70e987ed2 100644 --- a/library/Icinga/Web/Widget/Tabs.php +++ b/library/Icinga/Web/Widget/Tabs.php @@ -49,7 +49,7 @@ EOT; * @var string */ private $closeTpl = <<< 'EOT' -
dashboard->getPanes() as $pane): ?> + getDisabled()) continue; ?> - getDisabled() === true) continue; ?> + getDisabled()) continue; ?>
escape($pane->getName()) ?> @@ -43,7 +44,7 @@
qlink( diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index 415a08857..ab47afb3f 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -201,12 +201,6 @@ class Dashboard extends AbstractWidget { /** @var $pane Pane */ foreach ($panes as $pane) { - if ($pane->getDisabled()) { - if ($this->hasPane($pane->getTitle()) === true) { - $this->removePane($pane->getTitle()); - } - continue; - } if ($this->hasPane($pane->getTitle()) === true) { /** @var $current Pane */ $current = $this->panes[$pane->getName()]; @@ -231,6 +225,9 @@ class Dashboard extends AbstractWidget $this->tabs = new Tabs(); foreach ($this->panes as $key => $pane) { + if ($pane->getDisabled()) { + continue; + } $this->tabs->add( $key, array( diff --git a/library/Icinga/Web/Widget/Dashboard/Pane.php b/library/Icinga/Web/Widget/Dashboard/Pane.php index 587ea3a90..f323a613b 100644 --- a/library/Icinga/Web/Widget/Dashboard/Pane.php +++ b/library/Icinga/Web/Widget/Dashboard/Pane.php @@ -40,7 +40,7 @@ class Pane extends UserWidget * * @var bool */ - private $disabled; + private $disabled = false; /** * Create a new pane From 275d9bd4114772f03ebe114293f7dda01e188e6a Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 12 Apr 2016 14:24:37 +0200 Subject: [PATCH 096/109] Add CSS class for state badge groups --- modules/monitoring/library/Monitoring/Web/Widget/StateBadges.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/monitoring/library/Monitoring/Web/Widget/StateBadges.php b/modules/monitoring/library/Monitoring/Web/Widget/StateBadges.php index adf9344c3..04aa0261a 100644 --- a/modules/monitoring/library/Monitoring/Web/Widget/StateBadges.php +++ b/modules/monitoring/library/Monitoring/Web/Widget/StateBadges.php @@ -257,6 +257,7 @@ class StateBadges extends AbstractWidget $groupItem = new NavigationItem( uniqid(), array( + 'cssClass' => 'state-badge-group', 'label' => '', 'priority' => $this->priority++ ) From 7e15f68a7a7ff4fd96bf87d500b652bf7c065dcf Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Tue, 12 Apr 2016 15:03:13 +0200 Subject: [PATCH 097/109] CSS: Beautify state-badges --- modules/monitoring/public/css/module.less | 22 ++++++++++++++++++++++ public/css/icinga/mixins.less | 4 +--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index d803f41a5..4783bd6f4 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -45,6 +45,28 @@ padding-right: 0; } } + + .state-badge-group li { + margin-right: 1px; + } + + .state-badge-group li:last-child { + margin-right: 0; + } + + .state-badge-group .badge { + border-radius: 0; + } + + .state-badge-group li:first-child > .badge { + border-top-left-radius: 0.4em; + border-bottom-left-radius: 0.4em; + } + + .state-badge-group li:last-child > .badge { + border-top-right-radius: 0.4em; + border-bottom-right-radius: 0.4em; + } } // Performance data pie charts diff --git a/public/css/icinga/mixins.less b/public/css/icinga/mixins.less index 40d98f457..33c6fe022 100644 --- a/public/css/icinga/mixins.less +++ b/public/css/icinga/mixins.less @@ -56,9 +56,7 @@ } .rounded-corners(@border-radius: 0.4em) { - -webkit-border-radius: @border-radius; - -moz-border-radius: @border-radius; - border-radius: @border-radius; + border-radius: @border-radius; -webkit-background-clip: padding-box; -moz-background-clip: padding; From 9ec5a46faea33a271078c7991c50b15662c612a5 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 13 Apr 2016 12:55:01 +0200 Subject: [PATCH 098/109] Fix exception if all dashboards are disabled --- .../controllers/DashboardController.php | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index a2ea68fd3..4a7fda9ee 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -244,20 +244,35 @@ class DashboardController extends ActionController if (! $this->dashboard->hasPanes()) { $this->view->title = 'Dashboard'; } else { - if ($this->_getParam('pane')) { - $pane = $this->_getParam('pane'); - $this->dashboard->activate($pane); - } - if ($this->dashboard === null) { - $this->view->title = 'Dashboard'; - } else { - $this->view->title = $this->dashboard->getActivePane()->getTitle() . ' :: Dashboard'; - if ($this->hasParam('remove')) { - $this->dashboard->getActivePane()->removeDashlet($this->getParam('remove')); - $this->dashboard->getConfig()->saveIni(); - $this->redirectNow(URL::fromRequest()->remove('remove')); + $panes = array_filter( + $this->dashboard->getPanes(), + function ($pane) { + return ! $pane->getDisabled(); + } + ); + if (empty($panes)) { + $this->view->title = 'Dashboard'; + $this->getTabs()->add('dashboard', array( + 'active' => true, + 'title' => $this->translate('Dashboard'), + 'url' => Url::fromRequest() + )); + } else { + if ($this->_getParam('pane')) { + $pane = $this->_getParam('pane'); + $this->dashboard->activate($pane); + } + if ($this->dashboard === null) { + $this->view->title = 'Dashboard'; + } else { + $this->view->title = $this->dashboard->getActivePane()->getTitle() . ' :: Dashboard'; + if ($this->hasParam('remove')) { + $this->dashboard->getActivePane()->removeDashlet($this->getParam('remove')); + $this->dashboard->getConfig()->saveIni(); + $this->redirectNow(URL::fromRequest()->remove('remove')); + } + $this->view->dashboard = $this->dashboard; } - $this->view->dashboard = $this->dashboard; } } } From 621c0dbcadbce659bb51b8e2e6e6d53b492ea8da Mon Sep 17 00:00:00 2001 From: Marc DeTrano Date: Wed, 13 Apr 2016 12:59:09 +0200 Subject: [PATCH 099/109] Support data URIs in href resolves #11495 Signed-off-by: Eric Lippmann --- public/js/icinga/events.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index c1bc4c223..829ede335 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -421,7 +421,7 @@ var $target; var formerUrl; var remote = /^(?:[a-z]+:)\/\//; - if (href.match(/^(mailto|javascript):/)) { + if (href.match(/^(mailto|javascript|data):/)) { return true; } From ffd5a56ded0b56eac99541df76bc5c5afdf4628d Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 13 Apr 2016 13:43:39 +0200 Subject: [PATCH 100/109] Fix doc links --- doc/02-Installation.md | 22 +++++++++++----------- doc/03-Configuration.md | 16 ++++++++-------- doc/05-Authentication.md | 12 ++++++------ doc/06-Security.md | 17 ++++++++--------- doc/07-Preferences.md | 6 +++--- 5 files changed, 36 insertions(+), 37 deletions(-) diff --git a/doc/02-Installation.md b/doc/02-Installation.md index 04ec7b842..593354514 100644 --- a/doc/02-Installation.md +++ b/doc/02-Installation.md @@ -4,7 +4,7 @@ The preferred way of installing Icinga Web 2 is to use the official package repo system and distribution you are running. But it is also possible to install Icinga Web 2 directly from source. In case you are upgrading from an older version of Icinga Web 2 -please make sure to read the [upgrading](installation.md#upgrading) section +please make sure to read the [upgrading](02-Installation.md#upgrading) section thoroughly. ## Installing Requirements @@ -179,7 +179,7 @@ git clone git://git.icinga.org/icingaweb2.git ### Installing Requirements from Source -You will need to install certain dependencies depending on your setup listed [here](installation.md#installing-requirements). +You will need to install certain dependencies depending on your setup listed [here](02-Installation.md#installing-requirements). The following example installs Apache2 as web server, MySQL as RDBMS and uses the PHP adapter for MySQL. Adopt the package requirements to your needs (e.g. adding ldap for authentication) and distribution. @@ -318,7 +318,7 @@ Puppet, Ansible, Chef, etc. modules. > Read the documentation on the respective linked configuration sections before > deploying the configuration manually. > -> If you are unsure about certain settings, use the [setup wizard](installation.md#web-setup-wizard-from-source) once +> If you are unsure about certain settings, use the [setup wizard](02-Installation.md#web-setup-wizard-from-source) once > and then collect the generated configuration as well as sql dumps. #### Icinga Web 2 Manual Database Setup @@ -336,7 +336,7 @@ mysql -p icingaweb2 < /usr/share/icingaweb2/etc/schema/mysql.schema.sql ``` -Then generate a new password hash as described in the [authentication docs](authentication.md#authentication-configuration-db-setup) +Then generate a new password hash as described in the [authentication docs](05-Authentication.md#authentication-configuration-db-setup) and use it to insert a new user called `icingaadmin` into the database. ``` @@ -349,7 +349,7 @@ quit #### Icinga Web 2 Manual Configuration -[resources.ini](resources.md#resources) providing the details for the Icinga Web 2 and +[resources.ini](04-Resources.md#resources) providing the details for the Icinga Web 2 and Icinga 2 IDO database configuration. Example for MySQL: ``` @@ -375,7 +375,7 @@ username = "icinga" password = "icinga" ``` -[config.ini](configuration.md#configuration) defining general application settings. +[config.ini](03-Configuration.md#configuration) defining general application settings. ``` vim /etc/icingaweb2/config.ini @@ -391,7 +391,7 @@ type = "db" resource = "icingaweb2" ``` -[authentication.ini](authentication.md#authentication) for e.g. using the previously created database. +[authentication.ini](05-Authentication.md#authentication) for e.g. using the previously created database. ``` vim /etc/icingaweb2/authentication.ini @@ -402,7 +402,7 @@ resource = "icingaweb2" ``` -[roles.ini](security.md#security) granting the previously added `icingaadmin` user all permissions. +[roles.ini](06-Security.md#security) granting the previously added `icingaadmin` user all permissions. ``` vim /etc/icingaweb2/roles.ini @@ -415,7 +415,7 @@ permissions = "*" #### Icinga Web 2 Manual Configuration Monitoring Module -[config.ini](../modules/monitoring/doc/configuration.md#configuration) defining additional security settings. +**config.ini** defining additional security settings. ``` vim /etc/icingaweb2/modules/monitoring/config.ini @@ -424,7 +424,7 @@ vim /etc/icingaweb2/modules/monitoring/config.ini protected_customvars = "*pw*,*pass*,community" ``` -[backends.ini](../modules/monitoring/doc/configuration.md#configuration) referencing the Icinga 2 DB IDO resource. +**backends.ini** referencing the Icinga 2 DB IDO resource. ``` vim /etc/icingaweb2/modules/monitoring/backends.ini @@ -434,7 +434,7 @@ type = "ido" resource = "icinga2" ``` -[commandtransports.ini](../modules/monitoring/doc/commandtransports.md#commandtransports) defining the Icinga 2 command pipe. +**commandtransports.ini** defining the Icinga command pipe. ``` vim /etc/icingaweb2/modules/monitoring/commandtransports.ini diff --git a/doc/03-Configuration.md b/doc/03-Configuration.md index 90946be83..4df9ad2e6 100644 --- a/doc/03-Configuration.md +++ b/doc/03-Configuration.md @@ -5,11 +5,11 @@ Apart from its web configuration capabilities, the local configuration is stored in `/etc/icingaweb2` by default (depending on your config setup). - Location | File | Description - ------------------------------|-----------------------|--------------------------- - . | config.ini | General configuration (logging, preferences) - . | resources.ini | Global resources (Icinga Web 2 database for preferences and authentication, icinga ido database) - . | roles.ini | User specific roles (e.g. `administrators`) and permissions - . | [authentication.ini](authentication.md) | Authentication backends (e.g. database) - enabledModules | Symlink | Contains symlinks to enabled modules from `/usr/share/icingaweb2/modules/*`. Defaults to [monitoring](modules/monitoring/doc/configuration.md) and `doc`. - modules | Directory | Module specific configuration +File/Directory | Description +--------------------------------------------------------- +config.ini | General configuration (logging, preferences) +[resources.ini](04-Ressources.md) | Global resources (Icinga Web 2 database for preferences and authentication, Icinga IDO database) +roles.ini | User specific roles (e.g. `administrators`) and permissions +[authentication.ini](05-Authentication.md) | Authentication backends (e.g. database) +enabledModules | Contains symlinks to enabled modules +modules | Directory for module specific configuration diff --git a/doc/05-Authentication.md b/doc/05-Authentication.md index a1455e203..c30c593ff 100644 --- a/doc/05-Authentication.md +++ b/doc/05-Authentication.md @@ -63,7 +63,7 @@ Restart your web server to apply the changes. ## Active Directory or LDAP Authentication If you want to authenticate against Active Directory or LDAP, you have to define a -[LDAP resource](resources.md#resources-configuration-ldap) which will be referenced as data source for the +[LDAP resource](04-Resources.md#resources-configuration-ldap) which will be referenced as data source for the Active Directory or LDAP configuration method. ### LDAP @@ -71,7 +71,7 @@ Active Directory or LDAP configuration method. Directive | Description ------------------------|------------ **backend** | `ldap` -**resource** | The name of the LDAP resource defined in [resources.ini](resources.md#resources). +**resource** | The name of the LDAP resource defined in [resources.ini](04-Resources.md#resources). **user_class** | LDAP user class. **user_name_attribute** | LDAP attribute which contains the username. **filter** | LDAP search filter. @@ -96,7 +96,7 @@ with Icinga Web 2 (e.g. an alias) no matter what the primary user id might actua Directive | Description ------------------------|------------ **backend** | `msldap` -**resource** | The name of the LDAP resource defined in [resources.ini](resources.md#resources). +**resource** | The name of the LDAP resource defined in [resources.ini](04-Resources.md#resources). **Example:** @@ -109,13 +109,13 @@ resource = my_ad ## Database Authentication If you want to authenticate against a MySQL or a PostgreSQL database, you have to define a -[database resource](resources.md#resources-configuration-database) which will be referenced as data source for the database +[database resource](04-Resources.md#resources-configuration-database) which will be referenced as data source for the database authentication method. Directive | Description ------------------------|------------ **backend** | `db` -**resource** | The name of the database resource defined in [resources.ini](resources.md#resources). +**resource** | The name of the database resource defined in [resources.ini](04-Resources.md#resources). **Example:** @@ -132,7 +132,7 @@ For authenticating against a database, you have to import one of the following d * **etc/schema/preferences.mysql.sql** (for **MySQL** database) * **etc/schema/preferences.pgsql.sql** (for **PostgreSQL** databases) -After that you have to define the [database resource](resources.md#resources-configuration-database). +After that you have to define the [database resource](04-Resources.md#resources-configuration-database). **Manually Creating Users** diff --git a/doc/06-Security.md b/doc/06-Security.md index c39b508de..65c908342 100644 --- a/doc/06-Security.md +++ b/doc/06-Security.md @@ -21,9 +21,8 @@ things to which access can be managed: actions and objects. ### Actions Actions are all the things an Icinga Web 2 user can do, like changing a certain configuration, -changing permissions or sending a command to the Icinga instance through the -Command Pipe -in the monitoring module. All actions must be be **allowed explicitly** using permissions. +changing permissions or sending a command to the Icinga instance through the Icinga command pipe. +All actions must be be **allowed explicitly** using permissions. A permission is a simple list of identifiers of actions a user is allowed to do. Permissions are described in greater detail in the @@ -47,7 +46,7 @@ using Active Directory, and a user **icingaadmin** that is authenticated using a In the configuration, both can be referenced to by using their user names **icingaadmin** or **jdoe**. Icinga Web 2 users and groups are not configured by a configuration file, but provided by -an **authentication backend**. For extended information on setting up authentication backends and managing users, please read the chapter [Authentication](authentication.md#authentication). +an **authentication backend**. For extended information on setting up authentication backends and managing users, please read the chapter [Authentication](05-Authentication.md#authentication).
@@ -59,7 +58,7 @@ an **authentication backend**. For extended information on setting up authentica #### Managing Users When using a [Database -as authentication backend](authentication.md#authentication-configuration-db-authentication), it is possible to create, add and delete users directly in the frontend. This configuration +as authentication backend](05-Authentication.md#authentication-configuration-db-authentication), it is possible to create, add and delete users directly in the frontend. This configuration can be found at **Configuration > Authentication > Users **. ### Groups @@ -70,12 +69,12 @@ A user can be member of multiple groups and will inherit all permissions and res Like users, groups are identified solely by their **name** that is provided by a **group backend**. For extended information on setting up group backends, - please read the chapter [Authentication](authentication.md#authentication). + please read the chapter [Authentication](05-Authentication.md#authentication). #### Managing Groups -When using a [Database as an authentication backend](#authentication.md#authentication-configuration-db-authentication), +When using a [Database as an authentication backend](05-Authentication.md#authentication-configuration-db-authentication), it is possible to manage groups and group memberships directly in the frontend. This configuration can be found at **Configuration > Authentication > Groups **. @@ -168,7 +167,7 @@ module/<moduleName> | Allow access to module <moduleName> ### Monitoring Module Permissions The built-in monitoring module defines an additional set of permissions, that -is described in detail in the [monitoring module documentation](/icingaweb2/doc/module/doc/chapter/monitoring-security#monitoring-security). +is described in detail in the monitoring module documentation. ## Restrictions @@ -187,7 +186,7 @@ mentioned in the section [Syntax](#syntax). ### Filter Expressions Filters operate on columns. A complete list of all available filter columns on hosts and services can be found in -the [monitoring module documentation](/icingaweb2/doc/module/doc/chapter/monitoring-security#monitoring-security-restrictions). +the monitoring module documentation. Any filter expression that is allowed in the filtered view, is also an allowed filter expression. This means, that it is possible to define negations, wildcards, and even nested diff --git a/doc/07-Preferences.md b/doc/07-Preferences.md index ca26b66b0..e89a507bf 100644 --- a/doc/07-Preferences.md +++ b/doc/07-Preferences.md @@ -27,13 +27,13 @@ type = ini ### Store Preferences in a Database In order to be more flexible in distributed setups you can store preferences in a MySQL or in a PostgreSQL database. -For storing preferences in a database, you have to define a [database resource](resources.md#resources-configuration-database) +For storing preferences in a database, you have to define a [database resource](04-Resources.md#resources-configuration-database) which will be referenced as resource for the preferences storage. Directive | Description ------------------------|------------ **type** | `db` -**resource** | The name of the database resource defined in [resources.ini](resources.md#resources). +**resource** | The name of the database resource defined in [resources.ini](04-Resources.md#resources). **Example:** @@ -50,4 +50,4 @@ For storing preferences in a database, you have to import one of the following d * **etc/schema/preferences.mysql.sql** (for **MySQL** database) * **etc/schema/preferences.pgsql.sql** (for **PostgreSQL** databases) -After that you have to define the [database resource](resources.md#resources-configuration-database). +After that you have to define the [database resource](04-Resources.md#resources-configuration-database). From 0fdd02e0d215fc3030f8a8ad9a35433ab04aef3d Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 13 Apr 2016 13:47:11 +0200 Subject: [PATCH 101/109] Add version 2.3.0 upgrading note --- doc/02-Installation.md | 90 ++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/doc/02-Installation.md b/doc/02-Installation.md index 593354514..9afe087e8 100644 --- a/doc/02-Installation.md +++ b/doc/02-Installation.md @@ -451,46 +451,20 @@ Finally visit Icinga Web 2 in your browser to login as `icingaadmin` user: `/ici # Upgrading Icinga Web 2 -## Upgrading to Icinga Web 2 Beta 2 +## Upgrading to Icinga Web 2 2.3.0 -Icinga Web 2 Beta 2 introduces access control based on roles for secured actions. If you've already set up Icinga Web 2, -you are required to create the file **roles.ini** beneath Icinga Web 2's configuration directory with the following -content: -``` -[administrators] -users = "your_user_name, another_user_name" -permissions = "*" -``` +* Icinga Web 2 version 2.3.0 does not introduce any backward incompatible change. -After please log out from Icinga Web 2 and log in again for having all permissions granted. +## Upgrading to Icinga Web 2 2.2.0 -If you delegated authentication to your web server using the `autologin` backend, you have to switch to the `external` -authentication backend to be able to log in again. The new name better reflects what’s going on. A similar change -affects environments that opted for not storing preferences, your new backend is `none`. +* The menu entry `Authorization` beneath `Config` has been renamed to `Authentication`. The role, user backend and user + group backend configuration which was previously found beneath `Authentication` has been moved to `Application`. + +## Upgrading to Icinga Web 2 2.1.x -## Upgrading to Icinga Web 2 Beta 3 - -Because Icinga Web 2 Beta 3 does not introduce any backward incompatible change you don't have to change your -configuration files after upgrading to Icinga Web 2 Beta 3. - -## Upgrading to Icinga Web 2 Release Candidate 1 - -The first release candidate of Icinga Web 2 introduces the following non-backward compatible changes: - -* The database schema has been adjusted and the tables `icingaweb_group` and - `icingaweb_group_membership` were altered to ensure referential integrity. - Please use the upgrade script located in **etc/schema/** to update your - database schema - -* Users who are using PostgreSQL < v9.1 are required to upgrade their - environment to v9.1+ as this is the new minimum required version - for utilizing PostgreSQL as database backend - -* The restrictions `monitoring/hosts/filter` and `monitoring/services/filter` - provided by the monitoring module were merged together. The new - restriction is called `monitoring/filter/objects` and supports only a - predefined subset of filter columns. Please see the module's security - related documentation for more details. +* Since Icinga Web 2 version 2.1.3 LDAP user group backends respect the configuration option `group_filter`. + Users who changed the configuration manually and used the option `filter` instead + have to change it back to `group_filter`. ## Upgrading to Icinga Web 2 2.0.0 @@ -514,13 +488,43 @@ The first release candidate of Icinga Web 2 introduces the following non-backwar **<config-dir>/preferences/<username>/config.ini**. The content of the file remains unchanged. -## Upgrading to Icinga Web 2 2.1.x +## Upgrading to Icinga Web 2 Release Candidate 1 -* Since Icinga Web 2 version 2.1.3 LDAP user group backends respect the configuration option `group_filter`. - Users who changed the configuration manually and used the option `filter` instead - have to change it back to `group_filter`. +The first release candidate of Icinga Web 2 introduces the following non-backward compatible changes: -## Upgrading to Icinga Web 2 2.2.0 +* The database schema has been adjusted and the tables `icingaweb_group` and + `icingaweb_group_membership` were altered to ensure referential integrity. + Please use the upgrade script located in **etc/schema/** to update your + database schema -* The menu entry `Authorization` beneath `Config` has been renamed to `Authentication`. The role, user backend and user - group backend configuration which was previously found beneath `Authentication` has been moved to `Application`. +* Users who are using PostgreSQL < v9.1 are required to upgrade their + environment to v9.1+ as this is the new minimum required version + for utilizing PostgreSQL as database backend + +* The restrictions `monitoring/hosts/filter` and `monitoring/services/filter` + provided by the monitoring module were merged together. The new + restriction is called `monitoring/filter/objects` and supports only a + predefined subset of filter columns. Please see the module's security + related documentation for more details. + +## Upgrading to Icinga Web 2 Beta 3 + +Because Icinga Web 2 Beta 3 does not introduce any backward incompatible change you don't have to change your +configuration files after upgrading to Icinga Web 2 Beta 3. + +## Upgrading to Icinga Web 2 Beta 2 + +Icinga Web 2 Beta 2 introduces access control based on roles for secured actions. If you've already set up Icinga Web 2, +you are required to create the file **roles.ini** beneath Icinga Web 2's configuration directory with the following +content: +``` +[administrators] +users = "your_user_name, another_user_name" +permissions = "*" +``` + +After please log out from Icinga Web 2 and log in again for having all permissions granted. + +If you delegated authentication to your web server using the `autologin` backend, you have to switch to the `external` +authentication backend to be able to log in again. The new name better reflects what’s going on. A similar change +affects environments that opted for not storing preferences, your new backend is `none`. From 8034e9de23d77874f70fbf1e64b8506a46309057 Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Tue, 12 Apr 2016 13:53:51 +0200 Subject: [PATCH 102/109] Accessibility: Increase focus visibility in tactical overview fixes #11516 --- modules/monitoring/public/css/module.less | 1 - public/css/themes/high-contrast.less | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 4783bd6f4..af2458b8b 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -138,7 +138,6 @@ /* Any line of a box entry */ .boxview div.box.entry a { display: block; - color: inherit; } .boxview div.box.badge { diff --git a/public/css/themes/high-contrast.less b/public/css/themes/high-contrast.less index 299e1cce5..d5db9795c 100644 --- a/public/css/themes/high-contrast.less +++ b/public/css/themes/high-contrast.less @@ -59,3 +59,8 @@ #menu .active > a { text-decoration: underline; } + +.boxview a:focus { + color: @text-color; + text-decoration: underline; +} From 855e7f71208cb6d69b2190a7709182518178d382 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 13 Apr 2016 13:51:43 +0200 Subject: [PATCH 103/109] Fix icingacli monitoring list --problems fixes #11245 --- modules/monitoring/application/clicommands/ListCommand.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/monitoring/application/clicommands/ListCommand.php b/modules/monitoring/application/clicommands/ListCommand.php index 26f50f592..7e875e37b 100644 --- a/modules/monitoring/application/clicommands/ListCommand.php +++ b/modules/monitoring/application/clicommands/ListCommand.php @@ -55,6 +55,9 @@ class ListCommand extends Command $query->limit($limit, $this->params->shift('offset')); } foreach ($this->params->getParams() as $col => $filter) { + if (strtolower($col) === 'problems') { + $col = 'service_problem'; + } $query->where($col, $filter); } // $query->applyFilters($this->params->getParams()); From 61688288780ecc74bd9cde0de01dd802abe7992d Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Mon, 4 Apr 2016 16:34:23 +0200 Subject: [PATCH 104/109] CSS: Change font to Lucida Grande on OS X --- public/css/icinga/base.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/icinga/base.less b/public/css/icinga/base.less index 4aea04fb6..2491dad7a 100644 --- a/public/css/icinga/base.less +++ b/public/css/icinga/base.less @@ -44,7 +44,7 @@ @tr-hover-color: #F5FDFF; // Font families -@font-family: Calibri, Helvetica, sans-serif; +@font-family: Calibri, "Lucida Grande", sans-serif; @font-family-fixed: "Liberation Mono", "Lucida Console", Courier, monospace; @font-family-wide: Tahoma, Verdana, sans-serif; From 42112b28c5862e6ecd0bb02b2886f4b1e6320d22 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 13 Apr 2016 14:41:27 +0200 Subject: [PATCH 105/109] Revert "doc: Replace whitespaces with - for section IDs" This reverts commit 82d36e11cc7cf53f699730e5d5b97a83af5a95de. --- modules/doc/library/Doc/DocSection.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/modules/doc/library/Doc/DocSection.php b/modules/doc/library/Doc/DocSection.php index 3138a70be..ce5297e1d 100644 --- a/modules/doc/library/Doc/DocSection.php +++ b/modules/doc/library/Doc/DocSection.php @@ -88,14 +88,6 @@ class DocSection extends TreeNode return $this->content; } - /** - * {@inheritdoc} - */ - public function setId($id) - { - return parent::setId(str_replace(' ', '-', (string) $id)); - } - /** * Set the header level * From 04a3d3e90d3dcbe1fbbb82441cf14c9f99fd2fed Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 13 Apr 2016 14:49:34 +0200 Subject: [PATCH 106/109] Fix issue w/ duplicate section IDs fixes #11580 --- modules/doc/library/Doc/DocParser.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/doc/library/Doc/DocParser.php b/modules/doc/library/Doc/DocParser.php index 5b4986b45..ac98584b6 100644 --- a/modules/doc/library/Doc/DocParser.php +++ b/modules/doc/library/Doc/DocParser.php @@ -133,9 +133,11 @@ class DocParser */ protected function uuid($id, $filename, SimpleTree $tree) { - if ($tree->getNode($id) !== null) { - $id = $id . '-' . md5($filename); + $id = str_replace(' ', '-', $id); + if ($tree->getNode($id) === null) { + return $id; } + $id = $id . '-' . md5($filename); $offset = 0; while ($tree->getNode($id)) { if ($offset++ === 0) { From a8bf78b054e45ba4f59a056dc3634e0e212e90c0 Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Tue, 5 Apr 2016 13:21:37 +0200 Subject: [PATCH 107/109] CSS: Optimize button link styles --- public/css/icinga/main.less | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/public/css/icinga/main.less b/public/css/icinga/main.less index b7d2c7bb3..8737c5c99 100644 --- a/public/css/icinga/main.less +++ b/public/css/icinga/main.less @@ -69,6 +69,16 @@ a:hover > .icon-cancel { .button-link { .action-link(); + .rounded-corners(3px); + + background: @gray-lighter; + display: inline-block; + padding: 0.25em 0.5em; + + &:hover { + background: @gray-lightest; + text-decoration: none; + } } // List styles From 0a162008a2c9849f01786a11fe9e214467475790 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 13 Apr 2016 15:28:08 +0200 Subject: [PATCH 108/109] Increase font-weight of links in docs --- modules/doc/public/css/module.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/doc/public/css/module.less b/modules/doc/public/css/module.less index 035c18278..684d4a4bb 100644 --- a/modules/doc/public/css/module.less +++ b/modules/doc/public/css/module.less @@ -24,7 +24,8 @@ pre > code { } .chapter a { - border-bottom: 1px @gray-light dotted; + border-bottom: 1x @gray-light dotted; + font-weight: @font-weight-bold; &:hover { border-bottom: 1px @text-color solid; From 0461b060f87cd7b456eaa337a8ba83adbda2981c Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 13 Apr 2016 15:33:19 +0200 Subject: [PATCH 109/109] Fix typo in doc/module.less --- modules/doc/public/css/module.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/doc/public/css/module.less b/modules/doc/public/css/module.less index 684d4a4bb..35cfc3d3a 100644 --- a/modules/doc/public/css/module.less +++ b/modules/doc/public/css/module.less @@ -24,7 +24,7 @@ pre > code { } .chapter a { - border-bottom: 1x @gray-light dotted; + border-bottom: 1px @gray-light dotted; font-weight: @font-weight-bold; &:hover {