Merge branch 'bugfix/js-close-container-8590' of git.icinga.org:icingaweb2 into bugfix/js-close-container-8590

This commit is contained in:
Florian Strohmaier 2016-03-29 15:14:59 +02:00
commit 6ebfe7020d
102 changed files with 2411 additions and 1576 deletions

View File

@ -35,6 +35,11 @@ class apache {
require => Package['apache'],
}
package { 'mod_ssl':
ensure => latest,
notify => Service[$apache],
}
@user { $user:
alias => 'apache',
}

View File

@ -14,10 +14,12 @@ Daniel Shirley <aditaa@ig2ad.com>
Davide Demuru <davide.demuru@buongiorno.com>
Emil Vikström <emil@pixelstore.se>
Eric Lippmann <eric.lippmann@netways.de>
Florian Strohmaier <hello@florianstrohmaier.com>
Goran Rakic <grakic@devbase.net>
Gunnar Beutner <gunnar.beutner@netways.de>
Jannis Moßhammer <jannis.mosshammer@netways.de>
Jo Rhett <jo@chegg.com>
Joe Doherty <git@pjuu.com>
Johannes Meyer <johannes.meyer@netways.de>
Louis Sautier <sautier.louis@gmail.com>
Marcus Cobden <marcus@marcuscobden.co.uk>

View File

@ -1,5 +1,66 @@
# Icinga Web 2 Changelog
## What's New in Version 2.2.0
#### Features
* Feature 8487: Number headings in the documentation module
* Feature 8963: Feature commands in the multi select views
* Feature 10654: Render links in acknowledgements, comments and downtimes
* Feature 11062: Allow style classes in plugin output
* Feature 11238: Puppet/Vagrant: Install mod_ssl and forward port 443
#### Bugfixes
* Bug 7350: Tabs are missing if JS is disabled
* Bug 9800: Debian packaging: Ship translation module w/ the icingaweb2 package and install its config.ini
* Bug 10173: Failed commands give no useful error any more
* Bug 10251: Icinga Web 2 fails to run with PHP7
* Bug 10277: Special characters are incorrectly escaped for tooltips in the service grid
* Bug 10289: Doc module: Headers are cut off when clicking on TOC links
* Bug 10309: Move auth backend configuration to app config
* Bug 10310: Monitoring details: information/action ordering
* Bug 10362: Debian packaging: Separate package for CLI missing
* Bug 10366: Text plugin output treated as HTML in too many occasions
* Bug 10369: Accessibility: Focus not visible and lost after refresh
* Bug 10397: Users with no permissions can check multiple services
* Bug 10442: Edit user control should be more prominent
* Bug 10469: "Remove Acknowledgement" text missing in multi-select views
* Bug 10506: HTTP basic auth request is sent when using Kerberos authentication with Apache2 and mod_php
* Bug 10625: Return local date and time when lost connection to the web server
* Bug 10640: Respect protected_variables in nested custom variables too
* Bug 10778: Filters in the host group and service group overview not applied to state links
* Bug 10786: Whitespace characters are ignored in the plugin output in list views
* Bug 10805: Setup Wizard: Obsolete PHP sockets requirement
* Bug 10856: Benchmark is not rendered on many pages
* Bug 10871: Get rid of padding in controls
* Bug 10878: Dashboards different depending on username casing
* Bug 10881: Move iframe from modules to framework
* Bug 10917: Event grid tiles: The filter column "from" is not allowed here
* Bug 10918: Error on logout when using external authentication
* Bug 10921: icingacli monitoring list --format=csv throws error
* Bug 11000: Change license header to only reflect a file's year of creation/initial commit
* Bug 11008: Wobbling spinners
* Bug 11021: Global default theme is not applied while not authenticated
* Bug 11032: Fix icon_image size and provide a CSS class for theming
* Bug 11039: Misleading tooltip in Tactical Overview
* Bug 11051: Preferences and navigation items stored in INI files rely on case sensitive usernames
* Bug 11073: Active row is flickering on refresh
* Bug 11091: Custom navigation items: URL is not escaped/encoded
* Bug 11100: Comments are always persistent
* Bug 11114: Validate that a proper root DN is set for LDAP resources
* Bug 11117: Vendor: Update dompdf to version 0.6.2
* Bug 11119: icingacli shows ugly exception when unable to access the config directory
* Bug 11120: icingacli: command and action shortcuts have been broken
* Bug 11126: Invalid cookie value in cookie icingaweb2-tzo
* Bug 11142: LDAP User Groups backend group_filter
* Bug 11143: Layout: Tabs should be left-aligned
* Bug 11151: Having basic authentication on the webserver but not in Icinga Web 2 causes Web 2 to require basic auth
* Bug 11168: Debian packaging: Don't patch HTMLPurifier loading and install HTMLPurifier*.php files from the library/vendor root
* Bug 11187: Session cookie: Path too broad and unset secure flag on HTTPS
* Bug 11197: Menu items without url should ignore the target configuration
* Bug 11260: Scheduling downtimes through the API not working
## What's New in Version 2.1.1
#### Features

View File

