Merge branch 'master' into feature/secure-modules-9644

Conflicts:
	library/Icinga/Exception/IcingaException.php
This commit is contained in:
Eric Lippmann 2015-07-28 13:42:02 +02:00
commit 7cfc78558d
109 changed files with 1899 additions and 1465 deletions

View File

@ -3,7 +3,7 @@
set -e
if which puppet >/dev/null 2>&1; then
exit 0
exit 0
fi
RELEASEVER=$(rpm -q --qf "%{VERSION}" $(rpm -q --whatprovides redhat-release))
@ -20,7 +20,7 @@ esac
echo "Adding puppet repository.."
rpm --import "https://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs"
rpm -ivh $PUPPET >/dev/null
rpm -Uvh $PUPPET >/dev/null
echo "Installing puppet.."
yum install -y puppet >/dev/null

View File

@ -15,10 +15,10 @@
class epel {
yumrepo { 'epel':
mirrorlist => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=${::architecture}",
mirrorlist => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-${::operatingsystemmajrelease}&arch=${::architecture}",
enabled => '1',
gpgcheck => '0',
descr => "Extra Packages for Enterprise Linux 6 - ${::architecture}"
descr => "Extra Packages for Enterprise Linux ${::operatingsystemmajrelease} - ${::architecture}"
}
}

View File

