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

@ -20,7 +20,7 @@ esac
echo "Adding puppet repository.." echo "Adding puppet repository.."
rpm --import "https://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs" rpm --import "https://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs"
rpm -ivh $PUPPET >/dev/null rpm -Uvh $PUPPET >/dev/null
echo "Installing puppet.." echo "Installing puppet.."
yum install -y puppet >/dev/null yum install -y puppet >/dev/null

View File

@ -15,10 +15,10 @@
class epel { class epel {
yumrepo { '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', enabled => '1',
gpgcheck => '0', 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 include icinga_packages
package { [ package { [
'icinga2', 'icinga2-doc', 'icinga2-debuginfo' 'icinga2', 'icinga2-doc'
]: ]:
ensure => latest, ensure => latest,
require => Class['icinga_packages'], require => Class['icinga_packages'],
@ -35,7 +35,7 @@ class icinga2 {
links => follow, links => follow,
owner => 'icinga', owner => 'icinga',
group => 'icinga', group => 'icinga',
mode => 6750, mode => '6750',
} }
icinga2::feature { [ 'statusdata', 'command', 'compatlog' ]: } icinga2::feature { [ 'statusdata', 'command', 'compatlog' ]: }

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
# Class: mysql # 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: # Parameters:
# #
@ -16,21 +16,39 @@ class mysql {
Exec { path => '/usr/bin' } 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 { [ package { [
'mysql', 'mysql-server' $client_package_name, $server_package_name,
]: ]:
ensure => latest, ensure => latest,
} }
service { 'mysqld': service { $server_service_name:
ensure => running, alias => 'mysqld',
enable => true, 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'), 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 innodb_log_file_size = 64M
[mysqld_safe] [mysqld_safe]
log-error=/var/log/mysqld.log log-error=<%= @log_error %>
pid-file=/var/run/mysqld/mysqld.pid pid-file=<%= @pid_file %>
# Increase the amount of open files allowed per process. Warning: Make # Increase the amount of open files allowed per process. Warning: Make
# sure you have set the global system limit high enough! The high value # sure you have set the global system limit high enough! The high value

View File

@ -20,6 +20,18 @@ class openldap {
service { 'slapd': service { 'slapd':
ensure => running, 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", unless => "psql -tAc \"SELECT 1 FROM pg_roles WHERE rolname='${username}'\" | grep -q 1",
command => "psql -c \"CREATE ROLE ${username} WITH LOGIN PASSWORD '${password}';\" && \ command => "psql -c \"CREATE ROLE ${username} WITH LOGIN PASSWORD '${password}';\" && \
createdb -O ${username} -E UTF8 -T template0 ${name} && \ createdb -O ${username} -E UTF8 -T template0 ${name} && \
createlang plpgsql ${name}", (createlang plpgsql ${name} || true)",
user => 'postgres', user => 'postgres',
require => Class['pgsql'] require => Class['pgsql']
} }

View File

@ -20,24 +20,11 @@ class php {
package { 'php': package { 'php':
ensure => latest, 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'], notify => Service['apache'],
require => Package['apache'],
} }
file { '/etc/php.d/error_reporting.ini': php::phpd { ['error_reporting', 'timezone', 'xdebug_settings' ]:
content => template('php/error_reporting.ini.erb'),
require => Package['php'], 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 # 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: # Requires:
# #
@ -19,10 +19,15 @@ class icinga2_dev {
include monitoring_test_config include monitoring_test_config
icinga2::config { [ icinga2::config { [
'conf.d/test-config', 'conf.d/commands', 'constants' ]: 'conf.d/test-config', 'conf.d/commands', 'constants'
]:
source => 'puppet:///modules/icinga2_dev', source => 'puppet:///modules/icinga2_dev',
} }
icinga2::feature { 'api':
ensure => absent,
}
icinga2::feature { 'ido-pgsql': icinga2::feature { 'ido-pgsql':
ensure => absent, ensure => absent,
require => Class['icinga2_pgsql'], require => Class['icinga2_pgsql'],

View File

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

View File

@ -1,15 +1,27 @@
Alias /<%= @web_path %> /vagrant/public Alias /<%= @web_path %> "/vagrant/public"
<Directory "/vagrant/public/"> <Directory "/vagrant/public">
Options FollowSymLinks Options SymLinksIfOwnerMatch
AllowOverride None AllowOverride None
<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 Order allow,deny
Allow from all Allow from all
</IfModule>
# SetEnv ICINGAWEB_CONFIGDIR <%= @config %> SetEnv ICINGAWEB_CONFIGDIR <%= @config %>
EnableSendfile Off EnableSendfile Off
<IfModule mod_rewrite.c>
RewriteEngine on RewriteEngine on
RewriteBase /<%= @web_path %>/ RewriteBase /<%= @web_path %>/
RewriteCond %{REQUEST_FILENAME} -s [OR] RewriteCond %{REQUEST_FILENAME} -s [OR]
@ -17,7 +29,10 @@ Alias /<%= @web_path %> /vagrant/public
RewriteCond %{REQUEST_FILENAME} -d RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L] RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [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> </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.provision :shell, :path => ".puppet/manifests/puppet.sh"
config.vm.provider :virtualbox do |v, override| 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"] v.customize ["modifyvm", :id, "--memory", "1024"]
end end
config.vm.provider :parallels do |p, override| 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" 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.module_path = [ ".puppet/modules", ".puppet/profiles" ]
puppet.manifests_path = ".puppet/manifests" puppet.manifests_path = ".puppet/manifests"
puppet.manifest_file = "site.pp" puppet.manifest_file = "site.pp"
puppet.options = "--parser=future"
end end
end end

View File

@ -5,6 +5,8 @@ use Icinga\Application\Config;
use Icinga\Application\Icinga; use Icinga\Application\Icinga;
use Icinga\Application\Modules\Module; use Icinga\Application\Modules\Module;
use Icinga\Data\ResourceFactory; use Icinga\Data\ResourceFactory;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\NotFoundError;
use Icinga\Forms\Config\UserBackendConfigForm; use Icinga\Forms\Config\UserBackendConfigForm;
use Icinga\Forms\Config\UserBackendReorderForm; use Icinga\Forms\Config\UserBackendReorderForm;
use Icinga\Forms\Config\GeneralConfigForm; 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() public function createuserbackendAction()
{ {
$this->assertPermission('config/application/userbackend'); $this->assertPermission('config/application/userbackend');
$form = new UserBackendConfigForm(); $form = new UserBackendConfigForm();
$form->setRedirectUrl('config/userbackend');
$form->setTitle($this->translate('Create New User Backend')); $form->setTitle($this->translate('Create New User Backend'));
$form->addDescription($this->translate( $form->addDescription($this->translate(
'Create a new backend for authenticating your users. This backend' 'Create a new backend for authenticating your users. This backend'
. ' will be added at the end of your authentication order.' . ' will be added at the end of your authentication order.'
)); ));
$form->setIniConfig(Config::app('authentication')); $form->setIniConfig(Config::app('authentication'));
try {
$form->setResourceConfig(ResourceFactory::getResourceConfigs()); $form->setResourceConfig(ResourceFactory::getResourceConfigs());
$form->setRedirectUrl('config/userbackend'); } 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(); $form->handleRequest();
$this->view->form = $form; $this->view->form = $form;
$this->render('userbackend/create'); $this->render('form');
} }
/** /**
* Action for editing user backends * Edit a user backend
*/ */
public function edituserbackendAction() public function edituserbackendAction()
{ {
$this->assertPermission('config/application/userbackend'); $this->assertPermission('config/application/userbackend');
$backendName = $this->params->getRequired('backend');
$form = new UserBackendConfigForm(); $form = new UserBackendConfigForm();
$form->setTitle($this->translate('Edit User Backend'));
$form->setIniConfig(Config::app('authentication'));
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
$form->setRedirectUrl('config/userbackend'); $form->setRedirectUrl('config/userbackend');
$form->setAction(Url::fromRequest()); $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(); $form->handleRequest();
} catch (NotFoundError $_) {
$this->httpNotFound(sprintf($this->translate('User backend "%s" not found'), $backendName));
}
$this->view->form = $form; $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() public function removeuserbackendAction()
{ {
$this->assertPermission('config/application/userbackend'); $this->assertPermission('config/application/userbackend');
$form = new ConfirmRemovalForm(array( $backendName = $this->params->getRequired('backend');
'onSuccess' => function ($form) {
$configForm = new UserBackendConfigForm();
$configForm->setIniConfig(Config::app('authentication'));
$authBackend = $form->getRequest()->getQuery('backend');
try { $backendForm = new UserBackendConfigForm();
$configForm->remove($authBackend); $backendForm->setIniConfig(Config::app('authentication'));
} catch (InvalidArgumentException $e) { $form = new ConfirmRemovalForm();
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'));
$form->setRedirectUrl('config/userbackend'); $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(); $form->handleRequest();
$this->view->form = $form; $this->view->form = $form;
$this->render('userbackend/remove'); $this->render('form');
} }
/** /**

View File

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

View File

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

View File

@ -46,3 +46,12 @@ Font license info
Homepage: http://fontello.com 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 - If your project is open-source, usually, it will be ok to make LICENSE.txt
file publically available in your repository. 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. 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. - 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, - config.json - keeps your settings. You can import it back into fontello
to continue your work anytime, to continue your work
Why so many CSS files ? Why so many CSS files ?
@ -38,17 +38,17 @@ Why so many CSS files ?
Because we like to fit all your needs :) Because we like to fit all your needs :)
- basic file, <your_font_name>.css - is usually enougth, in contains @font-face - basic file, <your_font_name>.css - is usually enough, it contains @font-face
and character codes definition and character code definitions
- *-ie7.css - if you need IE7 support, but still don't wish to put char codes - *-ie7.css - if you need IE7 support, but still don't wish to put char codes
directly into html directly into html
- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face - *-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 rules, but still wish to benefit from css generation. That can be very
convenient for automated assets build systems. When you need to update font - convenient for automated asset build systems. When you need to update font -
no needs to manually edit files, just override old version with archive no need to manually edit files, just override old version with archive
content. See fontello source codes for example. content. See fontello source code for examples.
- *-embedded.css - basic css file, but with embedded WOFF font, to avoid - *-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. 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 Attention for server setup
-------------------------- --------------------------
You MUST setup server to reply with proper `mime-types` for font files. In other You MUST setup server to reply with proper `mime-types` for font files -
case, some browsers will fail to show fonts. otherwise some browsers will fail to show fonts.
Usually, `apache` already has necessary settings, but `nginx` and other 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/vnd.ms-fontobject` - eot
- `application/x-font-woff` - woff - `application/x-font-woff` - woff

View File

@ -672,6 +672,30 @@
"code": 59492, "code": 59492,
"src": "entypo" "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", "uid": "b90d80c250a9bbdd6cd3fe00e6351710",
"css": "ok", "css": "ok",

View File

@ -116,3 +116,7 @@
.icon-beaker:before { content: '\e872'; } /* '' */ .icon-beaker:before { content: '\e872'; } /* '' */
.icon-magic:before { content: '\e873'; } /* '' */ .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

@ -116,3 +116,7 @@
.icon-beaker { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe872;&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-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

@ -127,3 +127,7 @@
.icon-beaker { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe872;&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-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-face {
font-family: 'ifont'; font-family: 'ifont';
src: url('../font/ifont.eot?6491776'); src: url('../font/ifont.eot?54745533');
src: url('../font/ifont.eot?6491776#iefix') format('embedded-opentype'), src: url('../font/ifont.eot?54745533#iefix') format('embedded-opentype'),
url('../font/ifont.woff?6491776') format('woff'), url('../font/ifont.woff?54745533') format('woff'),
url('../font/ifont.ttf?6491776') format('truetype'), url('../font/ifont.ttf?54745533') format('truetype'),
url('../font/ifont.svg?6491776#ifont') format('svg'); url('../font/ifont.svg?54745533#ifont') format('svg');
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }
@ -14,7 +14,7 @@
@media screen and (-webkit-min-device-pixel-ratio:0) { @media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face { @font-face {
font-family: 'ifont'; font-family: 'ifont';
src: url('../font/ifont.svg?6491776#ifont') format('svg'); src: url('../font/ifont.svg?54745533#ifont') format('svg');
} }
} }
*/ */
@ -46,6 +46,10 @@
/* you can be more comfortable with increased icons size */ /* you can be more comfortable with increased icons size */
/* font-size: 120%; */ /* font-size: 120%; */
/* Font smoothing. That was taken from TWBS */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Uncomment for 3D effect */ /* Uncomment for 3D effect */
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
} }
@ -167,3 +171,7 @@
.icon-beaker:before { content: '\e872'; } /* '' */ .icon-beaker:before { content: '\e872'; } /* '' */
.icon-magic:before { content: '\e873'; } /* '' */ .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

@ -226,9 +226,55 @@ body {
} }
.i-code { .i-code {
display: none; display: none;
}
@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> </style>
<link rel="stylesheet" href="css/ifont.css">
<link rel="stylesheet" href="css/animation.css"><!--[if IE 7]><link rel="stylesheet" href="css/ifont-ie7.css"><![endif]--> <link rel="stylesheet" href="css/animation.css"><!--[if IE 7]><link rel="stylesheet" href="css/ifont-ie7.css"><![endif]-->
<script> <script>
function toggleCodes(on) { function toggleCodes(on) {
@ -255,181 +301,187 @@ body {
</div> </div>
<div id="icons" class="container"> <div id="icons" class="container">
<div class="row"> <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: 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="icon-user"></i> <span class="i-name">icon-user</span><span class="i-code">0xe801</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="icon-users"></i> <span class="i-name">icon-users</span><span class="i-code">0xe802</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="icon-ok"></i> <span class="i-name">icon-ok</span><span class="i-code">0xe803</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>
<div class="row"> <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: 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="icon-plus"></i> <span class="i-name">icon-plus</span><span class="i-code">0xe805</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="icon-minus"></i> <span class="i-name">icon-minus</span><span class="i-code">0xe806</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="icon-folder-empty"></i> <span class="i-name">icon-folder-empty</span><span class="i-code">0xe807</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>
<div class="row"> <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: 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="icon-upload"></i> <span class="i-name">icon-upload</span><span class="i-code">0xe809</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="icon-git"></i> <span class="i-name">icon-git</span><span class="i-code">0xe80a</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="icon-cubes"></i> <span class="i-name">icon-cubes</span><span class="i-code">0xe80b</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>
<div class="row"> <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: 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="icon-gauge"></i> <span class="i-name">icon-gauge</span><span class="i-code">0xe80d</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="icon-sitemap"></i> <span class="i-name">icon-sitemap</span><span class="i-code">0xe80e</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="icon-sort-name-up"></i> <span class="i-name">icon-sort-name-up</span><span class="i-code">0xe80f</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>
<div class="row"> <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: 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="icon-megaphone"></i> <span class="i-name">icon-megaphone</span><span class="i-code">0xe811</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="icon-bug"></i> <span class="i-name">icon-bug</span><span class="i-code">0xe812</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="icon-tasks"></i> <span class="i-name">icon-tasks</span><span class="i-code">0xe813</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>
<div class="row"> <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: 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="icon-off"></i> <span class="i-name">icon-off</span><span class="i-code">0xe815</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="icon-book"></i> <span class="i-name">icon-book</span><span class="i-code">0xe816</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="icon-paste"></i> <span class="i-name">icon-paste</span><span class="i-code">0xe817</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>
<div class="row"> <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: 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="icon-globe"></i> <span class="i-name">icon-globe</span><span class="i-code">0xe819</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="icon-cloud"></i> <span class="i-name">icon-cloud</span><span class="i-code">0xe81a</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="icon-flash"></i> <span class="i-name">icon-flash</span><span class="i-code">0xe81b</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>
<div class="row"> <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: 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="icon-down-dir"></i> <span class="i-name">icon-down-dir</span><span class="i-code">0xe81d</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="icon-up-dir"></i> <span class="i-name">icon-up-dir</span><span class="i-code">0xe81e</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="icon-left-dir"></i> <span class="i-name">icon-left-dir</span><span class="i-code">0xe81f</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>
<div class="row"> <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: 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="icon-down-open"></i> <span class="i-name">icon-down-open</span><span class="i-code">0xe821</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="icon-right-open"></i> <span class="i-name">icon-right-open</span><span class="i-code">0xe822</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="icon-up-open"></i> <span class="i-name">icon-up-open</span><span class="i-code">0xe823</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>
<div class="row"> <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: 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="icon-up-big"></i> <span class="i-name">icon-up-big</span><span class="i-code">0xe825</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="icon-right-big"></i> <span class="i-name">icon-right-big</span><span class="i-code">0xe826</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="icon-left-big"></i> <span class="i-name">icon-left-big</span><span class="i-code">0xe827</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>
<div class="row"> <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: 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="icon-resize-full-alt"></i> <span class="i-name">icon-resize-full-alt</span><span class="i-code">0xe829</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="icon-resize-full"></i> <span class="i-name">icon-resize-full</span><span class="i-code">0xe82a</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="icon-resize-small"></i> <span class="i-name">icon-resize-small</span><span class="i-code">0xe82b</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>
<div class="row"> <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: 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="icon-resize-horizontal"></i> <span class="i-name">icon-resize-horizontal</span><span class="i-code">0xe82d</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="icon-resize-vertical"></i> <span class="i-name">icon-resize-vertical</span><span class="i-code">0xe82e</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="icon-zoom-in"></i> <span class="i-name">icon-zoom-in</span><span class="i-code">0xe82f</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>
<div class="row"> <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: 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="icon-zoom-out"></i> <span class="i-name">icon-zoom-out</span><span class="i-code">0xe831</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="icon-lightbulb"></i> <span class="i-name">icon-lightbulb</span><span class="i-code">0xe832</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="icon-clock"></i> <span class="i-name">icon-clock</span><span class="i-code">0xe833</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>
<div class="row"> <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: 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="icon-volume-down"></i> <span class="i-name">icon-volume-down</span><span class="i-code">0xe835</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="icon-volume-off"></i> <span class="i-name">icon-volume-off</span><span class="i-code">0xe836</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="icon-mute"></i> <span class="i-name">icon-mute</span><span class="i-code">0xe837</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>
<div class="row"> <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: 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="icon-endtime"></i> <span class="i-name">icon-endtime</span><span class="i-code">0xe839</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="icon-starttime"></i> <span class="i-name">icon-starttime</span><span class="i-code">0xe83a</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="icon-calendar-empty"></i> <span class="i-name">icon-calendar-empty</span><span class="i-code">0xe83b</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>
<div class="row"> <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: 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="icon-wrench"></i> <span class="i-name">icon-wrench</span><span class="i-code">0xe83d</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="icon-sliders"></i> <span class="i-name">icon-sliders</span><span class="i-code">0xe83e</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="icon-services"></i> <span class="i-name">icon-services</span><span class="i-code">0xe83f</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>
<div class="row"> <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: 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="icon-phone"></i> <span class="i-name">icon-phone</span><span class="i-code">0xe841</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="icon-file-pdf"></i> <span class="i-name">icon-file-pdf</span><span class="i-code">0xe842</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="icon-file-word"></i> <span class="i-name">icon-file-word</span><span class="i-code">0xe843</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>
<div class="row"> <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: 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="icon-doc-text"></i> <span class="i-name">icon-doc-text</span><span class="i-code">0xe845</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="icon-trash"></i> <span class="i-name">icon-trash</span><span class="i-code">0xe846</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="icon-comment-empty"></i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xe847</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>
<div class="row"> <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: 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="icon-chat"></i> <span class="i-name">icon-chat</span><span class="i-code">0xe849</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="icon-chat-empty"></i> <span class="i-name">icon-chat-empty</span><span class="i-code">0xe84a</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="icon-bell"></i> <span class="i-name">icon-bell</span><span class="i-code">0xe84b</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>
<div class="row"> <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: 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="icon-attention-alt"></i> <span class="i-name">icon-attention-alt</span><span class="i-code">0xe84d</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="icon-print"></i> <span class="i-name">icon-print</span><span class="i-code">0xe84e</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="icon-edit"></i> <span class="i-name">icon-edit</span><span class="i-code">0xe84f</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>
<div class="row"> <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: 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="icon-reply"></i> <span class="i-name">icon-reply</span><span class="i-code">0xe851</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="icon-reply-all"></i> <span class="i-name">icon-reply-all</span><span class="i-code">0xe852</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="icon-eye"></i> <span class="i-name">icon-eye</span><span class="i-code">0xe853</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>
<div class="row"> <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: 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="icon-tags"></i> <span class="i-name">icon-tags</span><span class="i-code">0xe855</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="icon-lock-open-alt"></i> <span class="i-name">icon-lock-open-alt</span><span class="i-code">0xe856</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="icon-lock-open"></i> <span class="i-name">icon-lock-open</span><span class="i-code">0xe857</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>
<div class="row"> <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: 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="icon-home"></i> <span class="i-name">icon-home</span><span class="i-code">0xe859</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="icon-info"></i> <span class="i-name">icon-info</span><span class="i-code">0xe85a</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="icon-help"></i> <span class="i-name">icon-help</span><span class="i-code">0xe85b</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>
<div class="row"> <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: 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="icon-flapping"></i> <span class="i-name">icon-flapping</span><span class="i-code">0xe85d</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="icon-rewind"></i> <span class="i-name">icon-rewind</span><span class="i-code">0xe85e</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="icon-chart-line"></i> <span class="i-name">icon-chart-line</span><span class="i-code">0xe85f</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>
<div class="row"> <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: 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="icon-bell-off-empty"></i> <span class="i-name">icon-bell-off-empty</span><span class="i-code">0xe861</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="icon-plug"></i> <span class="i-name">icon-plug</span><span class="i-code">0xe862</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="icon-eye-off"></i> <span class="i-name">icon-eye-off</span><span class="i-code">0xe863</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>
<div class="row"> <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: 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="icon-cw"></i> <span class="i-name">icon-cw</span><span class="i-code">0xe865</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="icon-host"></i> <span class="i-name">icon-host</span><span class="i-code">0xe866</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="icon-thumbs-up"></i> <span class="i-name">icon-thumbs-up</span><span class="i-code">0xe867</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>
<div class="row"> <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: 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="icon-spinner"></i> <span class="i-name">icon-spinner</span><span class="i-code">0xe869</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="icon-attach"></i> <span class="i-name">icon-attach</span><span class="i-code">0xe86a</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="icon-keyboard"></i> <span class="i-name">icon-keyboard</span><span class="i-code">0xe86b</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>
<div class="row"> <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: 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="icon-wifi"></i> <span class="i-name">icon-wifi</span><span class="i-code">0xe86d</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="icon-moon"></i> <span class="i-name">icon-moon</span><span class="i-code">0xe86e</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="icon-chart-pie"></i> <span class="i-name">icon-chart-pie</span><span class="i-code">0xe86f</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>
<div class="row"> <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: 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="icon-chart-bar"></i> <span class="i-name">icon-chart-bar</span><span class="i-code">0xe871</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="icon-beaker"></i> <span class="i-name">icon-beaker</span><span class="i-code">0xe872</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="icon-magic"></i> <span class="i-name">icon-magic</span><span class="i-code">0xe873</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>
<div class="row"> <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> </div>
<div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></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; namespace Icinga\Forms\Config\Resource;
use Exception;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Data\ConfigObject;
use Icinga\Data\ResourceFactory;
use Icinga\Application\Platform; 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) public function createElements(array $formData)
{ {
@ -107,35 +106,4 @@ class DbResourceForm extends Form
return $this; 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; namespace Icinga\Forms\Config\Resource;
use Exception;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Data\ConfigObject;
use Icinga\Data\ResourceFactory;
use Icinga\Protocol\Ldap\LdapConnection; 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) public function createElements(array $formData)
{ {
@ -132,39 +131,4 @@ class LdapResourceForm extends Form
return $this; 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; namespace Icinga\Forms\Config;
use InvalidArgumentException; 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\ConfigForm;
use Icinga\Forms\Config\Resource\DbResourceForm; use Icinga\Forms\Config\Resource\DbResourceForm;
use Icinga\Forms\Config\Resource\FileResourceForm; use Icinga\Forms\Config\Resource\FileResourceForm;
use Icinga\Forms\Config\Resource\LdapResourceForm; use Icinga\Forms\Config\Resource\LdapResourceForm;
use Icinga\Forms\Config\Resource\LivestatusResourceForm; use Icinga\Forms\Config\Resource\LivestatusResourceForm;
use Icinga\Forms\Config\Resource\SshResourceForm; use Icinga\Forms\Config\Resource\SshResourceForm;
use Icinga\Application\Platform; use Icinga\Web\Form;
use Icinga\Exception\ConfigurationError; use Icinga\Web\Notification;
class ResourceConfigForm extends ConfigForm class ResourceConfigForm extends ConfigForm
{ {
@ -23,6 +28,7 @@ class ResourceConfigForm extends ConfigForm
{ {
$this->setName('form_config_resource'); $this->setName('form_config_resource');
$this->setSubmitLabel($this->translate('Save Changes')); $this->setSubmitLabel($this->translate('Save Changes'));
$this->setValidatePartial(true);
} }
/** /**
@ -141,7 +147,9 @@ class ResourceConfigForm extends ConfigForm
$resourceForm = $this->getResourceForm($this->getElement('type')->getValue()); $resourceForm = $this->getResourceForm($this->getElement('type')->getValue());
if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) { 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()); $this->addElement($this->getForceCreationCheckbox());
return false; return false;
} }
@ -255,4 +263,103 @@ class ResourceConfigForm extends ConfigForm
$this->addElements($this->getResourceForm($resourceType)->createElements($formData)->getElements()); $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; namespace Icinga\Forms\Config\UserBackend;
use Exception;
use Icinga\Web\Form; 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 * 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) public function createElements(array $formData)
{ {
@ -56,6 +54,20 @@ class DbBackendForm extends Form
'description' => $this->translate( 'description' => $this->translate(
'The name of this authentication provider that is used to differentiate it from others' '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( $this->addElement(
@ -67,7 +79,7 @@ class DbBackendForm extends Form
'description' => $this->translate( 'description' => $this->translate(
'The database connection to use for authenticating with this provider' '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_combine($this->resources, $this->resources)
: array() : array()
) )
@ -80,49 +92,5 @@ class DbBackendForm extends Form
'value' => 'db' '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; 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\Data\ResourceFactory;
use Icinga\Exception\AuthenticationException; use Icinga\Web\Form;
use Icinga\Authentication\User\UserBackend;
/** /**
* Form class for adding/modifying LDAP user backends * 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) public function createElements(array $formData)
{ {
@ -60,6 +56,20 @@ class LdapBackendForm extends Form
'label' => $this->translate('Backend Name'), 'label' => $this->translate('Backend Name'),
'description' => $this->translate( 'description' => $this->translate(
'The name of this authentication provider that is used to differentiate it from others.' '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( 'description' => $this->translate(
'The LDAP connection to use for authenticating with this provider.' '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_combine($this->resources, $this->resources)
: array() : 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( $this->addElement(
'text', 'text',
'user_class', 'user_class',
@ -87,7 +151,7 @@ class LdapBackendForm extends Form
'disabled' => $isAd ?: null, 'disabled' => $isAd ?: null,
'label' => $this->translate('LDAP User Object Class'), 'label' => $this->translate('LDAP User Object Class'),
'description' => $this->translate('The object class used for storing users on the LDAP server.'), 'description' => $this->translate('The object class used for storing users on the LDAP server.'),
'value' => $isAd ? 'user' : 'inetOrgPerson' 'value' => $userClass
) )
); );
$this->addElement( $this->addElement(
@ -96,7 +160,7 @@ class LdapBackendForm extends Form
array( array(
'preserveDefault' => true, 'preserveDefault' => true,
'allowEmpty' => true, 'allowEmpty' => true,
'value' => $isAd ? '!(objectClass=computer)' : null, 'value' => $filter,
'label' => $this->translate('LDAP Filter'), 'label' => $this->translate('LDAP Filter'),
'description' => $this->translate( 'description' => $this->translate(
'An additional filter to use when looking up users using the specified connection. ' 'An additional filter to use when looking up users using the specified connection. '
@ -139,7 +203,7 @@ class LdapBackendForm extends Form
'description' => $this->translate( 'description' => $this->translate(
'The attribute name used for storing the user name on the LDAP server.' 'The attribute name used for storing the user name on the LDAP server.'
), ),
'value' => $isAd ? 'sAMAccountName' : 'uid' 'value' => $userNameAttribute
) )
); );
$this->addElement( $this->addElement(
@ -154,48 +218,15 @@ class LdapBackendForm extends Form
'text', 'text',
'base_dn', 'base_dn',
array( array(
'preserveDefault' => true,
'required' => false, 'required' => false,
'label' => $this->translate('LDAP Base DN'), 'label' => $this->translate('LDAP Base DN'),
'description' => $this->translate( 'description' => $this->translate(
'The path where users can be found on the LDAP server. Leave ' . 'The path where users can be found on the LDAP server. Leave ' .
'empty to select all users available using the specified connection.' '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; namespace Icinga\Forms\Config;
use InvalidArgumentException; use InvalidArgumentException;
use Icinga\Forms\ConfigForm;
use Icinga\Web\Notification;
use Icinga\Application\Config; use Icinga\Application\Config;
use Icinga\Application\Platform; use Icinga\Authentication\User\UserBackend;
use Icinga\Data\ConfigObject;
use Icinga\Data\ResourceFactory;
use Icinga\Exception\ConfigurationError; 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\DbBackendForm;
use Icinga\Forms\Config\UserBackend\LdapBackendForm; 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 class UserBackendConfigForm extends ConfigForm
{ {
/** /**
* The available resources split by type * The available user backend resources split by type
* *
* @var array * @var array
*/ */
protected $resources; protected $resources;
/**
* The backend to load when displaying the form for the first time
*
* @var string
*/
protected $backendToLoad;
/** /**
* Initialize this form * Initialize this form
*/ */
@ -31,20 +44,45 @@ class UserBackendConfigForm extends ConfigForm
{ {
$this->setName('form_config_authbackend'); $this->setName('form_config_authbackend');
$this->setSubmitLabel($this->translate('Save Changes')); $this->setSubmitLabel($this->translate('Save Changes'));
$this->setValidatePartial(true);
} }
/** /**
* Set the resource configuration to use * Set the resource configuration to use
* *
* @param Config $resources The resource configuration * @param Config $resourceConfig The resource configuration
* *
* @return $this * @return $this
*
* @throws ConfigurationError In case there are no valid resources for authentication available
*/ */
public function setResourceConfig(Config $resourceConfig) public function setResourceConfig(Config $resourceConfig)
{ {
$resources = array(); $resources = array();
foreach ($resourceConfig as $name => $resource) { 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; $this->resources = $resources;
@ -57,6 +95,8 @@ class UserBackendConfigForm extends ConfigForm
* @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 * @return Form
*
* @throws InvalidArgumentException In case the given backend type is invalid
*/ */
public function getBackendForm($type) 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 string $name
*
* @param array $values The values to extend the configuration with
* *
* @return $this * @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 (! $this->config->hasSection($name)) {
if (! $name) { throw new NotFoundError('No user backend called "%s" found', $name);
throw new InvalidArgumentException($this->translate('User backend name missing'));
} elseif ($this->config->hasSection($name)) {
throw new InvalidArgumentException($this->translate('User backend already exists'));
} }
unset($values['name']); $this->backendToLoad = $name;
$this->config->setSection($name, $values);
return $this; return $this;
} }
/** /**
* Edit a particular user backend * Add a new user backend
* *
* @param string $name The name of the backend to edit * The backend to add is identified by the array-key `name'.
* @param array $values The values to edit the configuration with
* *
* @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) { if (! isset($data['name'])) {
throw new InvalidArgumentException($this->translate('Old user backend name missing')); throw new InvalidArgumentException('Key \'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'));
} }
$backendConfig = $this->config->getSection($name); $backendName = $data['name'];
if ($newName !== $name) { if ($this->config->hasSection($backendName)) {
// Only remove the old entry if it has changed as the order gets screwed when editing backend names throw new IcingaException(
$this->config->removeSection($name); $this->translate('A user backend with the name "%s" does already exist'),
$backendName
);
} }
unset($values['name']); unset($data['name']);
$this->config->setSection($newName, $backendConfig->merge($values)); $this->config->setSection($backendName, $data);
return $backendConfig; 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) { if (! $this->config->hasSection($name)) {
throw new InvalidArgumentException($this->translate('user backend name missing')); throw new NotFoundError('No user backend called "%s" found', $name);
} elseif (! $this->config->hasSection($name)) {
throw new InvalidArgumentException($this->translate('Unknown user backend provided'));
} }
$backendConfig = $this->config->getSection($name); $backendConfig = $this->config->getSection($name);
if (isset($data['name'])) {
if ($data['name'] !== $name) {
$this->config->removeSection($name); $this->config->removeSection($name);
return $backendConfig; $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 $this;
} }
/** /**
@ -169,14 +231,12 @@ class UserBackendConfigForm extends ConfigForm
* *
* @return $this * @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) public function move($name, $position)
{ {
if (! $name) { if (! $this->config->hasSection($name)) {
throw new InvalidArgumentException($this->translate('User backend name missing')); throw new NotFoundError('No user backend called "%s" found', $name);
} elseif (! $this->config->hasSection($name)) {
throw new InvalidArgumentException($this->translate('Unknown user backend provided'));
} }
$backendOrder = $this->config->keys(); $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 * @param array $formData
* 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()
*/ */
public function createElements(array $formData) public function createElements(array $formData)
{ {
@ -302,7 +266,7 @@ class UserBackendConfigForm extends ConfigForm
if (isset($this->resources['db'])) { if (isset($this->resources['db'])) {
$backendTypes['db'] = $this->translate('Database'); $backendTypes['db'] = $this->translate('Database');
} }
if (isset($this->resources['ldap']) && ($backendType === 'ldap' || Platform::extensionLoaded('ldap'))) { if (isset($this->resources['ldap'])) {
$backendTypes['ldap'] = 'LDAP'; $backendTypes['ldap'] = 'LDAP';
$backendTypes['msldap'] = 'ActiveDirectory'; $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 // 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 * Populate the configuration of the backend to load
*
* @return ConfigObject
*/ */
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; namespace Icinga\Forms\Config;
use InvalidArgumentException;
use Icinga\Web\Notification;
use Icinga\Forms\ConfigForm; use Icinga\Forms\ConfigForm;
use Icinga\Exception\NotFoundError;
use Icinga\Web\Notification;
class UserBackendReorderForm extends ConfigForm 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) public function createElements(array $formData)
{ {
@ -39,8 +41,6 @@ class UserBackendReorderForm extends ConfigForm
/** /**
* Update the user backend order and save the configuration * Update the user backend order and save the configuration
*
* @see Form::onSuccess()
*/ */
public function onSuccess() public function onSuccess()
{ {
@ -55,8 +55,8 @@ class UserBackendReorderForm extends ConfigForm
} else { } else {
return false; return false;
} }
} catch (InvalidArgumentException $e) { } catch (NotFoundError $_) {
Notification::error($e->getMessage()); Notification::error(sprintf($this->translate('User backend "%s" not found'), $backendName));
} }
} }
} }

View File

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

View File

@ -54,6 +54,7 @@ $iframeClass = $isIframe ? ' iframe' : '';
<div id="layout" class="default-layout<?php if ($showFullscreen): ?> fullscreen-layout<?php endif ?>"> <div id="layout" class="default-layout<?php if ($showFullscreen): ?> fullscreen-layout<?php endif ?>">
<?= $this->render('body.phtml') ?> <?= $this->render('body.phtml') ?>
</div> </div>
<iframe id="fileupload-frame-target" name="fileupload-frame-target"></iframe>
<!--[if IE 8]> <!--[if IE 8]>
<script type="text/javascript" src="<?= $this->href($ie8jsfile) ?>"></script> <script type="text/javascript" src="<?= $this->href($ie8jsfile) ?>"></script>
<![endif]--> <![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 <?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use \Zend_View_Helper_FormElement;
/** /**
* Helper to generate a "datetime" element * 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>
<td data-base-target="_self"> <td data-base-target="_self">
<?php if ($i > 0): ?> <?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', '%s|%s',
$backendNames[$i], $backendNames[$i],
$i - 1 $i - 1
@ -43,11 +43,11 @@
$this->translate('Move user backend %s upwards'), $this->translate('Move user backend %s upwards'),
$backendNames[$i] $backendNames[$i]
); ?>"> ); ?>">
<?= $this->icon('up-big'); ?> <?= $this->icon('up-small'); ?>
</button> </button>
<?php endif; ?> <?php endif; ?>
<?php if ($i + 1 < count($backendNames)): ?> <?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', '%s|%s',
$backendNames[$i], $backendNames[$i],
$i + 1 $i + 1
@ -57,7 +57,7 @@
$this->translate('Move user backend %s downwards'), $this->translate('Move user backend %s downwards'),
$backendNames[$i] $backendNames[$i]
); ?>"> ); ?>">
<?= $this->icon('down-big'); ?> <?= $this->icon('down-small'); ?>
</button> </button>
<?php endif; ?> <?php endif; ?>
</td> </td>

View File

@ -46,8 +46,6 @@ Requires: %{name}-vendor-HTMLPurifier
Requires: %{name}-vendor-JShrink Requires: %{name}-vendor-JShrink
Requires: %{name}-vendor-lessphp Requires: %{name}-vendor-lessphp
Requires: %{name}-vendor-Parsedown Requires: %{name}-vendor-Parsedown
Requires: %{zend}
Obsoletes: %{name}-vendor-zend
%description %description
@ -84,6 +82,10 @@ Requires: %{php}-gd %{php}-intl
%{?fedora:Requires: php-pecl-imagick} %{?fedora:Requires: php-pecl-imagick}
%{?rhel:Requires: php-pecl-imagick} %{?rhel:Requires: php-pecl-imagick}
%{?suse_version:Requires: %{php}-gettext %{php}-json %{php}-openssl %{php}-posix} %{?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 %description -n php-Icinga
Icinga Web 2 PHP library 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\FileWriter;
use Icinga\Application\Logger\Writer\SyslogWriter; use Icinga\Application\Logger\Writer\SyslogWriter;
use Icinga\Exception\ConfigurationError; use Icinga\Exception\ConfigurationError;
use Icinga\Exception\IcingaException;
/** /**
* Logger * Logger
@ -226,13 +227,7 @@ class Logger
$messages = array(); $messages = array();
$error = $message; $error = $message;
do { do {
$messages[] = sprintf( $messages[] = IcingaException::describe($error);
'%s in %s:%d with message: %s',
get_class($error),
$error->getFile(),
$error->getLine(),
$error->getMessage()
);
} while ($error = $error->getPrevious()); } while ($error = $error->getPrevious());
$message = implode(' <- ', $messages); $message = implode(' <- ', $messages);
} }

View File

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

View File

@ -4,6 +4,7 @@
namespace Icinga\Cli; namespace Icinga\Cli;
use Icinga\Application\ApplicationBootstrap as App; use Icinga\Application\ApplicationBootstrap as App;
use Icinga\Exception\IcingaException;
use Icinga\Exception\ProgrammingError; use Icinga\Exception\ProgrammingError;
use Icinga\Cli\Params; use Icinga\Cli\Params;
use Icinga\Cli\Screen; use Icinga\Cli\Screen;
@ -265,7 +266,8 @@ class Loader
if ($obj && $obj instanceof Command && $obj->showTrace()) { if ($obj && $obj instanceof Command && $obj->showTrace()) {
echo $this->formatTrace($e->getTrace()); 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) { if ($entry instanceof Inspection) {
$this->log[$entry->description] = $entry->toArray(); $this->log[$entry->description] = $entry->toArray();
} else { } else {
Logger::debug($entry);
$this->log[] = $entry; $this->log[] = $entry;
} }
} }
@ -77,7 +78,8 @@ class Inspection
if (isset($this->error)) { if (isset($this->error)) {
throw new ProgrammingError('Inspection object used after error'); throw new ProgrammingError('Inspection object used after error');
} }
$this->write($entry); Logger::error($entry);
$this->log[] = $entry;
$this->error = $entry; $this->error = $entry;
return $this; 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; namespace Icinga\Data;
use Countable; interface QueryInterface extends Fetchable, Filterable, Paginatable, Sortable {};
interface QueryInterface extends Fetchable, Filterable, Limitable, Sortable, Countable {};

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()); $e = new ReflectionClass(get_called_class());
return $e->newInstanceArgs($args); 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() public function bind()
{ {
if ($this->bound) { if ($this->bound) {
return; return $this;
} }
$ds = $this->getConnection(); $ds = $this->getConnection();
@ -332,6 +332,7 @@ class LdapConnection implements Selectable, Inspectable
} }
$this->bound = true; $this->bound = true;
return $this;
} }
/** /**

View File

@ -78,7 +78,7 @@ abstract class Repository implements Selectable
protected $filterColumns; 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 * This may be initialized by concrete repository implementations, in the following format
* <pre><code> * <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. * 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\Application\Logger;
use Icinga\Data\QueryInterface; use Icinga\Data\QueryInterface;
use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\Filter;
use Icinga\Data\SortRules;
use Icinga\Exception\QueryException; use Icinga\Exception\QueryException;
/** /**
* Query class supposed to mediate between a repository and its datasource's query * 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 * The repository being used
@ -212,6 +213,16 @@ class RepositoryQuery implements QueryInterface, Iterator
return $this->query->getFilter(); 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 * 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) public function order($field = null, $direction = null, $ignoreDefault = false)
{ {
$sortRules = $this->repository->getSortRules(); $sortRules = $this->getSortRules();
if ($field === null) { if ($field === null) {
// Use first available sort rule as default // Use first available sort rule as default
if (empty($sortRules)) { if (empty($sortRules)) {

View File

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

View File

@ -96,6 +96,9 @@ class ActionController extends Zend_Controller_Action
if ($this->rerenderLayout = $request->getUrl()->shift('renderLayout')) { if ($this->rerenderLayout = $request->getUrl()->shift('renderLayout')) {
$this->xhrLayout = 'body'; $this->xhrLayout = 'body';
} }
if ($request->getUrl()->shift('_disableLayout')) {
$this->_helper->layout()->disableLayout();
}
if ($this->requiresLogin()) { if ($this->requiresLogin()) {
$this->redirectToLogin(Url::fromRequest()); $this->redirectToLogin(Url::fromRequest());
@ -455,11 +458,11 @@ class ActionController extends Zend_Controller_Action
foreach ($notifications->getMessages() as $m) { foreach ($notifications->getMessages() as $m) {
$notificationList[] = rawurlencode($m->type . ' ' . $m->message); $notificationList[] = rawurlencode($m->type . ' ' . $m->message);
} }
$resp->setHeader('X-Icinga-Notification', implode('&', $notificationList)); $resp->setHeader('X-Icinga-Notification', implode('&', $notificationList), true);
} }
if ($this->reloadCss) { if ($this->reloadCss) {
$resp->setHeader('X-Icinga-CssReload', 'now'); $resp->setHeader('X-Icinga-CssReload', 'now', true);
} }
if ($this->view->title) { if ($this->view->title) {
@ -469,18 +472,19 @@ class ActionController extends Zend_Controller_Action
} }
$resp->setHeader( $resp->setHeader(
'X-Icinga-Title', 'X-Icinga-Title',
rawurlencode($this->view->title . ' :: Icinga Web') rawurlencode($this->view->title . ' :: Icinga Web'),
true
); );
} else { } else {
$resp->setHeader('X-Icinga-Title', rawurlencode('Icinga Web')); $resp->setHeader('X-Icinga-Title', rawurlencode('Icinga Web'), true);
} }
if ($this->rerenderLayout) { if ($this->rerenderLayout) {
$this->getResponse()->setHeader('X-Icinga-Container', 'layout'); $this->getResponse()->setHeader('X-Icinga-Container', 'layout', true);
} }
if ($this->autorefreshInterval !== null) { 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; namespace Icinga\Web;
use LogicException;
use Zend_Config; use Zend_Config;
use Zend_Form; use Zend_Form;
use Zend_Form_Element; use Zend_Form_Element;
use Zend_View_Interface; use Zend_View_Interface;
use Icinga\Application\Icinga; use Icinga\Application\Icinga;
use Icinga\Authentication\Manager; use Icinga\Authentication\Manager;
use Icinga\Exception\ProgrammingError;
use Icinga\Security\SecurityException; use Icinga\Security\SecurityException;
use Icinga\Util\Translator; use Icinga\Util\Translator;
use Icinga\Web\Form\ErrorLabeller; use Icinga\Web\Form\ErrorLabeller;
@ -84,7 +84,7 @@ class Form extends Zend_Form
/** /**
* The url to redirect to upon success * The url to redirect to upon success
* *
* @var string|Url * @var Url
*/ */
protected $redirectUrl; protected $redirectUrl;
@ -160,6 +160,13 @@ class Form extends Zend_Form
*/ */
protected $notifications; protected $notifications;
/**
* The hints of this form
*
* @var array
*/
protected $hints;
/** /**
* Whether the Autosubmit decorator should be applied to this form * Whether the Autosubmit decorator should be applied to this form
* *
@ -222,12 +229,12 @@ class Form extends Zend_Form
* *
* @return $this * @return $this
* *
* @throws LogicException If the callback is not callable * @throws ProgrammingError If the callback is not callable
*/ */
public function setOnSuccess($onSuccess) public function setOnSuccess($onSuccess)
{ {
if (! is_callable($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; $this->onSuccess = $onSuccess;
return $this; return $this;
@ -262,9 +269,17 @@ class Form extends Zend_Form
* @param string|Url $url The url to redirect to * @param string|Url $url The url to redirect to
* *
* @return $this * @return $this
*
* @throws ProgrammingError In case $url is neither a string nor a instance of Icinga\Web\Url
*/ */
public function setRedirectUrl($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; $this->redirectUrl = $url;
return $this; return $this;
} }
@ -272,14 +287,16 @@ class Form extends Zend_Form
/** /**
* Return the url to redirect to upon success * Return the url to redirect to upon success
* *
* @return string|Url * @return Url
*/ */
public function getRedirectUrl() public function getRedirectUrl()
{ {
if ($this->redirectUrl === null) { if ($this->redirectUrl === null) {
$url = Url::fromRequest(array(), $this->getRequest()); $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 // 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->redirectUrl->without(array_keys($this->getElements()));
}
} }
return $this->redirectUrl; return $this->redirectUrl;
@ -566,6 +583,49 @@ class Form extends Zend_Form
return $this->notifications; 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 * 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()) public function create(array $formData = array())
{ {
if (false === $this->created) { if (! $this->created) {
$this->createElements($formData); $this->createElements($formData);
$this->addFormIdentification() $this->addFormIdentification()
->addCsrfCounterMeasure() ->addCsrfCounterMeasure()
->addSubmitButton(); ->addSubmitButton();
if ($this->getAttrib('action') === null) {
// Use Form::getAttrib() instead of Form::getAction() here because we want to explicitly check against // 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. // 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 // For not setting the action attribute use Form::setAction(''). This is required for for the
// accessibility's enable/disable auto-refresh mechanic // accessibility's enable/disable auto-refresh mechanic
if ($this->getAttrib('action') === null) {
$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. // 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 // We MUST set an action as JS gets confused otherwise, if
// this form is being displayed in an additional column // this form is being displayed in an additional column
$this->setAction(Url::fromRequest()->without(array_keys($this->getElements()))); $this->setAction($action);
} }
$this->created = true; $this->created = true;
@ -862,7 +926,7 @@ class Form extends Zend_Form
*/ */
public function addFormIdentification() public function addFormIdentification()
{ {
if (false === $this->uidDisabled && $this->getElement($this->uidElementName) === null) { if (! $this->uidDisabled && $this->getElement($this->uidElementName) === null) {
$this->addElement( $this->addElement(
'hidden', 'hidden',
$this->uidElementName, $this->uidElementName,
@ -884,7 +948,7 @@ class Form extends Zend_Form
*/ */
public function addCsrfCounterMeasure() 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)); $this->addElement(new CsrfCounterMeasure($this->tokenElementName));
} }
@ -946,12 +1010,20 @@ class Form extends Zend_Form
$formData = $this->getRequestData(); $formData = $this->getRequestData();
if ($this->getUidDisabled() || $this->wasSent($formData)) { 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 $this->populate($formData); // Necessary to get isSubmitted() to work
if (! $this->getSubmitLabel() || $this->isSubmitted()) { if (! $this->getSubmitLabel() || $this->isSubmitted()) {
if ($this->isValid($formData) if ($this->isValid($formData)
&& (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $this)) && (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $this))
|| ($this->onSuccess === null && false !== $this->onSuccess()))) { || ($this->onSuccess === null && false !== $this->onSuccess()))) {
if (! $frameUpload) {
$this->getResponse()->redirectAndExit($this->getRedirectUrl()); $this->getResponse()->redirectAndExit($this->getRedirectUrl());
} else {
$this->getView()->layout()->redirectUrl = $this->getRedirectUrl()->getAbsoluteUrl();
}
} }
} elseif ($this->getValidatePartial()) { } elseif ($this->getValidatePartial()) {
// The form can't be processed but we may want to show validation errors though // 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')); ->addDecorator('HtmlTag', array('tag' => 'div', 'class' => 'header'));
} }
$this->addDecorator('FormErrors', array('onlyCustomFormErrors' => true)) $this->addDecorator('FormDescriptions')
->addDecorator('FormNotifications') ->addDecorator('FormNotifications')
->addDecorator('FormDescriptions') ->addDecorator('FormErrors', array('onlyCustomFormErrors' => true))
->addDecorator('FormElements') ->addDecorator('FormElements')
->addDecorator('FormHints')
//->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form')) //->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
->addDecorator('Form'); ->addDecorator('Form');
} }

View File

@ -7,35 +7,10 @@ use Zend_Form_Decorator_Abstract;
use Icinga\Web\Form; use Icinga\Web\Form;
/** /**
* Decorator to add a list of descriptions at the top of a form * Decorator to add a list of descriptions at the top or bottom of a form
*
* The description for required form elements is automatically being handled.
*/ */
class FormDescriptions extends Zend_Form_Decorator_Abstract 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 * Render form descriptions
* *
@ -55,18 +30,7 @@ class FormDescriptions extends Zend_Form_Decorator_Abstract
return $content; return $content;
} }
$descriptions = $this->recurseForm($form, $entirelyRequired); $descriptions = $this->recurseForm($form);
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()
));
}
if (empty($descriptions)) { if (empty($descriptions)) {
return $content; return $content;
} }
@ -93,52 +57,14 @@ class FormDescriptions extends Zend_Form_Decorator_Abstract
* Recurse the given form and return the descriptions for it and all of its subforms * Recurse the given form and return the descriptions for it and all of its subforms
* *
* @param Form $form The form to recurse * @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 * @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()); $descriptions = array($form->getDescriptions());
foreach ($form->getSubForms() as $subForm) { foreach ($form->getSubForms() as $subForm) {
$descriptions[] = $this->recurseForm($subForm, $entirelyRequired, $elementsPassed); $descriptions[] = $this->recurseForm($subForm);
}
if ($entirelyRequired) {
foreach ($requiredLabels as $label) {
$label->setRequiredSuffix('');
}
} }
return call_user_func_array('array_merge', $descriptions); 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 BadMethodCallException;
use Zend_Translate_Adapter; use Zend_Translate_Adapter;
use Zend_Validate_NotEmpty; use Zend_Validate_NotEmpty;
use Zend_Validate_File_MimeType;
use Icinga\Web\Form\Validator\DateTimeValidator; use Icinga\Web\Form\Validator\DateTimeValidator;
use Icinga\Web\Form\Validator\ReadablePathValidator; use Icinga\Web\Form\Validator\ReadablePathValidator;
use Icinga\Web\Form\Validator\WritablePathValidator; use Icinga\Web\Form\Validator\WritablePathValidator;
@ -43,6 +44,11 @@ class ErrorLabeller extends Zend_Translate_Adapter
return array( return array(
Zend_Validate_NotEmpty::IS_EMPTY => sprintf(t('%s is required and must not be empty'), $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::NOT_WRITABLE => sprintf(t('%s is not writable', 'config.path'), $label),
WritablePathValidator::DOES_NOT_EXIST => sprintf(t('%s does not exist', '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), ReadablePathValidator::NOT_READABLE => sprintf(t('%s is not readable', 'config.path'), $label),

View File

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

View File

@ -118,7 +118,13 @@ class MenuRenderer extends RecursiveIteratorIterator
try { try {
return $child->getRenderer()->render($child); return $child->getRenderer()->render($child);
} catch (Exception $e) { } 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 = new LessCompiler();
$less->disableExtendedImport();
foreach ($lessFiles as $file) { foreach ($lessFiles as $file) {
$less->addFile($file); $less->addFile($file);
} }

View File

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

View File

@ -3,30 +3,26 @@
namespace Icinga\Web\Widget; namespace Icinga\Web\Widget;
use Icinga\Application\Icinga;
use Icinga\Data\Sortable;
use Icinga\Data\SortRules;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Web\Request; use Icinga\Web\Request;
use Icinga\Data\Sortable;
use Icinga\Application\Icinga;
/** /**
* SortBox widget * SortBox widget
* *
* The "SortBox" Widget allows you to create a generic sort input for sortable views. It automatically creates a form * The "SortBox" Widget allows you to create a generic sort input for sortable views. It automatically creates a select
* containing a select box with all sort options and a dropbox with the sort direction. It also handles automatic * box with all sort options and a dropbox with the sort direction. It also handles automatic submission of sorting
* submission of sorting changes and draws an additional submit button when JavaScript is disabled. * 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 * 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. * to make sure the form is correctly populated when a request with a sort parameter is being made.
* *
* Example: * Call setQuery in case you'll do not want to handle URL parameters manually, but to automatically apply the user's
* <pre><code> * chosen sort rules on the given sortable query. This will also allow the SortBox to display the user the correct
* $this->view->sortControl = new SortBox( * default sort rules if the given query provides already some sort rules.
* $this->getRequest()->getActionName(),
* $columns
* );
* $this->view->sortControl->setRequest($this->getRequest());
* </code></pre>
*/ */
class SortBox extends AbstractWidget class SortBox extends AbstractWidget
{ {
@ -38,25 +34,25 @@ class SortBox extends AbstractWidget
protected $sortFields; protected $sortFields;
/** /**
* The name of the form that will be created * The name used to uniquely identfy the forms being created
* *
* @var string * @var string
*/ */
protected $name; protected $name;
/** /**
* A request object used for initial form population * The request to fetch sort rules from
* *
* @var Request * @var Request
*/ */
protected $request; protected $request;
/** /**
* What to apply sort parameters on * The query to apply sort rules on
* *
* @var Sortable * @var Sortable
*/ */
protected $query = null; protected $query;
/** /**
* Create a SortBox with the entries from $sortFields * 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 * @return $this
*/ */
@ -97,6 +93,8 @@ class SortBox extends AbstractWidget
} }
/** /**
* Set the query to apply sort rules on
*
* @param Sortable $query * @param Sortable $query
* *
* @return $this * @return $this
@ -107,19 +105,54 @@ class SortBox extends AbstractWidget
return $this; 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) public function handleRequest(Request $request = null)
{ {
if ($this->query !== null) { if ($this->query !== null) {
if ($request === null) { if ($request === null) {
$request = Icinga::app()->getFrontController()->getRequest(); $request = Icinga::app()->getFrontController()->getRequest();
} }
if ($sort = $request->getParam('sort')) {
if (($sort = $request->getParam('sort'))) {
$this->query->order($sort, $request->getParam('dir')); $this->query->order($sort, $request->getParam('dir'));
} elseif (($dir = $request->getParam('dir'))) {
$this->query->order(null, $dir);
} }
} }
return $this; 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 * Render this SortBox as HTML
* *
@ -127,43 +160,68 @@ class SortBox extends AbstractWidget
*/ */
public function render() public function render()
{ {
$form = new Form(); $columnForm = new Form();
$form->setTokenDisabled(); $columnForm->setTokenDisabled();
$form->setName($this->name); $columnForm->setName($this->name . '-column');
$form->setAttrib('class', 'sort-control inline'); $columnForm->setAttrib('class', 'inline');
$columnForm->addElement(
$form->addElement(
'select', 'select',
'sort', 'sort',
array( array(
'autosubmit' => true, 'autosubmit' => true,
'label' => $this->view()->translate('Sort by'), 'label' => $this->view()->translate('Sort by'),
'multiOptions' => $this->sortFields 'multiOptions' => $this->sortFields,
) 'decorators' => array(
);
$form->getElement('sort')->setDecorators(array(
array('ViewHelper'), array('ViewHelper'),
array('Label') array('Label')
)); )
$form->addElement( )
);
$orderForm = new Form();
$orderForm->setTokenDisabled();
$orderForm->setName($this->name . '-order');
$orderForm->setAttrib('class', 'inline');
$orderForm->addElement(
'select', 'select',
'dir', 'dir',
array( array(
'autosubmit' => true, 'autosubmit' => true,
'label' => $this->view()->translate('Direction', 'sort direction'),
'multiOptions' => array( 'multiOptions' => array(
'asc' => 'Asc', 'asc' => $this->view()->translate('Ascending', 'sort direction'),
'desc' => 'Desc', 'desc' => $this->view()->translate('Descending', 'sort direction')
), ),
'decorators' => array( 'decorators' => array(
array('ViewHelper') array('ViewHelper'),
array('Label', array('class' => 'no-js'))
) )
) )
); );
$column = null;
if ($this->request) { 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() private function renderRefreshTab()
{ {
$url = Url::fromRequest()->without('renderLayout'); $url = Icinga::app()->getFrontController()->getRequest()->getUrl();
$tab = $this->get($this->getActiveName()); $tab = $this->get($this->getActiveName());
if ($tab !== null) { if ($tab !== null) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,7 +4,7 @@
namespace Icinga\Module\Monitoring\Forms\Command\Object; namespace Icinga\Module\Monitoring\Forms\Command\Object;
use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand; 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; use Icinga\Web\Notification;
/** /**
@ -20,8 +20,7 @@ class DeleteCommentsCommandForm extends CommandForm
protected $comments; protected $comments;
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Zend_Form::init() For the method documentation.
*/ */
public function init() public function init()
{ {
@ -29,8 +28,7 @@ class DeleteCommentsCommandForm extends CommandForm
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::createElements() For the method documentation.
*/ */
public function createElements(array $formData = array()) public function createElements(array $formData = array())
{ {
@ -45,8 +43,7 @@ class DeleteCommentsCommandForm extends CommandForm
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
*/ */
public function getSubmitLabel() public function getSubmitLabel()
{ {
@ -54,8 +51,7 @@ class DeleteCommentsCommandForm extends CommandForm
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
*/ */
public function onSuccess() public function onSuccess()
{ {
@ -78,7 +74,7 @@ class DeleteCommentsCommandForm extends CommandForm
* *
* @param array $comments * @param array $comments
* *
* @return this fluent interface * @return $this
*/ */
public function setComments(array $comments) public function setComments(array $comments)
{ {

View File

@ -4,7 +4,7 @@
namespace Icinga\Module\Monitoring\Forms\Command\Object; namespace Icinga\Module\Monitoring\Forms\Command\Object;
use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand; 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; use Icinga\Web\Notification;
/** /**
@ -13,8 +13,7 @@ use Icinga\Web\Notification;
class DeleteDowntimeCommandForm extends CommandForm class DeleteDowntimeCommandForm extends CommandForm
{ {
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Zend_Form::init() For the method documentation.
*/ */
public function init() public function init()
{ {
@ -22,8 +21,7 @@ class DeleteDowntimeCommandForm extends CommandForm
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::createElements() For the method documentation.
*/ */
public function createElements(array $formData = array()) public function createElements(array $formData = array())
{ {
@ -59,8 +57,7 @@ class DeleteDowntimeCommandForm extends CommandForm
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::addSubmitButton() For the method documentation.
*/ */
public function addSubmitButton() public function addSubmitButton()
{ {
@ -81,8 +78,7 @@ class DeleteDowntimeCommandForm extends CommandForm
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
*/ */
public function onSuccess() public function onSuccess()
{ {

View File

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

View File

@ -109,7 +109,10 @@ class BackendConfigForm extends ConfigForm
$backendName = $data['name']; $backendName = $data['name'];
if ($this->config->hasSection($backendName)) { 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']); unset($data['name']);
@ -309,11 +312,16 @@ class BackendConfigForm extends ConfigForm
return false; return false;
} }
if (($el = $this->getElement('skip_validation')) === null || false === $el->isChecked()) {
$resourceConfig = ResourceFactory::getResourceConfig($this->getValue('resource')); $resourceConfig = ResourceFactory::getResourceConfig($this->getValue('resource'));
if (! self::isValidIdoSchema($this, $resourceConfig) || !self::isValidIdoInstance($this, $resourceConfig)) { if (! self::isValidIdoSchema($this, $resourceConfig) || !self::isValidIdoInstance($this, $resourceConfig)) {
if ($el === null) {
$this->addSkipValidationCheckbox(); $this->addSkipValidationCheckbox();
}
return false; return false;
} }
}
return true; return true;
} }

View File

@ -95,7 +95,10 @@ class InstanceConfigForm extends ConfigForm
$instanceName = $data['name']; $instanceName = $data['name'];
if ($this->config->hasSection($instanceName)) { 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']); unset($data['name']);

View File

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

View File

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

View File

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

View File

@ -60,5 +60,8 @@ class ProgramstatusQuery extends IdoQuery
if (version_compare($this->getIdoVersion(), '1.11.8', '<')) { if (version_compare($this->getIdoVersion(), '1.11.8', '<')) {
$this->columnMap['programstatus']['program_version'] = '(NULL)'; $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 * 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; return $this;
} }
} }

View File

@ -27,17 +27,20 @@ class DeleteDowntimeCommand extends IcingaCommand
/** /**
* Set if this command affects a service * 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 whether the command affects a service
* *
* @return type * @return bool
*/ */
public function getIsService() public function getIsService()
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,13 +1,13 @@
<?php <?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /* 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; use Icinga\Exception\IcingaException;
/** /**
* Exception thrown if a command was not sent * 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; namespace Icinga\Module\Monitoring\Web\Menu;
use Icinga\Web\Menu as Menu; use Icinga\Web\Menu;
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
use Icinga\Web\Menu\MenuItemRenderer; use Icinga\Web\Menu\MenuItemRenderer;
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
class BackendAvailabilityMenuItemRenderer extends MenuItemRenderer 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() protected function isCurrentlyRunning()
{ {
return MonitoringBackend::instance()->select()->from( $programStatus = MonitoringBackend::instance()
->select()
->from(
'programstatus', 'programstatus',
array( array('is_currently_running')
'is_currently_running'
) )
)->getQuery()->fetchRow()->is_currently_running; ->fetchRow();
return $programStatus !== false ? (bool) $programStatus : false;
} }
/** /**
* @see MenuItemRenderer::render() * {@inheritdoc}
*/ */
public function render(Menu $menu) public function render(Menu $menu)
{ {
return $this->getBadge() . $this->createLink($menu); return $this->getBadge() . $this->createLink($menu);
} }
/**
* Get the problem badge HTML
*
* @return string
*/
protected function getBadge() protected function getBadge()
{ {
if (! (bool)$this->isCurrentlyRunning()) { if (! $this->isCurrentlyRunning()) {
return sprintf( return sprintf(
'<div title="%s" class="badge-container"><span class="badge badge-critical">%s</span></div>', '<div title="%s" class="badge-container"><span class="badge badge-critical">%d</span></div>',
mt('monitoring', 'monitoring backend is not running'), sprintf(
mt('monitoring', 'Monitoring backend %s is not running'), MonitoringBackend::instance()->getName()
),
1 1
); );
} }
@ -51,10 +60,12 @@ class BackendAvailabilityMenuItemRenderer extends MenuItemRenderer
*/ */
public function getSummary() public function getSummary()
{ {
if (! (bool)$this->isCurrentlyRunning()) { if (! $this->isCurrentlyRunning()) {
return array( return array(
'problems' => 1, 'problems' => 1,
'title' => mt('monitoring', 'monitoring backend is not running') 'title' => sprintf(
mt('monitoring', 'Monitoring backend %s is not running'), MonitoringBackend::instance()->getName()
)
); );
} }
return null; return null;

View File

@ -89,9 +89,6 @@ class AdminAccountPage extends Form
} }
if (count($choices) > 1) { 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( $this->addElement(
'select', 'select',
'user_type', 'user_type',
@ -99,6 +96,7 @@ class AdminAccountPage extends Form
'required' => true, 'required' => true,
'autosubmit' => true, 'autosubmit' => true,
'label' => $this->translate('Type Of Definition'), 'label' => $this->translate('Type Of Definition'),
'description' => $this->translate('Choose how to define the desired account.'),
'multiOptions' => $choices, 'multiOptions' => $choices,
'value' => $choice 'value' => $choice
) )
@ -124,7 +122,7 @@ class AdminAccountPage extends Form
'label' => $this->translate('Username'), 'label' => $this->translate('Username'),
'description' => $this->translate( 'description' => $this->translate(
'Define the initial administrative account by providing a username that reflects' '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'), 'label' => $this->translate('Username'),
'description' => sprintf( 'description' => sprintf(
$this->translate( $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' 'setup.admin'
), ),
$this->backendConfig['backend'] === 'db' $this->backendConfig['backend'] === 'db'
@ -159,7 +157,7 @@ class AdminAccountPage extends Form
'required' => true, 'required' => true,
'label' => $this->translate('Username'), 'label' => $this->translate('Username'),
'description' => $this->translate( '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, 'required' => true,
'renderPassword' => true, 'renderPassword' => true,
'label' => $this->translate('Password'), '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( $this->addElement(
@ -181,7 +181,7 @@ class AdminAccountPage extends Form
'renderPassword' => true, 'renderPassword' => true,
'label' => $this->translate('Repeat password'), 'label' => $this->translate('Repeat password'),
'description' => $this->translate( '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( 'validators' => array(
array('identical', false, array('new_user_password')) array('identical', false, array('new_user_password'))

View File

@ -3,11 +3,12 @@
namespace Icinga\Module\Setup\Forms; 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\DbBackendForm;
use Icinga\Forms\Config\UserBackend\LdapBackendForm; use Icinga\Forms\Config\UserBackend\LdapBackendForm;
use Icinga\Forms\Config\UserBackend\ExternalBackendForm; use Icinga\Forms\Config\UserBackend\ExternalBackendForm;
use Icinga\Data\ConfigObject; use Icinga\Web\Form;
/** /**
* Wizard page to define authentication backend specific details * Wizard page to define authentication backend specific details
@ -66,14 +67,14 @@ class AuthBackendPage extends Form
$this->setRequiredCue(null); $this->setRequiredCue(null);
$backendForm = new DbBackendForm(); $backendForm = new DbBackendForm();
$backendForm->setRequiredCue(null); $backendForm->setRequiredCue(null);
$backendForm->createElements($formData)->removeElement('resource'); $backendForm->create($formData)->removeElement('resource');
$this->addDescription($this->translate( $this->addDescription($this->translate(
'As you\'ve chosen to use a database for authentication all you need ' '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.' . 'to do now is defining a name for your first authentication backend.'
)); ));
} elseif ($this->config['type'] === 'ldap') { } elseif ($this->config['type'] === 'ldap') {
$backendForm = new LdapBackendForm(); $backendForm = new LdapBackendForm();
$backendForm->createElements($formData)->removeElement('resource'); $backendForm->create($formData)->removeElement('resource');
$this->addDescription($this->translate( $this->addDescription($this->translate(
'Before you are able to authenticate using the LDAP connection defined earlier you need to' '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.' . ' 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' } else { // $this->config['type'] === 'external'
$backendForm = new ExternalBackendForm(); $backendForm = new ExternalBackendForm();
$backendForm->createElements($formData); $backendForm->create($formData);
$this->addDescription($this->translate( $this->addDescription($this->translate(
'You\'ve chosen to authenticate using a web server\'s mechanism so it may be necessary' '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.' . ' to adjust usernames before any permissions, restrictions, etc. are being applied.'
)); ));
} }
$this->addElements($backendForm->getElements()); $backendForm->getElement('name')->setValue('icingaweb2');
$this->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,7 +133,7 @@ class AuthBackendPage extends Form
*/ */
public function isValid($data) public function isValid($data)
{ {
if (false === parent::isValid($data)) { if (! parent::isValid($data)) {
return false; return false;
} }
@ -130,7 +146,9 @@ class AuthBackendPage extends Form
'value' => $this->getResourceConfig() 'value' => $this->getResourceConfig()
) )
); );
if (! LdapBackendForm::isValidUserBackend($self)) { $inspection = UserBackendConfigForm::inspectUserBackend($self);
if ($inspection && $inspection->hasError()) {
$this->error($inspection->getError());
$this->addSkipValidationCheckbox(); $this->addSkipValidationCheckbox();
return false; return false;
} }

View File

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

View File

@ -1,6 +1,6 @@
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
form.sort-control { div.sort-control {
.dontprint; .dontprint;
float: right; float: right;
@ -15,7 +15,13 @@ form.sort-control {
} }
select[name=dir] { select[name=dir] {
width: 5em; width: 8em;
margin-left: 0; 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; font-weight: bold;
} }
input, select { input, select, textarea {
box-sizing: border-box; box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
@ -44,10 +44,19 @@ input[type=submit] {
font-weight: bold; font-weight: bold;
text-align: center; text-align: center;
color: #fff; color: #fff;
border: 2px solid #ddd; border: 1px solid;
border-color: @colorPetrol; border-color: @colorPetrol;
background: @colorPetrol; background: @colorPetrol;
outline: 0; 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 { input[type=submit]:hover, a.button:hover, input[type=submit]:focus {
@ -87,10 +96,6 @@ button::-moz-focus-inner {
outline: 0; outline: 0;
} }
button {
cursor: pointer;
}
select::-moz-focus-inner { select::-moz-focus-inner {
border: 0; border: 0;
outline: 0; outline: 0;
@ -190,7 +195,8 @@ form ul.form-notifications {
} }
form div.element { form div.element {
margin: 0.5em 0; margin-top: 0.5em;
margin-bottom: 0.5em;
} }
form label { form label {
@ -200,6 +206,14 @@ form label {
width: 10em; width: 10em;
} }
form div.element > * {
vertical-align: top;
}
form dt {
vertical-align: top;
}
select, input[type=text], textarea { select, input[type=text], textarea {
width: 20em; width: 20em;
display: inline-block; 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 { #responsive-debug {
font-size: 0.9em; font-size: 0.9em;
font-family: Courier new, monospace; font-family: Courier new, monospace;
@ -401,3 +405,13 @@ html {
padding-top: 0em; padding-top: 0em;
font-size: 0.9em; 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; 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 { a {
color: #39a; color: #39a;
} }
@ -104,7 +113,7 @@ table.benchmark {
.info-box { .info-box {
padding: 0.5em; padding: 0.5em;
border: 1px solid lightgrey; border: 1px solid lightgrey;
background-color: #fbfcc5; background-color: #f2f4fd;
} }
/* Action table */ /* Action table */

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