@ -10,7 +10,7 @@
**Icinga Web 2** is the next generation open source monitoring web interface, framework
and command-line interface developed by the [Icinga Project](https://www.icinga.org/), supporting Icinga 2,
Icinga Core and any other monitoring backend compatible with the Livestatus Protocol.
Icinga Core and any other monitoring backend compatible with the IDO database.
![Icinga Web 2](https://www.icinga.org/wp-content/uploads/2015/10/Screen-Shot-2015-10-02-at-00.12.26.png "Icinga Web 2")

View File

@ -1 +1 @@
v2.1.2
v2.2.0

2
Vagrantfile vendored
View File

@ -18,6 +18,8 @@ end
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.network "forwarded_port", guest: 80, host: 8080,
auto_correct: true
config.vm.network "forwarded_port", guest: 443, host: 8443,
auto_correct: true
config.vm.provision :shell, :path => ".puppet/manifests/puppet.sh"

View File

@ -45,27 +45,12 @@ class ConfigController extends Controller
'url' => 'config/resource',
'baseTarget' => '_main'
));
return $tabs;
}
/**
* Create and return the tabs to display when showing authentication configuration
*/
public function createAuthenticationTabs()
{
$tabs = $this->getTabs();
$tabs->add('userbackend', array(
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
'label' => $this->translate('Users'),
$tabs->add('authentication', array(
'title' => $this->translate('Configure the user and group backends'),
'label' => $this->translate('Authentication'),
'url' => 'config/userbackend',
'baseTarget' => '_main'
));
$tabs->add('usergroupbackend', array(
'title' => $this->translate('Configure how users are associated with groups by Icinga Web 2'),
'label' => $this->translate('User Groups'),
'url' => 'usergroupbackend/list',
'baseTarget' => '_main'
));
return $tabs;
}
@ -184,17 +169,19 @@ class ConfigController extends Controller
}
/**
* Action for listing and reordering user backends
* Action for listing user and group backends
*/
public function userbackendAction()
{
$this->assertPermission('config/application/userbackend');
$this->assertPermission('config/application/usergroupbackend');
$form = new UserBackendReorderForm();
$form->setIniConfig(Config::app('authentication'));
$form->handleRequest();
$this->view->form = $form;
$this->createAuthenticationTabs()->activate('userbackend');
$this->view->backendNames = Config::app('groups');
$this->createApplicationTabs()->activate('authentication');
$this->render('userbackend/reorder');
}

View File

@ -39,6 +39,8 @@ class ListController extends Controller
*/
public function applicationlogAction()
{
$this->assertPermission('application/log');
if (! Logger::writesToFile()) {
$this->httpNotFound('Page not found');
}

View File

@ -29,16 +29,7 @@ class UsergroupbackendController extends Controller
*/
public function indexAction()
{
$this->redirectNow('usergroupbackend/list');
}
/**
* Show a list of all user group backends
*/
public function listAction()
{
$this->view->backendNames = Config::app('groups');
$this->createListTabs()->activate('usergroupbackend');
$this->redirectNow('config/userbackend');
}
/**
@ -47,7 +38,7 @@ class UsergroupbackendController extends Controller
public function createAction()
{
$form = new UserGroupBackendForm();
$form->setRedirectUrl('usergroupbackend/list');
$form->setRedirectUrl('config/userbackend');
$form->addDescription($this->translate('Create a new backend to associate users and groups with.'));
$form->setIniConfig(Config::app('groups'));
$form->setOnSuccess(function (UserGroupBackendForm $form) {
@ -78,7 +69,7 @@ class UsergroupbackendController extends Controller
$backendName = $this->params->getRequired('backend');
$form = new UserGroupBackendForm();
$form->setRedirectUrl('usergroupbackend/list');
$form->setRedirectUrl('config/userbackend');
$form->setIniConfig(Config::app('groups'));
$form->setOnSuccess(function (UserGroupBackendForm $form) use ($backendName) {
try {
@ -121,7 +112,7 @@ class UsergroupbackendController extends Controller
$backendForm = new UserGroupBackendForm();
$backendForm->setIniConfig(Config::app('groups'));
$form = new ConfirmRemovalForm();
$form->setRedirectUrl('usergroupbackend/list');
$form->setRedirectUrl('config/userbackend');
$form->setOnSuccess(function (ConfirmRemovalForm $form) use ($backendName, $backendForm) {
try {
$backendForm->delete($backendName);
@ -141,23 +132,4 @@ class UsergroupbackendController extends Controller
$this->renderForm($form, $this->translate('Remove User Group Backend'));
}
/**
* Create the tabs for the application configuration
*/
protected function createListTabs()
{
$tabs = $this->getTabs();
$tabs->add('userbackend', array(
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
'label' => $this->translate('Users'),
'url' => 'config/userbackend'
));
$tabs->add('usergroupbackend', array(
'title' => $this->translate('Configure how users are associated with groups by Icinga Web 2'),
'label' => $this->translate('User Groups'),
'url' => 'usergroupbackend/list'
));
return $tabs;
}
}

View File

@ -5,6 +5,7 @@ namespace Icinga\Forms\Dashboard;
use Icinga\Web\Widget\Dashboard;
use Icinga\Web\Form;
use Icinga\Web\Form\Validator\UrlValidator;
use Icinga\Web\Url;
use Icinga\Web\Widget\Dashboard\Dashlet;
@ -27,7 +28,7 @@ class DashletForm extends Form
if (! $this->getSubmitLabel()) {
$this->setSubmitLabel($this->translate('Add To Dashboard'));
}
$this->setAction(URL::fromRequest());
$this->setAction(Url::fromRequest());
}
/**
@ -68,7 +69,8 @@ class DashletForm extends Form
'label' => $this->translate('Url'),
'description' => $this->translate(
'Enter url being loaded in the dashlet. You can paste the full URL, including filters.'
)
),
'validators' => array(new UrlValidator())
)
);
$this->addElement(

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
<?= $tabs ?>
</div>
<div class="content">
<h1><?= $this->translate('User Backends') ?></h1>
<?= $this->qlink(
$this->translate('Create a New User Backend') ,
'config/createuserbackend',
@ -14,4 +15,57 @@
)
) ?>
<?= $form ?>
<h1><?= $this->translate('User Group Backends') ?></h1>
<?= $this->qlink(
$this->translate('Create a New User Group Backend') ,
'usergroupbackend/create',
null,
array(
'class' => 'button-link',
'data-base-target' => '_next',
'icon' => 'plus',
'title' => $this->translate('Create a new user group backend')
)
) ?>
<?php if (! count($backendNames)) { return; } ?>
<table class="table-row-selectable common-table" data-base-target="_next">
<thead>
<tr>
<th><?= $this->translate('Backend') ?></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($backendNames as $backendName => $config):
$type = $config->get('backend');
?>
<tr>
<td>
<?= $this->qlink(
$backendName,
'usergroupbackend/edit',
array('backend' => $backendName),
array(
'icon' => $type === 'external' ? 'magic' : ($type === 'ldap' || $type === 'msldap' ? 'sitemap' : 'database'),
'title' => sprintf($this->translate('Edit user group backend %s'), $backendName)
)
); ?>
</td>
<td class="icon-col text-right">
<?= $this->qlink(
null,
'usergroupbackend/remove',
array('backend' => $backendName),
array(
'class' => 'action-link',
'icon' => 'cancel',
'title' => sprintf($this->translate('Remove user group backend %s'), $backendName)
)
) ?>
</td>
</tr>
<?php endforeach ?>
</tbody>
</table>
</div>

View File

@ -20,7 +20,7 @@
<?php foreach ($this->dashboard->getPanes() as $pane): ?>
<tr style="background-color: #f1f1f1;">
<th colspan="2" style="text-align: left; padding: 0.5em;">
<?= $pane->getName(); ?>
<?= $this->escape($pane->getName()) ?>
</th>
<th>
<?= $this->qlink(

View File

@ -40,30 +40,26 @@
</td>
<td class="icon-col text-right" data-base-target="_self">
<?php if ($i > 0): ?>
<button type="submit" name="backend_newpos" class="link-button icon-only animated move-up" value="<?= sprintf(
'%s|%s',
$backendNames[$i],
$i - 1
<button type="submit" name="backend_newpos" class="link-button icon-only animated move-up" value="<?= $this->escape(
$backendNames[$i] . '|' . ($i - 1)
) ?>" title="<?= $this->translate(
'Move up in authentication order'
) ?>" aria-label="<?= sprintf(
) ?>" aria-label="<?= $this->escape(sprintf(
$this->translate('Move user backend %s upwards'),
$backendNames[$i]
) ?>">
)) ?>">
<?= $this->icon('up-small') ?>
</button>
<?php endif ?>
<?php if ($i + 1 < count($backendNames)): ?>
<button type="submit" name="backend_newpos" class="link-button icon-only animated move-down" value="<?= sprintf(
'%s|%s',
$backendNames[$i],
$i + 1
<button type="submit" name="backend_newpos" class="link-button icon-only animated move-down" value="<?= $this->escape(
$backendNames[$i] . '|' . ($i + 1)
) ?>" title="<?= $this->translate(
'Move down in authentication order'
) ?>" aria-label="<?= sprintf(
) ?>" aria-label="<?= $this->escape(sprintf(
$this->translate('Move user backend %s downwards'),
$backendNames[$i]
) ?>">
)) ?>">
<?= $this->icon('down-small') ?>
</button>
<?php endif ?>

View File

@ -4,29 +4,29 @@ use Icinga\Data\Updatable;
use Icinga\Data\Reducible;
use Icinga\Data\Selectable;
$editLink = null;
if ($this->hasPermission('config/authentication/users/edit') && $backend instanceof Updatable) {
$editLink = $this->qlink(
null,
'user/edit',
array(
'backend' => $backend->getName(),
'user' => $user->user_name
),
array(
'title' => sprintf($this->translate('Edit user %s'), $user->user_name),
'class' => 'user-edit',
'icon' => 'edit'
)
);
}
?>
<div class="controls separated">
<?php if (! $this->compact): ?>
<?= $tabs; ?>
<?php endif ?>
<h2 class="clearfix"><?= $this->escape($user->user_name) ?><span class="pull-right"><?= $editLink ?></span></h2>
<h2><?= $this->escape($user->user_name) ?></h2>
<?php
if ($this->hasPermission('config/authentication/users/edit') && $backend instanceof Updatable) {
echo $this->qlink(
$this->translate('Edit User'),
'user/edit',
array(
'backend' => $backend->getName(),
'user' => $user->user_name
),
array(
'class' => 'button-link',
'icon' => 'edit',
'title' => sprintf($this->translate('Edit user %s'), $user->user_name)
)
);
}
?>
<table class="name-value-table">
<tr>
<th><?= $this->translate('State'); ?></th>

View File

@ -1,56 +0,0 @@
<div class="controls">
<?= $tabs ?>
</div>
<div class="content">
<?= $this->qlink(
$this->translate('Create a New User Group Backend') ,
'usergroupbackend/create',
null,
array(
'class' => 'button-link',
'data-base-target' => '_next',
'icon' => 'plus',
'title' => $this->translate('Create a new user group backend')
)
) ?>
<?php if (! count($backendNames)) { return; } ?>
<table class="table-row-selectable common-table" data-base-target="_next">
<thead>
<tr>
<th><?= $this->translate('Backend') ?></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($backendNames as $backendName => $config):
$type = $config->get('backend');
?>
<tr>
<td>
<?= $this->qlink(
$backendName,
'usergroupbackend/edit',
array('backend' => $backendName),
array(
'icon' => $type === 'external' ? 'magic' : ($type === 'ldap' || $type === 'msldap' ? 'sitemap' : 'database'),
'title' => sprintf($this->translate('Edit user group backend %s'), $backendName)
)
); ?>
</td>
<td class="icon-col text-right">
<?= $this->qlink(
null,
'usergroupbackend/remove',
array('backend' => $backendName),
array(
'class' => 'action-link',
'icon' => 'cancel',
'title' => sprintf($this->translate('Remove user group backend %s'), $backendName)
)
) ?>
</td>
</tr>
<?php endforeach ?>
</tbody>
</table>
</div>

View File

@ -114,7 +114,7 @@ The packages for RHEL/CentOS depend on other packages which are distributed as p
#### <a id="package-repositories-wheezy-notes"></a> Debian wheezy Notes
The packages for Debian wheezy depend on other packages which are distributed as part of the
[wheezy-packports](http://backports.debian.org/) repository. Please make sure to enable this repository by following
[wheezy-backports](http://backports.debian.org/) repository. Please make sure to enable this repository by following
[these instructions](http://backports.debian.org/Instructions/).
### <a id="installing-from-package-example"></a> Installing Icinga Web 2
@ -519,3 +519,8 @@ The first release candidate of Icinga Web 2 introduces the following non-backwar
* 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`.
## <a id="upgrading-to-2.2.0"></a> Upgrading to Icinga Web 2 2.2.0
* 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`.

View File

@ -1,9 +1,9 @@
# Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+
# Icinga Web 2 | (c) 2013-2016 Icinga Development Team | GPLv2+
%define revision 1
Name: icingaweb2
Version: 2.1.2
Version: 2.2.0
Release: %{revision}%{?dist}
Summary: Icinga Web 2
Group: Applications/System
@ -165,6 +165,18 @@ Requires: %{php} >= 5.3.0
Icinga Web 2 vendor library Parsedown
%package vendor-Zend
Version: 1.12.15
Release: 1%{?dist}
Summary: Icinga Web 2 vendor library Zend Framework
Group: Development/Libraries
License: BSD
Requires: %{php} >= 5.3.0
%description vendor-Zend
Icinga Web 2 vendor library Zend
%prep
%setup -q
@ -177,7 +189,7 @@ cp -prv application doc %{buildroot}/%{basedir}
cp -pv etc/bash_completion.d/icingacli %{buildroot}/%{_sysconfdir}/bash_completion.d/icingacli
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} %{buildroot}/%{basedir}/library/vendor
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 -pv packages/files/apache/icingaweb2.conf %{buildroot}/%{wwwconfigdir}/icingaweb2.conf
cp -pv packages/files/bin/icingacli %{buildroot}/%{bindir}
@ -267,3 +279,8 @@ exit 0
%files vendor-Parsedown
%defattr(-,root,root)
%{basedir}/library/vendor/Parsedown
%files vendor-Zend
%defattr(-,root,root)
%{basedir}/library/vendor/Zend

View File

@ -520,25 +520,6 @@ abstract class ApplicationBootstrap
return $this;
}
/**
* Set up the resource factory
*
* @return $this
*/
protected function setupResourceFactory()
{
try {
$config = Config::app('resources');
ResourceFactory::setConfig($config);
} catch (NotReadableError $e) {
Logger::error(
new IcingaException('Cannot load resource configuration. An exception was thrown:', $e)
);
}
return $this;
}
/**
* Set up the user backend factory
*

View File

@ -41,7 +41,6 @@ class Cli extends ApplicationBootstrap
->setupInternationalization()
->parseBasicParams()
->setupLogger()
->setupResourceFactory()
->setupModuleManager()
->setupUserBackendFactory()
->loadSetupModuleIfNecessary();

View File

@ -120,7 +120,7 @@ class Manager
}
if (! is_readable($parent)) {
throw new NotReadableError(
'Cannot read enabled modules. Module directory\'s parent directory "%s" is not readable',
'Cannot read enabled modules. Config directory "%s" is not readable',
$parent
);
}

View File

@ -8,7 +8,7 @@ namespace Icinga\Application;
*/
class Version
{
const VERSION = '2.1.2';
const VERSION = '2.2.0';
/**
* Get the version of this instance of Icinga Web 2

View File

@ -82,10 +82,9 @@ class Web extends EmbeddedWeb
->setupLogging()
->setupErrorHandling()
->loadConfig()
->setupResourceFactory()
->setupRequest()
->setupSession()
->setupNotifications()
->setupRequest()
->setupResponse()
->setupZendMvc()
->setupModuleManager()
@ -322,13 +321,7 @@ class Web extends EmbeddedWeb
'priority' => 810
),
'authentication' => array(
'label' => t('Authentication'),
'url' => 'config/userbackend',
'permission' => 'config/application/*',
'priority' => 820
),
'authorization' => array(
'label' => t('Authorization'),
'label' => t('Authentication'),
'permission' => 'config/authentication/*',
'priority' => 830,
'url' => 'role/list'
@ -370,9 +363,10 @@ class Web extends EmbeddedWeb
if (Logger::writesToFile()) {
$menu['system']['children']['application_log'] = array(
'label' => t('Application Log'),
'url' => 'list/applicationlog',
'priority' => 710
'label' => t('Application Log'),
'url' => 'list/applicationlog',
'permission' => 'application/log',
'priority' => 710
);
}
} else {

View File

@ -3,7 +3,6 @@
use Icinga\Util\Translator;
/**
* No-op translate
*
@ -19,6 +18,11 @@ function N_($messageId)
return $messageId;
}
// Workaround for test issues, this is required unless our tests are able to
// accomplish "real" bootstrapping
if (function_exists('t')) {
return;
}
if (extension_loaded('gettext')) {

View File

@ -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;
@ -43,16 +44,12 @@ class AdmissionLoader
}
/**
* Get user permissions and restrictions
* Apply permissions, restrictions and roles to the given user
*
* @param User $user
*
* @return array
* @param User $user
*/
public function getPermissionsAndRestrictions(User $user)
public function applyRoles(User $user)
{
$permissions = array();
$restrictions = array();
$username = $user->getUsername();
try {
$roles = Config::app('roles');
@ -62,14 +59,18 @@ class AdmissionLoader
$username,
$e
);
return array($permissions, $restrictions);
return;
}
$userGroups = $user->getGroups();
foreach ($roles as $role) {
$permissions = array();
$restrictions = array();
$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']);
@ -81,8 +82,16 @@ class AdmissionLoader
}
$restrictions[$name][] = $restriction;
}
$roleObj = new Role();
$roleObjs[] = $roleObj
->setName($roleName)
->setPermissions($permissionsFromRole)
->setRestrictions($restrictionsFromRole);
}
}
return array($permissions, $restrictions);
$user->setPermissions($permissions);
$user->setRestrictions($restrictions);
$user->setRoles($roleObjs);
}
}