@ -15,7 +15,7 @@ class icinga2 {
include icinga_packages
package { [
'icinga2', 'icinga2-doc', 'icinga2-debuginfo'
'icinga2', 'icinga2-doc'
]:
ensure => latest,
require => Class['icinga_packages'],
@ -35,7 +35,7 @@ class icinga2 {
links => follow,
owner => 'icinga',
group => 'icinga',
mode => 6750,
mode => '6750',
}
icinga2::feature { [ 'statusdata', 'command', 'compatlog' ]: }

View File

@ -8,7 +8,7 @@
#
class icinga_packages {
yumrepo { 'icinga_packages':
baseurl => 'http://packages.icinga.org/epel/6/snapshot/',
baseurl => "http://packages.icinga.org/epel/${::operatingsystemmajrelease}/snapshot/",
enabled => '1',
gpgcheck => '1',
gpgkey => 'http://packages.icinga.org/icinga.key',

View File

@ -10,7 +10,7 @@ define icingaweb2::config::general (
content => template("${source}/${name}.ini.erb"),
owner => 'root',
group => $web_group,
mode => 0660,
mode => '0660',
replace => $replace,
}
}

View File

@ -20,7 +20,7 @@ define icingaweb2::config::module (
source => "${source}/modules/${module}/${name}.ini",
owner => 'root',
group => $web_group,
mode => 0660,
mode => '0660',
replace => $replace,
}
}

View File

@ -1,6 +1,6 @@
# Class: mysql
#
# This class installs the mysql server and client software.
# This class installs the MySQL server and client software on a RHEL or CentOS
#
# Parameters:
#
@ -16,21 +16,39 @@ class mysql {
Exec { path => '/usr/bin' }
if versioncmp($::operatingsystemmajrelease, '7') >= 0 {
$client_package_name = 'mariadb'
$server_package_name = 'mariadb-server'
$server_service_name = 'mariadb'
$cnf = '/etc/my.cnf.d/server.cnf'
$log_error = '/var/log/mariadb/mariadb.log'
$pid_file = '/var/run/mariadb/mariadb.pid'
} else {
$client_package_name = 'mysql'
$server_package_name = 'mysql-server'
$server_service_name = 'mysqld'
$cnf = '/etc/my.cnf'
$log_error = '/var/log/mysqld.log'
$pid_file = '/var/run/mysqld/mysqld.pid'
}
package { [
'mysql', 'mysql-server'
$client_package_name, $server_package_name,
]:
ensure => latest,
}
service { 'mysqld':
ensure => running,
service { $server_service_name:
alias => 'mysqld',
enable => true,
require => Package['mysql-server']
ensure => running,
require => Package[$server_package_name],
}
file { '/etc/my.cnf':
file { $cnf:
content => template('mysql/my.cnf.erb'),
require => Package['mysql-server'],
notify => Service['mysqld']
notify => Service['mysqld'],
recurse => true,
require => Package[$server_package_name],
}
}

View File

@ -104,8 +104,8 @@ innodb_file_per_table
innodb_log_file_size = 64M
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
log-error=<%= @log_error %>
pid-file=<%= @pid_file %>
# Increase the amount of open files allowed per process. Warning: Make
# sure you have set the global system limit high enough! The high value

View File

@ -20,6 +20,18 @@ class openldap {
service { 'slapd':
ensure => running,
require => Package['openldap-servers']
require => Package['openldap-servers'],
}
if versioncmp($::operatingsystemmajrelease, '7') >= 0 {
['core', 'cosine', 'inetorgperson', 'nis', 'misc', 'openldap'].each |String $schema| {
exec { "slapd-schema-${schema}":
command => "ldapadd -Y EXTERNAL -H ldapi:// -f /etc/openldap/schema/${schema}.ldif",
group => 'root',
require => Package['openldap-servers'],
unless => "test -n \"$(find /etc/openldap/slapd.d/cn=config/cn=schema/ -name cn={*}${schema}.ldif -print -quit)\"",
user => 'root',
}
}
}
}

View File

@ -25,7 +25,7 @@ define pgsql::database::create ($username, $password) {
unless => "psql -tAc \"SELECT 1 FROM pg_roles WHERE rolname='${username}'\" | grep -q 1",
command => "psql -c \"CREATE ROLE ${username} WITH LOGIN PASSWORD '${password}';\" && \
createdb -O ${username} -E UTF8 -T template0 ${name} && \
createlang plpgsql ${name}",
(createlang plpgsql ${name} || true)",
user => 'postgres',
require => Class['pgsql']
}

View File

@ -20,24 +20,11 @@ class php {
package { 'php':
ensure => latest,
require => Package['apache'],
notify => Service['apache']
}
# TODO(el): Always executed. Should be a resource
-> exec { 'php-timezone':
command => 'sed -re $\'s#^;?(date\\.timezone =).*$#\\1 "UTC"#\' -i /etc/php.ini',
notify => Service['apache'],
require => Package['apache'],
}
file { '/etc/php.d/error_reporting.ini':
content => template('php/error_reporting.ini.erb'),
php::phpd { ['error_reporting', 'timezone', 'xdebug_settings' ]:
require => Package['php'],
notify => Service['apache']
}
file { '/etc/php.d/xdebug_settings.ini':
content => template('php/xdebug_settings.ini.erb'),
require => Package['php'],
notify => Service['apache']
}
}

View File

@ -0,0 +1,21 @@
# define: php::phpd
#
# Provision php.d config
#
# Parameters:
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
define php::phpd {
include php
file { "/etc/php.d/$name.ini":
content => template("php/$name.ini.erb"),
notify => Service['apache'],
}
}

View File

@ -0,0 +1 @@
date.timezone = "UTC"

View File

@ -1,6 +1,6 @@
# Class: icinga2_dev
#
# This class installs Icinga 2 w/ MySQL and provides Icinga 2 test configuration.
# This class installs Icinga 2 w/ MySQL and PostgreSQL and provides Icinga 2 test configuration.
#
# Requires:
#
@ -19,10 +19,15 @@ class icinga2_dev {
include monitoring_test_config
icinga2::config { [
'conf.d/test-config', 'conf.d/commands', 'constants' ]:
'conf.d/test-config', 'conf.d/commands', 'constants'
]:
source => 'puppet:///modules/icinga2_dev',
}
icinga2::feature { 'api':
ensure => absent,
}
icinga2::feature { 'ido-pgsql':
ensure => absent,
require => Class['icinga2_pgsql'],

View File

@ -6,7 +6,7 @@ olcRootPW: {SSHA}N/2WMqT8q7cElh7KUQz+p9TJbjmKv/u9
replace: olcRootDN
olcRootDN: cn=admin,cn=config
dn: olcDatabase={2}bdb,cn=config
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: {SSHA}MxMpLBo2/TSymoIBf/Sb5iQac7Wwiur5

View File

@ -1,23 +1,38 @@
Alias /<%= @web_path %> /vagrant/public
Alias /<%= @web_path %> "/vagrant/public"
<Directory "/vagrant/public/">
Options FollowSymLinks
<Directory "/vagrant/public">
Options SymLinksIfOwnerMatch
AllowOverride None
Order allow,deny
Allow from all
# SetEnv ICINGAWEB_CONFIGDIR <%= @config %>
<IfModule mod_authz_core.c>
# Apache 2.4
<RequireAll>
Require all granted
</RequireAll>
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order allow,deny
Allow from all
</IfModule>
SetEnv ICINGAWEB_CONFIGDIR <%= @config %>
EnableSendfile Off
RewriteEngine on
RewriteBase /<%= @web_path %>/
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /<%= @web_path %>/
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
</IfModule>
php_value xdebug.idekey PHPSTORM
<IfModule !mod_rewrite.c>
DirectoryIndex error_norewrite.html
ErrorDocument 404 /error_norewrite.html
</IfModule>
</Directory>

5
Vagrantfile vendored
View File

@ -22,13 +22,13 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.provision :shell, :path => ".puppet/manifests/puppet.sh"
config.vm.provider :virtualbox do |v, override|
override.vm.box = "puppetlabs/centos-6.6-64-puppet"
override.vm.box = "puppetlabs/centos-7.0-64-puppet"
v.customize ["modifyvm", :id, "--memory", "1024"]
end
config.vm.provider :parallels do |p, override|
override.vm.box = "parallels/centos-6.5"
override.vm.box = "parallels/centos-7.1"
p.name = "Icinga Web 2 Development"
@ -47,5 +47,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
puppet.module_path = [ ".puppet/modules", ".puppet/profiles" ]
puppet.manifests_path = ".puppet/manifests"
puppet.manifest_file = "site.pp"
puppet.options = "--parser=future"
end
end

View File

@ -5,6 +5,8 @@ use Icinga\Application\Config;
use Icinga\Application\Icinga;
use Icinga\Application\Modules\Module;
use Icinga\Data\ResourceFactory;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\NotFoundError;
use Icinga\Forms\Config\UserBackendConfigForm;
use Icinga\Forms\Config\UserBackendReorderForm;
use Icinga\Forms\Config\GeneralConfigForm;
@ -195,80 +197,129 @@ class ConfigController extends Controller
}
/**
* Action for creating a new user backend
* Create a new user backend
*/
public function createuserbackendAction()
{
$this->assertPermission('config/application/userbackend');
$form = new UserBackendConfigForm();
$form->setRedirectUrl('config/userbackend');
$form->setTitle($this->translate('Create New User Backend'));
$form->addDescription($this->translate(
'Create a new backend for authenticating your users. This backend'
. ' will be added at the end of your authentication order.'
));
$form->setIniConfig(Config::app('authentication'));
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
$form->setRedirectUrl('config/userbackend');
try {
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
} catch (ConfigurationError $e) {
if ($this->hasPermission('config/application/resources')) {
Notification::error($e->getMessage());
$this->redirectNow('config/createresource');
}
throw $e; // No permission for resource configuration, show the error
}
$form->setOnSuccess(function (UserBackendConfigForm $form) {
try {
$form->add(array_filter($form->getValues()));
} catch (Exception $e) {
$form->error($e->getMessage());
return false;
}
if ($form->save()) {
Notification::success(t('User backend successfully created'));
return true;
}
return false;
});
$form->handleRequest();
$this->view->form = $form;
$this->render('userbackend/create');
$this->render('form');
}
/**
* Action for editing user backends
* Edit a user backend
*/
public function edituserbackendAction()
{
$this->assertPermission('config/application/userbackend');
$backendName = $this->params->getRequired('backend');
$form = new UserBackendConfigForm();
$form->setTitle($this->translate('Edit User Backend'));
$form->setIniConfig(Config::app('authentication'));
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
$form->setRedirectUrl('config/userbackend');
$form->setAction(Url::fromRequest());
$form->handleRequest();
$form->setTitle(sprintf($this->translate('Edit User Backend %s'), $backendName));
$form->setIniConfig(Config::app('authentication'));
$form->setOnSuccess(function (UserBackendConfigForm $form) use ($backendName) {
try {
$form->edit($backendName, array_map(
function ($v) {
return $v !== '' ? $v : null;
},
$form->getValues()
));
} catch (Exception $e) {
$form->error($e->getMessage());
return false;
}
if ($form->save()) {
Notification::success(sprintf(t('User backend "%s" successfully updated'), $backendName));
return true;
}
return false;
});
try {
$form->load($backendName);
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
$form->handleRequest();
} catch (NotFoundError $_) {
$this->httpNotFound(sprintf($this->translate('User backend "%s" not found'), $backendName));
}
$this->view->form = $form;
$this->render('userbackend/modify');
$this->render('form');
}
/**
* Action for removing a user backend
* Display a confirmation form to remove the backend identified by the 'backend' parameter
*/
public function removeuserbackendAction()
{
$this->assertPermission('config/application/userbackend');
$form = new ConfirmRemovalForm(array(
'onSuccess' => function ($form) {
$configForm = new UserBackendConfigForm();
$configForm->setIniConfig(Config::app('authentication'));
$authBackend = $form->getRequest()->getQuery('backend');
$backendName = $this->params->getRequired('backend');
try {
$configForm->remove($authBackend);
} catch (InvalidArgumentException $e) {
Notification::error($e->getMessage());
return false;
}
if ($configForm->save()) {
Notification::success(sprintf(
t('User backend "%s" has been successfully removed'),
$authBackend
));
} else {
return false;
}
}
));
$form->setTitle($this->translate('Remove User Backend'));
$backendForm = new UserBackendConfigForm();
$backendForm->setIniConfig(Config::app('authentication'));
$form = new ConfirmRemovalForm();
$form->setRedirectUrl('config/userbackend');
$form->setAction(Url::fromRequest());
$form->setTitle(sprintf($this->translate('Remove User Backend %s'), $backendName));
$form->setOnSuccess(function (ConfirmRemovalForm $form) use ($backendName, $backendForm) {
try {
$backendForm->delete($backendName);
} catch (Exception $e) {
$form->error($e->getMessage());
return false;
}
if ($backendForm->save()) {
Notification::success(sprintf(t('User backend "%s" successfully removed'), $backendName));
return true;
}
return false;
});
$form->handleRequest();
$this->view->form = $form;
$this->render('userbackend/remove');
$this->render('form');
}
/**

View File

@ -1,15 +1,14 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use Icinga\Web\Controller;
use Icinga\Web\Url;
use Icinga\Web\Widget\Tabextension\DashboardAction;
use Icinga\Web\Widget\Tabextension\OutputFormat;
use Icinga\Application\Config;
use Icinga\Application\Logger;
use Icinga\Data\ConfigObject;
use Icinga\Protocol\File\FileReader;
use \Zend_Controller_Action_Exception as ActionError;
use Icinga\Web\Controller;
use Icinga\Web\Url;
use Icinga\Web\Widget\Tabextension\DashboardAction;
use Icinga\Web\Widget\Tabextension\OutputFormat;
/**
* Class ListController
@ -40,7 +39,7 @@ class ListController extends Controller
public function applicationlogAction()
{
if (! Logger::writesToFile()) {
throw new ActionError('Site not found', 404);
$this->httpNotFound('Page not found');
}
$this->addTitleTab('application log');

View File

@ -78,7 +78,6 @@ class UsergroupbackendController extends Controller
$backendName = $this->params->getRequired('backend');
$form = new UserGroupBackendForm();
$form->setAction(Url::fromRequest());
$form->setRedirectUrl('usergroupbackend/list');
$form->setTitle(sprintf($this->translate('Edit User Group Backend %s'), $backendName));
$form->setIniConfig(Config::app('groups'));

View File

@ -46,3 +46,12 @@ Font license info
Homepage: http://fontello.com
## Typicons
(c) Stephen Hutchings 2012
Author: Stephen Hutchings
License: SIL (http://scripts.sil.org/OFL)
Homepage: http://typicons.com/

View File

@ -11,7 +11,7 @@ webfont pack. Details available in LICENSE.txt file.
- If your project is open-source, usually, it will be ok to make LICENSE.txt
file publically available in your repository.
- Fonts, used in Fontello, don't require to make clickable links on your site.
- Fonts, used in Fontello, don't require a clickable link on your site.
But any kind of additional authors crediting is welcome.
================================================================================
@ -29,8 +29,8 @@ Comments on archive content
- LICENSE.txt - license info about source fonts, used to build your one.
- config.json - keeps your settings. You can import it back to fontello anytime,
to continue your work
- config.json - keeps your settings. You can import it back into fontello
anytime, to continue your work
Why so many CSS files ?
@ -38,17 +38,17 @@ Why so many CSS files ?
Because we like to fit all your needs :)
- basic file, <your_font_name>.css - is usually enougth, in contains @font-face
and character codes definition
- basic file, <your_font_name>.css - is usually enough, it contains @font-face
and character code definitions
- *-ie7.css - if you need IE7 support, but still don't wish to put char codes
directly into html
- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face
rules, but still wish to benefit of css generation. That can be very
convenient for automated assets build systems. When you need to update font -
no needs to manually edit files, just override old version with archive
content. See fontello source codes for example.
rules, but still wish to benefit from css generation. That can be very
convenient for automated asset build systems. When you need to update font -
no need to manually edit files, just override old version with archive
content. See fontello source code for examples.
- *-embedded.css - basic css file, but with embedded WOFF font, to avoid
CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain.
@ -63,11 +63,11 @@ Because we like to fit all your needs :)
Attention for server setup
--------------------------
You MUST setup server to reply with proper `mime-types` for font files. In other
case, some browsers will fail to show fonts.
You MUST setup server to reply with proper `mime-types` for font files -
otherwise some browsers will fail to show fonts.
Usually, `apache` already has necessary settings, but `nginx` and other
webservers should be tuned. Here is list of mime types for our file extentions:
webservers should be tuned. Here is list of mime types for our file extensions:
- `application/vnd.ms-fontobject` - eot
- `application/x-font-woff` - woff

View File

@ -672,6 +672,30 @@
"code": 59492,
"src": "entypo"
},
{
"uid": "c16a63e911bc47b46dc2a7129d2f0c46",
"css": "down-small",
"code": 59509,
"src": "typicons"
},
{
"uid": "58b78b6ca784d5c3db5beefcd9e18061",
"css": "left-small",
"code": 59510,
"src": "typicons"
},
{
"uid": "877a233d7fdca8a1d82615b96ed0d7a2",
"css": "right-small",
"code": 59511,
"src": "typicons"
},
{
"uid": "62bc6fe2a82e4864e2b94d4c0985ee0c",
"css": "up-small",
"code": 59512,
"src": "typicons"
},
{
"uid": "b90d80c250a9bbdd6cd3fe00e6351710",
"css": "ok",

View File

@ -115,4 +115,8 @@
.icon-chart-bar:before { content: '\e871'; } /* '' */
.icon-beaker:before { content: '\e872'; } /* '' */
.icon-magic:before { content: '\e873'; } /* '' */
.icon-spin6:before { content: '\e874'; } /* '' */
.icon-spin6:before { content: '\e874'; } /* '' */
.icon-down-small:before { content: '\e875'; } /* '' */
.icon-left-small:before { content: '\e876'; } /* '' */
.icon-right-small:before { content: '\e877'; } /* '' */
.icon-up-small:before { content: '\e878'; } /* '' */

File diff suppressed because one or more lines are too long

View File

@ -115,4 +115,8 @@
.icon-chart-bar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe871;&nbsp;'); }
.icon-beaker { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe872;&nbsp;'); }
.icon-magic { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe873;&nbsp;'); }
.icon-spin6 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe874;&nbsp;'); }
.icon-spin6 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe874;&nbsp;'); }
.icon-down-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe875;&nbsp;'); }
.icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe876;&nbsp;'); }
.icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe877;&nbsp;'); }
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe878;&nbsp;'); }

View File

@ -126,4 +126,8 @@
.icon-chart-bar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe871;&nbsp;'); }
.icon-beaker { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe872;&nbsp;'); }
.icon-magic { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe873;&nbsp;'); }
.icon-spin6 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe874;&nbsp;'); }
.icon-spin6 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe874;&nbsp;'); }
.icon-down-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe875;&nbsp;'); }
.icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe876;&nbsp;'); }
.icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe877;&nbsp;'); }
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe878;&nbsp;'); }

View File

@ -1,10 +1,10 @@
@font-face {
font-family: 'ifont';
src: url('../font/ifont.eot?6491776');
src: url('../font/ifont.eot?6491776#iefix') format('embedded-opentype'),
url('../font/ifont.woff?6491776') format('woff'),
url('../font/ifont.ttf?6491776') format('truetype'),
url('../font/ifont.svg?6491776#ifont') format('svg');
src: url('../font/ifont.eot?54745533');
src: url('../font/ifont.eot?54745533#iefix') format('embedded-opentype'),
url('../font/ifont.woff?54745533') format('woff'),
url('../font/ifont.ttf?54745533') format('truetype'),
url('../font/ifont.svg?54745533#ifont') format('svg');
font-weight: normal;
font-style: normal;
}
@ -14,7 +14,7 @@
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'ifont';
src: url('../font/ifont.svg?6491776#ifont') format('svg');
src: url('../font/ifont.svg?54745533#ifont') format('svg');
}
}
*/
@ -35,7 +35,7 @@
/* For safety - reset parent styles, that can break glyph codes*/
font-variant: normal;
text-transform: none;
/* fix buttons height, for twitter bootstrap */
line-height: 1em;
@ -46,6 +46,10 @@
/* you can be more comfortable with increased icons size */
/* font-size: 120%; */
/* Font smoothing. That was taken from TWBS */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Uncomment for 3D effect */
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
}
@ -166,4 +170,8 @@
.icon-chart-bar:before { content: '\e871'; } /* '' */
.icon-beaker:before { content: '\e872'; } /* '' */
.icon-magic:before { content: '\e873'; } /* '' */
.icon-spin6:before { content: '\e874'; } /* '' */
.icon-spin6:before { content: '\e874'; } /* '' */
.icon-down-small:before { content: '\e875'; } /* '' */
.icon-left-small:before { content: '\e876'; } /* '' */
.icon-right-small:before { content: '\e877'; } /* '' */
.icon-up-small:before { content: '\e878'; } /* '' */

View File

@ -227,8 +227,54 @@ body {
.i-code {
display: none;
}
</style>
<link rel="stylesheet" href="css/ifont.css">
@font-face {
font-family: 'ifont';
src: url('./font/ifont.eot?11424534');
src: url('./font/ifont.eot?11424534#iefix') format('embedded-opentype'),
url('./font/ifont.woff?11424534') format('woff'),
url('./font/ifont.ttf?11424534') format('truetype'),
url('./font/ifont.svg?11424534#ifont') format('svg');
font-weight: normal;
font-style: normal;
}
.demo-icon
{
font-family: "ifont";
font-style: normal;
font-weight: normal;
speak: none;
display: inline-block;
text-decoration: inherit;
width: 1em;
margin-right: .2em;
text-align: center;
/* opacity: .8; */
/* For safety - reset parent styles, that can break glyph codes*/
font-variant: normal;
text-transform: none;
/* fix buttons height, for twitter bootstrap */
line-height: 1em;
/* Animation center compensation - margins should be symmetric */
/* remove if not needed */
margin-left: .2em;
/* You can be more comfortable with increased icons size */
/* font-size: 120%; */
/* Font smoothing. That was taken from TWBS */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Uncomment for 3D effect */
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
}
</style>
<link rel="stylesheet" href="css/animation.css"><!--[if IE 7]><link rel="stylesheet" href="css/ifont-ie7.css"><![endif]-->
<script>
function toggleCodes(on) {
@ -255,181 +301,187 @@ body {
</div>
<div id="icons" class="container">
<div class="row">
<div title="Code: 0xe800" class="the-icons span3"><i class="icon-dashboard"></i> <span class="i-name">icon-dashboard</span><span class="i-code">0xe800</span></div>
<div title="Code: 0xe801" class="the-icons span3"><i class="icon-user"></i> <span class="i-name">icon-user</span><span class="i-code">0xe801</span></div>
<div title="Code: 0xe802" class="the-icons span3"><i class="icon-users"></i> <span class="i-name">icon-users</span><span class="i-code">0xe802</span></div>
<div title="Code: 0xe803" class="the-icons span3"><i class="icon-ok"></i> <span class="i-name">icon-ok</span><span class="i-code">0xe803</span></div>
<div title="Code: 0xe800" class="the-icons span3"><i class="demo-icon icon-dashboard">&#xe800;</i> <span class="i-name">icon-dashboard</span><span class="i-code">0xe800</span></div>
<div title="Code: 0xe801" class="the-icons span3"><i class="demo-icon icon-user">&#xe801;</i> <span class="i-name">icon-user</span><span class="i-code">0xe801</span></div>
<div title="Code: 0xe802" class="the-icons span3"><i class="demo-icon icon-users">&#xe802;</i> <span class="i-name">icon-users</span><span class="i-code">0xe802</span></div>
<div title="Code: 0xe803" class="the-icons span3"><i class="demo-icon icon-ok">&#xe803;</i> <span class="i-name">icon-ok</span><span class="i-code">0xe803</span></div>
</div>
<div class="row">
<div title="Code: 0xe804" class="the-icons span3"><i class="icon-cancel"></i> <span class="i-name">icon-cancel</span><span class="i-code">0xe804</span></div>
<div title="Code: 0xe805" class="the-icons span3"><i class="icon-plus"></i> <span class="i-name">icon-plus</span><span class="i-code">0xe805</span></div>
<div title="Code: 0xe806" class="the-icons span3"><i class="icon-minus"></i> <span class="i-name">icon-minus</span><span class="i-code">0xe806</span></div>
<div title="Code: 0xe807" class="the-icons span3"><i class="icon-folder-empty"></i> <span class="i-name">icon-folder-empty</span><span class="i-code">0xe807</span></div>
<div title="Code: 0xe804" class="the-icons span3"><i class="demo-icon icon-cancel">&#xe804;</i> <span class="i-name">icon-cancel</span><span class="i-code">0xe804</span></div>
<div title="Code: 0xe805" class="the-icons span3"><i class="demo-icon icon-plus">&#xe805;</i> <span class="i-name">icon-plus</span><span class="i-code">0xe805</span></div>
<div title="Code: 0xe806" class="the-icons span3"><i class="demo-icon icon-minus">&#xe806;</i> <span class="i-name">icon-minus</span><span class="i-code">0xe806</span></div>
<div title="Code: 0xe807" class="the-icons span3"><i class="demo-icon icon-folder-empty">&#xe807;</i> <span class="i-name">icon-folder-empty</span><span class="i-code">0xe807</span></div>
</div>
<div class="row">
<div title="Code: 0xe808" class="the-icons span3"><i class="icon-download"></i> <span class="i-name">icon-download</span><span class="i-code">0xe808</span></div>
<div title="Code: 0xe809" class="the-icons span3"><i class="icon-upload"></i> <span class="i-name">icon-upload</span><span class="i-code">0xe809</span></div>
<div title="Code: 0xe80a" class="the-icons span3"><i class="icon-git"></i> <span class="i-name">icon-git</span><span class="i-code">0xe80a</span></div>
<div title="Code: 0xe80b" class="the-icons span3"><i class="icon-cubes"></i> <span class="i-name">icon-cubes</span><span class="i-code">0xe80b</span></div>
<div title="Code: 0xe808" class="the-icons span3"><i class="demo-icon icon-download">&#xe808;</i> <span class="i-name">icon-download</span><span class="i-code">0xe808</span></div>
<div title="Code: 0xe809" class="the-icons span3"><i class="demo-icon icon-upload">&#xe809;</i> <span class="i-name">icon-upload</span><span class="i-code">0xe809</span></div>
<div title="Code: 0xe80a" class="the-icons span3"><i class="demo-icon icon-git">&#xe80a;</i> <span class="i-name">icon-git</span><span class="i-code">0xe80a</span></div>
<div title="Code: 0xe80b" class="the-icons span3"><i class="demo-icon icon-cubes">&#xe80b;</i> <span class="i-name">icon-cubes</span><span class="i-code">0xe80b</span></div>
</div>
<div class="row">
<div title="Code: 0xe80c" class="the-icons span3"><i class="icon-database"></i> <span class="i-name">icon-database</span><span class="i-code">0xe80c</span></div>
<div title="Code: 0xe80d" class="the-icons span3"><i class="icon-gauge"></i> <span class="i-name">icon-gauge</span><span class="i-code">0xe80d</span></div>
<div title="Code: 0xe80e" class="the-icons span3"><i class="icon-sitemap"></i> <span class="i-name">icon-sitemap</span><span class="i-code">0xe80e</span></div>
<div title="Code: 0xe80f" class="the-icons span3"><i class="icon-sort-name-up"></i> <span class="i-name">icon-sort-name-up</span><span class="i-code">0xe80f</span></div>
<div title="Code: 0xe80c" class="the-icons span3"><i class="demo-icon icon-database">&#xe80c;</i> <span class="i-name">icon-database</span><span class="i-code">0xe80c</span></div>
<div title="Code: 0xe80d" class="the-icons span3"><i class="demo-icon icon-gauge">&#xe80d;</i> <span class="i-name">icon-gauge</span><span class="i-code">0xe80d</span></div>
<div title="Code: 0xe80e" class="the-icons span3"><i class="demo-icon icon-sitemap">&#xe80e;</i> <span class="i-name">icon-sitemap</span><span class="i-code">0xe80e</span></div>
<div title="Code: 0xe80f" class="the-icons span3"><i class="demo-icon icon-sort-name-up">&#xe80f;</i> <span class="i-name">icon-sort-name-up</span><span class="i-code">0xe80f</span></div>
</div>
<div class="row">
<div title="Code: 0xe810" class="the-icons span3"><i class="icon-sort-name-down"></i> <span class="i-name">icon-sort-name-down</span><span class="i-code">0xe810</span></div>
<div title="Code: 0xe811" class="the-icons span3"><i class="icon-megaphone"></i> <span class="i-name">icon-megaphone</span><span class="i-code">0xe811</span></div>
<div title="Code: 0xe812" class="the-icons span3"><i class="icon-bug"></i> <span class="i-name">icon-bug</span><span class="i-code">0xe812</span></div>
<div title="Code: 0xe813" class="the-icons span3"><i class="icon-tasks"></i> <span class="i-name">icon-tasks</span><span class="i-code">0xe813</span></div>
<div title="Code: 0xe810" class="the-icons span3"><i class="demo-icon icon-sort-name-down">&#xe810;</i> <span class="i-name">icon-sort-name-down</span><span class="i-code">0xe810</span></div>
<div title="Code: 0xe811" class="the-icons span3"><i class="demo-icon icon-megaphone">&#xe811;</i> <span class="i-name">icon-megaphone</span><span class="i-code">0xe811</span></div>
<div title="Code: 0xe812" class="the-icons span3"><i class="demo-icon icon-bug">&#xe812;</i> <span class="i-name">icon-bug</span><span class="i-code">0xe812</span></div>
<div title="Code: 0xe813" class="the-icons span3"><i class="demo-icon icon-tasks">&#xe813;</i> <span class="i-name">icon-tasks</span><span class="i-code">0xe813</span></div>
</div>
<div class="row">
<div title="Code: 0xe814" class="the-icons span3"><i class="icon-filter"></i> <span class="i-name">icon-filter</span><span class="i-code">0xe814</span></div>
<div title="Code: 0xe815" class="the-icons span3"><i class="icon-off"></i> <span class="i-name">icon-off</span><span class="i-code">0xe815</span></div>
<div title="Code: 0xe816" class="the-icons span3"><i class="icon-book"></i> <span class="i-name">icon-book</span><span class="i-code">0xe816</span></div>
<div title="Code: 0xe817" class="the-icons span3"><i class="icon-paste"></i> <span class="i-name">icon-paste</span><span class="i-code">0xe817</span></div>
<div title="Code: 0xe814" class="the-icons span3"><i class="demo-icon icon-filter">&#xe814;</i> <span class="i-name">icon-filter</span><span class="i-code">0xe814</span></div>
<div title="Code: 0xe815" class="the-icons span3"><i class="demo-icon icon-off">&#xe815;</i> <span class="i-name">icon-off</span><span class="i-code">0xe815</span></div>
<div title="Code: 0xe816" class="the-icons span3"><i class="demo-icon icon-book">&#xe816;</i> <span class="i-name">icon-book</span><span class="i-code">0xe816</span></div>
<div title="Code: 0xe817" class="the-icons span3"><i class="demo-icon icon-paste">&#xe817;</i> <span class="i-name">icon-paste</span><span class="i-code">0xe817</span></div>
</div>
<div class="row">
<div title="Code: 0xe818" class="the-icons span3"><i class="icon-scissors"></i> <span class="i-name">icon-scissors</span><span class="i-code">0xe818</span></div>
<div title="Code: 0xe819" class="the-icons span3"><i class="icon-globe"></i> <span class="i-name">icon-globe</span><span class="i-code">0xe819</span></div>
<div title="Code: 0xe81a" class="the-icons span3"><i class="icon-cloud"></i> <span class="i-name">icon-cloud</span><span class="i-code">0xe81a</span></div>
<div title="Code: 0xe81b" class="the-icons span3"><i class="icon-flash"></i> <span class="i-name">icon-flash</span><span class="i-code">0xe81b</span></div>
<div title="Code: 0xe818" class="the-icons span3"><i class="demo-icon icon-scissors">&#xe818;</i> <span class="i-name">icon-scissors</span><span class="i-code">0xe818</span></div>
<div title="Code: 0xe819" class="the-icons span3"><i class="demo-icon icon-globe">&#xe819;</i> <span class="i-name">icon-globe</span><span class="i-code">0xe819</span></div>
<div title="Code: 0xe81a" class="the-icons span3"><i class="demo-icon icon-cloud">&#xe81a;</i> <span class="i-name">icon-cloud</span><span class="i-code">0xe81a</span></div>
<div title="Code: 0xe81b" class="the-icons span3"><i class="demo-icon icon-flash">&#xe81b;</i> <span class="i-name">icon-flash</span><span class="i-code">0xe81b</span></div>
</div>
<div class="row">
<div title="Code: 0xe81c" class="the-icons span3"><i class="icon-barchart"></i> <span class="i-name">icon-barchart</span><span class="i-code">0xe81c</span></div>
<div title="Code: 0xe81d" class="the-icons span3"><i class="icon-down-dir"></i> <span class="i-name">icon-down-dir</span><span class="i-code">0xe81d</span></div>
<div title="Code: 0xe81e" class="the-icons span3"><i class="icon-up-dir"></i> <span class="i-name">icon-up-dir</span><span class="i-code">0xe81e</span></div>
<div title="Code: 0xe81f" class="the-icons span3"><i class="icon-left-dir"></i> <span class="i-name">icon-left-dir</span><span class="i-code">0xe81f</span></div>
<div title="Code: 0xe81c" class="the-icons span3"><i class="demo-icon icon-barchart">&#xe81c;</i> <span class="i-name">icon-barchart</span><span class="i-code">0xe81c</span></div>
<div title="Code: 0xe81d" class="the-icons span3"><i class="demo-icon icon-down-dir">&#xe81d;</i> <span class="i-name">icon-down-dir</span><span class="i-code">0xe81d</span></div>
<div title="Code: 0xe81e" class="the-icons span3"><i class="demo-icon icon-up-dir">&#xe81e;</i> <span class="i-name">icon-up-dir</span><span class="i-code">0xe81e</span></div>
<div title="Code: 0xe81f" class="the-icons span3"><i class="demo-icon icon-left-dir">&#xe81f;</i> <span class="i-name">icon-left-dir</span><span class="i-code">0xe81f</span></div>
</div>
<div class="row">
<div title="Code: 0xe820" class="the-icons span3"><i class="icon-right-dir"></i> <span class="i-name">icon-right-dir</span><span class="i-code">0xe820</span></div>
<div title="Code: 0xe821" class="the-icons span3"><i class="icon-down-open"></i> <span class="i-name">icon-down-open</span><span class="i-code">0xe821</span></div>
<div title="Code: 0xe822" class="the-icons span3"><i class="icon-right-open"></i> <span class="i-name">icon-right-open</span><span class="i-code">0xe822</span></div>
<div title="Code: 0xe823" class="the-icons span3"><i class="icon-up-open"></i> <span class="i-name">icon-up-open</span><span class="i-code">0xe823</span></div>
<div title="Code: 0xe820" class="the-icons span3"><i class="demo-icon icon-right-dir">&#xe820;</i> <span class="i-name">icon-right-dir</span><span class="i-code">0xe820</span></div>
<div title="Code: 0xe821" class="the-icons span3"><i class="demo-icon icon-down-open">&#xe821;</i> <span class="i-name">icon-down-open</span><span class="i-code">0xe821</span></div>
<div title="Code: 0xe822" class="the-icons span3"><i class="demo-icon icon-right-open">&#xe822;</i> <span class="i-name">icon-right-open</span><span class="i-code">0xe822</span></div>
<div title="Code: 0xe823" class="the-icons span3"><i class="demo-icon icon-up-open">&#xe823;</i> <span class="i-name">icon-up-open</span><span class="i-code">0xe823</span></div>
</div>
<div class="row">
<div title="Code: 0xe824" class="the-icons span3"><i class="icon-left-open"></i> <span class="i-name">icon-left-open</span><span class="i-code">0xe824</span></div>
<div title="Code: 0xe825" class="the-icons span3"><i class="icon-up-big"></i> <span class="i-name">icon-up-big</span><span class="i-code">0xe825</span></div>
<div title="Code: 0xe826" class="the-icons span3"><i class="icon-right-big"></i> <span class="i-name">icon-right-big</span><span class="i-code">0xe826</span></div>
<div title="Code: 0xe827" class="the-icons span3"><i class="icon-left-big"></i> <span class="i-name">icon-left-big</span><span class="i-code">0xe827</span></div>
<div title="Code: 0xe824" class="the-icons span3"><i class="demo-icon icon-left-open">&#xe824;</i> <span class="i-name">icon-left-open</span><span class="i-code">0xe824</span></div>
<div title="Code: 0xe825" class="the-icons span3"><i class="demo-icon icon-up-big">&#xe825;</i> <span class="i-name">icon-up-big</span><span class="i-code">0xe825</span></div>
<div title="Code: 0xe826" class="the-icons span3"><i class="demo-icon icon-right-big">&#xe826;</i> <span class="i-name">icon-right-big</span><span class="i-code">0xe826</span></div>
<div title="Code: 0xe827" class="the-icons span3"><i class="demo-icon icon-left-big">&#xe827;</i> <span class="i-name">icon-left-big</span><span class="i-code">0xe827</span></div>
</div>
<div class="row">
<div title="Code: 0xe828" class="the-icons span3"><i class="icon-down-big"></i> <span class="i-name">icon-down-big</span><span class="i-code">0xe828</span></div>
<div title="Code: 0xe829" class="the-icons span3"><i class="icon-resize-full-alt"></i> <span class="i-name">icon-resize-full-alt</span><span class="i-code">0xe829</span></div>
<div title="Code: 0xe82a" class="the-icons span3"><i class="icon-resize-full"></i> <span class="i-name">icon-resize-full</span><span class="i-code">0xe82a</span></div>
<div title="Code: 0xe82b" class="the-icons span3"><i class="icon-resize-small"></i> <span class="i-name">icon-resize-small</span><span class="i-code">0xe82b</span></div>
<div title="Code: 0xe828" class="the-icons span3"><i class="demo-icon icon-down-big">&#xe828;</i> <span class="i-name">icon-down-big</span><span class="i-code">0xe828</span></div>
<div title="Code: 0xe829" class="the-icons span3"><i class="demo-icon icon-resize-full-alt">&#xe829;</i> <span class="i-name">icon-resize-full-alt</span><span class="i-code">0xe829</span></div>
<div title="Code: 0xe82a" class="the-icons span3"><i class="demo-icon icon-resize-full">&#xe82a;</i> <span class="i-name">icon-resize-full</span><span class="i-code">0xe82a</span></div>
<div title="Code: 0xe82b" class="the-icons span3"><i class="demo-icon icon-resize-small">&#xe82b;</i> <span class="i-name">icon-resize-small</span><span class="i-code">0xe82b</span></div>
</div>
<div class="row">
<div title="Code: 0xe82c" class="the-icons span3"><i class="icon-move"></i> <span class="i-name">icon-move</span><span class="i-code">0xe82c</span></div>
<div title="Code: 0xe82d" class="the-icons span3"><i class="icon-resize-horizontal"></i> <span class="i-name">icon-resize-horizontal</span><span class="i-code">0xe82d</span></div>
<div title="Code: 0xe82e" class="the-icons span3"><i class="icon-resize-vertical"></i> <span class="i-name">icon-resize-vertical</span><span class="i-code">0xe82e</span></div>
<div title="Code: 0xe82f" class="the-icons span3"><i class="icon-zoom-in"></i> <span class="i-name">icon-zoom-in</span><span class="i-code">0xe82f</span></div>
<div title="Code: 0xe82c" class="the-icons span3"><i class="demo-icon icon-move">&#xe82c;</i> <span class="i-name">icon-move</span><span class="i-code">0xe82c</span></div>
<div title="Code: 0xe82d" class="the-icons span3"><i class="demo-icon icon-resize-horizontal">&#xe82d;</i> <span class="i-name">icon-resize-horizontal</span><span class="i-code">0xe82d</span></div>
<div title="Code: 0xe82e" class="the-icons span3"><i class="demo-icon icon-resize-vertical">&#xe82e;</i> <span class="i-name">icon-resize-vertical</span><span class="i-code">0xe82e</span></div>
<div title="Code: 0xe82f" class="the-icons span3"><i class="demo-icon icon-zoom-in">&#xe82f;</i> <span class="i-name">icon-zoom-in</span><span class="i-code">0xe82f</span></div>
</div>
<div class="row">
<div title="Code: 0xe830" class="the-icons span3"><i class="icon-block"></i> <span class="i-name">icon-block</span><span class="i-code">0xe830</span></div>
<div title="Code: 0xe831" class="the-icons span3"><i class="icon-zoom-out"></i> <span class="i-name">icon-zoom-out</span><span class="i-code">0xe831</span></div>
<div title="Code: 0xe832" class="the-icons span3"><i class="icon-lightbulb"></i> <span class="i-name">icon-lightbulb</span><span class="i-code">0xe832</span></div>
<div title="Code: 0xe833" class="the-icons span3"><i class="icon-clock"></i> <span class="i-name">icon-clock</span><span class="i-code">0xe833</span></div>
<div title="Code: 0xe830" class="the-icons span3"><i class="demo-icon icon-block">&#xe830;</i> <span class="i-name">icon-block</span><span class="i-code">0xe830</span></div>
<div title="Code: 0xe831" class="the-icons span3"><i class="demo-icon icon-zoom-out">&#xe831;</i> <span class="i-name">icon-zoom-out</span><span class="i-code">0xe831</span></div>
<div title="Code: 0xe832" class="the-icons span3"><i class="demo-icon icon-lightbulb">&#xe832;</i> <span class="i-name">icon-lightbulb</span><span class="i-code">0xe832</span></div>
<div title="Code: 0xe833" class="the-icons span3"><i class="demo-icon icon-clock">&#xe833;</i> <span class="i-name">icon-clock</span><span class="i-code">0xe833</span></div>
</div>
<div class="row">
<div title="Code: 0xe834" class="the-icons span3"><i class="icon-volume-up"></i> <span class="i-name">icon-volume-up</span><span class="i-code">0xe834</span></div>
<div title="Code: 0xe835" class="the-icons span3"><i class="icon-volume-down"></i> <span class="i-name">icon-volume-down</span><span class="i-code">0xe835</span></div>
<div title="Code: 0xe836" class="the-icons span3"><i class="icon-volume-off"></i> <span class="i-name">icon-volume-off</span><span class="i-code">0xe836</span></div>
<div title="Code: 0xe837" class="the-icons span3"><i class="icon-mute"></i> <span class="i-name">icon-mute</span><span class="i-code">0xe837</span></div>
<div title="Code: 0xe834" class="the-icons span3"><i class="demo-icon icon-volume-up">&#xe834;</i> <span class="i-name">icon-volume-up</span><span class="i-code">0xe834</span></div>
<div title="Code: 0xe835" class="the-icons span3"><i class="demo-icon icon-volume-down">&#xe835;</i> <span class="i-name">icon-volume-down</span><span class="i-code">0xe835</span></div>
<div title="Code: 0xe836" class="the-icons span3"><i class="demo-icon icon-volume-off">&#xe836;</i> <span class="i-name">icon-volume-off</span><span class="i-code">0xe836</span></div>
<div title="Code: 0xe837" class="the-icons span3"><i class="demo-icon icon-mute">&#xe837;</i> <span class="i-name">icon-mute</span><span class="i-code">0xe837</span></div>
</div>
<div class="row">
<div title="Code: 0xe838" class="the-icons span3"><i class="icon-mic"></i> <span class="i-name">icon-mic</span><span class="i-code">0xe838</span></div>
<div title="Code: 0xe839" class="the-icons span3"><i class="icon-endtime"></i> <span class="i-name">icon-endtime</span><span class="i-code">0xe839</span></div>
<div title="Code: 0xe83a" class="the-icons span3"><i class="icon-starttime"></i> <span class="i-name">icon-starttime</span><span class="i-code">0xe83a</span></div>
<div title="Code: 0xe83b" class="the-icons span3"><i class="icon-calendar-empty"></i> <span class="i-name">icon-calendar-empty</span><span class="i-code">0xe83b</span></div>
<div title="Code: 0xe838" class="the-icons span3"><i class="demo-icon icon-mic">&#xe838;</i> <span class="i-name">icon-mic</span><span class="i-code">0xe838</span></div>
<div title="Code: 0xe839" class="the-icons span3"><i class="demo-icon icon-endtime">&#xe839;</i> <span class="i-name">icon-endtime</span><span class="i-code">0xe839</span></div>
<div title="Code: 0xe83a" class="the-icons span3"><i class="demo-icon icon-starttime">&#xe83a;</i> <span class="i-name">icon-starttime</span><span class="i-code">0xe83a</span></div>
<div title="Code: 0xe83b" class="the-icons span3"><i class="demo-icon icon-calendar-empty">&#xe83b;</i> <span class="i-name">icon-calendar-empty</span><span class="i-code">0xe83b</span></div>
</div>
<div class="row">
<div title="Code: 0xe83c" class="the-icons span3"><i class="icon-calendar"></i> <span class="i-name">icon-calendar</span><span class="i-code">0xe83c</span></div>
<div title="Code: 0xe83d" class="the-icons span3"><i class="icon-wrench"></i> <span class="i-name">icon-wrench</span><span class="i-code">0xe83d</span></div>
<div title="Code: 0xe83e" class="the-icons span3"><i class="icon-sliders"></i> <span class="i-name">icon-sliders</span><span class="i-code">0xe83e</span></div>
<div title="Code: 0xe83f" class="the-icons span3"><i class="icon-services"></i> <span class="i-name">icon-services</span><span class="i-code">0xe83f</span></div>
<div title="Code: 0xe83c" class="the-icons span3"><i class="demo-icon icon-calendar">&#xe83c;</i> <span class="i-name">icon-calendar</span><span class="i-code">0xe83c</span></div>
<div title="Code: 0xe83d" class="the-icons span3"><i class="demo-icon icon-wrench">&#xe83d;</i> <span class="i-name">icon-wrench</span><span class="i-code">0xe83d</span></div>
<div title="Code: 0xe83e" class="the-icons span3"><i class="demo-icon icon-sliders">&#xe83e;</i> <span class="i-name">icon-sliders</span><span class="i-code">0xe83e</span></div>
<div title="Code: 0xe83f" class="the-icons span3"><i class="demo-icon icon-services">&#xe83f;</i> <span class="i-name">icon-services</span><span class="i-code">0xe83f</span></div>
</div>
<div class="row">
<div title="Code: 0xe840" class="the-icons span3"><i class="icon-service"></i> <span class="i-name">icon-service</span><span class="i-code">0xe840</span></div>
<div title="Code: 0xe841" class="the-icons span3"><i class="icon-phone"></i> <span class="i-name">icon-phone</span><span class="i-code">0xe841</span></div>
<div title="Code: 0xe842" class="the-icons span3"><i class="icon-file-pdf"></i> <span class="i-name">icon-file-pdf</span><span class="i-code">0xe842</span></div>
<div title="Code: 0xe843" class="the-icons span3"><i class="icon-file-word"></i> <span class="i-name">icon-file-word</span><span class="i-code">0xe843</span></div>
<div title="Code: 0xe840" class="the-icons span3"><i class="demo-icon icon-service">&#xe840;</i> <span class="i-name">icon-service</span><span class="i-code">0xe840</span></div>
<div title="Code: 0xe841" class="the-icons span3"><i class="demo-icon icon-phone">&#xe841;</i> <span class="i-name">icon-phone</span><span class="i-code">0xe841</span></div>
<div title="Code: 0xe842" class="the-icons span3"><i class="demo-icon icon-file-pdf">&#xe842;</i> <span class="i-name">icon-file-pdf</span><span class="i-code">0xe842</span></div>
<div title="Code: 0xe843" class="the-icons span3"><i class="demo-icon icon-file-word">&#xe843;</i> <span class="i-name">icon-file-word</span><span class="i-code">0xe843</span></div>
</div>
<div class="row">
<div title="Code: 0xe844" class="the-icons span3"><i class="icon-file-excel"></i> <span class="i-name">icon-file-excel</span><span class="i-code">0xe844</span></div>
<div title="Code: 0xe845" class="the-icons span3"><i class="icon-doc-text"></i> <span class="i-name">icon-doc-text</span><span class="i-code">0xe845</span></div>
<div title="Code: 0xe846" class="the-icons span3"><i class="icon-trash"></i> <span class="i-name">icon-trash</span><span class="i-code">0xe846</span></div>
<div title="Code: 0xe847" class="the-icons span3"><i class="icon-comment-empty"></i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xe847</span></div>
<div title="Code: 0xe844" class="the-icons span3"><i class="demo-icon icon-file-excel">&#xe844;</i> <span class="i-name">icon-file-excel</span><span class="i-code">0xe844</span></div>
<div title="Code: 0xe845" class="the-icons span3"><i class="demo-icon icon-doc-text">&#xe845;</i> <span class="i-name">icon-doc-text</span><span class="i-code">0xe845</span></div>
<div title="Code: 0xe846" class="the-icons span3"><i class="demo-icon icon-trash">&#xe846;</i> <span class="i-name">icon-trash</span><span class="i-code">0xe846</span></div>
<div title="Code: 0xe847" class="the-icons span3"><i class="demo-icon icon-comment-empty">&#xe847;</i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xe847</span></div>
</div>
<div class="row">
<div title="Code: 0xe848" class="the-icons span3"><i class="icon-comment"></i> <span class="i-name">icon-comment</span><span class="i-code">0xe848</span></div>
<div title="Code: 0xe849" class="the-icons span3"><i class="icon-chat"></i> <span class="i-name">icon-chat</span><span class="i-code">0xe849</span></div>
<div title="Code: 0xe84a" class="the-icons span3"><i class="icon-chat-empty"></i> <span class="i-name">icon-chat-empty</span><span class="i-code">0xe84a</span></div>
<div title="Code: 0xe84b" class="the-icons span3"><i class="icon-bell"></i> <span class="i-name">icon-bell</span><span class="i-code">0xe84b</span></div>
<div title="Code: 0xe848" class="the-icons span3"><i class="demo-icon icon-comment">&#xe848;</i> <span class="i-name">icon-comment</span><span class="i-code">0xe848</span></div>
<div title="Code: 0xe849" class="the-icons span3"><i class="demo-icon icon-chat">&#xe849;</i> <span class="i-name">icon-chat</span><span class="i-code">0xe849</span></div>
<div title="Code: 0xe84a" class="the-icons span3"><i class="demo-icon icon-chat-empty">&#xe84a;</i> <span class="i-name">icon-chat-empty</span><span class="i-code">0xe84a</span></div>
<div title="Code: 0xe84b" class="the-icons span3"><i class="demo-icon icon-bell">&#xe84b;</i> <span class="i-name">icon-bell</span><span class="i-code">0xe84b</span></div>
</div>
<div class="row">
<div title="Code: 0xe84c" class="the-icons span3"><i class="icon-bell-alt"></i> <span class="i-name">icon-bell-alt</span><span class="i-code">0xe84c</span></div>
<div title="Code: 0xe84d" class="the-icons span3"><i class="icon-attention-alt"></i> <span class="i-name">icon-attention-alt</span><span class="i-code">0xe84d</span></div>
<div title="Code: 0xe84e" class="the-icons span3"><i class="icon-print"></i> <span class="i-name">icon-print</span><span class="i-code">0xe84e</span></div>
<div title="Code: 0xe84f" class="the-icons span3"><i class="icon-edit"></i> <span class="i-name">icon-edit</span><span class="i-code">0xe84f</span></div>
<div title="Code: 0xe84c" class="the-icons span3"><i class="demo-icon icon-bell-alt">&#xe84c;</i> <span class="i-name">icon-bell-alt</span><span class="i-code">0xe84c</span></div>
<div title="Code: 0xe84d" class="the-icons span3"><i class="demo-icon icon-attention-alt">&#xe84d;</i> <span class="i-name">icon-attention-alt</span><span class="i-code">0xe84d</span></div>
<div title="Code: 0xe84e" class="the-icons span3"><i class="demo-icon icon-print">&#xe84e;</i> <span class="i-name">icon-print</span><span class="i-code">0xe84e</span></div>
<div title="Code: 0xe84f" class="the-icons span3"><i class="demo-icon icon-edit">&#xe84f;</i> <span class="i-name">icon-edit</span><span class="i-code">0xe84f</span></div>
</div>
<div class="row">
<div title="Code: 0xe850" class="the-icons span3"><i class="icon-forward"></i> <span class="i-name">icon-forward</span><span class="i-code">0xe850</span></div>
<div title="Code: 0xe851" class="the-icons span3"><i class="icon-reply"></i> <span class="i-name">icon-reply</span><span class="i-code">0xe851</span></div>
<div title="Code: 0xe852" class="the-icons span3"><i class="icon-reply-all"></i> <span class="i-name">icon-reply-all</span><span class="i-code">0xe852</span></div>
<div title="Code: 0xe853" class="the-icons span3"><i class="icon-eye"></i> <span class="i-name">icon-eye</span><span class="i-code">0xe853</span></div>
<div title="Code: 0xe850" class="the-icons span3"><i class="demo-icon icon-forward">&#xe850;</i> <span class="i-name">icon-forward</span><span class="i-code">0xe850</span></div>
<div title="Code: 0xe851" class="the-icons span3"><i class="demo-icon icon-reply">&#xe851;</i> <span class="i-name">icon-reply</span><span class="i-code">0xe851</span></div>
<div title="Code: 0xe852" class="the-icons span3"><i class="demo-icon icon-reply-all">&#xe852;</i> <span class="i-name">icon-reply-all</span><span class="i-code">0xe852</span></div>
<div title="Code: 0xe853" class="the-icons span3"><i class="demo-icon icon-eye">&#xe853;</i> <span class="i-name">icon-eye</span><span class="i-code">0xe853</span></div>
</div>
<div class="row">
<div title="Code: 0xe854" class="the-icons span3"><i class="icon-tag"></i> <span class="i-name">icon-tag</span><span class="i-code">0xe854</span></div>
<div title="Code: 0xe855" class="the-icons span3"><i class="icon-tags"></i> <span class="i-name">icon-tags</span><span class="i-code">0xe855</span></div>
<div title="Code: 0xe856" class="the-icons span3"><i class="icon-lock-open-alt"></i> <span class="i-name">icon-lock-open-alt</span><span class="i-code">0xe856</span></div>
<div title="Code: 0xe857" class="the-icons span3"><i class="icon-lock-open"></i> <span class="i-name">icon-lock-open</span><span class="i-code">0xe857</span></div>
<div title="Code: 0xe854" class="the-icons span3"><i class="demo-icon icon-tag">&#xe854;</i> <span class="i-name">icon-tag</span><span class="i-code">0xe854</span></div>
<div title="Code: 0xe855" class="the-icons span3"><i class="demo-icon icon-tags">&#xe855;</i> <span class="i-name">icon-tags</span><span class="i-code">0xe855</span></div>
<div title="Code: 0xe856" class="the-icons span3"><i class="demo-icon icon-lock-open-alt">&#xe856;</i> <span class="i-name">icon-lock-open-alt</span><span class="i-code">0xe856</span></div>
<div title="Code: 0xe857" class="the-icons span3"><i class="demo-icon icon-lock-open">&#xe857;</i> <span class="i-name">icon-lock-open</span><span class="i-code">0xe857</span></div>
</div>
<div class="row">
<div title="Code: 0xe858" class="the-icons span3"><i class="icon-lock"></i> <span class="i-name">icon-lock</span><span class="i-code">0xe858</span></div>
<div title="Code: 0xe859" class="the-icons span3"><i class="icon-home"></i> <span class="i-name">icon-home</span><span class="i-code">0xe859</span></div>
<div title="Code: 0xe85a" class="the-icons span3"><i class="icon-info"></i> <span class="i-name">icon-info</span><span class="i-code">0xe85a</span></div>
<div title="Code: 0xe85b" class="the-icons span3"><i class="icon-help"></i> <span class="i-name">icon-help</span><span class="i-code">0xe85b</span></div>
<div title="Code: 0xe858" class="the-icons span3"><i class="demo-icon icon-lock">&#xe858;</i> <span class="i-name">icon-lock</span><span class="i-code">0xe858</span></div>
<div title="Code: 0xe859" class="the-icons span3"><i class="demo-icon icon-home">&#xe859;</i> <span class="i-name">icon-home</span><span class="i-code">0xe859</span></div>
<div title="Code: 0xe85a" class="the-icons span3"><i class="demo-icon icon-info">&#xe85a;</i> <span class="i-name">icon-info</span><span class="i-code">0xe85a</span></div>
<div title="Code: 0xe85b" class="the-icons span3"><i class="demo-icon icon-help">&#xe85b;</i> <span class="i-name">icon-help</span><span class="i-code">0xe85b</span></div>
</div>
<div class="row">
<div title="Code: 0xe85c" class="the-icons span3"><i class="icon-search"></i> <span class="i-name">icon-search</span><span class="i-code">0xe85c</span></div>
<div title="Code: 0xe85d" class="the-icons span3"><i class="icon-flapping"></i> <span class="i-name">icon-flapping</span><span class="i-code">0xe85d</span></div>
<div title="Code: 0xe85e" class="the-icons span3"><i class="icon-rewind"></i> <span class="i-name">icon-rewind</span><span class="i-code">0xe85e</span></div>
<div title="Code: 0xe85f" class="the-icons span3"><i class="icon-chart-line"></i> <span class="i-name">icon-chart-line</span><span class="i-code">0xe85f</span></div>
<div title="Code: 0xe85c" class="the-icons span3"><i class="demo-icon icon-search">&#xe85c;</i> <span class="i-name">icon-search</span><span class="i-code">0xe85c</span></div>
<div title="Code: 0xe85d" class="the-icons span3"><i class="demo-icon icon-flapping">&#xe85d;</i> <span class="i-name">icon-flapping</span><span class="i-code">0xe85d</span></div>
<div title="Code: 0xe85e" class="the-icons span3"><i class="demo-icon icon-rewind">&#xe85e;</i> <span class="i-name">icon-rewind</span><span class="i-code">0xe85e</span></div>
<div title="Code: 0xe85f" class="the-icons span3"><i class="demo-icon icon-chart-line">&#xe85f;</i> <span class="i-name">icon-chart-line</span><span class="i-code">0xe85f</span></div>
</div>
<div class="row">
<div title="Code: 0xe860" class="the-icons span3"><i class="icon-bell-off"></i> <span class="i-name">icon-bell-off</span><span class="i-code">0xe860</span></div>
<div title="Code: 0xe861" class="the-icons span3"><i class="icon-bell-off-empty"></i> <span class="i-name">icon-bell-off-empty</span><span class="i-code">0xe861</span></div>
<div title="Code: 0xe862" class="the-icons span3"><i class="icon-plug"></i> <span class="i-name">icon-plug</span><span class="i-code">0xe862</span></div>
<div title="Code: 0xe863" class="the-icons span3"><i class="icon-eye-off"></i> <span class="i-name">icon-eye-off</span><span class="i-code">0xe863</span></div>
<div title="Code: 0xe860" class="the-icons span3"><i class="demo-icon icon-bell-off">&#xe860;</i> <span class="i-name">icon-bell-off</span><span class="i-code">0xe860</span></div>
<div title="Code: 0xe861" class="the-icons span3"><i class="demo-icon icon-bell-off-empty">&#xe861;</i> <span class="i-name">icon-bell-off-empty</span><span class="i-code">0xe861</span></div>
<div title="Code: 0xe862" class="the-icons span3"><i class="demo-icon icon-plug">&#xe862;</i> <span class="i-name">icon-plug</span><span class="i-code">0xe862</span></div>
<div title="Code: 0xe863" class="the-icons span3"><i class="demo-icon icon-eye-off">&#xe863;</i> <span class="i-name">icon-eye-off</span><span class="i-code">0xe863</span></div>
</div>
<div class="row">
<div title="Code: 0xe864" class="the-icons span3"><i class="icon-reschedule"></i> <span class="i-name">icon-reschedule</span><span class="i-code">0xe864</span></div>
<div title="Code: 0xe865" class="the-icons span3"><i class="icon-cw"></i> <span class="i-name">icon-cw</span><span class="i-code">0xe865</span></div>
<div title="Code: 0xe866" class="the-icons span3"><i class="icon-host"></i> <span class="i-name">icon-host</span><span class="i-code">0xe866</span></div>
<div title="Code: 0xe867" class="the-icons span3"><i class="icon-thumbs-up"></i> <span class="i-name">icon-thumbs-up</span><span class="i-code">0xe867</span></div>
<div title="Code: 0xe864" class="the-icons span3"><i class="demo-icon icon-reschedule">&#xe864;</i> <span class="i-name">icon-reschedule</span><span class="i-code">0xe864</span></div>
<div title="Code: 0xe865" class="the-icons span3"><i class="demo-icon icon-cw">&#xe865;</i> <span class="i-name">icon-cw</span><span class="i-code">0xe865</span></div>
<div title="Code: 0xe866" class="the-icons span3"><i class="demo-icon icon-host">&#xe866;</i> <span class="i-name">icon-host</span><span class="i-code">0xe866</span></div>
<div title="Code: 0xe867" class="the-icons span3"><i class="demo-icon icon-thumbs-up">&#xe867;</i> <span class="i-name">icon-thumbs-up</span><span class="i-code">0xe867</span></div>
</div>
<div class="row">
<div title="Code: 0xe868" class="the-icons span3"><i class="icon-thumbs-down"></i> <span class="i-name">icon-thumbs-down</span><span class="i-code">0xe868</span></div>
<div title="Code: 0xe869" class="the-icons span3"><i class="icon-spinner"></i> <span class="i-name">icon-spinner</span><span class="i-code">0xe869</span></div>
<div title="Code: 0xe86a" class="the-icons span3"><i class="icon-attach"></i> <span class="i-name">icon-attach</span><span class="i-code">0xe86a</span></div>
<div title="Code: 0xe86b" class="the-icons span3"><i class="icon-keyboard"></i> <span class="i-name">icon-keyboard</span><span class="i-code">0xe86b</span></div>
<div title="Code: 0xe868" class="the-icons span3"><i class="demo-icon icon-thumbs-down">&#xe868;</i> <span class="i-name">icon-thumbs-down</span><span class="i-code">0xe868</span></div>
<div title="Code: 0xe869" class="the-icons span3"><i class="demo-icon icon-spinner">&#xe869;</i> <span class="i-name">icon-spinner</span><span class="i-code">0xe869</span></div>
<div title="Code: 0xe86a" class="the-icons span3"><i class="demo-icon icon-attach">&#xe86a;</i> <span class="i-name">icon-attach</span><span class="i-code">0xe86a</span></div>
<div title="Code: 0xe86b" class="the-icons span3"><i class="demo-icon icon-keyboard">&#xe86b;</i> <span class="i-name">icon-keyboard</span><span class="i-code">0xe86b</span></div>
</div>
<div class="row">
<div title="Code: 0xe86c" class="the-icons span3"><i class="icon-menu"></i> <span class="i-name">icon-menu</span><span class="i-code">0xe86c</span></div>
<div title="Code: 0xe86d" class="the-icons span3"><i class="icon-wifi"></i> <span class="i-name">icon-wifi</span><span class="i-code">0xe86d</span></div>
<div title="Code: 0xe86e" class="the-icons span3"><i class="icon-moon"></i> <span class="i-name">icon-moon</span><span class="i-code">0xe86e</span></div>
<div title="Code: 0xe86f" class="the-icons span3"><i class="icon-chart-pie"></i> <span class="i-name">icon-chart-pie</span><span class="i-code">0xe86f</span></div>
<div title="Code: 0xe86c" class="the-icons span3"><i class="demo-icon icon-menu">&#xe86c;</i> <span class="i-name">icon-menu</span><span class="i-code">0xe86c</span></div>
<div title="Code: 0xe86d" class="the-icons span3"><i class="demo-icon icon-wifi">&#xe86d;</i> <span class="i-name">icon-wifi</span><span class="i-code">0xe86d</span></div>
<div title="Code: 0xe86e" class="the-icons span3"><i class="demo-icon icon-moon">&#xe86e;</i> <span class="i-name">icon-moon</span><span class="i-code">0xe86e</span></div>
<div title="Code: 0xe86f" class="the-icons span3"><i class="demo-icon icon-chart-pie">&#xe86f;</i> <span class="i-name">icon-chart-pie</span><span class="i-code">0xe86f</span></div>
</div>
<div class="row">
<div title="Code: 0xe870" class="the-icons span3"><i class="icon-chart-area"></i> <span class="i-name">icon-chart-area</span><span class="i-code">0xe870</span></div>
<div title="Code: 0xe871" class="the-icons span3"><i class="icon-chart-bar"></i> <span class="i-name">icon-chart-bar</span><span class="i-code">0xe871</span></div>
<div title="Code: 0xe872" class="the-icons span3"><i class="icon-beaker"></i> <span class="i-name">icon-beaker</span><span class="i-code">0xe872</span></div>
<div title="Code: 0xe873" class="the-icons span3"><i class="icon-magic"></i> <span class="i-name">icon-magic</span><span class="i-code">0xe873</span></div>
<div title="Code: 0xe870" class="the-icons span3"><i class="demo-icon icon-chart-area">&#xe870;</i> <span class="i-name">icon-chart-area</span><span class="i-code">0xe870</span></div>
<div title="Code: 0xe871" class="the-icons span3"><i class="demo-icon icon-chart-bar">&#xe871;</i> <span class="i-name">icon-chart-bar</span><span class="i-code">0xe871</span></div>
<div title="Code: 0xe872" class="the-icons span3"><i class="demo-icon icon-beaker">&#xe872;</i> <span class="i-name">icon-beaker</span><span class="i-code">0xe872</span></div>
<div title="Code: 0xe873" class="the-icons span3"><i class="demo-icon icon-magic">&#xe873;</i> <span class="i-name">icon-magic</span><span class="i-code">0xe873</span></div>
</div>
<div class="row">
<div title="Code: 0xe874" class="the-icons span3"><i class="icon-spin6 animate-spin"></i> <span class="i-name">icon-spin6</span><span class="i-code">0xe874</span></div>
<div title="Code: 0xe874" class="the-icons span3"><i class="demo-icon icon-spin6 animate-spin">&#xe874;</i> <span class="i-name">icon-spin6</span><span class="i-code">0xe874</span></div>
<div title="Code: 0xe875" class="the-icons span3"><i class="demo-icon icon-down-small">&#xe875;</i> <span class="i-name">icon-down-small</span><span class="i-code">0xe875</span></div>
<div title="Code: 0xe876" class="the-icons span3"><i class="demo-icon icon-left-small">&#xe876;</i> <span class="i-name">icon-left-small</span><span class="i-code">0xe876</span></div>
<div title="Code: 0xe877" class="the-icons span3"><i class="demo-icon icon-right-small">&#xe877;</i> <span class="i-name">icon-right-small</span><span class="i-code">0xe877</span></div>
</div>
<div class="row">
<div title="Code: 0xe878" class="the-icons span3"><i class="demo-icon icon-up-small">&#xe878;</i> <span class="i-name">icon-up-small</span><span class="i-code">0xe878</span></div>
</div>
</div>
<div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></div>

View File

@ -3,10 +3,7 @@
namespace Icinga\Forms\Config\Resource;
use Exception;
use Icinga\Web\Form;
use Icinga\Data\ConfigObject;
use Icinga\Data\ResourceFactory;
use Icinga\Application\Platform;
/**
@ -23,7 +20,9 @@ class DbResourceForm extends Form
}
/**
* @see Form::createElements()
* Create and add elements to this form
*
* @param array $formData The data sent by the user
*/
public function createElements(array $formData)
{
@ -107,35 +106,4 @@ class DbResourceForm extends Form
return $this;
}
/**
* Validate that the current configuration points to a valid resource
*
* @see Form::onSuccess()
*/
public function onSuccess()
{
if (false === static::isValidResource($this)) {
return false;
}
}
/**
* Validate the resource configuration by trying to connect with it
*
* @param Form $form The form to fetch the configuration values from
*
* @return bool Whether validation succeeded or not
*/
public static function isValidResource(Form $form)
{
$result = ResourceFactory::createResource(new ConfigObject($form->getValues()))->inspect();
if ($result->hasError()) {
$form->addError(sprintf($form->translate('Connectivity validation failed: %s'), $result->getError()));
}
// TODO: display diagnostics in $result->toArray() to the user
return ! $result->hasError();
}
}

View File

@ -3,10 +3,7 @@
namespace Icinga\Forms\Config\Resource;
use Exception;
use Icinga\Web\Form;
use Icinga\Data\ConfigObject;
use Icinga\Data\ResourceFactory;
use Icinga\Protocol\Ldap\LdapConnection;
/**
@ -23,7 +20,9 @@ class LdapResourceForm extends Form
}
/**
* @see Form::createElements()
* Create and add elements to this form
*
* @param array $formData The data sent by the user
*/
public function createElements(array $formData)
{
@ -132,39 +131,4 @@ class LdapResourceForm extends Form
return $this;
}
/**
* Validate that the current configuration points to a valid resource
*
* @see Form::onSuccess()
*/
public function onSuccess()
{
if (false === static::isValidResource($this)) {
return false;
}
}
/**
* Validate the resource configuration by trying to connect with it
*
* @param Form $form The form to fetch the configuration values from
*
* @return bool Whether validation succeeded or not
*/
public static function isValidResource(Form $form)
{
$result = ResourceFactory::createResource(new ConfigObject($form->getValues()))->inspect();
if ($result->hasError()) {
$form->addError(sprintf(
'%s (%s)',
$form->translate('Connectivity validation failed, connection to the given resource not possible.'),
$result->getError()
));
}
// TODO: display diagnostics in $result->toArray() to the user
return ! $result->hasError();
}
}

View File

@ -4,15 +4,20 @@
namespace Icinga\Forms\Config;
use InvalidArgumentException;
use Icinga\Web\Notification;
use Icinga\Application\Platform;
use Icinga\Exception\ConfigurationError;
use Icinga\Data\ConfigObject;
use Icinga\Data\Inspectable;
use Icinga\Data\Inspection;
use Icinga\Data\ResourceFactory;
use Icinga\Forms\ConfigForm;
use Icinga\Forms\Config\Resource\DbResourceForm;
use Icinga\Forms\Config\Resource\FileResourceForm;
use Icinga\Forms\Config\Resource\LdapResourceForm;
use Icinga\Forms\Config\Resource\LivestatusResourceForm;
use Icinga\Forms\Config\Resource\SshResourceForm;
use Icinga\Application\Platform;
use Icinga\Exception\ConfigurationError;
use Icinga\Web\Form;
use Icinga\Web\Notification;
class ResourceConfigForm extends ConfigForm
{
@ -23,6 +28,7 @@ class ResourceConfigForm extends ConfigForm
{
$this->setName('form_config_resource');
$this->setSubmitLabel($this->translate('Save Changes'));
$this->setValidatePartial(true);
}
/**
@ -141,7 +147,9 @@ class ResourceConfigForm extends ConfigForm
$resourceForm = $this->getResourceForm($this->getElement('type')->getValue());
if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) {
if (method_exists($resourceForm, 'isValidResource') && false === $resourceForm::isValidResource($this)) {
$inspection = static::inspectResource($this);
if ($inspection !== null && $inspection->hasError()) {
$this->error($inspection->getError());
$this->addElement($this->getForceCreationCheckbox());
return false;
}
@ -255,4 +263,103 @@ class ResourceConfigForm extends ConfigForm
$this->addElements($this->getResourceForm($resourceType)->createElements($formData)->getElements());
}
/**
* Create a resource by using the given form's values and return its inspection results
*
* @param Form $form
*
* @return Inspection
*/
public static function inspectResource(Form $form)
{
if ($form->getValue('type') !== 'ssh') {
$resource = ResourceFactory::createResource(new ConfigObject($form->getValues()));
if ($resource instanceof Inspectable) {
return $resource->inspect();
}
}
}
/**
* Run the configured resource's inspection checks and show the result, if necessary
*
* This will only run any validation if the user pushed the 'resource_validation' button.
*
* @param array $formData
*
* @return bool
*/
public function isValidPartial(array $formData)
{
if ($this->getElement('resource_validation')->isChecked() && parent::isValid($formData)) {
$inspection = static::inspectResource($this);
if ($inspection !== null) {
$join = function ($e) use (& $join) {
return is_string($e) ? $e : join("\n", array_map($join, $e));
};
$this->addElement(
'note',
'inspection_output',
array(
'order' => 0,
'value' => '<strong>' . $this->translate('Validation Log') . "</strong>\n\n"
. join("\n", array_map($join, $inspection->toArray())),
'decorators' => array(
'ViewHelper',
array('HtmlTag', array('tag' => 'pre', 'class' => 'log-output')),
)
)
);
if ($inspection->hasError()) {
$this->warning(sprintf(
$this->translate('Failed to successfully validate the configuration: %s'),
$inspection->getError()
));
return false;
}
}
$this->info($this->translate('The configuration has been successfully validated.'));
}
return true;
}
/**
* Add a submit button to this form and one to manually validate the configuration
*
* Calls parent::addSubmitButton() to add the submit button.
*
* @return $this
*/
public function addSubmitButton()
{
parent::addSubmitButton()
->getElement('btn_submit')
->setDecorators(array('ViewHelper'));
$this->addElement(
'submit',
'resource_validation',
array(
'ignore' => true,
'label' => $this->translate('Validate Configuration'),
'decorators' => array('ViewHelper')
)
);
$this->addDisplayGroup(
array('btn_submit', 'resource_validation'),
'submit_validation',
array(
'decorators' => array(
'FormElements',
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
)
)
);
return $this;
}
}

View File

@ -3,11 +3,7 @@
namespace Icinga\Forms\Config\UserBackend;
use Exception;
use Icinga\Web\Form;
use Icinga\Data\ConfigObject;
use Icinga\Data\ResourceFactory;
use Icinga\Authentication\User\DbUserBackend;
/**
* Form class for adding/modifying database user backends
@ -43,7 +39,9 @@ class DbBackendForm extends Form
}
/**
* @see Form::createElements()
* Create and add elements to this form
*
* @param array $formData
*/
public function createElements(array $formData)
{
@ -56,6 +54,20 @@ class DbBackendForm extends Form
'description' => $this->translate(
'The name of this authentication provider that is used to differentiate it from others'
),
'validators' => array(
array(
'Regex',
false,
array(
'pattern' => '/^[^\\[\\]:]+$/',
'messages' => array(
'regexNotMatch' => $this->translate(
'The name cannot contain \'[\', \']\' or \':\'.'
)
)
)
)
)
)
);
$this->addElement(
@ -67,7 +79,7 @@ class DbBackendForm extends Form
'description' => $this->translate(
'The database connection to use for authenticating with this provider'
),
'multiOptions' => false === empty($this->resources)
'multiOptions' => !empty($this->resources)
? array_combine($this->resources, $this->resources)
: array()
)
@ -80,49 +92,5 @@ class DbBackendForm extends Form
'value' => 'db'
)
);
return $this;
}
/**
* Validate that the selected resource is a valid database user backend
*
* @see Form::onSuccess()
*/
public function onSuccess()
{
if (false === static::isValidUserBackend($this)) {
return false;
}
}
/**
* Validate the configuration by creating a backend and requesting the user count
*
* @param Form $form The form to fetch the configuration values from
*
* @return bool Whether validation succeeded or not
*/
public static function isValidUserBackend(Form $form)
{
$backend = new DbUserBackend(ResourceFactory::createResource($form->getResourceConfig()));
$result = $backend->inspect();
if ($result->hasError()) {
$form->addError(sprintf($form->translate('Using the specified backend failed: %s'), $result->getError()));
}
// TODO: display diagnostics in $result->toArray() to the user
return ! $result->hasError();
}
/**
* Return the configuration for the chosen resource
*
* @return ConfigObject
*/
public function getResourceConfig()
{
return ResourceFactory::getResourceConfig($this->getValue('resource'));
}
}

View File

@ -3,14 +3,8 @@
namespace Icinga\Forms\Config\UserBackend;
use Exception;
use Icinga\Authentication\User\LdapUserBackend;
use Icinga\Data\Inspection;
use Icinga\Web\Form;
use Icinga\Data\ConfigObject;
use Icinga\Data\ResourceFactory;
use Icinga\Exception\AuthenticationException;
use Icinga\Authentication\User\UserBackend;
use Icinga\Web\Form;
/**
* Form class for adding/modifying LDAP user backends
@ -46,7 +40,9 @@ class LdapBackendForm extends Form
}
/**
* @see Form::createElements()
* Create and add elements to this form
*
* @param array $formData
*/
public function createElements(array $formData)
{
@ -60,6 +56,20 @@ class LdapBackendForm extends Form
'label' => $this->translate('Backend Name'),
'description' => $this->translate(
'The name of this authentication provider that is used to differentiate it from others.'
),
'validators' => array(
array(
'Regex',
false,
array(
'pattern' => '/^[^\\[\\]:]+$/',
'messages' => array(
'regexNotMatch' => $this->translate(
'The name cannot contain \'[\', \']\' or \':\'.'
)
)
)
)
)
)
);
@ -72,11 +82,65 @@ class LdapBackendForm extends Form
'description' => $this->translate(
'The LDAP connection to use for authenticating with this provider.'
),
'multiOptions' => false === empty($this->resources)
'multiOptions' => !empty($this->resources)
? array_combine($this->resources, $this->resources)
: array()
)
);
$baseDn = null;
$hasAdOid = false;
if (! $isAd && !empty($this->resources)) {
$this->addElement(
'button',
'discovery_btn',
array(
'type' => 'submit',
'value' => 'discovery_btn',
'label' => $this->translate('Discover', 'A button to discover LDAP capabilities'),
'title' => $this->translate(
'Push to fill in the chosen connection\'s default settings.'
),
'decorators' => array(
array('ViewHelper', array('separator' => '')),
array('HtmlTag', array('tag' => 'div', 'class' => 'element'))
),
'formnovalidate' => 'formnovalidate'
)
);
$this->addDisplayGroup(
array('resource', 'discovery_btn'),
'connection_discovery',
array(
'decorators' => array(
'FormElements',
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
)
)
);
if ($this->getElement('discovery_btn')->isChecked()) {
$connection = ResourceFactory::create(
isset($formData['resource']) ? $formData['resource'] : reset($this->resources)
);
$capabilities = $connection->bind()->getCapabilities();
$baseDn = $capabilities->getDefaultNamingContext();
$hasAdOid = $capabilities->isActiveDirectory();
}
}
if ($isAd || $hasAdOid) {
// ActiveDirectory defaults
$userClass = 'user';
$filter = '!(objectClass=computer)';
$userNameAttribute = 'sAMAccountName';
} else {
// OpenLDAP defaults
$userClass = 'inetOrgPerson';
$filter = null;
$userNameAttribute = 'uid';
}
$this->addElement(
'text',
'user_class',
@ -87,7 +151,7 @@ class LdapBackendForm extends Form
'disabled' => $isAd ?: null,
'label' => $this->translate('LDAP User Object Class'),
'description' => $this->translate('The object class used for storing users on the LDAP server.'),
'value' => $isAd ? 'user' : 'inetOrgPerson'
'value' => $userClass
)
);
$this->addElement(
@ -96,7 +160,7 @@ class LdapBackendForm extends Form
array(
'preserveDefault' => true,
'allowEmpty' => true,
'value' => $isAd ? '!(objectClass=computer)' : null,
'value' => $filter,
'label' => $this->translate('LDAP Filter'),
'description' => $this->translate(
'An additional filter to use when looking up users using the specified connection. '
@ -139,7 +203,7 @@ class LdapBackendForm extends Form
'description' => $this->translate(
'The attribute name used for storing the user name on the LDAP server.'
),
'value' => $isAd ? 'sAMAccountName' : 'uid'
'value' => $userNameAttribute
)
);
$this->addElement(
@ -154,48 +218,15 @@ class LdapBackendForm extends Form
'text',
'base_dn',
array(
'required' => false,
'label' => $this->translate('LDAP Base DN'),
'description' => $this->translate(
'preserveDefault' => true,
'required' => false,
'label' => $this->translate('LDAP Base DN'),
'description' => $this->translate(
'The path where users can be found on the LDAP server. Leave ' .
'empty to select all users available using the specified connection.'
)
),
'value' => $baseDn
)
);
return $this;
}
/**
* Validate that the selected resource is a valid ldap user backend
*
* @see Form::onSuccess()
*/
public function onSuccess()
{
if (false === static::isValidUserBackend($this)) {
return false;
}
}
/**
* Validate the configuration by creating a backend and requesting the user count
*
* @param Form $form The form to fetch the configuration values from
*
* @return bool Whether validation succeeded or not
*/
public static function isValidUserBackend(Form $form)
{
/**
* @var $result Inspection
*/
$result = UserBackend::create(null, new ConfigObject($form->getValues()))->inspect();
if ($result->hasError()) {
$form->addError($result->getError());
}
// TODO: display diagnostics in $result->toArray() to the user
return ! $result->hasError();
}
}