View File

@ -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();
@ -244,7 +242,8 @@ class Auth
$this->user = Session::getSession()->get('user');
if ($this->user !== null && $this->user->isExternalUser() === true) {
list($originUsername, $field) = $this->user->getExternalUserInformation();
if (! array_key_exists($field, $_SERVER) || $_SERVER[$field] !== $originUsername) {
$username = getenv($field); // usually REMOTE_USER here
if ( !$username || $username !== $originUsername) {
$this->removeAuthorization();
}
}

View File

@ -0,0 +1,109 @@
<?php
/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
namespace Icinga\Authentication;
class Role
{
/**
* Name of the role
*
* @var string
*/
protected $name;
/**
* Permissions of the role
*
* @var string[]
*/
protected $permissions = array();
/**
* Restrictions of the role
*
* @var string[]
*/
protected $restrictions = array();
/**
* Get the name of the role
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set the name of the role
*
* @param string $name
*
* @return $this
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get the permissions of the role
*
* @return string[]
*/
public function getPermissions()
{
return $this->permissions;
}
/**
* Set the permissions of the role
*
* @param string[] $permissions
*
* @return $this
*/
public function setPermissions(array $permissions)
{
$this->permissions = $permissions;
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;
}
/**
* Set the restrictions of the role
*
* @param string[] $restrictions
*
* @return $this
*/
public function setRestrictions(array $restrictions)
{
$this->restrictions = $restrictions;
return $this;
}
}

View File

@ -1,143 +0,0 @@
<?php
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
namespace Icinga\Authentication\UserGroup;
use Icinga\Exception\StatementException;
use Icinga\Data\Filter\Filter;
use Icinga\Repository\IniRepository;
use Icinga\User;
use Icinga\Util\StringHelper;
class IniUserGroupBackend extends IniRepository implements UserGroupBackendInterface
{
/**
* The query columns being provided
*
* @var array
*/
protected $queryColumns = array(
'groups' => array(
'group' => 'name',
'group_name' => 'name',
'parent' => 'parent',
'created_at' => 'ctime',
'last_modified' => 'mtime',
'users'
)
);
/**
* The columns which are not permitted to be queried
*
* @var array
*/
protected $blacklistedQueryColumns = array('group');
/**
* The search columns being provided
*
* @var array
*/
protected $searchColumns = array('group');
/**
* The value conversion rules to apply on a query or statement
*
* @var array
*/
protected $conversionRules = array(
'groups' => array(
'created_at' => 'date_time',
'last_modified' => 'date_time',
'users' => 'comma_separated_string'
)
);
/**
* Initialize this ini user group backend
*/
protected function init()
{
$this->ds->getConfigObject()->setKeyColumn('name');
}
/**
* Initialize this repository's filter columns
*
* @return array
*/
protected function initializeFilterColumns()
{
return array(
t('User Group') => 'group',
t('Parent') => 'parent',
t('Created At') => 'created_at',
t('Last Modified') => 'last_modified'
);
}
/**
* Add a new group to this backend
*
* @param string $target
* @param array $data
*
* @throws StatementException In case the operation has failed
*/
public function insert($target, array $data)
{
$data['created_at'] = time();
parent::insert($target, $data);
}
/**
* Update groups of this backend, optionally limited using a filter
*
* @param string $target
* @param array $data
* @param Filter $filter
*
* @throws StatementException In case the operation has failed
*/
public function update($target, array $data, Filter $filter = null)
{
$data['last_modified'] = time();
parent::update($target, $data, $filter);
}
/**
* Return the groups the given user is a member of
*
* @param User $user
*
* @return array
*/
public function getMemberships(User $user)
{
$result = $this->select()->fetchAll();
$groups = array();
foreach ($result as $group) {
$groups[$group->group_name] = $group->parent;
}
$username = strtolower($user->getUsername());
$memberships = array();
foreach ($result as $group) {
if ($group->users && !in_array($group->group_name, $memberships)) {
$users = array_map('strtolower', StringHelper::trimSplit($group->users));
if (in_array($username, $users)) {
$memberships[] = $group->group_name;
$parent = $groups[$group->group_name];
while ($parent !== null) {
$memberships[] = $parent;
$parent = isset($groups[$parent]) ? $groups[$parent] : null;
}
}
}
}
return $memberships;
}
}

View File

@ -22,8 +22,7 @@ class UserGroupBackend
protected static $defaultBackends = array(
'db',
'ldap',
'msldap',
//'ini'
'msldap'
);
/**
@ -155,9 +154,6 @@ class UserGroupBackend
case 'db':
$backend = new DbUserGroupBackend($resource);
break;
case 'ini':
$backend = new IniUserGroupBackend($resource);
break;
case 'ldap':
case 'msldap':
$backend = new LdapUserGroupBackend($resource);

View File

@ -5,6 +5,7 @@ namespace Icinga\Cli;
use Icinga\Application\ApplicationBootstrap as App;
use Icinga\Exception\IcingaException;
use Icinga\Exception\NotReadableError;
use Icinga\Exception\ProgrammingError;
use Icinga\Cli\Params;
use Icinga\Cli\Screen;
@ -421,10 +422,14 @@ class Loader
{
if ($this->modules === null) {
$this->modules = array();
$this->modules = array_unique(array_merge(
$this->app->getModuleManager()->listEnabledModules(),
$this->app->getModuleManager()->listLoadedModules()
));
try {
$this->modules = array_unique(array_merge(
$this->app->getModuleManager()->listEnabledModules(),
$this->app->getModuleManager()->listLoadedModules()
));
} catch (NotReadableError $e) {
$this->fail($e->getMessage());
}
}
return $this->modules;
}

View File

@ -152,7 +152,13 @@ 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 (isset($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;
case 'oci':

View File

@ -67,16 +67,14 @@ class ResourceFactory implements ConfigAwareFactory
}
/**
* Check if the existing resources are set. If not, throw an error.
* Check if the existing resources are set. If not, load them from resources.ini
*
* @throws ConfigurationError
*/
private static function assertResourcesExist()
{
if (self::$resources === null) {
throw new ConfigurationError(
'Resources not set up. Please contact your Icinga Web administrator'
);
self::$resources = Config::app('resources');
}
}

View File

@ -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;
@ -91,6 +92,13 @@ class User
*/
protected $groups = array();
/**
* Roles of this user
*
* @var Role[]
*/
protected $roles = array();
/**
* Preferences object
*
@ -229,13 +237,39 @@ 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;
}
/**
* 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;
}
/**

View File

@ -53,7 +53,11 @@ class TimezoneDetect
}
if (Platform::isCli() === false && array_key_exists(self::$cookieName, $_COOKIE)) {
list($offset, $dst) = explode(',', $_COOKIE[self::$cookieName]);
$cookieValue = $_COOKIE[self::$cookieName];
list($offset, $dst) = explode(
strpos($cookieValue, ',') === false ? '-' : ',',
$cookieValue
);
$timezoneName = timezone_name_from_abbr('', (int)$offset, (int)$dst);
self::$success = (bool)$timezoneName;

View File

@ -209,6 +209,7 @@ class Controller extends ModuleActionController
);
$editor = Widget::create('filterEditor');
/** @var \Icinga\Web\Widget\FilterEditor $editor */
call_user_func_array(
array($editor, 'preserveParams'),
array_merge($defaultPreservedParams, $preserveParams ?: array())
@ -221,10 +222,12 @@ class Controller extends ModuleActionController
->setSearchColumns($searchColumns)
->handleRequest($this->getRequest());
if (! $this->view->compact) {
$this->view->filterEditor = $editor;
if ($this->view->compact) {
$editor->setVisible(false);
}
$this->view->filterEditor = $editor;
return $this;
}
}

View File

@ -459,15 +459,13 @@ class ActionController extends Zend_Controller_Action
$layout->innerLayout = $this->innerLayout;
if ($user = $req->getUser()) {
// Cast preference app.show_benchmark to bool because preferences loaded from a preferences storage are
// always strings
if ((bool) $user->getPreferences()->getValue('icingaweb', 'show_benchmark', false) === true) {
if (!$this->_helper->viewRenderer->getNoRender()) {
if ((bool) $user->getPreferences()->getValue('icingaweb', 'show_benchmark', false)) {
if ($this->_helper->layout()->isEnabled()) {
$layout->benchmark = $this->renderBenchmark();
}
}
if ((bool) $user->getPreferences()->getValue('icingaweb', 'auto_refresh', true) === false) {
if (! (bool) $user->getPreferences()->getValue('icingaweb', 'auto_refresh', true)) {
$this->disableAutoRefresh();
}
}

View File

@ -96,6 +96,9 @@ class Cookie
*/
public function getDomain()
{
if ($this->domain === null) {
$this->domain = Config::app()->get('cookie', 'domain');
}
return $this->domain;
}
@ -182,9 +185,9 @@ class Cookie
if ($path === null) {
// The following call could be used as default for ConfigObject::get(), but we prevent unnecessary
// function calls here, if the path is set in the config
$path = Icinga::app()->getRequest()->getBaseUrl();
$path = Icinga::app()->getRequest()->getBaseUrl() . '/'; // Zend has rtrim($baseUrl, '/')
}
return $path;
$this->path = $path;
}
return $this->path;
}
@ -219,7 +222,7 @@ class Cookie
// function calls here, if the secure flag is set in the config
$secure = Icinga::app()->getRequest()->isSecure();
}
return $secure;
$this->secure = $secure;
}
return $this->secure;
}

View File

@ -0,0 +1,41 @@
<?php
/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
namespace Icinga\Web\Form\Validator;
use Zend_Validate_Abstract;
/**
* Validator that checks whether a textfield doesn't contain raw double quotes
*/
class UrlValidator extends Zend_Validate_Abstract
{
/**
* Error templates
*
* @var array
*
* @see Zend_Validate_Abstract::$_messageTemplates
*/
protected $_messageTemplates = array(
'HAS_QUOTES' => 'The url must not contain raw double quotes. If you really need double quotes, use %22 instead.'
);
/**
* Validate the input value
*
* @param string $value The string to validate
*
* @return bool true if and only if the input is valid, otherwise false
*
* @see Zend_Validate_Abstract::isValid()
*/
public function isValid($value)
{
$hasQuotes = false === strpos($value, '"');
if (! $hasQuotes) {
$this->_error('HAS_QUOTES');
}
return $hasQuotes;
}
}

View File

@ -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;
}

View File

@ -260,8 +260,9 @@ class Menu implements RecursiveIterator
));
if (Logger::writesToFile()) {
$section->add(t('Application Log'), array(
'url' => 'list/applicationlog',
'priority' => 710
'url' => 'list/applicationlog',
'permission' => 'application/log',
'priority' => 710
));
}

View File

@ -5,6 +5,7 @@ namespace Icinga\Web\Session;
use Icinga\Application\Logger;
use Icinga\Exception\ConfigurationError;
use Icinga\Web\Cookie;
/**
* Session implementation in PHP
@ -102,11 +103,21 @@ class PhpSession extends Session
ini_set('session.cache_limiter', null);
}
$cookie = new Cookie('bogus');
session_set_cookie_params(
0,
$cookie->getPath(),
$cookie->getDomain(),
$cookie->isSecure(),
true
);
session_start();
if ($this->hasBeenTouched) {
ini_set('session.use_cookies', true);
ini_set('session.use_only_cookies', true);
/** @noinspection PhpUndefinedVariableInspection */
ini_set('session.cache_limiter', $cacheLimiter);
}
}

View File

@ -212,17 +212,18 @@ class Url
}
/**
* Set the new Filter of the url to be the current filter and the given filter
* Add the given filter to the current filter of the URL
*
* @param Filter $and
* @param Filter $and
*
* @return $this
*/
public function addFilter($and)
{
$this->setQueryString(
Filter::matchAll(
$and,
Filter::fromQueryString($this->getQueryString())
)->toQueryString()
Filter::fromQueryString($this->getQueryString())
->andFilter($and)
->toQueryString()
);
return $this;
}

View File