View File

@ -4,26 +4,39 @@
namespace Icinga\Forms\Config;
use InvalidArgumentException;
use Icinga\Forms\ConfigForm;
use Icinga\Web\Notification;
use Icinga\Application\Config;
use Icinga\Application\Platform;
use Icinga\Data\ConfigObject;
use Icinga\Data\ResourceFactory;
use Icinga\Authentication\User\UserBackend;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\IcingaException;
use Icinga\Exception\NotFoundError;
use Icinga\Data\ConfigObject;
use Icinga\Data\Inspectable;
use Icinga\Data\Inspection;
use Icinga\Forms\ConfigForm;
use Icinga\Forms\Config\UserBackend\ExternalBackendForm;
use Icinga\Forms\Config\UserBackend\DbBackendForm;
use Icinga\Forms\Config\UserBackend\LdapBackendForm;
use Icinga\Forms\Config\UserBackend\ExternalBackendForm;
use Icinga\Web\Form;
/**
* Form for managing user backends
*/
class UserBackendConfigForm extends ConfigForm
{
/**
* The available resources split by type
* The available user backend resources split by type
*
* @var array
*/
protected $resources;
/**
* The backend to load when displaying the form for the first time
*
* @var string
*/
protected $backendToLoad;
/**
* Initialize this form
*/
@ -31,20 +44,45 @@ class UserBackendConfigForm extends ConfigForm
{
$this->setName('form_config_authbackend');
$this->setSubmitLabel($this->translate('Save Changes'));
$this->setValidatePartial(true);
}
/**
* Set the resource configuration to use
*
* @param Config $resources The resource configuration
* @param Config $resourceConfig The resource configuration
*
* @return $this
*
* @throws ConfigurationError In case there are no valid resources for authentication available
*/
public function setResourceConfig(Config $resourceConfig)
{
$resources = array();
foreach ($resourceConfig as $name => $resource) {
$resources[strtolower($resource->type)][] = $name;
if (in_array($resource->type, array('db', 'ldap'))) {
$resources[$resource->type][] = $name;
}
}
if (empty($resources)) {
$externalBackends = $this->config->toArray();
array_walk(
$externalBackends,
function (& $authBackendCfg) {
if (! isset($authBackendCfg['backend']) || $authBackendCfg['backend'] !== 'external') {
$authBackendCfg = null;
}
}
);
if (count(array_filter($externalBackends)) > 0 && (
$this->backendToLoad === null || !isset($externalBackends[$this->backendToLoad])
)) {
throw new ConfigurationError($this->translate(
'Could not find any valid user backend resources.'
. ' Please configure a resource for authentication first.'
));
}
}
$this->resources = $resources;
@ -54,9 +92,11 @@ class UserBackendConfigForm extends ConfigForm
/**
* Return a form object for the given backend type
*
* @param string $type The backend type for which to return a form
* @param string $type The backend type for which to return a form
*
* @return Form
*
* @throws InvalidArgumentException In case the given backend type is invalid
*/
public function getBackendForm($type)
{
@ -84,81 +124,103 @@ class UserBackendConfigForm extends ConfigForm
}
/**
* Add a particular user backend
* Populate the form with the given backend's config
*
* The backend to add is identified by the array-key `name'.
*
* @param array $values The values to extend the configuration with
* @param string $name
*
* @return $this
*
* @throws InvalidArgumentException In case the backend does already exist
* @throws NotFoundError In case no backend with the given name is found
*/
public function add(array $values)
public function load($name)
{
$name = isset($values['name']) ? $values['name'] : '';
if (! $name) {
throw new InvalidArgumentException($this->translate('User backend name missing'));
} elseif ($this->config->hasSection($name)) {
throw new InvalidArgumentException($this->translate('User backend already exists'));
if (! $this->config->hasSection($name)) {
throw new NotFoundError('No user backend called "%s" found', $name);
}
unset($values['name']);
$this->config->setSection($name, $values);
$this->backendToLoad = $name;
return $this;
}
/**
* Edit a particular user backend
* Add a new user backend
*
* @param string $name The name of the backend to edit
* @param array $values The values to edit the configuration with
* The backend to add is identified by the array-key `name'.
*
* @return array The edited backend configuration
* @param array $data
*
* @throws InvalidArgumentException In case the backend does not exist
* @return $this
*
* @throws InvalidArgumentException In case $data does not contain a backend name
* @throws IcingaException In case a backend with the same name already exists
*/
public function edit($name, array $values)
public function add(array $data)
{
if (! $name) {
throw new InvalidArgumentException($this->translate('Old user backend name missing'));
} elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) {
throw new InvalidArgumentException($this->translate('New user backend name missing'));
} elseif (! $this->config->hasSection($name)) {
throw new InvalidArgumentException($this->translate('Unknown user backend provided'));
if (! isset($data['name'])) {
throw new InvalidArgumentException('Key \'name\' missing');
}
$backendConfig = $this->config->getSection($name);
if ($newName !== $name) {
// Only remove the old entry if it has changed as the order gets screwed when editing backend names
$this->config->removeSection($name);
$backendName = $data['name'];
if ($this->config->hasSection($backendName)) {
throw new IcingaException(
$this->translate('A user backend with the name "%s" does already exist'),
$backendName
);
}
unset($values['name']);
$this->config->setSection($newName, $backendConfig->merge($values));
return $backendConfig;
unset($data['name']);
$this->config->setSection($backendName, $data);
return $this;
}
/**
* Remove the given user backend
* Edit a user backend
*
* @param string $name The name of the backend to remove
* @param string $name
* @param array $data
*
* @return array The removed backend configuration
* @return $this
*
* @throws InvalidArgumentException In case the backend does not exist
* @throws NotFoundError In case no backend with the given name is found
*/
public function remove($name)
public function edit($name, array $data)
{
if (! $name) {
throw new InvalidArgumentException($this->translate('user backend name missing'));
} elseif (! $this->config->hasSection($name)) {
throw new InvalidArgumentException($this->translate('Unknown user backend provided'));
if (! $this->config->hasSection($name)) {
throw new NotFoundError('No user backend called "%s" found', $name);
}
$backendConfig = $this->config->getSection($name);
if (isset($data['name'])) {
if ($data['name'] !== $name) {
$this->config->removeSection($name);
$name = $data['name'];
}
unset($data['name']);
}
$backendConfig->merge($data);
foreach ($backendConfig->toArray() as $k => $v) {
if ($v === null) {
unset($backendConfig->$k);
}
}
$this->config->setSection($name, $backendConfig);
return $this;
}
/**
* Remove a user backend
*
* @param string $name
*
* @return $this
*/
public function delete($name)
{
$this->config->removeSection($name);
return $backendConfig;
return $this;
}
/**
@ -169,14 +231,12 @@ class UserBackendConfigForm extends ConfigForm
*
* @return $this
*
* @throws InvalidArgumentException In case the backend does not exist
* @throws NotFoundError In case no backend with the given name is found
*/
public function move($name, $position)
{
if (! $name) {
throw new InvalidArgumentException($this->translate('User backend name missing'));
} elseif (! $this->config->hasSection($name)) {
throw new InvalidArgumentException($this->translate('Unknown user backend provided'));
if (! $this->config->hasSection($name)) {
throw new NotFoundError('No user backend called "%s" found', $name);
}
$backendOrder = $this->config->keys();
@ -194,105 +254,9 @@ class UserBackendConfigForm extends ConfigForm
}
/**
* Add or edit an user backend and save the configuration
* Create and add elements to this form
*
* Performs a connectivity validation using the submitted values. A checkbox is
* added to the form to skip the check if it fails and redirection is aborted.
*
* @see Form::onSuccess()
*/
public function onSuccess()
{
if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) {
$backendForm = $this->getBackendForm($this->getElement('type')->getValue());
if (false === $backendForm::isValidUserBackend($this)) {
$this->addElement($this->getForceCreationCheckbox());
return false;
}
}
$authBackend = $this->request->getQuery('backend');
try {
if ($authBackend === null) { // create new backend
$this->add($this->getValues());
$message = $this->translate('User backend "%s" has been successfully created');
} else { // edit existing backend
$this->edit($authBackend, $this->getValues());
$message = $this->translate('User backend "%s" has been successfully changed');
}
} catch (InvalidArgumentException $e) {
Notification::error($e->getMessage());
return;
}
if ($this->save()) {
Notification::success(sprintf($message, $this->getElement('name')->getValue()));
} else {
return false;
}
}
/**
* Populate the form in case an user backend is being edited
*
* @see Form::onRequest()
*
* @throws ConfigurationError In case the backend name is missing in the request or is invalid
*/
public function onRequest()
{
$authBackend = $this->request->getQuery('backend');
if ($authBackend !== null) {
if ($authBackend === '') {
throw new ConfigurationError($this->translate('User backend name missing'));
} elseif (! $this->config->hasSection($authBackend)) {
throw new ConfigurationError($this->translate('Unknown user backend provided'));
} elseif ($this->config->getSection($authBackend)->backend === null) {
throw new ConfigurationError(
sprintf($this->translate('Backend "%s" has no `backend\' setting'), $authBackend)
);
}
$configValues = $this->config->getSection($authBackend)->toArray();
$configValues['type'] = $configValues['backend'];
$configValues['name'] = $authBackend;
$this->populate($configValues);
} elseif (empty($this->resources)) {
$externalBackends = array_filter(
$this->config->toArray(),
function ($authBackendCfg) {
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'external';
}
);
if (false === empty($externalBackends)) {
throw new ConfigurationError($this->translate('Could not find any resources for authentication'));
}
}
}
/**
* Return a checkbox to be displayed at the beginning of the form
* which allows the user to skip the connection validation
*
* @return Zend_Form_Element
*/
protected function getForceCreationCheckbox()
{
return $this->createElement(
'checkbox',
'force_creation',
array(
'order' => 0,
'ignore' => true,
'label' => $this->translate('Force Changes'),
'description' => $this->translate('Check this box to enforce changes without connectivity validation')
)
);
}
/**
* @see Form::createElements()
* @param array $formData
*/
public function createElements(array $formData)
{
@ -302,7 +266,7 @@ class UserBackendConfigForm extends ConfigForm
if (isset($this->resources['db'])) {
$backendTypes['db'] = $this->translate('Database');
}
if (isset($this->resources['ldap']) && ($backendType === 'ldap' || Platform::extensionLoaded('ldap'))) {
if (isset($this->resources['ldap'])) {
$backendTypes['ldap'] = 'LDAP';
$backendTypes['msldap'] = 'ActiveDirectory';
}
@ -336,21 +300,186 @@ class UserBackendConfigForm extends ConfigForm
)
);
if (isset($formData['force_creation']) && $formData['force_creation']) {
if (isset($formData['skip_validation']) && $formData['skip_validation']) {
// In case another error occured and the checkbox was displayed before
$this->addElement($this->getForceCreationCheckbox());
$this->addSkipValidationCheckbox();
}
$this->addElements($this->getBackendForm($backendType)->createElements($formData)->getElements());
$this->addSubForm($this->getBackendForm($backendType)->create($formData), 'backend_form');
}
/**
* Return the configuration for the chosen resource
*
* @return ConfigObject
* Populate the configuration of the backend to load
*/
public function getResourceConfig()
public function onRequest()
{
return ResourceFactory::getResourceConfig($this->getValue('resource'));
if ($this->backendToLoad) {
$data = $this->config->getSection($this->backendToLoad)->toArray();
$data['name'] = $this->backendToLoad;
$data['type'] = $data['backend'];
$this->populate($data);
}
}
/**
* Retrieve all form element values
*
* @param bool $suppressArrayNotation Ignored
*
* @return array
*/
public function getValues($suppressArrayNotation = false)
{
$values = parent::getValues();
$values = array_merge($values, $values['backend_form']);
unset($values['backend_form']);
return $values;
}
/**
* Return whether the given values are valid
*
* @param array $formData The data to validate
*
* @return bool
*/
public function isValid($formData)
{
if (! parent::isValid($formData)) {
return false;
}
if (($el = $this->getElement('skip_validation')) === null || false === $el->isChecked()) {
$inspection = static::inspectUserBackend($this);
if ($inspection && $inspection->hasError()) {
$this->error($inspection->getError());
if ($el === null) {
$this->addSkipValidationCheckbox();
}
return false;
}
}
return true;
}
/**
* Create a user backend by using the given form's values and return its inspection results
*
* Returns null for non-inspectable backends.
*
* @param Form $form
*
* @return Inspection|null
*/
public static function inspectUserBackend(Form $form)
{
$backend = UserBackend::create(null, new ConfigObject($form->getValues()));
if ($backend instanceof Inspectable) {
return $backend->inspect();
}
}
/**
* Add a checkbox to the form by which the user can skip the connection validation
*/
protected function addSkipValidationCheckbox()
{
$this->addElement(
'checkbox',
'skip_validation',
array(
'order' => 0,
'ignore' => true,
'required' => true,
'label' => $this->translate('Skip Validation'),
'description' => $this->translate(
'Check this box to enforce changes without validating that authentication is possible.'
)
)
);
}
/**
* Run the configured backend's inspection checks and show the result, if necessary
*
* This will only run any validation if the user pushed the 'backend_validation' button.
*
* @param array $formData
*
* @return bool
*/
public function isValidPartial(array $formData)
{
if ($this->getElement('backend_validation')->isChecked() && parent::isValid($formData)) {
$inspection = static::inspectUserBackend($this);
if ($inspection !== null) {
$join = function ($e) use (& $join) {
return is_string($e) ? $e : join("\n", array_map($join, $e));
};
$this->addElement(
'note',
'inspection_output',
array(
'order' => 0,
'value' => '<strong>' . $this->translate('Validation Log') . "</strong>\n\n"
. join("\n", array_map($join, $inspection->toArray())),
'decorators' => array(
'ViewHelper',
array('HtmlTag', array('tag' => 'pre', 'class' => 'log-output')),
)
)
);
if ($inspection->hasError()) {
$this->warning(sprintf(
$this->translate('Failed to successfully validate the configuration: %s'),
$inspection->getError()
));
return false;
}
}
$this->info($this->translate('The configuration has been successfully validated.'));
}
return true;
}
/**
* Add a submit button to this form and one to manually validate the configuration
*
* Calls parent::addSubmitButton() to add the submit button.
*
* @return $this
*/
public function addSubmitButton()
{
parent::addSubmitButton()
->getElement('btn_submit')
->setDecorators(array('ViewHelper'));
$this->addElement(
'submit',
'backend_validation',
array(
'ignore' => true,
'label' => $this->translate('Validate Configuration'),
'decorators' => array('ViewHelper')
)
);
$this->addDisplayGroup(
array('btn_submit', 'backend_validation'),
'submit_validation',
array(
'decorators' => array(
'FormElements',
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
)
)
);
return $this;
}
}

View File

@ -3,9 +3,9 @@
namespace Icinga\Forms\Config;
use InvalidArgumentException;
use Icinga\Web\Notification;
use Icinga\Forms\ConfigForm;
use Icinga\Exception\NotFoundError;
use Icinga\Web\Notification;
class UserBackendReorderForm extends ConfigForm
{
@ -29,7 +29,9 @@ class UserBackendReorderForm extends ConfigForm
}
/**
* @see Form::createElements()
* Create and add elements to this form
*
* @param array $formData
*/
public function createElements(array $formData)
{
@ -39,8 +41,6 @@ class UserBackendReorderForm extends ConfigForm
/**
* Update the user backend order and save the configuration
*
* @see Form::onSuccess()
*/
public function onSuccess()
{
@ -55,8 +55,8 @@ class UserBackendReorderForm extends ConfigForm
} else {
return false;
}
} catch (InvalidArgumentException $e) {
Notification::error($e->getMessage());
} catch (NotFoundError $_) {
Notification::error(sprintf($this->translate('User backend "%s" not found'), $backendName));
}
}
}

View File

@ -205,10 +205,7 @@ class PreferenceForm extends Form
array(
'ignore' => true,
'label' => $this->translate('Save to the Preferences'),
'decorators' => array(
'ViewHelper',
array('HtmlTag', array('tag' => 'div'))
)
'decorators' => array('ViewHelper')
)
);
}
@ -219,10 +216,7 @@ class PreferenceForm extends Form
array(
'ignore' => true,
'label' => $this->translate('Save for the current Session'),
'decorators' => array(
'ViewHelper',
array('HtmlTag', array('tag' => 'div'))
)
'decorators' => array('ViewHelper')
)
);

View File

@ -54,6 +54,7 @@ $iframeClass = $isIframe ? ' iframe' : '';
<div id="layout" class="default-layout<?php if ($showFullscreen): ?> fullscreen-layout<?php endif ?>">
<?= $this->render('body.phtml') ?>
</div>
<iframe id="fileupload-frame-target" name="fileupload-frame-target"></iframe>
<!--[if IE 8]>
<script type="text/javascript" src="<?= $this->href($ie8jsfile) ?>"></script>
<![endif]-->

View File

@ -0,0 +1,10 @@
<html>
<head>
<?php if (isset($this->layout()->redirectUrl)): ?>
<meta name="redirectUrl" content="<?= $this->layout()->redirectUrl; ?>">
<?php endif ?>
</head>
<body>
<?= $this->render('inline.phtml'); ?>
</body>
</html>

View File

@ -1,8 +1,6 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use \Zend_View_Helper_FormElement;
/**
* Helper to generate a "datetime" element
*/

View File

@ -1,6 +0,0 @@
<div class="controls">
<?= $this->tabs->showOnlyCloseButton() ?>
</div>
<div class="content">
<?= $form; ?>
</div>

View File

@ -1,6 +0,0 @@
<div class="controls">
<?= $this->tabs->showOnlyCloseButton() ?>
</div>
<div class="content">
<?= $form; ?>
</div>