@ -55,6 +55,13 @@ class FilterEditor extends AbstractWidget
*/
private $selectedIdx;
/**
* Whether the filter control is visible
*
* @var bool
*/
protected $visible = true;
/**
* Create a new FilterWidget
*
@ -144,6 +151,30 @@ class FilterEditor extends AbstractWidget
return $this;
}
/**
* Get whether the filter control is visible
*
* @return bool
*/
public function isVisible()
{
return $this->visible;
}
/**
* Set whether the filter control is visible
*
* @param bool $visible
*
* @return $this
*/
public function setVisible($visible)
{
$this->visible = (bool) $visible;
return $this;
}
protected function redirectNow($url)
{
$response = Icinga::app()->getFrontController()->getResponse();
@ -731,6 +762,9 @@ class FilterEditor extends AbstractWidget
public function render()
{
if (! $this->visible) {
return '';
}
if (! $this->preservedUrl()->getParam('modifyFilter')) {
return '<div class="filter">' . $this->renderSearch() . $this->view()->escape($this->shorten($this->filter, 50)) . '</div>';
}

View File

@ -1,4 +1,4 @@
Module: doc
Version: 2.1.2
Version: 2.2.0
Description: Documentation module
Extracts, shows and exports documentation for Icinga Web 2 and its modules.

View File

@ -48,6 +48,7 @@ class Monitoring_ActionsController extends Controller
$form = new ScheduleHostDowntimeCommandForm();
$form
->setIsApiTarget(true)
->setBackend($this->backend)
->setObjects($hostList->fetch())
->handleRequest($this->getRequest());
}
@ -96,6 +97,7 @@ class Monitoring_ActionsController extends Controller
$form = new ScheduleServiceDowntimeCommandForm();
$form
->setIsApiTarget(true)
->setBackend($this->backend)
->setObjects($serviceList->fetch())
->handleRequest($this->getRequest());
}

View File

@ -93,6 +93,7 @@ class HealthController extends Controller
$this->view->programStatus = $programStatus;
$toggleFeaturesForm = new ToggleInstanceFeaturesCommandForm();
$toggleFeaturesForm
->setBackend($this->backend)
->setStatus($programStatus)
->load($programStatus)
->handleRequest();

View File

@ -151,7 +151,6 @@ class HostController extends MonitoredObjectController
$this->assertPermission('monitoring/command/downtime/schedule');
$form = new ScheduleHostDowntimeCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Schedule Host Downtime'));
$this->handleCommandForm($form);
}
@ -164,7 +163,6 @@ class HostController extends MonitoredObjectController
$this->assertPermission('monitoring/command/process-check-result');
$form = new ProcessCheckResultCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Submit Passive Host Check Result'));
$this->handleCommandForm($form);
}

View File

@ -69,6 +69,7 @@ class HostsController extends Controller
protected function handleCommandForm(ObjectsCommandForm $form)
{
$form
->setBackend($this->backend)
->setObjects($this->hostList)
->setRedirectUrl(Url::fromPath('monitoring/hosts/show')->setParams($this->params))
->handleRequest();
@ -83,11 +84,13 @@ class HostsController extends Controller
public function showAction()
{
$this->setAutorefreshInterval(15);
$checkNowForm = new CheckNowCommandForm();
$checkNowForm
->setObjects($this->hostList)
->handleRequest();
$this->view->checkNowForm = $checkNowForm;
if ($this->Auth()->hasPermission('monitoring/command/schedule-check')) {
$checkNowForm = new CheckNowCommandForm();
$checkNowForm
->setObjects($this->hostList)
->handleRequest();
$this->view->checkNowForm = $checkNowForm;
}
$acknowledgedObjects = $this->hostList->getAcknowledgedObjects();
if (! empty($acknowledgedObjects)) {
@ -192,7 +195,6 @@ class HostsController extends Controller
$this->assertPermission('monitoring/command/downtime/schedule');
$form = new ScheduleHostDowntimeCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Schedule Host Downtimes'));
$this->handleCommandForm($form);
}
@ -205,7 +207,6 @@ class HostsController extends Controller
$this->assertPermission('monitoring/command/process-check-result');
$form = new ProcessCheckResultCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Submit Passive Host Check Results'));
$this->handleCommandForm($form);
}

View File

@ -121,7 +121,6 @@ class ServiceController extends MonitoredObjectController
$this->assertPermission('monitoring/command/process-check-result');
$form = new ProcessCheckResultCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Submit Passive Service Check Result'));
$this->handleCommandForm($form);
}

View File

@ -75,6 +75,7 @@ class ServicesController extends Controller
protected function handleCommandForm(ObjectsCommandForm $form)
{
$form
->setBackend($this->backend)
->setObjects($this->serviceList)
->setRedirectUrl(Url::fromPath('monitoring/services/show')->setParams($this->params))
->handleRequest();
@ -90,11 +91,13 @@ class ServicesController extends Controller
public function showAction()
{
$this->setAutorefreshInterval(15);
$checkNowForm = new CheckNowCommandForm();
$checkNowForm
->setObjects($this->serviceList)
->handleRequest();
$this->view->checkNowForm = $checkNowForm;
if ($this->Auth()->hasPermission('monitoring/command/schedule-check')) {
$checkNowForm = new CheckNowCommandForm();
$checkNowForm
->setObjects($this->serviceList)
->handleRequest();
$this->view->checkNowForm = $checkNowForm;
}
$acknowledgedObjects = $this->serviceList->getAcknowledgedObjects();
if (! empty($acknowledgedObjects)) {
@ -207,7 +210,6 @@ class ServicesController extends Controller
$this->assertPermission('monitoring/command/process-check-result');
$form = new ProcessCheckResultCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Submit Passive Service Check Results'));
$this->handleCommandForm($form);
}

View File

@ -138,7 +138,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
)
);
if (! preg_match('~^v2\.\d+\.\d+.*$~', $this->status->program_version)) {
if (! $this->getBackend()->isIcinga2($this->status->program_version)) {
$this->addElement(
'checkbox',
ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING,

View File

@ -34,21 +34,21 @@ class AddCommentCommandForm extends ObjectsCommandForm
*/
public function createElements(array $formData = array())
{
$this->addElements(array(
$this->addElement(
'textarea',
'comment',
array(
'textarea',
'comment',
array(
'required' => true,
'label' => $this->translate('Comment'),
'description' => $this->translate(
'If you work with other administrators, you may find it useful to share information about the'
. ' the host or service that is having problems. Make sure you enter a brief description of'
. ' what you are doing.'
)
'required' => true,
'label' => $this->translate('Comment'),
'description' => $this->translate(
'If you work with other administrators, you may find it useful to share information about the'
. ' the host or service that is having problems. Make sure you enter a brief description of'
. ' what you are doing.'
)
),
array(
)
);
if (! $this->getBackend()->isIcinga2()) {
$this->addElement(
'checkbox',
'persistent',
array(
@ -59,8 +59,8 @@ class AddCommentCommandForm extends ObjectsCommandForm
. ' restarted.'
)
)
)
));
);
}
return $this;
}
@ -76,7 +76,9 @@ class AddCommentCommandForm extends ObjectsCommandForm
$comment->setObject($object);
$comment->setComment($this->getElement('comment')->getValue());
$comment->setAuthor($this->request->getUser()->getUsername());
$comment->setPersistent($this->getElement('persistent')->isChecked());
if (($persistent = $this->getElement('persistent')) !== null) {
$comment->setPersistent($persistent->isChecked());
}
$this->getTransport($this->request)->send($comment);
}
Notification::success($this->translatePlural(

View File

@ -124,7 +124,7 @@ class ProcessCheckResultCommandForm extends ObjectsCommandForm
ProcessCheckResultCommand::HOST_DOWN => $this->translate('DOWN', 'icinga.state')
);
if (substr($this->getBackend()->getProgramVersion(), 0, 2) !== 'v2') {
if (! $this->getBackend()->isIcinga2()) {
$options[ProcessCheckResultCommand::HOST_UNREACHABLE] = $this->translate('UNREACHABLE', 'icinga.state');
}

View File

@ -12,8 +12,40 @@ use Icinga\Web\Notification;
class RemoveAcknowledgementCommandForm extends ObjectsCommandForm
{
/**
* (non-PHPDoc)
* @see \Zend_Form::init() For the method documentation.
* Whether to show the submit label next to the remove icon
*
* The submit label is disabled in detail views but should be enabled in multi-select views.
*
* @var bool
*/
protected $labelEnabled = false;
/**
* Whether to show the submit label next to the remove icon
*
* @return bool
*/
public function isLabelEnabled()
{
return $this->labelEnabled;
}
/**
* Set whether to show the submit label next to the remove icon
*
* @param bool $labelEnabled
*
* @return $this
*/
public function setLabelEnabled($labelEnabled)
{
$this->labelEnabled = (bool) $labelEnabled;
return $this;
}
/**
* {@inheritdoc}
*/
public function init()
{
@ -36,7 +68,7 @@ class RemoveAcknowledgementCommandForm extends ObjectsCommandForm
),
'escape' => false,
'ignore' => true,
'label' => $this->getView()->icon('cancel'),
'label' => $this->getSubmitLabel(),
'title' => $this->translatePlural(
'Remove problem acknowledgement',
'Remove problem acknowledgements',
@ -45,12 +77,29 @@ class RemoveAcknowledgementCommandForm extends ObjectsCommandForm
'type' => 'submit'
)
);
return $this;
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
* {@inheritdoc}
*/
public function getSubmitLabel()
{
$label = $this->getView()->icon('cancel');
if ($this->isLabelEnabled()) {
$label .= $this->translatePlural(
'Remove problem acknowledgement',
'Remove problem acknowledgements',
count($this->objects)
);
}
return $label;
}
/**
* {@inheritdoc}
*/
public function onSuccess()
{
@ -66,6 +115,7 @@ class RemoveAcknowledgementCommandForm extends ObjectsCommandForm
'Removing problem acknowledgements..',
count($this->objects)
));
return true;
}
}

View File

@ -33,7 +33,7 @@ class ScheduleHostDowntimeCommandForm extends ScheduleServiceDowntimeCommandForm
)
);
if (substr($this->getBackend()->getProgramVersion(), 0, 2) !== 'v2') {
if (! $this->getBackend()->isIcinga2()) {
$this->addElement(
'select',
'child_hosts',

View File

@ -59,7 +59,7 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm
'permission' => 'monitoring/command/feature/object/flap-detection'
)
);
if (preg_match('~^[vr]2\.\d+\.\d+.*$~', $this->getIcingaVersion())) {
if ($this->getBackend()->isIcinga2()) {
unset($features[ToggleObjectFeatureCommand::FEATURE_OBSESSING]);
}
$this->features = $features;
@ -176,14 +176,4 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm
return true;
}
/**
* Fetch and return the program version of the current instance
*
* @return string
*/
protected function getIcingaVersion()
{
return $this->getBackend()->select()->from('programstatus', array('program_version'))->fetchOne();
}
}

View File

@ -0,0 +1,38 @@
<?php
/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
/**
* Helper for escaping comments, but preserving links
*/
class Zend_View_Helper_EscapeComment extends Zend_View_Helper_Abstract
{
/**
* The purifier to use for escaping
*
* @var HTMLPurifier
*/
protected static $purifier;
/**
* Escape any comment for being placed inside HTML, but preserve simple links (<a href="...">).
*
* @param string $comment
*
* @return string
*/
public function escapeComment($comment)
{
if (self::$purifier === null) {
require_once 'HTMLPurifier/Bootstrap.php';
require_once 'HTMLPurifier.php';
require_once 'HTMLPurifier.autoload.php';
$config = HTMLPurifier_Config::createDefault();
$config->set('Core.EscapeNonASCIICharacters', true);
$config->set('HTML.Allowed', 'a[href]');
$config->set('Cache.DefinitionImpl', null);
self::$purifier = new HTMLPurifier($config);
}
return self::$purifier->purify($comment);
}
}

View File

@ -27,13 +27,14 @@ 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->icon(
return $this->view->img(
Macro::resolveMacros($object->host_icon_image, $object),
null,
array(
'alt' => $object->host_icon_image_alt,
'title' => $object->host_icon_image_alt,
'data-tooltip-delay' => 0
'alt' => $object->host_icon_image_alt,
'data-tooltip-delay' => 0,
'class' => 'host-icon-image',
'title' => $object->host_icon_image_alt
)
);
}
@ -49,13 +50,14 @@ 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->icon(
return $this->view->img(
Macro::resolveMacros($object->service_icon_image, $object),
null,
array(
'alt' => $object->service_icon_image_alt,
'title' => $object->service_icon_image_alt,
'data-tooltip-delay' => 0
'alt' => $object->service_icon_image_alt,
'class' => 'service-icon-image',
'data-tooltip-delay' => 0,
'title' => $object->service_icon_image_alt
)
);
}

View File

@ -97,7 +97,7 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract
$config = HTMLPurifier_Config::createDefault();
$config->set('Core.EscapeNonASCIICharacters', true);
$config->set('HTML.Allowed', 'p,br,b,a[href],i,table,tr,td[colspan],div[class]');
$config->set('HTML.Allowed', 'p,br,b,a[href],i,table,tr,td[colspan],div,*[class]');
// This avoids permission problems:
// $config->set('Core.DefinitionCache', null);
$config->set('Cache.DefinitionImpl', null);

View File

@ -45,7 +45,7 @@
</tr>
<tr title="<?= $this->translate('A comment, as entered by the author, associated with the scheduled downtime'); ?>">
<th><?= $this->translate('Comment') ?></th>
<td class="comment-text"><?= $this->nl2br($this->escape($this->downtime->comment)) ?></td>
<td class="comment-text"><?= $this->nl2br($this->escapeComment($this->downtime->comment)) ?></td>
</tr>
</tbody>
</table>

View File

@ -50,7 +50,7 @@
'<b>' . $acknowledgedCount . '</b>'
); ?> </th>
<td>
<?= $removeAckForm ?>
<?= $removeAckForm->setLabelEnabled(true) ?>
</td>
</tr>
<?php endif ?>
@ -174,10 +174,12 @@
</td>
</tr>
<tr>
<th> <?= $this->translate('Schedule Check') ?> </th>
<td> <?= $checkNowForm ?> </td>
</tr>
<?php if (isset($checkNowForm)): // Form is unset if the current user lacks the respective permission ?>
<tr>
<th> <?= $this->translate('Schedule Check') ?> </th>
<td> <?= $checkNowForm ?> </td>
</tr>
<?php endif ?>
<tr>
<th></th>

View File

@ -50,6 +50,7 @@ if (! $this->compact): ?>
$stateBadges = new StateBadges();
$stateBadges
->setUrl('monitoring/list/hosts')
->setBaseFilter($this->filterEditor->getFilter())
->add(
StateBadges::STATE_UP,
$hostgroup->hosts_up,

View File

@ -86,9 +86,7 @@ if (! $this->compact): ?>
<?php endif ?>
<span class="state-icons"><?= implode(' ', $this->hostFlags($host)) ?></span>
</div>
<p class="overview-plugin-output">
<?= $this->pluginOutput($this->ellipsis($host->host_output, 10000), true) ?>
</p>
<p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($host->host_output, 10000), true) ?></p>
</td>
<?php foreach($this->addColumns as $col): ?>
<td><?= $this->escape($host->$col) ?></td>

View File

@ -65,14 +65,12 @@ if (! $this->compact): ?>
)
) ?>
<?php else: ?>
<?= $this->translate('Sent out to any contact') ?>
<?= $this->translate('Not sent out to any contact') ?>
<?php endif ?>
</div>
<?php endif ?>
</div>
<p class="overview-plugin-output">
<?= $this->pluginOutput($this->ellipsis($notification->notification_output, 10000), true) ?>
</p>
<p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($notification->notification_output, 10000), true) ?></p>
</td>
</tr>
<?php endforeach ?>

View File

@ -82,7 +82,7 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . '
$service->host_display_name
),
'class' => 'bg-color-' . Service::getStateText($service->service_state) . ($service->service_handled ? ' handled' : ''),
'title' => $this->escape($service->service_output)
'title' => $service->service_output
)
) ?>
</td>

View File

@ -43,6 +43,7 @@ if (! $this->compact): ?>
$stateBadges = new StateBadges();
$stateBadges
->setUrl('monitoring/list/services')
->setBaseFilter($this->filterEditor->getFilter())
->add(
StateBadges::STATE_OK,
$serviceGroup->services_ok,

View File

@ -90,9 +90,7 @@ if (! $this->compact): ?>
<div class="overview-performance-data">
<?= $this->perfdata($service->service_perfdata, true, 5) ?>
</div>
<p class="overview-plugin-output">
<?= $this->pluginOutput($this->ellipsis($service->service_output, 10000), true) ?>
</p>
<p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($service->service_output, 10000), true) ?></p>
</div>
</td>
<?php foreach($this->addColumns as $col): ?>

View File

@ -36,10 +36,11 @@
<?= $this->timeAgo($comment->timestamp) ?>
</span>
<span class="comment-icons" data-base-target="_self">
<?= $comment->persistent ? $this->icon('attach', 'This comment is persistent.') : '' ?>
<?= $comment->persistent ? $this->icon('attach', 'This comment is persistent') : '' ?>
<?= $comment->expiration ? $this->icon('clock', sprintf(
$this->translate('This comment expires %s.'),
$this->timeUntil($comment->expiration)
$this->translate('This comment expires on %s at %s'),
$this->formatDate($comment->expiration),
$this->formatTime($comment->expiration)
)) : '' ?>
<?php if (isset($delCommentForm)) {
$deleteButton = clone $delCommentForm;
@ -56,5 +57,5 @@
</span>
</div>
<p class="comment-text">
<?= $this->nl2br($this->escape($comment->comment)) ?>
<?= $this->nl2br($this->escapeComment($comment->comment)) ?>
</p>

View File

@ -67,6 +67,6 @@
</span>
</div>
<p class="comment-text">
<?= $this->nl2br($this->escape($downtime->comment)) ?>
<?= $this->nl2br($this->escapeComment($downtime->comment)) ?>
</p>
</td>

View File

@ -143,12 +143,11 @@ $history->limit($limit * $page);
) ?>
<?php endif ?>
<?php endif ?>
<p class="overview-plugin-output">
<?php if ($icon) {
echo $this->icon($icon, null, $iconCssClass ? array('class' => $iconCssClass) : array());
} ?>
<?= nl2br($this->createTicketLinks($this->escape($msg)), false) ?>
</p>
<p class="overview-plugin-output"><?php if ($icon) {
echo $this->icon($icon, null, $iconCssClass ? array('class' => $iconCssClass) : array());
} ?><?= $this->nl2br($this->createTicketLinks($this->escapeComment($msg)))
// TODO(ak): this allows only a[href] in messages, but plugin output allows more
?></p>
</td>
</tr>
<?php endforeach ?>