View File

@ -33,7 +33,7 @@
</td>
<td data-base-target="_self">
<?php if ($i > 0): ?>
<button type="submit" name="backend_newpos" value="<?= sprintf(
<button type="submit" name="backend_newpos" class="icon-only" value="<?= sprintf(
'%s|%s',
$backendNames[$i],
$i - 1
@ -43,11 +43,11 @@
$this->translate('Move user backend %s upwards'),
$backendNames[$i]
); ?>">
<?= $this->icon('up-big'); ?>
<?= $this->icon('up-small'); ?>
</button>
<?php endif; ?>
<?php if ($i + 1 < count($backendNames)): ?>
<button type="submit" name="backend_newpos" value="<?= sprintf(
<button type="submit" name="backend_newpos" class="icon-only" value="<?= sprintf(
'%s|%s',
$backendNames[$i],
$i + 1
@ -57,7 +57,7 @@
$this->translate('Move user backend %s downwards'),
$backendNames[$i]
); ?>">
<?= $this->icon('down-big'); ?>
<?= $this->icon('down-small'); ?>
</button>
<?php endif; ?>
</td>

View File

@ -46,8 +46,6 @@ Requires: %{name}-vendor-HTMLPurifier
Requires: %{name}-vendor-JShrink
Requires: %{name}-vendor-lessphp
Requires: %{name}-vendor-Parsedown
Requires: %{zend}
Obsoletes: %{name}-vendor-zend
%description
@ -84,6 +82,10 @@ Requires: %{php}-gd %{php}-intl
%{?fedora:Requires: php-pecl-imagick}
%{?rhel:Requires: php-pecl-imagick}
%{?suse_version:Requires: %{php}-gettext %{php}-json %{php}-openssl %{php}-posix}
Requires: %{zend}
Obsoletes: %{name}-vendor-zend
Requires: %{zend}-Db-Adapter-Pdo-Mysql
Requires: %{zend}-Db-Adapter-Pdo-Pgsql
%description -n php-Icinga
Icinga Web 2 PHP library