View File

@ -49,7 +49,7 @@
) ?>
</th>
<td>
<?= $removeAckForm ?>
<?= $removeAckForm->setLabelEnabled(true) ?>
</td>
</tr>
<?php endif ?>
@ -176,10 +176,12 @@
</td>
</tr>
<tr>
<th> <?= $this->translate('Schedule Check') ?> </th>
<td> <?= $checkNowForm ?> </td>
</tr>
<?php if (isset($checkNowForm)): // Form is unset if the current user lacks the respective permission ?>
<tr>
<th> <?= $this->translate('Schedule Check') ?> </th>
<td> <?= $checkNowForm ?> </td>
</tr>
<?php endif ?>
<tr>
<th></th>

View File

@ -44,7 +44,7 @@ $acknowledgement = $object->acknowledgement;
} ?>
</dt>
<dd>
<?= $this->nl2br($this->createTicketLinks($this->escape($acknowledgement->getComment()))) ?>
<?= $this->nl2br($this->createTicketLinks($this->escapeComment($acknowledgement->getComment()))) ?>
</dd>
</dl>
<?php elseif (isset($removeAckForm)): ?>

View File

@ -4,16 +4,14 @@
<?= $this->translate('Check Source') ?>
</th>
<td>
<?php if ($object->is_reachable !== null) {
if ((bool) $object->is_reachable) {
echo $this->icon('circle', $this->translate('Is reachable'), array('class' => 'fg-color-ok'));
} else {
echo $this->icon('circle', $this->translate('Not reachable'), array('class' => 'fg-color-critical'));
}
} ?>
<?= $this->escape($object->check_source) ?>
<?php if ($object->is_reachable !== null): ?>
<span class="check-source-meta"><?= (bool) $object->is_reachable ? $this->translate('is reachable') : $this->translate('is not reachable') ?></span>
<?php if ((bool) $object->is_reachable) {
echo $this->icon('circle', $this->translate('Is reachable'), array('class' => 'check-source-reachable'));
} else {
echo $this->icon('circle', $this->translate('Not reachable'), array('class' => 'check-source-not-reachable'));
} ?>
<?php endif ?>
</td>
</tr>

View File

@ -6,18 +6,28 @@ $activeChecksEnabled = (bool) $object->active_checks_enabled;
<tr>
<th><?= $activeChecksEnabled ? $this->translate('Last check') : $this->translate('Last update') ?></th>
<td data-base-target="_self">
<?php if ((int) $object->state !== 99): ?>
<?= $this->timeAgo($object->last_check) ?>
<?php if ($object->next_update < time()): ?>
<?= $this->icon('circle', $this->translate('Check result is late'), array('class' => 'check-result-late')) ?>
<?php endif ?>
<?php endif ?>
<?php if (isset($checkNowForm)) { // Form is unset if the current user lacks the respective permission
echo $checkNowForm;
} ?>
<?php if ((int) $object->state !== 99) {
echo $this->timeAgo($object->last_check);
} ?>
</td>
</tr>
<tr>
<th><?= $activeChecksEnabled ? $this->translate('Next check') : $this->translate('Next update') ?></th>
<td>
<?php if ((int) $object->state !== 99) {
if ($activeChecksEnabled) {
echo $this->timeUntil($object->next_check);
} else {
echo sprintf($this->translate('expected %s'), $this->timeUntil($object->next_update));
}
} ?>
<?php if ($activeChecksEnabled && $this->hasPermission('monitoring/command/schedule-check')) {
if ($object->getType() === $object::TYPE_SERVICE) {
echo $this->qlink(
@ -49,16 +59,6 @@ $activeChecksEnabled = (bool) $object->active_checks_enabled;
);
}
} ?>
<?php if ((int) $object->state !== 99) {
if ($activeChecksEnabled) {
echo $this->timeUntil($object->next_check);
} else {
echo sprintf($this->translate('expected %s'), $this->timeUntil($object->next_update));
}
} ?>
<?php if ($object->next_update < time()) {
echo $this->icon('circle', $this->translate('Check result is late'), array('class' => 'fg-color-critical'));
} ?>
</td>
</tr>

View File

@ -67,7 +67,7 @@ if (empty($object->comments) && ! $addLink) {
} ?>
</dt>
<dd>
<?= $this->nl2br($this->createTicketLinks($this->escape($comment->comment))) ?>
<?= $this->nl2br($this->createTicketLinks($this->escapeComment($comment->comment))) ?>
</dd>
<?php endforeach ?>
</dl>

View File

@ -96,7 +96,7 @@ if (empty($object->comments) && ! $addLink) {
} ?>
</dt>
<dd>
<?= $this->nl2br($this->createTicketLinks($this->escape($downtime->comment))) ?>
<?= $this->nl2br($this->createTicketLinks($this->escapeComment($downtime->comment))) ?>
</dd>
<?php endforeach ?>
</dl>

View File