View File

@ -8,6 +8,7 @@ use Icinga\Data\ConfigObject;
use Icinga\Application\Logger\Writer\FileWriter;
use Icinga\Application\Logger\Writer\SyslogWriter;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\IcingaException;
/**
* Logger
@ -226,13 +227,7 @@ class Logger
$messages = array();
$error = $message;
do {
$messages[] = sprintf(
'%s in %s:%d with message: %s',
get_class($error),
$error->getFile(),
$error->getLine(),
$error->getMessage()
);
$messages[] = IcingaException::describe($error);
} while ($error = $error->getPrevious());
$message = implode(' <- ', $messages);
}

View File

@ -260,7 +260,7 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
$insp->write($this->ds->inspect());
try {
$users = $this->select()->where('is_active', true)->count();
if ($users > 1) {
if ($users >= 1) {
$insp->write(sprintf('%s active users', $users));
} else {
return $insp->error('0 active users', $users);

View File

@ -4,6 +4,7 @@
namespace Icinga\Cli;
use Icinga\Application\ApplicationBootstrap as App;
use Icinga\Exception\IcingaException;
use Icinga\Exception\ProgrammingError;
use Icinga\Cli\Params;
use Icinga\Cli\Screen;
@ -265,7 +266,8 @@ class Loader
if ($obj && $obj instanceof Command && $obj->showTrace()) {
echo $this->formatTrace($e->getTrace());
}
$this->fail($e->getMessage());
$this->fail(IcingaException::describe($e));
}
}

View File

@ -59,6 +59,7 @@ class Inspection
if ($entry instanceof Inspection) {
$this->log[$entry->description] = $entry->toArray();
} else {
Logger::debug($entry);
$this->log[] = $entry;
}
}
@ -77,7 +78,8 @@ class Inspection
if (isset($this->error)) {
throw new ProgrammingError('Inspection object used after error');
}
$this->write($entry);
Logger::error($entry);
$this->log[] = $entry;
$this->error = $entry;
return $this;
}

View File

@ -0,0 +1,9 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Data;
use Countable;
interface Paginatable extends Limitable, Countable {};

View File

@ -3,6 +3,4 @@
namespace Icinga\Data;
use Countable;
interface QueryInterface extends Fetchable, Filterable, Limitable, Sortable, Countable {};
interface QueryInterface extends Fetchable, Filterable, Paginatable, Sortable {};

View File

@ -0,0 +1,14 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Data;
interface SortRules
{
/**
* Return some sort rules
*
* @return array
*/
public function getSortRules();
}

View File

@ -40,4 +40,24 @@ class IcingaException extends Exception
$e = new ReflectionClass(get_called_class());
return $e->newInstanceArgs($args);
}
/**
* Return the given exception formatted as one-liner
*
* The format used is: %class% in %path%:%line% with message: %message%
*
* @param Exception $exception
*
* @return string
*/
public static function describe(Exception $exception)
{
return sprintf(
'%s in %s:%d with message: %s',
get_class($exception),
$exception->getFile(),
$exception->getLine(),
$exception->getMessage()
);
}
}

View File