@ -28,7 +28,7 @@ use Icinga\Module\Monitoring\Object\Service;
<?php if ($services_critical_handled): ?>
<?= $this->qlink(
$services_critical_handled . ' ' . (
$services_critical_unhandled ? $this->translate('Acknowledged') : Service::getStateText(2, true)
$services_critical_unhandled ? $this->translate('Handled') : Service::getStateText(2, true)
),
'monitoring/list/services',
array(
@ -38,8 +38,8 @@ use Icinga\Module\Monitoring\Object\Service;
),
array('title' => sprintf(
$this->translatePlural(
'List %u service that is currently in state CRITICAL (Acknowledged)',
'List %u services which are currently in state CRITICAL (Acknowledged)',
'List %u service that is currently in state CRITICAL (Handled)',
'List %u services which are currently in state CRITICAL (Handled)',
$services_critical_handled
),
$services_critical_handled
@ -127,7 +127,7 @@ use Icinga\Module\Monitoring\Object\Service;
<?php if ($services_warning_handled): ?>
<?= $this->qlink(
$services_warning_handled . ' ' . (
$services_warning_unhandled ? $this->translate('Acknowledged') : Service::getStateText(1, true)
$services_warning_unhandled ? $this->translate('Handled') : Service::getStateText(1, true)
),
'monitoring/list/services',
array(
@ -137,8 +137,8 @@ use Icinga\Module\Monitoring\Object\Service;
),
array('title' => sprintf(
$this->translatePlural(
'List %u service that is currently in state WARNING (Acknowledged)',
'List %u services which are currently in state WARNING (Acknowledged)',
'List %u service that is currently in state WARNING (Handled)',
'List %u services which are currently in state WARNING (Handled)',
$services_warning_handled
),
$services_warning_handled
@ -226,7 +226,7 @@ use Icinga\Module\Monitoring\Object\Service;
<?php if ($services_unknown_handled): ?>
<?= $this->qlink(
$services_unknown_handled . ' ' . (
$services_unknown_unhandled ? $this->translate('Acknowledged') : Service::getStateText(3, true)
$services_unknown_unhandled ? $this->translate('Handled') : Service::getStateText(3, true)
),
'monitoring/list/services',
array(
@ -236,8 +236,8 @@ use Icinga\Module\Monitoring\Object\Service;
),
array('title' => sprintf(
$this->translatePlural(
'List %u service that is currently in state UNKNOWN (Acknowledged)',
'List %u services which are currently in state UNKNOWN (Acknowledged)',
'List %u service that is currently in state UNKNOWN (Handled)',
'List %u services which are currently in state UNKNOWN (Handled)',
$services_unknown_handled
),
$services_unknown_handled

View File

@ -341,4 +341,22 @@ class MonitoringBackend implements Selectable, Queryable, ConnectionInterface
{
return $this->select()->from('programstatus', array('program_version'))->fetchOne();
}
/**
* Get whether the backend is Icinga 2
*
* @param string $programVersion
*
* @return bool
*/
public function isIcinga2($programVersion = null)
{
if ($programVersion === null) {
$programVersion = $this->select()->from('programstatus', array('program_version'))->fetchOne();
}
return (bool) preg_match(
'/^[vr]2\.\d+\.\d+.*$/',
$programVersion
);
}
}

View File

@ -111,16 +111,16 @@ class CommandTransport implements CommandTransportInterface
*/
public function send(IcingaCommand $command, $now = null)
{
$tries = 0;
foreach (static::getConfig() as $transportConfig) {
$transport = static::createTransport($transportConfig);
$errors = array();
foreach (static::getConfig() as $name => $transportConfig) {
$transport = static::createTransport($transportConfig);
if ($this->transferPossible($command, $transport)) {
try {
$transport->send($command, $now);
} catch (CommandTransportException $e) {
Logger::error($e);
$tries += 1;
$errors[] = sprintf('%s: %s.', $name, rtrim($e->getMessage(), '.'));
continue; // Try the next transport
}
@ -128,14 +128,8 @@ class CommandTransport implements CommandTransportInterface
}
}
if ($tries > 0) {
throw new CommandTransportException(
mt(
'monitoring',
'Failed to send external Icinga command. None of the configured transports'
. ' was able to transfer the command. Please see the log for more details.'
)
);
if (! empty($errors)) {
throw new CommandTransportException(implode("\n", $errors));
}
throw new CommandTransportException(

View File

@ -95,7 +95,9 @@ abstract class DataView implements QueryInterface, SortRules, FilterColumns, Ite
public function dump()
{
$this->order();
if (! $this->isSorted) {
$this->order();
}
return $this->query->dump();
}

View File

@ -89,7 +89,11 @@ class HostStatus extends DataView
) {
return array('host', 'host_address', 'host_address6');
} else {
return array('host', 'host_display_name');
if ($this->connection->isIcinga2()) {
return array('host', 'host_display_name');
} else {
return array('host', 'host_display_name', 'host_alias');
}
}
}

View File

@ -3,6 +3,7 @@
namespace Icinga\Module\Monitoring\Object;
use stdClass;
use InvalidArgumentException;
use Icinga\Application\Config;
use Icinga\Data\Filter\Filter;
@ -456,18 +457,34 @@ abstract class MonitoredObject implements Filterable
$customvars = $this->hostVariables;
}
$this->customvars = array();
foreach ($customvars as $name => $value) {
if ($blacklistPattern && preg_match($blacklistPattern, $name)) {
$this->customvars[$name] = '***';
} else {
$this->customvars[$name] = $value;
}
}
$this->customvars = $this->obfuscateCustomVars($customvars, $blacklistPattern);
return $this;
}
/**
* Obfuscate custom variables recursively
*
* @param stdClass|array $customvars The custom variables to obfuscate
* @param string $blacklistPattern Which custom variables to obfuscate
*
* @return stdClass|array The obfuscated custom variables
*/
protected function obfuscateCustomVars($customvars, $blacklistPattern)
{
$obfuscatedCustomVars = array();
foreach ($customvars as $name => $value) {
if ($blacklistPattern && preg_match($blacklistPattern, $name)) {
$obfuscatedCustomVars[$name] = '***';
} else {
$obfuscatedCustomVars[$name] = $value instanceof stdClass || is_array($value)
? $this->obfuscateCustomVars($value, $blacklistPattern)
: $value;
}
}
return $customvars instanceof stdClass ? (object) $obfuscatedCustomVars : $obfuscatedCustomVars;
}
/**
* Fetch the host custom variables related to this object
*

View File

@ -122,6 +122,7 @@ abstract class MonitoredObjectController extends Controller
protected function handleCommandForm(ObjectsCommandForm $form)
{
$form
->setBackend($this->backend)
->setObjects($this->object)
->setRedirectUrl(Url::fromPath($this->commandRedirectUrl)->setParams($this->params))
->handleRequest();

View File

@ -1,5 +1,5 @@
Module: monitoring
Version: 2.1.2
Version: 2.2.0
Description: Icinga monitoring module
This is the core module for most Icingaweb users. It provides an
abstraction layer for various Icinga data backends.

View File

@ -1,5 +1,26 @@
/*! Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
// Styles for the icon displayed if a check source is reachable
.check-source-reachable {
color: @color-ok;
}
// Styles for the icon displayed if a check source is not reachable
.check-source-not-reachable {
color: @color-critical;
}
// Styles for the icon displayed if a check result is late
.check-result-late {
color: @color-critical;
&:before {
// Remove right margin because the check now form may be displayed right next to the icon and we already have a gap
// because of inline-blocks
margin-right: 0;
}
}
// Show more and load more links in overviews
.action-links {
text-align: right;

View File

@ -2,6 +2,13 @@
@border-left-width: 6px;
// Icon images in list and detail views
.host-icon-image,
.service-icon-image {
max-width: 2em;
vertical-align: middle;
}
// Check source reachable information in the host and service detail views
.check-source-meta {
font-size: @font-size-small;
@ -77,6 +84,7 @@
font-family: @font-family-fixed;
font-size: @font-size-small;
margin: 0;
white-space: pre-wrap;
}
// Table for performance data in detail views
@ -201,16 +209,12 @@
border-spacing: 0 1px;
width: 100%;
tr[href] {
.transition(background 0.2s ease);
tr[href].active {
background-color: @tr-active-color;
}
&.active {
background-color: @tr-active-color;
}
&:hover {
background-color: @tr-hover-color;
cursor: pointer;
}
tr[href]:hover {
background-color: @tr-hover-color;
cursor: pointer;
}
}

View File

@ -1,5 +1,5 @@
Module: setup
Version: 2.1.2
Version: 2.2.0
Description: Setup module
Web based wizard for setting up Icinga Web 2 and its modules.
This includes the data backends (e.g. relational database, LDAP),

View File

@ -1,5 +1,5 @@
Module: test
Version: 2.1.2
Version: 2.2.0
Description: Translation module
This module allows developers to run (unit) tests against Icinga Web 2 and
any of its modules. Usually you do not need to enable this.

View File

@ -1,5 +1,5 @@
Module: translation
Version: 2.1.2
Version: 2.2.0
Description: Translation module
This module allows developers and translators to translate Icinga Web 2 and
its modules for multiple languages. You do not need this module to run an

View File

@ -163,10 +163,11 @@ td, th {
// Styles for when containers are loading. JS will remove this once the containers are ready
.impact {
.active > a, // Remove > a once .tabs layout has been fixed
.controls,
.content {
.transition(background-color 2s 1s linear !important);
background-color: @gray-lighter !important;
}
}
.impact > .controls, .impact li.active a {
.transition(background-color 2s 1s linear !important);
background-color: @gray-lighter !important;
}

View File

@ -127,6 +127,8 @@ label {
border: none;
padding: 0;
text-align: left;
&:hover {
text-decoration: underline;
}

View File

@ -68,23 +68,6 @@ a:hover > .icon-cancel {
.button-link {
.action-link();
.button();
display: inline-block;
height: 35px;
line-height: 20px;
min-width: 175px;
&:hover {
text-decoration: none;
}
* {
line-height: inherit;
}
i {
font-size: 16px;
}
}
// List styles
@ -162,26 +145,21 @@ a:hover > .icon-cancel {
}
}
tr[href] {
.transition(background 0.2s ease);
tr[href].active {
background-color: @tr-active-color;
border-left-color: @icinga-blue;
}
&.active {
background-color: @tr-active-color;
border-left-color: @icinga-blue;
transition: none;
}
&:hover {
background-color: @tr-hover-color;
cursor: pointer;
}
tr[href]:hover {
background-color: @tr-hover-color;
cursor: pointer;
}
caption {
border-top: 1px solid @gray-light;
caption-side: bottom;
text-align: right;
font-style: italic;
text-align: right;
}
}

View File

@ -107,6 +107,14 @@
position: static;
}
.tabs > li > .close-container-control {
display: none;
}
#layout.twocols .tabs > li > .close-container-control {
display: block;
}
#close-container-control-ghost {
display: none;
}

View File

@ -217,7 +217,7 @@
$ = undefined;
oldjQuery.getScript(
oldConfig.baseUrl + 'js/icinga.min.js'
oldConfig.baseUrl.replace(/\/$/, '') + '/js/icinga.min.js'
).done(function () {
var jQuery = window.jQuery;
window.icinga = new window.Icinga(oldConfig);

View File

@ -243,7 +243,6 @@
*/
Navigation.prototype.onPopState = function (url, data) {
// 1. get selection data and set active menu
console.log('popstate:', data);
if (data) {
var active = this.icinga.utils.getElementByDomPath(data);
if (!active) {

View File

@ -36,6 +36,12 @@
var self = event.data.self;
var icinga = self.icinga;
if (! icinga) {
// Attempt to catch a rare error, race condition, whatever
console.log('Got no icinga in applyHandlers');
return;
}
if (self.initializeModules) {
var loaded = false;
var moduleName = $target.data('icingaModule');

View File

@ -681,11 +681,17 @@
req.addToHistory = false;
} else {
if (this.failureNotice === null) {
var now = new Date();
var padString = this.icinga.utils.padString;
this.failureNotice = this.createNotice(
'error',
'The connection to the Icinga web server was lost at ' +
this.icinga.utils.timeShort() +
'.',
'The connection to the Icinga web server was lost at '
+ now.getFullYear()
+ '-' + padString(now.getMonth() + 1, 0, 2)
+ '-' + padString(now.getDate(), 0, 2)
+ ' ' + padString(now.getHours(), 0, 2)
+ ':' + padString(now.getMinutes(), 0, 2)
+ '.',
true
);
@ -737,7 +743,7 @@
if (forceFocus && forceFocus.length) {
activeElementPath = this.icinga.utils.getCSSPath($(forceFocus));
} else if (document.activeElement.id === 'search') {
} else if (document.activeElement && document.activeElement.id === 'search') {
activeElementPath = '#search';
} else if (document.activeElement
&& document.activeElement !== document.body

View File

@ -73,7 +73,7 @@
return;
}
this.writeCookie(this.cookieName, timezoneOffset + ',' + Number(dst), 1);
this.writeCookie(this.cookieName, timezoneOffset + '-' + Number(dst), 1);
},
/**

Some files were not shown because too many files have changed in this diff Show More