@ -314,7 +314,7 @@ class LdapConnection implements Selectable, Inspectable
public function bind()
{
if ($this->bound) {
return;
return $this;
}
$ds = $this->getConnection();
@ -332,6 +332,7 @@ class LdapConnection implements Selectable, Inspectable
}
$this->bound = true;
return $this;
}
/**

View File

@ -78,7 +78,7 @@ abstract class Repository implements Selectable
protected $filterColumns;
/**
* The default sort rules to be applied on a query
* The sort rules to be applied on a query
*
* This may be initialized by concrete repository implementations, in the following format
* <pre><code>
@ -284,7 +284,7 @@ abstract class Repository implements Selectable
}
/**
* Return the default sort rules to be applied on a query
* Return the sort rules to be applied on a query
*
* Calls $this->initializeSortRules() in case $this->sortRules is null.
*

View File

@ -9,12 +9,13 @@ use Icinga\Application\Benchmark;
use Icinga\Application\Logger;
use Icinga\Data\QueryInterface;
use Icinga\Data\Filter\Filter;
use Icinga\Data\SortRules;
use Icinga\Exception\QueryException;
/**
* Query class supposed to mediate between a repository and its datasource's query
*/
class RepositoryQuery implements QueryInterface, Iterator
class RepositoryQuery implements QueryInterface, SortRules, Iterator
{
/**
* The repository being used
@ -212,6 +213,16 @@ class RepositoryQuery implements QueryInterface, Iterator
return $this->query->getFilter();
}
/**
* Return the sort rules being applied on this query
*
* @return array
*/
public function getSortRules()
{
return $this->repository->getSortRules();
}
/**
* Add a sort rule for this query
*
@ -226,7 +237,7 @@ class RepositoryQuery implements QueryInterface, Iterator
*/
public function order($field = null, $direction = null, $ignoreDefault = false)
{
$sortRules = $this->repository->getSortRules();
$sortRules = $this->getSortRules();
if ($field === null) {
// Use first available sort rule as default
if (empty($sortRules)) {

View File

@ -37,13 +37,13 @@ class Controller extends ModuleActionController
return;
}
if (($sort = $request->getPost('sort'))) {
if (($sort = $request->getPost('sort')) || ($direction = $request->getPost('dir'))) {
$url = Url::fromRequest();
$url->setParam('sort', $sort);
if (($dir = $request->getPost('dir'))) {
$url->setParam('dir', $dir);
if ($sort) {
$url->setParam('sort', $sort);
$url->remove('dir');
} else {
$url->removeParam('dir');
$url->setParam('dir', $direction);
}
$this->redirectNow($url);

View File

@ -96,6 +96,9 @@ class ActionController extends Zend_Controller_Action
if ($this->rerenderLayout = $request->getUrl()->shift('renderLayout')) {
$this->xhrLayout = 'body';
}
if ($request->getUrl()->shift('_disableLayout')) {
$this->_helper->layout()->disableLayout();
}
if ($this->requiresLogin()) {
$this->redirectToLogin(Url::fromRequest());
@ -455,11 +458,11 @@ class ActionController extends Zend_Controller_Action
foreach ($notifications->getMessages() as $m) {
$notificationList[] = rawurlencode($m->type . ' ' . $m->message);
}
$resp->setHeader('X-Icinga-Notification', implode('&', $notificationList));
$resp->setHeader('X-Icinga-Notification', implode('&', $notificationList), true);
}
if ($this->reloadCss) {
$resp->setHeader('X-Icinga-CssReload', 'now');
$resp->setHeader('X-Icinga-CssReload', 'now', true);
}
if ($this->view->title) {
@ -469,18 +472,19 @@ class ActionController extends Zend_Controller_Action
}
$resp->setHeader(
'X-Icinga-Title',
rawurlencode($this->view->title . ' :: Icinga Web')
rawurlencode($this->view->title . ' :: Icinga Web'),
true
);
} else {
$resp->setHeader('X-Icinga-Title', rawurlencode('Icinga Web'));
$resp->setHeader('X-Icinga-Title', rawurlencode('Icinga Web'), true);
}
if ($this->rerenderLayout) {
$this->getResponse()->setHeader('X-Icinga-Container', 'layout');
$this->getResponse()->setHeader('X-Icinga-Container', 'layout', true);
}
if ($this->autorefreshInterval !== null) {
$resp->setHeader('X-Icinga-Refresh', $this->autorefreshInterval);
$resp->setHeader('X-Icinga-Refresh', $this->autorefreshInterval, true);
}
}

View File

@ -3,13 +3,13 @@
namespace Icinga\Web;
use LogicException;
use Zend_Config;
use Zend_Form;
use Zend_Form_Element;
use Zend_View_Interface;
use Icinga\Application\Icinga;
use Icinga\Authentication\Manager;
use Icinga\Exception\ProgrammingError;
use Icinga\Security\SecurityException;
use Icinga\Util\Translator;
use Icinga\Web\Form\ErrorLabeller;
@ -84,7 +84,7 @@ class Form extends Zend_Form
/**
* The url to redirect to upon success
*
* @var string|Url
* @var Url
*/
protected $redirectUrl;
@ -160,6 +160,13 @@ class Form extends Zend_Form
*/
protected $notifications;
/**
* The hints of this form
*
* @var array
*/
protected $hints;
/**
* Whether the Autosubmit decorator should be applied to this form
*
@ -222,12 +229,12 @@ class Form extends Zend_Form
*
* @return $this
*
* @throws LogicException If the callback is not callable
* @throws ProgrammingError If the callback is not callable
*/
public function setOnSuccess($onSuccess)
{
if (! is_callable($onSuccess)) {
throw new LogicException('The option `onSuccess\' is not callable');
throw new ProgrammingError('The option `onSuccess\' is not callable');
}
$this->onSuccess = $onSuccess;
return $this;
@ -262,9 +269,17 @@ class Form extends Zend_Form
* @param string|Url $url The url to redirect to
*
* @return $this
*
* @throws ProgrammingError In case $url is neither a string nor a instance of Icinga\Web\Url
*/
public function setRedirectUrl($url)
{
if (is_string($url)) {
$url = Url::fromPath($url, array(), $this->getRequest());
} elseif (! $url instanceof Url) {
throw new ProgrammingError('$url must be a string or instance of Icinga\Web\Url');
}
$this->redirectUrl = $url;
return $this;
}
@ -272,14 +287,16 @@ class Form extends Zend_Form
/**
* Return the url to redirect to upon success
*
* @return string|Url
* @return Url
*/
public function getRedirectUrl()
{
if ($this->redirectUrl === null) {
$url = Url::fromRequest(array(), $this->getRequest());
// Be sure to remove all form dependent params because we do not want to submit it again
$this->redirectUrl = $url->without(array_keys($this->getElements()));
$this->redirectUrl = $this->getRequest()->getUrl();
if ($this->getMethod() === 'get') {
// Be sure to remove all form dependent params because we do not want to submit it again
$this->redirectUrl = $this->redirectUrl->without(array_keys($this->getElements()));
}
}
return $this->redirectUrl;
@ -566,6 +583,49 @@ class Form extends Zend_Form
return $this->notifications;
}
/**
* Set the hints for this form
*
* @param array $hints
*
* @return $this
*/
public function setHints(array $hints)
{
$this->hints = $hints;
return $this;
}
/**
* Add a hint for this form
*
* If $hint is an array the second value should be an
* array as well containing additional HTML properties.
*
* @param string|array $hint
*
* @return $this
*/
public function addHint($hint)
{
$this->hints[] = $hint;
return $this;
}
/**
* Return the hints of this form
*
* @return array
*/
public function getHints()
{
if ($this->hints === null) {
return array();
}
return $this->hints;
}
/**
* Set whether the Autosubmit decorator should be applied to this form
*
@ -600,22 +660,26 @@ class Form extends Zend_Form
*/
public function create(array $formData = array())
{
if (false === $this->created) {
if (! $this->created) {
$this->createElements($formData);
$this->addFormIdentification()
->addCsrfCounterMeasure()
->addSubmitButton();
// Use Form::getAttrib() instead of Form::getAction() here because we want to explicitly check against
// null. Form::getAction() would return the empty string '' if the action is not set.
// For not setting the action attribute use Form::setAction(''). This is required for for the
// accessibility's enable/disable auto-refresh mechanic
if ($this->getAttrib('action') === null) {
// Use Form::getAttrib() instead of Form::getAction() here because we want to explicitly check against
// null. Form::getAction() would return the empty string '' if the action is not set.
// For not setting the action attribute use Form::setAction(''). This is required for for the
// accessibility's enable/disable auto-refresh mechanic
$action = $this->getRequest()->getUrl();
if ($this->getMethod() === 'get') {
$action = $action->without(array_keys($this->getElements()));
}
// TODO(el): Re-evalute this necessity. JavaScript could use the container's URL if there's no action set.
// We MUST set an action as JS gets confused otherwise, if
// this form is being displayed in an additional column
$this->setAction(Url::fromRequest()->without(array_keys($this->getElements())));
$this->setAction($action);
}
$this->created = true;
@ -862,7 +926,7 @@ class Form extends Zend_Form
*/
public function addFormIdentification()
{
if (false === $this->uidDisabled && $this->getElement($this->uidElementName) === null) {
if (! $this->uidDisabled && $this->getElement($this->uidElementName) === null) {
$this->addElement(
'hidden',
$this->uidElementName,
@ -884,7 +948,7 @@ class Form extends Zend_Form
*/
public function addCsrfCounterMeasure()
{
if (false === $this->tokenDisabled && $this->getElement($this->tokenElementName) === null) {
if (! $this->tokenDisabled && $this->getElement($this->tokenElementName) === null) {
$this->addElement(new CsrfCounterMeasure($this->tokenElementName));
}
@ -946,12 +1010,20 @@ class Form extends Zend_Form
$formData = $this->getRequestData();
if ($this->getUidDisabled() || $this->wasSent($formData)) {
if (($frameUpload = (bool) $request->getUrl()->shift('_frameUpload', false))) {
$this->getView()->layout()->setLayout('wrapped');
}
$this->populate($formData); // Necessary to get isSubmitted() to work
if (! $this->getSubmitLabel() || $this->isSubmitted()) {
if ($this->isValid($formData)
&& (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $this))
|| ($this->onSuccess === null && false !== $this->onSuccess()))) {
$this->getResponse()->redirectAndExit($this->getRedirectUrl());
if (! $frameUpload) {
$this->getResponse()->redirectAndExit($this->getRedirectUrl());
} else {
$this->getView()->layout()->redirectUrl = $this->getRedirectUrl()->getAbsoluteUrl();
}
}
} elseif ($this->getValidatePartial()) {
// The form can't be processed but we may want to show validation errors though
@ -1087,10 +1159,11 @@ class Form extends Zend_Form
->addDecorator('HtmlTag', array('tag' => 'div', 'class' => 'header'));
}
$this->addDecorator('FormErrors', array('onlyCustomFormErrors' => true))
$this->addDecorator('FormDescriptions')
->addDecorator('FormNotifications')
->addDecorator('FormDescriptions')
->addDecorator('FormErrors', array('onlyCustomFormErrors' => true))
->addDecorator('FormElements')
->addDecorator('FormHints')
//->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
->addDecorator('Form');
}

View File

@ -7,35 +7,10 @@ use Zend_Form_Decorator_Abstract;
use Icinga\Web\Form;
/**
* Decorator to add a list of descriptions at the top of a form
*
* The description for required form elements is automatically being handled.
* Decorator to add a list of descriptions at the top or bottom of a form
*/
class FormDescriptions extends Zend_Form_Decorator_Abstract
{
/**
* A list of element class names to be ignored when detecting which message to use to describe required elements
*
* @var array
*/
protected $blacklist;
/**
* {@inheritdoc}
*/
public function __construct($options = null)
{
parent::__construct($options);
$this->blacklist = array(
'Zend_Form_Element_Hidden',
'Zend_Form_Element_Submit',
'Zend_Form_Element_Button',
'Icinga\Web\Form\Element\Note',
'Icinga\Web\Form\Element\Button',
'Icinga\Web\Form\Element\CsrfCounterMeasure'
);
}
/**
* Render form descriptions
*
@ -55,18 +30,7 @@ class FormDescriptions extends Zend_Form_Decorator_Abstract
return $content;
}
$descriptions = $this->recurseForm($form, $entirelyRequired);
if ($entirelyRequired) {
$descriptions[] = $form->getView()->translate(
'All fields are required and must be filled in to complete the form.'
);
} elseif ($entirelyRequired === false) {
$descriptions[] = $form->getView()->translate(sprintf(
'Required fields are marked with %s and must be filled in to complete the form.',
$form->getRequiredCue()
));
}
$descriptions = $this->recurseForm($form);
if (empty($descriptions)) {
return $content;
}
@ -92,53 +56,15 @@ class FormDescriptions extends Zend_Form_Decorator_Abstract
/**
* Recurse the given form and return the descriptions for it and all of its subforms
*
* @param Form $form The form to recurse
* @param mixed $entirelyRequired Set by reference, true means all elements in the hierarchy are
* required, false only a partial subset and null none at all
* @param bool $elementsPassed Whether there were any elements passed during the recursion until now
* @param Form $form The form to recurse
*
* @return array
*/
protected function recurseForm(Form $form, & $entirelyRequired = null, $elementsPassed = false)
protected function recurseForm(Form $form)
{
$requiredLabels = array();
if ($form->getRequiredCue() !== null) {
$partiallyRequired = $partiallyOptional = false;
foreach ($form->getElements() as $element) {
if (! in_array($element->getType(), $this->blacklist)) {
if (! $element->isRequired()) {
$partiallyOptional = true;
if ($entirelyRequired) {
$entirelyRequired = false;
}
} else {
$partiallyRequired = true;
if (($label = $element->getDecorator('label')) !== false) {
$requiredLabels[] = $label;
}
}
}
}
if (! $elementsPassed) {
$elementsPassed = $partiallyRequired || $partiallyOptional;
if ($entirelyRequired === null && $partiallyRequired) {
$entirelyRequired = ! $partiallyOptional;
}
} elseif ($entirelyRequired === null && $partiallyRequired) {
$entirelyRequired = false;
}
}
$descriptions = array($form->getDescriptions());
foreach ($form->getSubForms() as $subForm) {
$descriptions[] = $this->recurseForm($subForm, $entirelyRequired, $elementsPassed);
}
if ($entirelyRequired) {
foreach ($requiredLabels as $label) {
$label->setRequiredSuffix('');
}
$descriptions[] = $this->recurseForm($subForm);
}
return call_user_func_array('array_merge', $descriptions);

View File

@ -0,0 +1,142 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Web\Form\Decorator;
use Zend_Form_Decorator_Abstract;
use Icinga\Web\Form;
/**
* Decorator to add a list of hints at the top or bottom of a form
*
* The hint for required form elements is automatically being handled.
*/
class FormHints extends Zend_Form_Decorator_Abstract
{
/**
* A list of element class names to be ignored when detecting which message to use to describe required elements
*
* @var array
*/
protected $blacklist;
/**
* {@inheritdoc}
*/
public function __construct($options = null)
{
parent::__construct($options);
$this->blacklist = array(
'Zend_Form_Element_Hidden',
'Zend_Form_Element_Submit',
'Zend_Form_Element_Button',
'Icinga\Web\Form\Element\Note',
'Icinga\Web\Form\Element\Button',
'Icinga\Web\Form\Element\CsrfCounterMeasure'
);
}
/**
* Render form hints
*
* @param string $content The html rendered so far
*
* @return string The updated html
*/
public function render($content = '')
{
$form = $this->getElement();
if (! $form instanceof Form) {
return $content;
}
$view = $form->getView();
if ($view === null) {
return $content;
}
$hints = $this->recurseForm($form, $entirelyRequired);
if ($entirelyRequired !== null) {
$hints[] = $form->getView()->translate(sprintf(
'Required fields are marked with %s and must be filled in to complete the form.',
$form->getRequiredCue()
));
}
if (empty($hints)) {
return $content;
}
$html = '<ul class="hints">';
foreach ($hints as $hint) {
if (is_array($hint)) {
list($hint, $properties) = $hint;
$html .= '<li' . $view->propertiesToString($properties) . '>' . $view->escape($hint) . '</li>';
} else {
$html .= '<li>' . $view->escape($hint) . '</li>';
}
}
switch ($this->getPlacement()) {
case self::APPEND:
return $content . $html . '</ul>';
case self::PREPEND:
return $html . '</ul>' . $content;
}
}
/**
* Recurse the given form and return the hints for it and all of its subforms
*
* @param Form $form The form to recurse
* @param mixed $entirelyRequired Set by reference, true means all elements in the hierarchy are
* required, false only a partial subset and null none at all
* @param bool $elementsPassed Whether there were any elements passed during the recursion until now
*
* @return array
*/
protected function recurseForm(Form $form, & $entirelyRequired = null, $elementsPassed = false)
{
$requiredLabels = array();
if ($form->getRequiredCue() !== null) {
$partiallyRequired = $partiallyOptional = false;
foreach ($form->getElements() as $element) {
if (! in_array($element->getType(), $this->blacklist)) {
if (! $element->isRequired()) {
$partiallyOptional = true;
if ($entirelyRequired) {
$entirelyRequired = false;
}
} else {
$partiallyRequired = true;
if (($label = $element->getDecorator('label')) !== false) {
$requiredLabels[] = $label;
}
}
}
}
if (! $elementsPassed) {
$elementsPassed = $partiallyRequired || $partiallyOptional;
if ($entirelyRequired === null && $partiallyRequired) {
$entirelyRequired = ! $partiallyOptional;
}
} elseif ($entirelyRequired === null && $partiallyRequired) {
$entirelyRequired = false;
}
}
$hints = array($form->getHints());
foreach ($form->getSubForms() as $subForm) {
$hints[] = $this->recurseForm($subForm, $entirelyRequired, $elementsPassed);
}
if ($entirelyRequired) {
foreach ($requiredLabels as $label) {
$label->setRequiredSuffix('');
}
}
return call_user_func_array('array_merge', $hints);
}
}

View File

@ -6,6 +6,7 @@ namespace Icinga\Web\Form;
use BadMethodCallException;
use Zend_Translate_Adapter;
use Zend_Validate_NotEmpty;
use Zend_Validate_File_MimeType;
use Icinga\Web\Form\Validator\DateTimeValidator;
use Icinga\Web\Form\Validator\ReadablePathValidator;
use Icinga\Web\Form\Validator\WritablePathValidator;
@ -42,10 +43,15 @@ class ErrorLabeller extends Zend_Translate_Adapter
$label = $element->getLabel() ?: $element->getName();
return array(
Zend_Validate_NotEmpty::IS_EMPTY => sprintf(t('%s is required and must not be empty'), $label),
WritablePathValidator::NOT_WRITABLE => sprintf(t('%s is not writable', 'config.path'), $label),
WritablePathValidator::DOES_NOT_EXIST => sprintf(t('%s does not exist', 'config.path'), $label),
ReadablePathValidator::NOT_READABLE => sprintf(t('%s is not readable', 'config.path'), $label),
Zend_Validate_NotEmpty::IS_EMPTY => sprintf(t('%s is required and must not be empty'), $label),
Zend_Validate_File_MimeType::FALSE_TYPE => sprintf(
t('%s (%%value%%) has a false MIME type of "%%type%%"'),
$label
),
Zend_Validate_File_MimeType::NOT_DETECTED => sprintf(t('%s (%%value%%) has no MIME type'), $label),
WritablePathValidator::NOT_WRITABLE => sprintf(t('%s is not writable', 'config.path'), $label),
WritablePathValidator::DOES_NOT_EXIST => sprintf(t('%s does not exist', 'config.path'), $label),
ReadablePathValidator::NOT_READABLE => sprintf(t('%s is not readable', 'config.path'), $label),
DateTimeValidator::INVALID_DATETIME_FORMAT => sprintf(
t('%s not in the expected format: %%value%%'),
$label

View File

@ -8,7 +8,6 @@ use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RegexIterator;
use RecursiveRegexIterator;
use Zend_Controller_Front;
use Icinga\Application\Icinga;
use lessc;
@ -31,8 +30,6 @@ class LessCompiler
*/
private $lessc;
private $baseUrl;
private $source;
/**
@ -44,6 +41,17 @@ class LessCompiler
$this->lessc = new lessc();
}
/**
* Disable the extendend import functionality
*
* @return $this
*/
public function disableExtendedImport()
{
$this->lessc->importDisabled = true;
return $this;
}
public function compress()
{
$this->lessc->setPreserveComments(false);

View File

@ -118,7 +118,13 @@ class MenuRenderer extends RecursiveIteratorIterator
try {
return $child->getRenderer()->render($child);
} catch (Exception $e) {
Logger::error('Could not invoke custom renderer. Exception: '. $e->getMessage());
Logger::error(
'Could not invoke custom menu renderer. %s in %s:%d with message: %s',
get_class($e),
$e->getFile(),
$e->getLine(),
$e->getMessage()
);
}
}

View File

@ -99,6 +99,7 @@ class StyleSheet
}
$less = new LessCompiler();
$less->disableExtendedImport();
foreach ($lessFiles as $file) {
$less->addFile($file);
}

View File

@ -3,7 +3,7 @@
namespace Icinga\Web\Widget;
use Icinga\Data\QueryInterface;
use Icinga\Data\Paginatable;
use Icinga\Exception\ProgrammingError;
/**
@ -14,7 +14,7 @@ class Paginator extends AbstractWidget
/**
* The query the paginator widget is created for
*
* @var QueryInterface
* @var Paginatable
*/
protected $query;
@ -28,11 +28,11 @@ class Paginator extends AbstractWidget
/**
* Set the query to create the paginator widget for
*
* @param QueryInterface $query
* @param Paginatable $query
*
* @return $this
*/
public function setQuery(QueryInterface $query)
public function setQuery(Paginatable $query)
{
$this->query = $query;
return $this;

View File

@ -3,30 +3,26 @@
namespace Icinga\Web\Widget;
use Icinga\Application\Icinga;
use Icinga\Data\Sortable;
use Icinga\Data\SortRules;
use Icinga\Web\Form;
use Icinga\Web\Request;
use Icinga\Data\Sortable;
use Icinga\Application\Icinga;
/**
* SortBox widget
*
* The "SortBox" Widget allows you to create a generic sort input for sortable views. It automatically creates a form
* containing a select box with all sort options and a dropbox with the sort direction. It also handles automatic
* submission of sorting changes and draws an additional submit button when JavaScript is disabled.
* The "SortBox" Widget allows you to create a generic sort input for sortable views. It automatically creates a select
* box with all sort options and a dropbox with the sort direction. It also handles automatic submission of sorting
* changes and draws an additional submit button when JavaScript is disabled.
*
* The constructor takes an string for the component name and an array containing the select options, where the key is
* The constructor takes a string for the component name and an array containing the select options, where the key is
* the value to be submitted and the value is the label that will be shown. You then should call setRequest in order
* to make sure the form is correctly populated when a request with a sort parameter is being made.
*
* Example:
* <pre><code>
* $this->view->sortControl = new SortBox(
* $this->getRequest()->getActionName(),
* $columns
* );
* $this->view->sortControl->setRequest($this->getRequest());
* </code></pre>
* Call setQuery in case you'll do not want to handle URL parameters manually, but to automatically apply the user's
* chosen sort rules on the given sortable query. This will also allow the SortBox to display the user the correct
* default sort rules if the given query provides already some sort rules.
*/
class SortBox extends AbstractWidget
{
@ -38,25 +34,25 @@ class SortBox extends AbstractWidget
protected $sortFields;
/**
* The name of the form that will be created
* The name used to uniquely identfy the forms being created
*
* @var string
*/
protected $name;
/**
* A request object used for initial form population
* The request to fetch sort rules from
*
* @var Request
*/
protected $request;
/**
* What to apply sort parameters on
* The query to apply sort rules on
*
* @var Sortable
*/
protected $query = null;
protected $query;
/**
* Create a SortBox with the entries from $sortFields
@ -84,9 +80,9 @@ class SortBox extends AbstractWidget
}
/**
* Apply the parameters from the given request on this SortBox
* Set the request to fetch sort rules from
*
* @param Request $request The request to use for populating the form
* @param Request $request
*
* @return $this
*/
@ -97,9 +93,11 @@ class SortBox extends AbstractWidget
}
/**
* @param Sortable $query
* Set the query to apply sort rules on
*
* @return $this
* @param Sortable $query
*
* @return $this
*/
public function setQuery(Sortable $query)
{
@ -107,19 +105,54 @@ class SortBox extends AbstractWidget
return $this;
}
/**
* Apply the sort rules from the given or current request on the query
*
* @param Request $request
*
* @return $this
*/
public function handleRequest(Request $request = null)
{
if ($this->query !== null) {
if ($request === null) {
$request = Icinga::app()->getFrontController()->getRequest();
}
if ($sort = $request->getParam('sort')) {
if (($sort = $request->getParam('sort'))) {
$this->query->order($sort, $request->getParam('dir'));
} elseif (($dir = $request->getParam('dir'))) {
$this->query->order(null, $dir);
}
}
return $this;
}
/**
* Return the default sort rule for the query
*
* @param string $column An optional column
*
* @return array An array of two values: $column, $direction
*/
protected function getSortDefaults($column = null)
{
$direction = null;
if ($this->query !== null && $this->query instanceof SortRules) {
$sortRules = $this->query->getSortRules();
if ($column === null) {
$column = key($sortRules);
}
if ($column !== null && isset($sortRules[$column]['order'])) {
$direction = strtoupper($sortRules[$column]['order']) === Sortable::SORT_DESC ? 'desc' : 'asc';
}
}
return array($column, $direction);
}
/**
* Render this SortBox as HTML
*
@ -127,43 +160,68 @@ class SortBox extends AbstractWidget
*/
public function render()
{
$form = new Form();
$form->setTokenDisabled();
$form->setName($this->name);
$form->setAttrib('class', 'sort-control inline');
$form->addElement(
$columnForm = new Form();
$columnForm->setTokenDisabled();
$columnForm->setName($this->name . '-column');
$columnForm->setAttrib('class', 'inline');
$columnForm->addElement(
'select',
'sort',
array(
'autosubmit' => true,
'label' => $this->view()->translate('Sort by'),
'multiOptions' => $this->sortFields
)
);
$form->getElement('sort')->setDecorators(array(
array('ViewHelper'),
array('Label')
));
$form->addElement(
'select',
'dir',
array(
'autosubmit' => true,
'multiOptions' => array(
'asc' => 'Asc',
'desc' => 'Desc',
),
'multiOptions' => $this->sortFields,
'decorators' => array(
array('ViewHelper')
array('ViewHelper'),
array('Label')
)
)
);
$orderForm = new Form();
$orderForm->setTokenDisabled();
$orderForm->setName($this->name . '-order');
$orderForm->setAttrib('class', 'inline');
$orderForm->addElement(
'select',
'dir',
array(
'autosubmit' => true,
'label' => $this->view()->translate('Direction', 'sort direction'),
'multiOptions' => array(
'asc' => $this->view()->translate('Ascending', 'sort direction'),
'desc' => $this->view()->translate('Descending', 'sort direction')
),
'decorators' => array(
array('ViewHelper'),
array('Label', array('class' => 'no-js'))
)
)
);
$column = null;
if ($this->request) {
$form->populate($this->request->getParams());
$url = $this->request->getUrl();
if ($url->hasParam('sort')) {
$column = $url->getParam('sort');
if ($url->hasParam('dir')) {
$direction = $url->getParam('dir');
} else {
list($_, $direction) = $this->getSortDefaults($column);
}
} elseif ($url->hasParam('dir')) {
$direction = $url->getParam('dir');
list($column, $_) = $this->getSortDefaults();
}
}
return $form;
if ($column === null) {
list($column, $direction) = $this->getSortDefaults();
}
$columnForm->populate(array('sort' => $column));
$orderForm->populate(array('dir' => $direction));
return '<div class="sort-control">' . $columnForm . $orderForm . '</div>';
}
}

View File

@ -309,7 +309,7 @@ EOT;
private function renderRefreshTab()
{
$url = Url::fromRequest()->without('renderLayout');
$url = Icinga::app()->getFrontController()->getRequest()->getUrl();
$tab = $this->get($this->getActiveName());
if ($tab !== null) {

View File

@ -1,7 +1,6 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use \Zend_Controller_Action_Exception;
use Icinga\Application\Icinga;
use Icinga\Module\Doc\DocController;
@ -25,10 +24,7 @@ class Doc_IcingawebController extends DocController
return $path;
}
}
throw new Zend_Controller_Action_Exception(
$this->translate('Documentation for Icinga Web 2 is not available'),
404
);
$this->httpNotFound($this->translate('Documentation for Icinga Web 2 is not available'));
}
/**

View File

@ -1,7 +1,6 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use \Zend_Controller_Action_Exception;
use Icinga\Application\Icinga;
use Icinga\Module\Doc\DocController;
use Icinga\Module\Doc\Exception\DocException;

View File

@ -1,7 +1,6 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use \Zend_Controller_Action_Exception;
use Icinga\Application\Icinga;
use Icinga\Module\Doc\DocController;
use Icinga\Module\Doc\DocParser;

View File

@ -9,6 +9,7 @@ class Monitoring_TacticalController extends MonitoringController
{
public function indexAction()
{
$this->setAutorefreshInterval(15);
$this->getTabs()->add(
'tactical_overview',
array(

View File

@ -16,7 +16,7 @@ abstract class CommandForm extends Form
/**
* Monitoring backend
*
* @var Backend
* @var MonitoringBackend
*/
protected $backend;
@ -36,7 +36,7 @@ abstract class CommandForm extends Form
/**
* Get the monitoring backend
*
* @return Backend
* @return MonitoringBackend
*/
public function getBackend()
{

View File

@ -13,8 +13,7 @@ use Icinga\Web\Notification;
class DeleteCommentCommandForm extends CommandForm
{
/**
* (non-PHPDoc)
* @see \Zend_Form::init() For the method documentation.
* {@inheritdoc}
*/
public function init()
{
@ -22,8 +21,7 @@ class DeleteCommentCommandForm extends CommandForm
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::createElements() For the method documentation.
* {@inheritdoc}
*/
public function createElements(array $formData = array())
{
@ -59,8 +57,7 @@ class DeleteCommentCommandForm extends CommandForm
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::addSubmitButton() For the method documentation.
* {@inheritdoc}
*/
public function addSubmitButton()
{
@ -81,8 +78,7 @@ class DeleteCommentCommandForm extends CommandForm
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
* {@inheritdoc}
*/
public function onSuccess()
{

View File

@ -4,7 +4,7 @@
namespace Icinga\Module\Monitoring\Forms\Command\Object;
use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand;
use \Icinga\Module\Monitoring\Forms\Command\CommandForm;
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
use Icinga\Web\Notification;
/**
@ -20,8 +20,7 @@ class DeleteCommentsCommandForm extends CommandForm
protected $comments;
/**
* (non-PHPDoc)
* @see \Zend_Form::init() For the method documentation.
* {@inheritdoc}
*/
public function init()
{
@ -29,8 +28,7 @@ class DeleteCommentsCommandForm extends CommandForm
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::createElements() For the method documentation.
* {@inheritdoc}
*/
public function createElements(array $formData = array())
{
@ -45,8 +43,7 @@ class DeleteCommentsCommandForm extends CommandForm
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
* {@inheritdoc}
*/
public function getSubmitLabel()
{
@ -54,8 +51,7 @@ class DeleteCommentsCommandForm extends CommandForm
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
* {@inheritdoc}
*/
public function onSuccess()
{
@ -76,9 +72,9 @@ class DeleteCommentsCommandForm extends CommandForm
/**
* Set the comments to be deleted upon success
*
* @param array $comments
* @param array $comments
*
* @return this fluent interface
* @return $this
*/
public function setComments(array $comments)
{

View File

@ -4,7 +4,7 @@
namespace Icinga\Module\Monitoring\Forms\Command\Object;
use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
use \Icinga\Module\Monitoring\Forms\Command\CommandForm;
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
use Icinga\Web\Notification;
/**
@ -13,17 +13,15 @@ use Icinga\Web\Notification;
class DeleteDowntimeCommandForm extends CommandForm
{
/**
* (non-PHPDoc)
* @see \Zend_Form::init() For the method documentation.
* {@inheritdoc}
*/
public function init()
{
$this->setAttrib('class', 'inline');
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::createElements() For the method documentation.
* {@inheritdoc}
*/
public function createElements(array $formData = array())
{
@ -57,10 +55,9 @@ class DeleteDowntimeCommandForm extends CommandForm
);
return $this;
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::addSubmitButton() For the method documentation.
* {@inheritdoc}
*/
public function addSubmitButton()
{
@ -79,10 +76,9 @@ class DeleteDowntimeCommandForm extends CommandForm
);
return $this;
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
* {@inheritdoc}
*/
public function onSuccess()
{
@ -90,7 +86,7 @@ class DeleteDowntimeCommandForm extends CommandForm
$cmd->setDowntimeId($this->getElement('downtime_id')->getValue());
$cmd->setIsService($this->getElement('downtime_is_service')->getValue());
$this->getTransport($this->request)->send($cmd);
$redirect = $this->getElement('redirect')->getValue();
if (! empty($redirect)) {
$this->setRedirectUrl($redirect);

View File

@ -4,7 +4,7 @@
namespace Icinga\Module\Monitoring\Forms\Command\Object;
use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
use \Icinga\Module\Monitoring\Forms\Command\CommandForm;
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
use Icinga\Web\Notification;
/**
@ -18,10 +18,9 @@ class DeleteDowntimesCommandForm extends CommandForm
* @var array
*/
protected $downtimes;
/**
* (non-PHPDoc)
* @see \Zend_Form::init() For the method documentation.
* {@inheritdoc}
*/
public function init()
{
@ -29,8 +28,7 @@ class DeleteDowntimesCommandForm extends CommandForm
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::createElements() For the method documentation.
* {@inheritdoc}
*/
public function createElements(array $formData = array())
{
@ -43,19 +41,17 @@ class DeleteDowntimesCommandForm extends CommandForm
));
return $this;
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
* {@inheritdoc}
*/
public function getSubmitLabel()
{
return $this->translatePlural('Remove', 'Remove All', count($this->downtimes));
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
* {@inheritdoc}
*/
public function onSuccess()
{
@ -72,13 +68,13 @@ class DeleteDowntimesCommandForm extends CommandForm
Notification::success($this->translate('Deleting downtime.'));
return true;
}
/**
* Set the downtimes to be deleted upon success
*
* @param type $downtimes
* @param array $downtimes
*
* @return $this
* @return $this
*/
public function setDowntimes(array $downtimes)
{

View File

@ -109,7 +109,10 @@ class BackendConfigForm extends ConfigForm
$backendName = $data['name'];
if ($this->config->hasSection($backendName)) {
throw new IcingaException('A monitoring backend with the name "%s" does already exist', $backendName);
throw new IcingaException(
$this->translate('A monitoring backend with the name "%s" does already exist'),
$backendName
);
}
unset($data['name']);
@ -309,10 +312,15 @@ class BackendConfigForm extends ConfigForm
return false;
}
$resourceConfig = ResourceFactory::getResourceConfig($this->getValue('resource'));
if (! self::isValidIdoSchema($this, $resourceConfig) || !self::isValidIdoInstance($this, $resourceConfig)) {
$this->addSkipValidationCheckbox();
return false;
if (($el = $this->getElement('skip_validation')) === null || false === $el->isChecked()) {
$resourceConfig = ResourceFactory::getResourceConfig($this->getValue('resource'));
if (! self::isValidIdoSchema($this, $resourceConfig) || !self::isValidIdoInstance($this, $resourceConfig)) {
if ($el === null) {
$this->addSkipValidationCheckbox();
}
return false;
}
}
return true;

View File

@ -95,7 +95,10 @@ class InstanceConfigForm extends ConfigForm
$instanceName = $data['name'];
if ($this->config->hasSection($instanceName)) {
throw new IcingaException('A monitoring instance with the name "%s" does already exist', $instanceName);
throw new IcingaException(
$this->translate('A monitoring instance with the name "%s" does already exist'),
$instanceName
);
}
unset($data['name']);

View File

@ -3,9 +3,7 @@
namespace Icinga\Module\Monitoring\Forms;
use Icinga\Data\Filter\FilterNot;
use Icinga\Web\Url;
use \Zend_Form;
use Icinga\Web\Form;
use Icinga\Data\Filter\Filter;
@ -15,7 +13,7 @@ use Icinga\Data\Filter\Filter;
class EventOverviewForm extends Form
{
/**
* Initialize this form
* {@inheritdoc}
*/
public function init()
{
@ -28,7 +26,7 @@ class EventOverviewForm extends Form
}
/**
* @see Form::createElements()
* {@inheritdoc}
*/
public function createElements(array $formData)
{

View File

@ -4,6 +4,7 @@
namespace Icinga\Module\Monitoring\Forms\Setup;
use Icinga\Data\ConfigObject;
use Icinga\Forms\Config\ResourceConfigForm;
use Icinga\Forms\Config\Resource\DbResourceForm;
use Icinga\Web\Form;
use Icinga\Module\Monitoring\Forms\Config\BackendConfigForm;
@ -71,13 +72,17 @@ class IdoResourcePage extends Form
}
if (! isset($formData['skip_validation']) || !$formData['skip_validation']) {
$configObject = new ConfigObject($this->getValues());
if (! DbResourceForm::isValidResource($this, $configObject)) {
$inspection = ResourceConfigForm::inspectResource($this);
if ($inspection !== null && $inspection->hasError()) {
$this->error($inspection->getError());
$this->addSkipValidationCheckbox($this->translate(
'Check this to not to validate connectivity with the given database server.'
));
return false;
} elseif (
}
$configObject = new ConfigObject($this->getValues());
if (
! BackendConfigForm::isValidIdoSchema($this, $configObject)
|| !BackendConfigForm::isValidIdoInstance($this, $configObject)
) {

View File

@ -3,7 +3,6 @@
namespace Icinga\Module\Monitoring\Forms;
use \Zend_Form;
use Icinga\Web\Form;
use Icinga\Data\Filter\Filter;
@ -13,7 +12,7 @@ use Icinga\Data\Filter\Filter;
class StatehistoryForm extends Form
{
/**
* Initialize this form
* {@inheritdoc}
*/
public function init()
{
@ -56,7 +55,7 @@ class StatehistoryForm extends Form
}
/**
* @see Form::createElements()
* {@inheritdoc}
*/
public function createElements(array $formData)
{

View File

@ -60,5 +60,8 @@ class ProgramstatusQuery extends IdoQuery
if (version_compare($this->getIdoVersion(), '1.11.8', '<')) {
$this->columnMap['programstatus']['program_version'] = '(NULL)';
}
if (version_compare($this->getIdoVersion(), '1.8', '<')) {
$this->columnMap['programstatus']['disable_notif_expire_time'] = '(NULL)';
}
}
}

View File

@ -60,13 +60,13 @@ class DeleteCommentCommand extends IcingaCommand
/**
* Set whether the command affects a service
*
* @param boolean $value The value, defaults to true
* @param bool $isService
*
* @return this fluent interface
* @return $this
*/
public function setIsService($value = true)
public function setIsService($isService = true)
{
$this->isService = (bool) $value;
$this->isService = (bool) $isService;
return $this;
}
}

View File

@ -27,17 +27,20 @@ class DeleteDowntimeCommand extends IcingaCommand
/**
* Set if this command affects a service
*
* @param type $value
* @param bool $isService
*
* @return $this
*/
public function setIsService($value = true)
public function setIsService($isService = true)
{
$this->isService = (bool) $value;
$this->isService = (bool) $isService;
return $this;
}
/**
* Return whether the command affects a service
*
* @return type
* @return bool
*/
public function getIsService()
{

View File

@ -3,9 +3,20 @@
namespace Icinga\Module\Monitoring\Command\Transport;
use Icinga\Module\Monitoring\Command\IcingaCommand;
/**
* Interface for Icinga command transports
*/
interface CommandTransportInterface
{
/**
* Send an Icinga command over the Icinga command transport
*
* @param IcingaCommand $command The command to send
* @param int|null $now Timestamp of the command or null for now
*
* @throws \Icinga\Module\Monitoring\Exception\CommandTransportException If sending the Icinga command failed
*/
public function send(IcingaCommand $command, $now = null);
}

View File

@ -7,9 +7,9 @@ use Exception;
use RuntimeException;
use Icinga\Application\Logger;
use Icinga\Exception\ConfigurationError;
use Icinga\Module\Monitoring\Command\Exception\TransportException;
use Icinga\Module\Monitoring\Command\IcingaCommand;
use Icinga\Module\Monitoring\Command\Renderer\IcingaCommandFileCommandRenderer;
use Icinga\Module\Monitoring\Exception\CommandTransportException;
use Icinga\Util\File;
/**
@ -104,7 +104,7 @@ class LocalCommandFile implements CommandTransportInterface
* @param int|null $now
*
* @throws ConfigurationError
* @throws TransportException
* @throws CommandTransportException
*/
public function send(IcingaCommand $command, $now = null)
{
@ -129,7 +129,7 @@ class LocalCommandFile implements CommandTransportInterface
// Assume RuntimeException thrown by SplFileObject in the format: __METHOD__ . "({$filename}): Message"
$message = substr($message, $pos + 1);
}
throw new TransportException(
throw new CommandTransportException(
'Can\'t send external Icinga command to the local command file "%s": %s',
$this->path,
$message

View File

@ -6,9 +6,9 @@ namespace Icinga\Module\Monitoring\Command\Transport;
use Icinga\Application\Logger;
use Icinga\Data\ResourceFactory;
use Icinga\Exception\ConfigurationError;
use Icinga\Module\Monitoring\Command\Exception\TransportException;
use Icinga\Module\Monitoring\Command\IcingaCommand;
use Icinga\Module\Monitoring\Command\Renderer\IcingaCommandFileCommandRenderer;
use Icinga\Module\Monitoring\Exception\CommandTransportException;
/**
* A remote Icinga command file
@ -224,7 +224,7 @@ class RemoteCommandFile implements CommandTransportInterface
* @param int|null $now
*
* @throws ConfigurationError
* @throws TransportException
* @throws CommandTransportException
*/
public function send(IcingaCommand $command, $now = null)
{
@ -260,7 +260,7 @@ class RemoteCommandFile implements CommandTransportInterface
);
exec($ssh, $output, $status);
if ($status !== 0) {
throw new TransportException(
throw new CommandTransportException(
'Can\'t send external Icinga command: %s',
implode(' ', $output)
);

View File

@ -36,8 +36,10 @@ class Customvar extends DataView
{
return array(
'varname' => array(
'varname' => self::SORT_ASC,
'varvalue' => self::SORT_ASC,
'columns' => array(
'varname',
'varvalue'
)
)
);
}

View File

@ -5,6 +5,7 @@ namespace Icinga\Module\Monitoring\DataView;
use IteratorAggregate;
use Icinga\Data\QueryInterface;
use Icinga\Data\SortRules;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterMatch;
use Icinga\Data\PivotTable;
@ -18,7 +19,7 @@ use Icinga\Module\Monitoring\Backend\MonitoringBackend;
/**
* A read-only view of an underlying query
*/
abstract class DataView implements QueryInterface, IteratorAggregate
abstract class DataView implements QueryInterface, SortRules, IteratorAggregate
{
/**
* The query used to populate the view

View File

@ -49,8 +49,7 @@ class EventHistory extends DataView
{
return array(
'timestamp' => array(
'columns' => array('timestamp'),
'order' => 'DESC'
'order' => self::SORT_DESC
)
);
}

View File

@ -1,13 +1,13 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Module\Monitoring\Command\Exception;
namespace Icinga\Module\Monitoring\Exception;
use Icinga\Exception\IcingaException;
/**
* Exception thrown if a command was not sent
*/
class TransportException extends IcingaException
class CommandTransportException extends IcingaException
{
}

View File

@ -3,41 +3,50 @@
namespace Icinga\Module\Monitoring\Web\Menu;
use Icinga\Web\Menu as Menu;
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
use Icinga\Web\Menu;
use Icinga\Web\Menu\MenuItemRenderer;
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
class BackendAvailabilityMenuItemRenderer extends MenuItemRenderer
{
/**
* Checks whether the monitoring backend is running or not
* Get whether or not the monitoring backend is currently running
*
* @return mixed
* @return bool
*/
protected function isCurrentlyRunning()
{
return MonitoringBackend::instance()->select()->from(
'programstatus',
array(
'is_currently_running'
$programStatus = MonitoringBackend::instance()
->select()
->from(
'programstatus',
array('is_currently_running')
)
)->getQuery()->fetchRow()->is_currently_running;
->fetchRow();
return $programStatus !== false ? (bool) $programStatus : false;
}
/**
* @see MenuItemRenderer::render()
* {@inheritdoc}
*/
public function render(Menu $menu)
{
return $this->getBadge() . $this->createLink($menu);
}
/**
* Get the problem badge HTML
*
* @return string
*/
protected function getBadge()
{
if (! (bool)$this->isCurrentlyRunning()) {
if (! $this->isCurrentlyRunning()) {
return sprintf(
'<div title="%s" class="badge-container"><span class="badge badge-critical">%s</span></div>',
mt('monitoring', 'monitoring backend is not running'),
'<div title="%s" class="badge-container"><span class="badge badge-critical">%d</span></div>',
sprintf(
mt('monitoring', 'Monitoring backend %s is not running'), MonitoringBackend::instance()->getName()
),
1
);
}
@ -51,10 +60,12 @@ class BackendAvailabilityMenuItemRenderer extends MenuItemRenderer
*/
public function getSummary()
{
if (! (bool)$this->isCurrentlyRunning()) {
if (! $this->isCurrentlyRunning()) {
return array(
'problems' => 1,
'title' => mt('monitoring', 'monitoring backend is not running')
'problems' => 1,
'title' => sprintf(
mt('monitoring', 'Monitoring backend %s is not running'), MonitoringBackend::instance()->getName()
)
);
}
return null;

View File

@ -89,9 +89,6 @@ class AdminAccountPage extends Form
}
if (count($choices) > 1) {
$this->addDescription($this->translate(
'Below are several options you can choose from for how to define the desired account.'
));
$this->addElement(
'select',
'user_type',
@ -99,6 +96,7 @@ class AdminAccountPage extends Form
'required' => true,
'autosubmit' => true,
'label' => $this->translate('Type Of Definition'),
'description' => $this->translate('Choose how to define the desired account.'),
'multiOptions' => $choices,
'value' => $choice
)
@ -124,7 +122,7 @@ class AdminAccountPage extends Form
'label' => $this->translate('Username'),
'description' => $this->translate(
'Define the initial administrative account by providing a username that reflects'
. ' a user created later or one that is authenticated using external mechanisms'
. ' a user created later or one that is authenticated using external mechanisms.'
)
)
);
@ -139,7 +137,7 @@ class AdminAccountPage extends Form
'label' => $this->translate('Username'),
'description' => sprintf(
$this->translate(
'Choose a user reported by the %s backend as the initial administrative account',
'Choose a user reported by the %s backend as the initial administrative account.',
'setup.admin'
),
$this->backendConfig['backend'] === 'db'
@ -159,7 +157,7 @@ class AdminAccountPage extends Form
'required' => true,
'label' => $this->translate('Username'),
'description' => $this->translate(
'Enter the username to be used when creating an initial administrative account'
'Enter the username to be used when creating an initial administrative account.'
)
)
);
@ -170,7 +168,9 @@ class AdminAccountPage extends Form
'required' => true,
'renderPassword' => true,
'label' => $this->translate('Password'),
'description' => $this->translate('Enter the password to assign to the newly created account')
'description' => $this->translate(
'Enter the password to assign to the newly created account.'
)
)
);
$this->addElement(
@ -181,7 +181,7 @@ class AdminAccountPage extends Form
'renderPassword' => true,
'label' => $this->translate('Repeat password'),
'description' => $this->translate(
'Please repeat the password given above to avoid typing errors'
'Please repeat the password given above to avoid typing errors.'
),
'validators' => array(
array('identical', false, array('new_user_password'))

View File

@ -3,11 +3,12 @@
namespace Icinga\Module\Setup\Forms;
use Icinga\Web\Form;
use Icinga\Data\ConfigObject;
use Icinga\Forms\Config\UserBackendConfigForm;
use Icinga\Forms\Config\UserBackend\DbBackendForm;
use Icinga\Forms\Config\UserBackend\LdapBackendForm;
use Icinga\Forms\Config\UserBackend\ExternalBackendForm;
use Icinga\Data\ConfigObject;
use Icinga\Web\Form;
/**
* Wizard page to define authentication backend specific details
@ -66,14 +67,14 @@ class AuthBackendPage extends Form
$this->setRequiredCue(null);
$backendForm = new DbBackendForm();
$backendForm->setRequiredCue(null);
$backendForm->createElements($formData)->removeElement('resource');
$backendForm->create($formData)->removeElement('resource');
$this->addDescription($this->translate(
'As you\'ve chosen to use a database for authentication all you need '
. 'to do now is defining a name for your first authentication backend.'
));
} elseif ($this->config['type'] === 'ldap') {
$backendForm = new LdapBackendForm();
$backendForm->createElements($formData)->removeElement('resource');
$backendForm->create($formData)->removeElement('resource');
$this->addDescription($this->translate(
'Before you are able to authenticate using the LDAP connection defined earlier you need to'
. ' provide some more information so that Icinga Web 2 is able to locate account details.'
@ -97,15 +98,30 @@ class AuthBackendPage extends Form
);
} else { // $this->config['type'] === 'external'
$backendForm = new ExternalBackendForm();
$backendForm->createElements($formData);
$backendForm->create($formData);
$this->addDescription($this->translate(
'You\'ve chosen to authenticate using a web server\'s mechanism so it may be necessary'
. ' to adjust usernames before any permissions, restrictions, etc. are being applied.'
));
}
$this->addElements($backendForm->getElements());
$this->getElement('name')->setValue('icingaweb2');
$backendForm->getElement('name')->setValue('icingaweb2');
$this->addSubForm($backendForm, 'backend_form');
}
/**
* Retrieve all form element values
*
* @param bool $suppressArrayNotation Ignored
*
* @return array
*/
public function getValues($suppressArrayNotation = false)
{
$values = parent::getValues();
$values = array_merge($values, $values['backend_form']);
unset($values['backend_form']);
return $values;
}
/**
@ -117,11 +133,11 @@ class AuthBackendPage extends Form
*/
public function isValid($data)
{
if (false === parent::isValid($data)) {
if (! parent::isValid($data)) {
return false;
}
if ($this->config['type'] === 'ldap' && ( !isset($data['skip_validation']) || $data['skip_validation'] == 0)) {
if ($this->config['type'] === 'ldap' && (! isset($data['skip_validation']) || $data['skip_validation'] == 0)) {
$self = clone $this;
$self->addElement(
'text',
@ -130,7 +146,9 @@ class AuthBackendPage extends Form
'value' => $this->getResourceConfig()
)
);
if (! LdapBackendForm::isValidUserBackend($self)) {
$inspection = UserBackendConfigForm::inspectUserBackend($self);
if ($inspection && $inspection->hasError()) {
$this->error($inspection->getError());
$this->addSkipValidationCheckbox();
return false;
}

View File

@ -4,6 +4,7 @@
namespace Icinga\Module\Setup\Forms;
use Icinga\Web\Form;
use Icinga\Forms\Config\ResourceConfigForm;
use Icinga\Forms\Config\Resource\LdapResourceForm;
/**
@ -65,12 +66,14 @@ class LdapResourcePage extends Form
*/
public function isValid($data)
{
if (false === parent::isValid($data)) {
if (! parent::isValid($data)) {
return false;
}
if (false === isset($data['skip_validation']) || $data['skip_validation'] == 0) {
if (false === LdapResourceForm::isValidResource($this)) {
if (! isset($data['skip_validation']) || $data['skip_validation'] == 0) {
$inspection = ResourceConfigForm::inspectResource($this);
if ($inspection !== null && $inspection->hasError()) {
$this->error($inspection->getError());
$this->addSkipValidationCheckbox();
return false;
}

View File

@ -1,6 +1,6 @@
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
form.sort-control {
div.sort-control {
.dontprint;
float: right;
@ -15,7 +15,13 @@ form.sort-control {
}
select[name=dir] {
width: 5em;
width: 8em;
margin-left: 0;
}
}
html.no-js div.sort-control form {
display: table;
margin-left: auto;
margin-top: 0.25em;
}

View File

@ -25,7 +25,7 @@ label {
font-weight: bold;
}
input, select {
input, select, textarea {
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@ -44,10 +44,19 @@ input[type=submit] {
font-weight: bold;
text-align: center;
color: #fff;
border: 2px solid #ddd;
border: 1px solid;
border-color: @colorPetrol;
background: @colorPetrol;
outline: 0;
&[disabled] {
background-color: #666;
border-color: black;
}
&:hover[disabled], &:active[disabled], &:focus[disabled] {
background-color: #666;
}
}
input[type=submit]:hover, a.button:hover, input[type=submit]:focus {
@ -87,10 +96,6 @@ button::-moz-focus-inner {
outline: 0;
}
button {
cursor: pointer;
}
select::-moz-focus-inner {
border: 0;
outline: 0;
@ -190,7 +195,8 @@ form ul.form-notifications {
}
form div.element {
margin: 0.5em 0;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
form label {
@ -200,6 +206,14 @@ form label {
width: 10em;
}
form div.element > * {
vertical-align: top;
}
form dt {
vertical-align: top;
}
select, input[type=text], textarea {
width: 20em;
display: inline-block;
@ -259,3 +273,76 @@ form ul.descriptions {
}
}
}
form ul.hints {
.non-list-like-list;
padding: 0.5em 0.5em 0 0.5em;
li {
font-size: 0.8em;
padding-bottom: 0.5em;
}
}
.control-group {
& > * {
float: left;
margin-right: 0.5em;
}
div.element {
margin-top: 0;
margin-bottom: 0;
}
&:after {
content: ".";
visibility: hidden;
display: block;
height: 0;
clear: both;
}
}
button, .button-like {
font-size: 0.9em;
font-weight: bold;
outline: 0;
color: #fff;
padding: 0.2em;
border: 1px solid;
border-color: @colorPetrol;
background: @colorPetrol;
&[disabled] {
background-color: #666;
border-color: black;
}
&:hover, &:focus, &:active {
background-color: #333;
border-color: #333;
cursor: pointer;
&[disabled] {
background-color: #666;
}
}
&.icon-only {
font-size: 1.5em;
padding: 0;
border: none;
color: inherit;
background-color: transparent;
&:hover, &:focus, &:active {
color: #666;
}
}
}
a.button-like {
cursor: default;
text-decoration: none;
}

View File

@ -47,6 +47,10 @@ html {
}
}
#fileupload-frame-target {
display: none;
}
#responsive-debug {
font-size: 0.9em;
font-family: Courier new, monospace;
@ -401,3 +405,13 @@ html {
padding-top: 0em;
font-size: 0.9em;
}
// Hide non-javascript elements if javascript is enabled
html.js *.no-js {
.sr-only;
}
// Hide javascript elements if javascript is disabled
html.no-js *.js {
.sr-only;
}

View File

@ -12,6 +12,15 @@ p code {
padding: 0.3em;
}
pre.log-output {
padding: 0.5em;
margin-top: 0;
margin-bottom: 2em;
max-height: 12em;
overflow: auto;
border: 1px solid #ddd;
}
a {
color: #39a;
}
@ -104,7 +113,7 @@ table.benchmark {
.info-box {
padding: 0.5em;
border: 1px solid lightgrey;
background-color: #fbfcc5;
background-color: #f2f4fd;
}
/* Action table */

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