mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-04-08 17:15:08 +02:00
Merge branch 'master' into feature/secure-modules-9644
Conflicts: library/Icinga/Exception/IcingaException.php
This commit is contained in:
commit
7cfc78558d
@ -3,7 +3,7 @@
|
||||
set -e
|
||||
|
||||
if which puppet >/dev/null 2>&1; then
|
||||
exit 0
|
||||
exit 0
|
||||
fi
|
||||
|
||||
RELEASEVER=$(rpm -q --qf "%{VERSION}" $(rpm -q --whatprovides redhat-release))
|
||||
@ -20,7 +20,7 @@ esac
|
||||
|
||||
echo "Adding puppet repository.."
|
||||
rpm --import "https://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs"
|
||||
rpm -ivh $PUPPET >/dev/null
|
||||
rpm -Uvh $PUPPET >/dev/null
|
||||
|
||||
echo "Installing puppet.."
|
||||
yum install -y puppet >/dev/null
|
||||
|
@ -15,10 +15,10 @@
|
||||
class epel {
|
||||
|
||||
yumrepo { 'epel':
|
||||
mirrorlist => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=${::architecture}",
|
||||
mirrorlist => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-${::operatingsystemmajrelease}&arch=${::architecture}",
|
||||
enabled => '1',
|
||||
gpgcheck => '0',
|
||||
descr => "Extra Packages for Enterprise Linux 6 - ${::architecture}"
|
||||
descr => "Extra Packages for Enterprise Linux ${::operatingsystemmajrelease} - ${::architecture}"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ class icinga2 {
|
||||
include icinga_packages
|
||||
|
||||
package { [
|
||||
'icinga2', 'icinga2-doc', 'icinga2-debuginfo'
|
||||
'icinga2', 'icinga2-doc'
|
||||
]:
|
||||
ensure => latest,
|
||||
require => Class['icinga_packages'],
|
||||
@ -35,7 +35,7 @@ class icinga2 {
|
||||
links => follow,
|
||||
owner => 'icinga',
|
||||
group => 'icinga',
|
||||
mode => 6750,
|
||||
mode => '6750',
|
||||
}
|
||||
|
||||
icinga2::feature { [ 'statusdata', 'command', 'compatlog' ]: }
|
||||
|
@ -8,7 +8,7 @@
|
||||
#
|
||||
class icinga_packages {
|
||||
yumrepo { 'icinga_packages':
|
||||
baseurl => 'http://packages.icinga.org/epel/6/snapshot/',
|
||||
baseurl => "http://packages.icinga.org/epel/${::operatingsystemmajrelease}/snapshot/",
|
||||
enabled => '1',
|
||||
gpgcheck => '1',
|
||||
gpgkey => 'http://packages.icinga.org/icinga.key',
|
||||
|
@ -10,7 +10,7 @@ define icingaweb2::config::general (
|
||||
content => template("${source}/${name}.ini.erb"),
|
||||
owner => 'root',
|
||||
group => $web_group,
|
||||
mode => 0660,
|
||||
mode => '0660',
|
||||
replace => $replace,
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ define icingaweb2::config::module (
|
||||
source => "${source}/modules/${module}/${name}.ini",
|
||||
owner => 'root',
|
||||
group => $web_group,
|
||||
mode => 0660,
|
||||
mode => '0660',
|
||||
replace => $replace,
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Class: mysql
|
||||
#
|
||||
# This class installs the mysql server and client software.
|
||||
# This class installs the MySQL server and client software on a RHEL or CentOS
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
@ -16,21 +16,39 @@ class mysql {
|
||||
|
||||
Exec { path => '/usr/bin' }
|
||||
|
||||
if versioncmp($::operatingsystemmajrelease, '7') >= 0 {
|
||||
$client_package_name = 'mariadb'
|
||||
$server_package_name = 'mariadb-server'
|
||||
$server_service_name = 'mariadb'
|
||||
$cnf = '/etc/my.cnf.d/server.cnf'
|
||||
$log_error = '/var/log/mariadb/mariadb.log'
|
||||
$pid_file = '/var/run/mariadb/mariadb.pid'
|
||||
} else {
|
||||
$client_package_name = 'mysql'
|
||||
$server_package_name = 'mysql-server'
|
||||
$server_service_name = 'mysqld'
|
||||
$cnf = '/etc/my.cnf'
|
||||
$log_error = '/var/log/mysqld.log'
|
||||
$pid_file = '/var/run/mysqld/mysqld.pid'
|
||||
}
|
||||
|
||||
package { [
|
||||
'mysql', 'mysql-server'
|
||||
$client_package_name, $server_package_name,
|
||||
]:
|
||||
ensure => latest,
|
||||
}
|
||||
|
||||
service { 'mysqld':
|
||||
ensure => running,
|
||||
service { $server_service_name:
|
||||
alias => 'mysqld',
|
||||
enable => true,
|
||||
require => Package['mysql-server']
|
||||
ensure => running,
|
||||
require => Package[$server_package_name],
|
||||
}
|
||||
|
||||
file { '/etc/my.cnf':
|
||||
file { $cnf:
|
||||
content => template('mysql/my.cnf.erb'),
|
||||
require => Package['mysql-server'],
|
||||
notify => Service['mysqld']
|
||||
notify => Service['mysqld'],
|
||||
recurse => true,
|
||||
require => Package[$server_package_name],
|
||||
}
|
||||
}
|
||||
|
@ -104,8 +104,8 @@ innodb_file_per_table
|
||||
innodb_log_file_size = 64M
|
||||
|
||||
[mysqld_safe]
|
||||
log-error=/var/log/mysqld.log
|
||||
pid-file=/var/run/mysqld/mysqld.pid
|
||||
log-error=<%= @log_error %>
|
||||
pid-file=<%= @pid_file %>
|
||||
|
||||
# Increase the amount of open files allowed per process. Warning: Make
|
||||
# sure you have set the global system limit high enough! The high value
|
||||
|
@ -20,6 +20,18 @@ class openldap {
|
||||
|
||||
service { 'slapd':
|
||||
ensure => running,
|
||||
require => Package['openldap-servers']
|
||||
require => Package['openldap-servers'],
|
||||
}
|
||||
|
||||
if versioncmp($::operatingsystemmajrelease, '7') >= 0 {
|
||||
['core', 'cosine', 'inetorgperson', 'nis', 'misc', 'openldap'].each |String $schema| {
|
||||
exec { "slapd-schema-${schema}":
|
||||
command => "ldapadd -Y EXTERNAL -H ldapi:// -f /etc/openldap/schema/${schema}.ldif",
|
||||
group => 'root',
|
||||
require => Package['openldap-servers'],
|
||||
unless => "test -n \"$(find /etc/openldap/slapd.d/cn=config/cn=schema/ -name cn={*}${schema}.ldif -print -quit)\"",
|
||||
user => 'root',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ define pgsql::database::create ($username, $password) {
|
||||
unless => "psql -tAc \"SELECT 1 FROM pg_roles WHERE rolname='${username}'\" | grep -q 1",
|
||||
command => "psql -c \"CREATE ROLE ${username} WITH LOGIN PASSWORD '${password}';\" && \
|
||||
createdb -O ${username} -E UTF8 -T template0 ${name} && \
|
||||
createlang plpgsql ${name}",
|
||||
(createlang plpgsql ${name} || true)",
|
||||
user => 'postgres',
|
||||
require => Class['pgsql']
|
||||
}
|
||||
|
@ -20,24 +20,11 @@ class php {
|
||||
|
||||
package { 'php':
|
||||
ensure => latest,
|
||||
require => Package['apache'],
|
||||
notify => Service['apache']
|
||||
}
|
||||
# TODO(el): Always executed. Should be a resource
|
||||
-> exec { 'php-timezone':
|
||||
command => 'sed -re $\'s#^;?(date\\.timezone =).*$#\\1 "UTC"#\' -i /etc/php.ini',
|
||||
notify => Service['apache'],
|
||||
require => Package['apache'],
|
||||
}
|
||||
|
||||
file { '/etc/php.d/error_reporting.ini':
|
||||
content => template('php/error_reporting.ini.erb'),
|
||||
php::phpd { ['error_reporting', 'timezone', 'xdebug_settings' ]:
|
||||
require => Package['php'],
|
||||
notify => Service['apache']
|
||||
}
|
||||
|
||||
file { '/etc/php.d/xdebug_settings.ini':
|
||||
content => template('php/xdebug_settings.ini.erb'),
|
||||
require => Package['php'],
|
||||
notify => Service['apache']
|
||||
}
|
||||
}
|
||||
|
21
.puppet/modules/php/manifests/phpd.pp
Normal file
21
.puppet/modules/php/manifests/phpd.pp
Normal 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'],
|
||||
}
|
||||
}
|
1
.puppet/modules/php/templates/timezone.ini.erb
Normal file
1
.puppet/modules/php/templates/timezone.ini.erb
Normal file
@ -0,0 +1 @@
|
||||
date.timezone = "UTC"
|
@ -1,6 +1,6 @@
|
||||
# Class: icinga2_dev
|
||||
#
|
||||
# This class installs Icinga 2 w/ MySQL and provides Icinga 2 test configuration.
|
||||
# This class installs Icinga 2 w/ MySQL and PostgreSQL and provides Icinga 2 test configuration.
|
||||
#
|
||||
# Requires:
|
||||
#
|
||||
@ -19,10 +19,15 @@ class icinga2_dev {
|
||||
include monitoring_test_config
|
||||
|
||||
icinga2::config { [
|
||||
'conf.d/test-config', 'conf.d/commands', 'constants' ]:
|
||||
'conf.d/test-config', 'conf.d/commands', 'constants'
|
||||
]:
|
||||
source => 'puppet:///modules/icinga2_dev',
|
||||
}
|
||||
|
||||
icinga2::feature { 'api':
|
||||
ensure => absent,
|
||||
}
|
||||
|
||||
icinga2::feature { 'ido-pgsql':
|
||||
ensure => absent,
|
||||
require => Class['icinga2_pgsql'],
|
||||
|
@ -6,7 +6,7 @@ olcRootPW: {SSHA}N/2WMqT8q7cElh7KUQz+p9TJbjmKv/u9
|
||||
replace: olcRootDN
|
||||
olcRootDN: cn=admin,cn=config
|
||||
|
||||
dn: olcDatabase={2}bdb,cn=config
|
||||
dn: olcDatabase={2}hdb,cn=config
|
||||
changetype: modify
|
||||
replace: olcRootPW
|
||||
olcRootPW: {SSHA}MxMpLBo2/TSymoIBf/Sb5iQac7Wwiur5
|
||||
|
@ -1,23 +1,38 @@
|
||||
Alias /<%= @web_path %> /vagrant/public
|
||||
Alias /<%= @web_path %> "/vagrant/public"
|
||||
|
||||
<Directory "/vagrant/public/">
|
||||
Options FollowSymLinks
|
||||
<Directory "/vagrant/public">
|
||||
Options SymLinksIfOwnerMatch
|
||||
AllowOverride None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
|
||||
# SetEnv ICINGAWEB_CONFIGDIR <%= @config %>
|
||||
<IfModule mod_authz_core.c>
|
||||
# Apache 2.4
|
||||
<RequireAll>
|
||||
Require all granted
|
||||
</RequireAll>
|
||||
</IfModule>
|
||||
|
||||
<IfModule !mod_authz_core.c>
|
||||
# Apache 2.2
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</IfModule>
|
||||
|
||||
SetEnv ICINGAWEB_CONFIGDIR <%= @config %>
|
||||
|
||||
EnableSendfile Off
|
||||
|
||||
RewriteEngine on
|
||||
RewriteBase /<%= @web_path %>/
|
||||
RewriteCond %{REQUEST_FILENAME} -s [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -l [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule ^.*$ - [NC,L]
|
||||
RewriteRule ^.*$ index.php [NC,L]
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
RewriteBase /<%= @web_path %>/
|
||||
RewriteCond %{REQUEST_FILENAME} -s [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -l [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule ^.*$ - [NC,L]
|
||||
RewriteRule ^.*$ index.php [NC,L]
|
||||
</IfModule>
|
||||
|
||||
php_value xdebug.idekey PHPSTORM
|
||||
<IfModule !mod_rewrite.c>
|
||||
DirectoryIndex error_norewrite.html
|
||||
ErrorDocument 404 /error_norewrite.html
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
|
5
Vagrantfile
vendored
5
Vagrantfile
vendored
@ -22,13 +22,13 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
config.vm.provision :shell, :path => ".puppet/manifests/puppet.sh"
|
||||
|
||||
config.vm.provider :virtualbox do |v, override|
|
||||
override.vm.box = "puppetlabs/centos-6.6-64-puppet"
|
||||
override.vm.box = "puppetlabs/centos-7.0-64-puppet"
|
||||
|
||||
v.customize ["modifyvm", :id, "--memory", "1024"]
|
||||
end
|
||||
|
||||
config.vm.provider :parallels do |p, override|
|
||||
override.vm.box = "parallels/centos-6.5"
|
||||
override.vm.box = "parallels/centos-7.1"
|
||||
|
||||
p.name = "Icinga Web 2 Development"
|
||||
|
||||
@ -47,5 +47,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
puppet.module_path = [ ".puppet/modules", ".puppet/profiles" ]
|
||||
puppet.manifests_path = ".puppet/manifests"
|
||||
puppet.manifest_file = "site.pp"
|
||||
puppet.options = "--parser=future"
|
||||
end
|
||||
end
|
||||
|
@ -5,6 +5,8 @@ use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Modules\Module;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\Config\UserBackendConfigForm;
|
||||
use Icinga\Forms\Config\UserBackendReorderForm;
|
||||
use Icinga\Forms\Config\GeneralConfigForm;
|
||||
@ -195,80 +197,129 @@ class ConfigController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for creating a new user backend
|
||||
* Create a new user backend
|
||||
*/
|
||||
public function createuserbackendAction()
|
||||
{
|
||||
$this->assertPermission('config/application/userbackend');
|
||||
$form = new UserBackendConfigForm();
|
||||
$form->setRedirectUrl('config/userbackend');
|
||||
$form->setTitle($this->translate('Create New User Backend'));
|
||||
$form->addDescription($this->translate(
|
||||
'Create a new backend for authenticating your users. This backend'
|
||||
. ' will be added at the end of your authentication order.'
|
||||
));
|
||||
$form->setIniConfig(Config::app('authentication'));
|
||||
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||
$form->setRedirectUrl('config/userbackend');
|
||||
|
||||
try {
|
||||
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||
} catch (ConfigurationError $e) {
|
||||
if ($this->hasPermission('config/application/resources')) {
|
||||
Notification::error($e->getMessage());
|
||||
$this->redirectNow('config/createresource');
|
||||
}
|
||||
|
||||
throw $e; // No permission for resource configuration, show the error
|
||||
}
|
||||
|
||||
$form->setOnSuccess(function (UserBackendConfigForm $form) {
|
||||
try {
|
||||
$form->add(array_filter($form->getValues()));
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($form->save()) {
|
||||
Notification::success(t('User backend successfully created'));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('userbackend/create');
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for editing user backends
|
||||
* Edit a user backend
|
||||
*/
|
||||
public function edituserbackendAction()
|
||||
{
|
||||
$this->assertPermission('config/application/userbackend');
|
||||
$backendName = $this->params->getRequired('backend');
|
||||
|
||||
$form = new UserBackendConfigForm();
|
||||
$form->setTitle($this->translate('Edit User Backend'));
|
||||
$form->setIniConfig(Config::app('authentication'));
|
||||
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||
$form->setRedirectUrl('config/userbackend');
|
||||
$form->setAction(Url::fromRequest());
|
||||
$form->handleRequest();
|
||||
$form->setTitle(sprintf($this->translate('Edit User Backend %s'), $backendName));
|
||||
$form->setIniConfig(Config::app('authentication'));
|
||||
$form->setOnSuccess(function (UserBackendConfigForm $form) use ($backendName) {
|
||||
try {
|
||||
$form->edit($backendName, array_map(
|
||||
function ($v) {
|
||||
return $v !== '' ? $v : null;
|
||||
},
|
||||
$form->getValues()
|
||||
));
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($form->save()) {
|
||||
Notification::success(sprintf(t('User backend "%s" successfully updated'), $backendName));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
try {
|
||||
$form->load($backendName);
|
||||
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||
$form->handleRequest();
|
||||
} catch (NotFoundError $_) {
|
||||
$this->httpNotFound(sprintf($this->translate('User backend "%s" not found'), $backendName));
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('userbackend/modify');
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for removing a user backend
|
||||
* Display a confirmation form to remove the backend identified by the 'backend' parameter
|
||||
*/
|
||||
public function removeuserbackendAction()
|
||||
{
|
||||
$this->assertPermission('config/application/userbackend');
|
||||
$form = new ConfirmRemovalForm(array(
|
||||
'onSuccess' => function ($form) {
|
||||
$configForm = new UserBackendConfigForm();
|
||||
$configForm->setIniConfig(Config::app('authentication'));
|
||||
$authBackend = $form->getRequest()->getQuery('backend');
|
||||
$backendName = $this->params->getRequired('backend');
|
||||
|
||||
try {
|
||||
$configForm->remove($authBackend);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($configForm->save()) {
|
||||
Notification::success(sprintf(
|
||||
t('User backend "%s" has been successfully removed'),
|
||||
$authBackend
|
||||
));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
));
|
||||
$form->setTitle($this->translate('Remove User Backend'));
|
||||
$backendForm = new UserBackendConfigForm();
|
||||
$backendForm->setIniConfig(Config::app('authentication'));
|
||||
$form = new ConfirmRemovalForm();
|
||||
$form->setRedirectUrl('config/userbackend');
|
||||
$form->setAction(Url::fromRequest());
|
||||
$form->setTitle(sprintf($this->translate('Remove User Backend %s'), $backendName));
|
||||
$form->setOnSuccess(function (ConfirmRemovalForm $form) use ($backendName, $backendForm) {
|
||||
try {
|
||||
$backendForm->delete($backendName);
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($backendForm->save()) {
|
||||
Notification::success(sprintf(t('User backend "%s" successfully removed'), $backendName));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('userbackend/remove');
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,15 +1,14 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Protocol\File\FileReader;
|
||||
use \Zend_Controller_Action_Exception as ActionError;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||
|
||||
/**
|
||||
* Class ListController
|
||||
@ -40,7 +39,7 @@ class ListController extends Controller
|
||||
public function applicationlogAction()
|
||||
{
|
||||
if (! Logger::writesToFile()) {
|
||||
throw new ActionError('Site not found', 404);
|
||||
$this->httpNotFound('Page not found');
|
||||
}
|
||||
|
||||
$this->addTitleTab('application log');
|
||||
|
@ -78,7 +78,6 @@ class UsergroupbackendController extends Controller
|
||||
$backendName = $this->params->getRequired('backend');
|
||||
|
||||
$form = new UserGroupBackendForm();
|
||||
$form->setAction(Url::fromRequest());
|
||||
$form->setRedirectUrl('usergroupbackend/list');
|
||||
$form->setTitle(sprintf($this->translate('Edit User Group Backend %s'), $backendName));
|
||||
$form->setIniConfig(Config::app('groups'));
|
||||
|
@ -46,3 +46,12 @@ Font license info
|
||||
Homepage: http://fontello.com
|
||||
|
||||
|
||||
## Typicons
|
||||
|
||||
(c) Stephen Hutchings 2012
|
||||
|
||||
Author: Stephen Hutchings
|
||||
License: SIL (http://scripts.sil.org/OFL)
|
||||
Homepage: http://typicons.com/
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@ webfont pack. Details available in LICENSE.txt file.
|
||||
- If your project is open-source, usually, it will be ok to make LICENSE.txt
|
||||
file publically available in your repository.
|
||||
|
||||
- Fonts, used in Fontello, don't require to make clickable links on your site.
|
||||
- Fonts, used in Fontello, don't require a clickable link on your site.
|
||||
But any kind of additional authors crediting is welcome.
|
||||
================================================================================
|
||||
|
||||
@ -29,8 +29,8 @@ Comments on archive content
|
||||
|
||||
- LICENSE.txt - license info about source fonts, used to build your one.
|
||||
|
||||
- config.json - keeps your settings. You can import it back to fontello anytime,
|
||||
to continue your work
|
||||
- config.json - keeps your settings. You can import it back into fontello
|
||||
anytime, to continue your work
|
||||
|
||||
|
||||
Why so many CSS files ?
|
||||
@ -38,17 +38,17 @@ Why so many CSS files ?
|
||||
|
||||
Because we like to fit all your needs :)
|
||||
|
||||
- basic file, <your_font_name>.css - is usually enougth, in contains @font-face
|
||||
and character codes definition
|
||||
- basic file, <your_font_name>.css - is usually enough, it contains @font-face
|
||||
and character code definitions
|
||||
|
||||
- *-ie7.css - if you need IE7 support, but still don't wish to put char codes
|
||||
directly into html
|
||||
|
||||
- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face
|
||||
rules, but still wish to benefit of css generation. That can be very
|
||||
convenient for automated assets build systems. When you need to update font -
|
||||
no needs to manually edit files, just override old version with archive
|
||||
content. See fontello source codes for example.
|
||||
rules, but still wish to benefit from css generation. That can be very
|
||||
convenient for automated asset build systems. When you need to update font -
|
||||
no need to manually edit files, just override old version with archive
|
||||
content. See fontello source code for examples.
|
||||
|
||||
- *-embedded.css - basic css file, but with embedded WOFF font, to avoid
|
||||
CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain.
|
||||
@ -63,11 +63,11 @@ Because we like to fit all your needs :)
|
||||
Attention for server setup
|
||||
--------------------------
|
||||
|
||||
You MUST setup server to reply with proper `mime-types` for font files. In other
|
||||
case, some browsers will fail to show fonts.
|
||||
You MUST setup server to reply with proper `mime-types` for font files -
|
||||
otherwise some browsers will fail to show fonts.
|
||||
|
||||
Usually, `apache` already has necessary settings, but `nginx` and other
|
||||
webservers should be tuned. Here is list of mime types for our file extentions:
|
||||
webservers should be tuned. Here is list of mime types for our file extensions:
|
||||
|
||||
- `application/vnd.ms-fontobject` - eot
|
||||
- `application/x-font-woff` - woff
|
||||
|
@ -672,6 +672,30 @@
|
||||
"code": 59492,
|
||||
"src": "entypo"
|
||||
},
|
||||
{
|
||||
"uid": "c16a63e911bc47b46dc2a7129d2f0c46",
|
||||
"css": "down-small",
|
||||
"code": 59509,
|
||||
"src": "typicons"
|
||||
},
|
||||
{
|
||||
"uid": "58b78b6ca784d5c3db5beefcd9e18061",
|
||||
"css": "left-small",
|
||||
"code": 59510,
|
||||
"src": "typicons"
|
||||
},
|
||||
{
|
||||
"uid": "877a233d7fdca8a1d82615b96ed0d7a2",
|
||||
"css": "right-small",
|
||||
"code": 59511,
|
||||
"src": "typicons"
|
||||
},
|
||||
{
|
||||
"uid": "62bc6fe2a82e4864e2b94d4c0985ee0c",
|
||||
"css": "up-small",
|
||||
"code": 59512,
|
||||
"src": "typicons"
|
||||
},
|
||||
{
|
||||
"uid": "b90d80c250a9bbdd6cd3fe00e6351710",
|
||||
"css": "ok",
|
||||
|
@ -115,4 +115,8 @@
|
||||
.icon-chart-bar:before { content: '\e871'; } /* '' */
|
||||
.icon-beaker:before { content: '\e872'; } /* '' */
|
||||
.icon-magic:before { content: '\e873'; } /* '' */
|
||||
.icon-spin6:before { content: '\e874'; } /* '' */
|
||||
.icon-spin6:before { content: '\e874'; } /* '' */
|
||||
.icon-down-small:before { content: '\e875'; } /* '' */
|
||||
.icon-left-small:before { content: '\e876'; } /* '' */
|
||||
.icon-right-small:before { content: '\e877'; } /* '' */
|
||||
.icon-up-small:before { content: '\e878'; } /* '' */
|
File diff suppressed because one or more lines are too long
@ -115,4 +115,8 @@
|
||||
.icon-chart-bar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-beaker { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-magic { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-spin6 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-spin6 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-down-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
@ -126,4 +126,8 @@
|
||||
.icon-chart-bar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-beaker { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-magic { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-spin6 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-spin6 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-down-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
24
application/fonts/fontello-ifont/css/ifont.css
vendored
24
application/fonts/fontello-ifont/css/ifont.css
vendored
@ -1,10 +1,10 @@
|
||||
@font-face {
|
||||
font-family: 'ifont';
|
||||
src: url('../font/ifont.eot?6491776');
|
||||
src: url('../font/ifont.eot?6491776#iefix') format('embedded-opentype'),
|
||||
url('../font/ifont.woff?6491776') format('woff'),
|
||||
url('../font/ifont.ttf?6491776') format('truetype'),
|
||||
url('../font/ifont.svg?6491776#ifont') format('svg');
|
||||
src: url('../font/ifont.eot?54745533');
|
||||
src: url('../font/ifont.eot?54745533#iefix') format('embedded-opentype'),
|
||||
url('../font/ifont.woff?54745533') format('woff'),
|
||||
url('../font/ifont.ttf?54745533') format('truetype'),
|
||||
url('../font/ifont.svg?54745533#ifont') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@ -14,7 +14,7 @@
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
@font-face {
|
||||
font-family: 'ifont';
|
||||
src: url('../font/ifont.svg?6491776#ifont') format('svg');
|
||||
src: url('../font/ifont.svg?54745533#ifont') format('svg');
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ -35,7 +35,7 @@
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
@ -46,6 +46,10 @@
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
@ -166,4 +170,8 @@
|
||||
.icon-chart-bar:before { content: '\e871'; } /* '' */
|
||||
.icon-beaker:before { content: '\e872'; } /* '' */
|
||||
.icon-magic:before { content: '\e873'; } /* '' */
|
||||
.icon-spin6:before { content: '\e874'; } /* '' */
|
||||
.icon-spin6:before { content: '\e874'; } /* '' */
|
||||
.icon-down-small:before { content: '\e875'; } /* '' */
|
||||
.icon-left-small:before { content: '\e876'; } /* '' */
|
||||
.icon-right-small:before { content: '\e877'; } /* '' */
|
||||
.icon-up-small:before { content: '\e878'; } /* '' */
|
@ -227,8 +227,54 @@ body {
|
||||
.i-code {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="css/ifont.css">
|
||||
@font-face {
|
||||
font-family: 'ifont';
|
||||
src: url('./font/ifont.eot?11424534');
|
||||
src: url('./font/ifont.eot?11424534#iefix') format('embedded-opentype'),
|
||||
url('./font/ifont.woff?11424534') format('woff'),
|
||||
url('./font/ifont.ttf?11424534') format('truetype'),
|
||||
url('./font/ifont.svg?11424534#ifont') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
.demo-icon
|
||||
{
|
||||
font-family: "ifont";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
speak: none;
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
margin-right: .2em;
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
margin-left: .2em;
|
||||
|
||||
/* You can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="css/animation.css"><!--[if IE 7]><link rel="stylesheet" href="css/ifont-ie7.css"><![endif]-->
|
||||
<script>
|
||||
function toggleCodes(on) {
|
||||
@ -255,181 +301,187 @@ body {
|
||||
</div>
|
||||
<div id="icons" class="container">
|
||||
<div class="row">
|
||||
<div title="Code: 0xe800" class="the-icons span3"><i class="icon-dashboard"></i> <span class="i-name">icon-dashboard</span><span class="i-code">0xe800</span></div>
|
||||
<div title="Code: 0xe801" class="the-icons span3"><i class="icon-user"></i> <span class="i-name">icon-user</span><span class="i-code">0xe801</span></div>
|
||||
<div title="Code: 0xe802" class="the-icons span3"><i class="icon-users"></i> <span class="i-name">icon-users</span><span class="i-code">0xe802</span></div>
|
||||
<div title="Code: 0xe803" class="the-icons span3"><i class="icon-ok"></i> <span class="i-name">icon-ok</span><span class="i-code">0xe803</span></div>
|
||||
<div title="Code: 0xe800" class="the-icons span3"><i class="demo-icon icon-dashboard"></i> <span class="i-name">icon-dashboard</span><span class="i-code">0xe800</span></div>
|
||||
<div title="Code: 0xe801" class="the-icons span3"><i class="demo-icon icon-user"></i> <span class="i-name">icon-user</span><span class="i-code">0xe801</span></div>
|
||||
<div title="Code: 0xe802" class="the-icons span3"><i class="demo-icon icon-users"></i> <span class="i-name">icon-users</span><span class="i-code">0xe802</span></div>
|
||||
<div title="Code: 0xe803" class="the-icons span3"><i class="demo-icon icon-ok"></i> <span class="i-name">icon-ok</span><span class="i-code">0xe803</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe804" class="the-icons span3"><i class="icon-cancel"></i> <span class="i-name">icon-cancel</span><span class="i-code">0xe804</span></div>
|
||||
<div title="Code: 0xe805" class="the-icons span3"><i class="icon-plus"></i> <span class="i-name">icon-plus</span><span class="i-code">0xe805</span></div>
|
||||
<div title="Code: 0xe806" class="the-icons span3"><i class="icon-minus"></i> <span class="i-name">icon-minus</span><span class="i-code">0xe806</span></div>
|
||||
<div title="Code: 0xe807" class="the-icons span3"><i class="icon-folder-empty"></i> <span class="i-name">icon-folder-empty</span><span class="i-code">0xe807</span></div>
|
||||
<div title="Code: 0xe804" class="the-icons span3"><i class="demo-icon icon-cancel"></i> <span class="i-name">icon-cancel</span><span class="i-code">0xe804</span></div>
|
||||
<div title="Code: 0xe805" class="the-icons span3"><i class="demo-icon icon-plus"></i> <span class="i-name">icon-plus</span><span class="i-code">0xe805</span></div>
|
||||
<div title="Code: 0xe806" class="the-icons span3"><i class="demo-icon icon-minus"></i> <span class="i-name">icon-minus</span><span class="i-code">0xe806</span></div>
|
||||
<div title="Code: 0xe807" class="the-icons span3"><i class="demo-icon icon-folder-empty"></i> <span class="i-name">icon-folder-empty</span><span class="i-code">0xe807</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe808" class="the-icons span3"><i class="icon-download"></i> <span class="i-name">icon-download</span><span class="i-code">0xe808</span></div>
|
||||
<div title="Code: 0xe809" class="the-icons span3"><i class="icon-upload"></i> <span class="i-name">icon-upload</span><span class="i-code">0xe809</span></div>
|
||||
<div title="Code: 0xe80a" class="the-icons span3"><i class="icon-git"></i> <span class="i-name">icon-git</span><span class="i-code">0xe80a</span></div>
|
||||
<div title="Code: 0xe80b" class="the-icons span3"><i class="icon-cubes"></i> <span class="i-name">icon-cubes</span><span class="i-code">0xe80b</span></div>
|
||||
<div title="Code: 0xe808" class="the-icons span3"><i class="demo-icon icon-download"></i> <span class="i-name">icon-download</span><span class="i-code">0xe808</span></div>
|
||||
<div title="Code: 0xe809" class="the-icons span3"><i class="demo-icon icon-upload"></i> <span class="i-name">icon-upload</span><span class="i-code">0xe809</span></div>
|
||||
<div title="Code: 0xe80a" class="the-icons span3"><i class="demo-icon icon-git"></i> <span class="i-name">icon-git</span><span class="i-code">0xe80a</span></div>
|
||||
<div title="Code: 0xe80b" class="the-icons span3"><i class="demo-icon icon-cubes"></i> <span class="i-name">icon-cubes</span><span class="i-code">0xe80b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe80c" class="the-icons span3"><i class="icon-database"></i> <span class="i-name">icon-database</span><span class="i-code">0xe80c</span></div>
|
||||
<div title="Code: 0xe80d" class="the-icons span3"><i class="icon-gauge"></i> <span class="i-name">icon-gauge</span><span class="i-code">0xe80d</span></div>
|
||||
<div title="Code: 0xe80e" class="the-icons span3"><i class="icon-sitemap"></i> <span class="i-name">icon-sitemap</span><span class="i-code">0xe80e</span></div>
|
||||
<div title="Code: 0xe80f" class="the-icons span3"><i class="icon-sort-name-up"></i> <span class="i-name">icon-sort-name-up</span><span class="i-code">0xe80f</span></div>
|
||||
<div title="Code: 0xe80c" class="the-icons span3"><i class="demo-icon icon-database"></i> <span class="i-name">icon-database</span><span class="i-code">0xe80c</span></div>
|
||||
<div title="Code: 0xe80d" class="the-icons span3"><i class="demo-icon icon-gauge"></i> <span class="i-name">icon-gauge</span><span class="i-code">0xe80d</span></div>
|
||||
<div title="Code: 0xe80e" class="the-icons span3"><i class="demo-icon icon-sitemap"></i> <span class="i-name">icon-sitemap</span><span class="i-code">0xe80e</span></div>
|
||||
<div title="Code: 0xe80f" class="the-icons span3"><i class="demo-icon icon-sort-name-up"></i> <span class="i-name">icon-sort-name-up</span><span class="i-code">0xe80f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe810" class="the-icons span3"><i class="icon-sort-name-down"></i> <span class="i-name">icon-sort-name-down</span><span class="i-code">0xe810</span></div>
|
||||
<div title="Code: 0xe811" class="the-icons span3"><i class="icon-megaphone"></i> <span class="i-name">icon-megaphone</span><span class="i-code">0xe811</span></div>
|
||||
<div title="Code: 0xe812" class="the-icons span3"><i class="icon-bug"></i> <span class="i-name">icon-bug</span><span class="i-code">0xe812</span></div>
|
||||
<div title="Code: 0xe813" class="the-icons span3"><i class="icon-tasks"></i> <span class="i-name">icon-tasks</span><span class="i-code">0xe813</span></div>
|
||||
<div title="Code: 0xe810" class="the-icons span3"><i class="demo-icon icon-sort-name-down"></i> <span class="i-name">icon-sort-name-down</span><span class="i-code">0xe810</span></div>
|
||||
<div title="Code: 0xe811" class="the-icons span3"><i class="demo-icon icon-megaphone"></i> <span class="i-name">icon-megaphone</span><span class="i-code">0xe811</span></div>
|
||||
<div title="Code: 0xe812" class="the-icons span3"><i class="demo-icon icon-bug"></i> <span class="i-name">icon-bug</span><span class="i-code">0xe812</span></div>
|
||||
<div title="Code: 0xe813" class="the-icons span3"><i class="demo-icon icon-tasks"></i> <span class="i-name">icon-tasks</span><span class="i-code">0xe813</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe814" class="the-icons span3"><i class="icon-filter"></i> <span class="i-name">icon-filter</span><span class="i-code">0xe814</span></div>
|
||||
<div title="Code: 0xe815" class="the-icons span3"><i class="icon-off"></i> <span class="i-name">icon-off</span><span class="i-code">0xe815</span></div>
|
||||
<div title="Code: 0xe816" class="the-icons span3"><i class="icon-book"></i> <span class="i-name">icon-book</span><span class="i-code">0xe816</span></div>
|
||||
<div title="Code: 0xe817" class="the-icons span3"><i class="icon-paste"></i> <span class="i-name">icon-paste</span><span class="i-code">0xe817</span></div>
|
||||
<div title="Code: 0xe814" class="the-icons span3"><i class="demo-icon icon-filter"></i> <span class="i-name">icon-filter</span><span class="i-code">0xe814</span></div>
|
||||
<div title="Code: 0xe815" class="the-icons span3"><i class="demo-icon icon-off"></i> <span class="i-name">icon-off</span><span class="i-code">0xe815</span></div>
|
||||
<div title="Code: 0xe816" class="the-icons span3"><i class="demo-icon icon-book"></i> <span class="i-name">icon-book</span><span class="i-code">0xe816</span></div>
|
||||
<div title="Code: 0xe817" class="the-icons span3"><i class="demo-icon icon-paste"></i> <span class="i-name">icon-paste</span><span class="i-code">0xe817</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe818" class="the-icons span3"><i class="icon-scissors"></i> <span class="i-name">icon-scissors</span><span class="i-code">0xe818</span></div>
|
||||
<div title="Code: 0xe819" class="the-icons span3"><i class="icon-globe"></i> <span class="i-name">icon-globe</span><span class="i-code">0xe819</span></div>
|
||||
<div title="Code: 0xe81a" class="the-icons span3"><i class="icon-cloud"></i> <span class="i-name">icon-cloud</span><span class="i-code">0xe81a</span></div>
|
||||
<div title="Code: 0xe81b" class="the-icons span3"><i class="icon-flash"></i> <span class="i-name">icon-flash</span><span class="i-code">0xe81b</span></div>
|
||||
<div title="Code: 0xe818" class="the-icons span3"><i class="demo-icon icon-scissors"></i> <span class="i-name">icon-scissors</span><span class="i-code">0xe818</span></div>
|
||||
<div title="Code: 0xe819" class="the-icons span3"><i class="demo-icon icon-globe"></i> <span class="i-name">icon-globe</span><span class="i-code">0xe819</span></div>
|
||||
<div title="Code: 0xe81a" class="the-icons span3"><i class="demo-icon icon-cloud"></i> <span class="i-name">icon-cloud</span><span class="i-code">0xe81a</span></div>
|
||||
<div title="Code: 0xe81b" class="the-icons span3"><i class="demo-icon icon-flash"></i> <span class="i-name">icon-flash</span><span class="i-code">0xe81b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe81c" class="the-icons span3"><i class="icon-barchart"></i> <span class="i-name">icon-barchart</span><span class="i-code">0xe81c</span></div>
|
||||
<div title="Code: 0xe81d" class="the-icons span3"><i class="icon-down-dir"></i> <span class="i-name">icon-down-dir</span><span class="i-code">0xe81d</span></div>
|
||||
<div title="Code: 0xe81e" class="the-icons span3"><i class="icon-up-dir"></i> <span class="i-name">icon-up-dir</span><span class="i-code">0xe81e</span></div>
|
||||
<div title="Code: 0xe81f" class="the-icons span3"><i class="icon-left-dir"></i> <span class="i-name">icon-left-dir</span><span class="i-code">0xe81f</span></div>
|
||||
<div title="Code: 0xe81c" class="the-icons span3"><i class="demo-icon icon-barchart"></i> <span class="i-name">icon-barchart</span><span class="i-code">0xe81c</span></div>
|
||||
<div title="Code: 0xe81d" class="the-icons span3"><i class="demo-icon icon-down-dir"></i> <span class="i-name">icon-down-dir</span><span class="i-code">0xe81d</span></div>
|
||||
<div title="Code: 0xe81e" class="the-icons span3"><i class="demo-icon icon-up-dir"></i> <span class="i-name">icon-up-dir</span><span class="i-code">0xe81e</span></div>
|
||||
<div title="Code: 0xe81f" class="the-icons span3"><i class="demo-icon icon-left-dir"></i> <span class="i-name">icon-left-dir</span><span class="i-code">0xe81f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe820" class="the-icons span3"><i class="icon-right-dir"></i> <span class="i-name">icon-right-dir</span><span class="i-code">0xe820</span></div>
|
||||
<div title="Code: 0xe821" class="the-icons span3"><i class="icon-down-open"></i> <span class="i-name">icon-down-open</span><span class="i-code">0xe821</span></div>
|
||||
<div title="Code: 0xe822" class="the-icons span3"><i class="icon-right-open"></i> <span class="i-name">icon-right-open</span><span class="i-code">0xe822</span></div>
|
||||
<div title="Code: 0xe823" class="the-icons span3"><i class="icon-up-open"></i> <span class="i-name">icon-up-open</span><span class="i-code">0xe823</span></div>
|
||||
<div title="Code: 0xe820" class="the-icons span3"><i class="demo-icon icon-right-dir"></i> <span class="i-name">icon-right-dir</span><span class="i-code">0xe820</span></div>
|
||||
<div title="Code: 0xe821" class="the-icons span3"><i class="demo-icon icon-down-open"></i> <span class="i-name">icon-down-open</span><span class="i-code">0xe821</span></div>
|
||||
<div title="Code: 0xe822" class="the-icons span3"><i class="demo-icon icon-right-open"></i> <span class="i-name">icon-right-open</span><span class="i-code">0xe822</span></div>
|
||||
<div title="Code: 0xe823" class="the-icons span3"><i class="demo-icon icon-up-open"></i> <span class="i-name">icon-up-open</span><span class="i-code">0xe823</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe824" class="the-icons span3"><i class="icon-left-open"></i> <span class="i-name">icon-left-open</span><span class="i-code">0xe824</span></div>
|
||||
<div title="Code: 0xe825" class="the-icons span3"><i class="icon-up-big"></i> <span class="i-name">icon-up-big</span><span class="i-code">0xe825</span></div>
|
||||
<div title="Code: 0xe826" class="the-icons span3"><i class="icon-right-big"></i> <span class="i-name">icon-right-big</span><span class="i-code">0xe826</span></div>
|
||||
<div title="Code: 0xe827" class="the-icons span3"><i class="icon-left-big"></i> <span class="i-name">icon-left-big</span><span class="i-code">0xe827</span></div>
|
||||
<div title="Code: 0xe824" class="the-icons span3"><i class="demo-icon icon-left-open"></i> <span class="i-name">icon-left-open</span><span class="i-code">0xe824</span></div>
|
||||
<div title="Code: 0xe825" class="the-icons span3"><i class="demo-icon icon-up-big"></i> <span class="i-name">icon-up-big</span><span class="i-code">0xe825</span></div>
|
||||
<div title="Code: 0xe826" class="the-icons span3"><i class="demo-icon icon-right-big"></i> <span class="i-name">icon-right-big</span><span class="i-code">0xe826</span></div>
|
||||
<div title="Code: 0xe827" class="the-icons span3"><i class="demo-icon icon-left-big"></i> <span class="i-name">icon-left-big</span><span class="i-code">0xe827</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe828" class="the-icons span3"><i class="icon-down-big"></i> <span class="i-name">icon-down-big</span><span class="i-code">0xe828</span></div>
|
||||
<div title="Code: 0xe829" class="the-icons span3"><i class="icon-resize-full-alt"></i> <span class="i-name">icon-resize-full-alt</span><span class="i-code">0xe829</span></div>
|
||||
<div title="Code: 0xe82a" class="the-icons span3"><i class="icon-resize-full"></i> <span class="i-name">icon-resize-full</span><span class="i-code">0xe82a</span></div>
|
||||
<div title="Code: 0xe82b" class="the-icons span3"><i class="icon-resize-small"></i> <span class="i-name">icon-resize-small</span><span class="i-code">0xe82b</span></div>
|
||||
<div title="Code: 0xe828" class="the-icons span3"><i class="demo-icon icon-down-big"></i> <span class="i-name">icon-down-big</span><span class="i-code">0xe828</span></div>
|
||||
<div title="Code: 0xe829" class="the-icons span3"><i class="demo-icon icon-resize-full-alt"></i> <span class="i-name">icon-resize-full-alt</span><span class="i-code">0xe829</span></div>
|
||||
<div title="Code: 0xe82a" class="the-icons span3"><i class="demo-icon icon-resize-full"></i> <span class="i-name">icon-resize-full</span><span class="i-code">0xe82a</span></div>
|
||||
<div title="Code: 0xe82b" class="the-icons span3"><i class="demo-icon icon-resize-small"></i> <span class="i-name">icon-resize-small</span><span class="i-code">0xe82b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe82c" class="the-icons span3"><i class="icon-move"></i> <span class="i-name">icon-move</span><span class="i-code">0xe82c</span></div>
|
||||
<div title="Code: 0xe82d" class="the-icons span3"><i class="icon-resize-horizontal"></i> <span class="i-name">icon-resize-horizontal</span><span class="i-code">0xe82d</span></div>
|
||||
<div title="Code: 0xe82e" class="the-icons span3"><i class="icon-resize-vertical"></i> <span class="i-name">icon-resize-vertical</span><span class="i-code">0xe82e</span></div>
|
||||
<div title="Code: 0xe82f" class="the-icons span3"><i class="icon-zoom-in"></i> <span class="i-name">icon-zoom-in</span><span class="i-code">0xe82f</span></div>
|
||||
<div title="Code: 0xe82c" class="the-icons span3"><i class="demo-icon icon-move"></i> <span class="i-name">icon-move</span><span class="i-code">0xe82c</span></div>
|
||||
<div title="Code: 0xe82d" class="the-icons span3"><i class="demo-icon icon-resize-horizontal"></i> <span class="i-name">icon-resize-horizontal</span><span class="i-code">0xe82d</span></div>
|
||||
<div title="Code: 0xe82e" class="the-icons span3"><i class="demo-icon icon-resize-vertical"></i> <span class="i-name">icon-resize-vertical</span><span class="i-code">0xe82e</span></div>
|
||||
<div title="Code: 0xe82f" class="the-icons span3"><i class="demo-icon icon-zoom-in"></i> <span class="i-name">icon-zoom-in</span><span class="i-code">0xe82f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe830" class="the-icons span3"><i class="icon-block"></i> <span class="i-name">icon-block</span><span class="i-code">0xe830</span></div>
|
||||
<div title="Code: 0xe831" class="the-icons span3"><i class="icon-zoom-out"></i> <span class="i-name">icon-zoom-out</span><span class="i-code">0xe831</span></div>
|
||||
<div title="Code: 0xe832" class="the-icons span3"><i class="icon-lightbulb"></i> <span class="i-name">icon-lightbulb</span><span class="i-code">0xe832</span></div>
|
||||
<div title="Code: 0xe833" class="the-icons span3"><i class="icon-clock"></i> <span class="i-name">icon-clock</span><span class="i-code">0xe833</span></div>
|
||||
<div title="Code: 0xe830" class="the-icons span3"><i class="demo-icon icon-block"></i> <span class="i-name">icon-block</span><span class="i-code">0xe830</span></div>
|
||||
<div title="Code: 0xe831" class="the-icons span3"><i class="demo-icon icon-zoom-out"></i> <span class="i-name">icon-zoom-out</span><span class="i-code">0xe831</span></div>
|
||||
<div title="Code: 0xe832" class="the-icons span3"><i class="demo-icon icon-lightbulb"></i> <span class="i-name">icon-lightbulb</span><span class="i-code">0xe832</span></div>
|
||||
<div title="Code: 0xe833" class="the-icons span3"><i class="demo-icon icon-clock"></i> <span class="i-name">icon-clock</span><span class="i-code">0xe833</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe834" class="the-icons span3"><i class="icon-volume-up"></i> <span class="i-name">icon-volume-up</span><span class="i-code">0xe834</span></div>
|
||||
<div title="Code: 0xe835" class="the-icons span3"><i class="icon-volume-down"></i> <span class="i-name">icon-volume-down</span><span class="i-code">0xe835</span></div>
|
||||
<div title="Code: 0xe836" class="the-icons span3"><i class="icon-volume-off"></i> <span class="i-name">icon-volume-off</span><span class="i-code">0xe836</span></div>
|
||||
<div title="Code: 0xe837" class="the-icons span3"><i class="icon-mute"></i> <span class="i-name">icon-mute</span><span class="i-code">0xe837</span></div>
|
||||
<div title="Code: 0xe834" class="the-icons span3"><i class="demo-icon icon-volume-up"></i> <span class="i-name">icon-volume-up</span><span class="i-code">0xe834</span></div>
|
||||
<div title="Code: 0xe835" class="the-icons span3"><i class="demo-icon icon-volume-down"></i> <span class="i-name">icon-volume-down</span><span class="i-code">0xe835</span></div>
|
||||
<div title="Code: 0xe836" class="the-icons span3"><i class="demo-icon icon-volume-off"></i> <span class="i-name">icon-volume-off</span><span class="i-code">0xe836</span></div>
|
||||
<div title="Code: 0xe837" class="the-icons span3"><i class="demo-icon icon-mute"></i> <span class="i-name">icon-mute</span><span class="i-code">0xe837</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe838" class="the-icons span3"><i class="icon-mic"></i> <span class="i-name">icon-mic</span><span class="i-code">0xe838</span></div>
|
||||
<div title="Code: 0xe839" class="the-icons span3"><i class="icon-endtime"></i> <span class="i-name">icon-endtime</span><span class="i-code">0xe839</span></div>
|
||||
<div title="Code: 0xe83a" class="the-icons span3"><i class="icon-starttime"></i> <span class="i-name">icon-starttime</span><span class="i-code">0xe83a</span></div>
|
||||
<div title="Code: 0xe83b" class="the-icons span3"><i class="icon-calendar-empty"></i> <span class="i-name">icon-calendar-empty</span><span class="i-code">0xe83b</span></div>
|
||||
<div title="Code: 0xe838" class="the-icons span3"><i class="demo-icon icon-mic"></i> <span class="i-name">icon-mic</span><span class="i-code">0xe838</span></div>
|
||||
<div title="Code: 0xe839" class="the-icons span3"><i class="demo-icon icon-endtime"></i> <span class="i-name">icon-endtime</span><span class="i-code">0xe839</span></div>
|
||||
<div title="Code: 0xe83a" class="the-icons span3"><i class="demo-icon icon-starttime"></i> <span class="i-name">icon-starttime</span><span class="i-code">0xe83a</span></div>
|
||||
<div title="Code: 0xe83b" class="the-icons span3"><i class="demo-icon icon-calendar-empty"></i> <span class="i-name">icon-calendar-empty</span><span class="i-code">0xe83b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe83c" class="the-icons span3"><i class="icon-calendar"></i> <span class="i-name">icon-calendar</span><span class="i-code">0xe83c</span></div>
|
||||
<div title="Code: 0xe83d" class="the-icons span3"><i class="icon-wrench"></i> <span class="i-name">icon-wrench</span><span class="i-code">0xe83d</span></div>
|
||||
<div title="Code: 0xe83e" class="the-icons span3"><i class="icon-sliders"></i> <span class="i-name">icon-sliders</span><span class="i-code">0xe83e</span></div>
|
||||
<div title="Code: 0xe83f" class="the-icons span3"><i class="icon-services"></i> <span class="i-name">icon-services</span><span class="i-code">0xe83f</span></div>
|
||||
<div title="Code: 0xe83c" class="the-icons span3"><i class="demo-icon icon-calendar"></i> <span class="i-name">icon-calendar</span><span class="i-code">0xe83c</span></div>
|
||||
<div title="Code: 0xe83d" class="the-icons span3"><i class="demo-icon icon-wrench"></i> <span class="i-name">icon-wrench</span><span class="i-code">0xe83d</span></div>
|
||||
<div title="Code: 0xe83e" class="the-icons span3"><i class="demo-icon icon-sliders"></i> <span class="i-name">icon-sliders</span><span class="i-code">0xe83e</span></div>
|
||||
<div title="Code: 0xe83f" class="the-icons span3"><i class="demo-icon icon-services"></i> <span class="i-name">icon-services</span><span class="i-code">0xe83f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe840" class="the-icons span3"><i class="icon-service"></i> <span class="i-name">icon-service</span><span class="i-code">0xe840</span></div>
|
||||
<div title="Code: 0xe841" class="the-icons span3"><i class="icon-phone"></i> <span class="i-name">icon-phone</span><span class="i-code">0xe841</span></div>
|
||||
<div title="Code: 0xe842" class="the-icons span3"><i class="icon-file-pdf"></i> <span class="i-name">icon-file-pdf</span><span class="i-code">0xe842</span></div>
|
||||
<div title="Code: 0xe843" class="the-icons span3"><i class="icon-file-word"></i> <span class="i-name">icon-file-word</span><span class="i-code">0xe843</span></div>
|
||||
<div title="Code: 0xe840" class="the-icons span3"><i class="demo-icon icon-service"></i> <span class="i-name">icon-service</span><span class="i-code">0xe840</span></div>
|
||||
<div title="Code: 0xe841" class="the-icons span3"><i class="demo-icon icon-phone"></i> <span class="i-name">icon-phone</span><span class="i-code">0xe841</span></div>
|
||||
<div title="Code: 0xe842" class="the-icons span3"><i class="demo-icon icon-file-pdf"></i> <span class="i-name">icon-file-pdf</span><span class="i-code">0xe842</span></div>
|
||||
<div title="Code: 0xe843" class="the-icons span3"><i class="demo-icon icon-file-word"></i> <span class="i-name">icon-file-word</span><span class="i-code">0xe843</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe844" class="the-icons span3"><i class="icon-file-excel"></i> <span class="i-name">icon-file-excel</span><span class="i-code">0xe844</span></div>
|
||||
<div title="Code: 0xe845" class="the-icons span3"><i class="icon-doc-text"></i> <span class="i-name">icon-doc-text</span><span class="i-code">0xe845</span></div>
|
||||
<div title="Code: 0xe846" class="the-icons span3"><i class="icon-trash"></i> <span class="i-name">icon-trash</span><span class="i-code">0xe846</span></div>
|
||||
<div title="Code: 0xe847" class="the-icons span3"><i class="icon-comment-empty"></i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xe847</span></div>
|
||||
<div title="Code: 0xe844" class="the-icons span3"><i class="demo-icon icon-file-excel"></i> <span class="i-name">icon-file-excel</span><span class="i-code">0xe844</span></div>
|
||||
<div title="Code: 0xe845" class="the-icons span3"><i class="demo-icon icon-doc-text"></i> <span class="i-name">icon-doc-text</span><span class="i-code">0xe845</span></div>
|
||||
<div title="Code: 0xe846" class="the-icons span3"><i class="demo-icon icon-trash"></i> <span class="i-name">icon-trash</span><span class="i-code">0xe846</span></div>
|
||||
<div title="Code: 0xe847" class="the-icons span3"><i class="demo-icon icon-comment-empty"></i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xe847</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe848" class="the-icons span3"><i class="icon-comment"></i> <span class="i-name">icon-comment</span><span class="i-code">0xe848</span></div>
|
||||
<div title="Code: 0xe849" class="the-icons span3"><i class="icon-chat"></i> <span class="i-name">icon-chat</span><span class="i-code">0xe849</span></div>
|
||||
<div title="Code: 0xe84a" class="the-icons span3"><i class="icon-chat-empty"></i> <span class="i-name">icon-chat-empty</span><span class="i-code">0xe84a</span></div>
|
||||
<div title="Code: 0xe84b" class="the-icons span3"><i class="icon-bell"></i> <span class="i-name">icon-bell</span><span class="i-code">0xe84b</span></div>
|
||||
<div title="Code: 0xe848" class="the-icons span3"><i class="demo-icon icon-comment"></i> <span class="i-name">icon-comment</span><span class="i-code">0xe848</span></div>
|
||||
<div title="Code: 0xe849" class="the-icons span3"><i class="demo-icon icon-chat"></i> <span class="i-name">icon-chat</span><span class="i-code">0xe849</span></div>
|
||||
<div title="Code: 0xe84a" class="the-icons span3"><i class="demo-icon icon-chat-empty"></i> <span class="i-name">icon-chat-empty</span><span class="i-code">0xe84a</span></div>
|
||||
<div title="Code: 0xe84b" class="the-icons span3"><i class="demo-icon icon-bell"></i> <span class="i-name">icon-bell</span><span class="i-code">0xe84b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe84c" class="the-icons span3"><i class="icon-bell-alt"></i> <span class="i-name">icon-bell-alt</span><span class="i-code">0xe84c</span></div>
|
||||
<div title="Code: 0xe84d" class="the-icons span3"><i class="icon-attention-alt"></i> <span class="i-name">icon-attention-alt</span><span class="i-code">0xe84d</span></div>
|
||||
<div title="Code: 0xe84e" class="the-icons span3"><i class="icon-print"></i> <span class="i-name">icon-print</span><span class="i-code">0xe84e</span></div>
|
||||
<div title="Code: 0xe84f" class="the-icons span3"><i class="icon-edit"></i> <span class="i-name">icon-edit</span><span class="i-code">0xe84f</span></div>
|
||||
<div title="Code: 0xe84c" class="the-icons span3"><i class="demo-icon icon-bell-alt"></i> <span class="i-name">icon-bell-alt</span><span class="i-code">0xe84c</span></div>
|
||||
<div title="Code: 0xe84d" class="the-icons span3"><i class="demo-icon icon-attention-alt"></i> <span class="i-name">icon-attention-alt</span><span class="i-code">0xe84d</span></div>
|
||||
<div title="Code: 0xe84e" class="the-icons span3"><i class="demo-icon icon-print"></i> <span class="i-name">icon-print</span><span class="i-code">0xe84e</span></div>
|
||||
<div title="Code: 0xe84f" class="the-icons span3"><i class="demo-icon icon-edit"></i> <span class="i-name">icon-edit</span><span class="i-code">0xe84f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe850" class="the-icons span3"><i class="icon-forward"></i> <span class="i-name">icon-forward</span><span class="i-code">0xe850</span></div>
|
||||
<div title="Code: 0xe851" class="the-icons span3"><i class="icon-reply"></i> <span class="i-name">icon-reply</span><span class="i-code">0xe851</span></div>
|
||||
<div title="Code: 0xe852" class="the-icons span3"><i class="icon-reply-all"></i> <span class="i-name">icon-reply-all</span><span class="i-code">0xe852</span></div>
|
||||
<div title="Code: 0xe853" class="the-icons span3"><i class="icon-eye"></i> <span class="i-name">icon-eye</span><span class="i-code">0xe853</span></div>
|
||||
<div title="Code: 0xe850" class="the-icons span3"><i class="demo-icon icon-forward"></i> <span class="i-name">icon-forward</span><span class="i-code">0xe850</span></div>
|
||||
<div title="Code: 0xe851" class="the-icons span3"><i class="demo-icon icon-reply"></i> <span class="i-name">icon-reply</span><span class="i-code">0xe851</span></div>
|
||||
<div title="Code: 0xe852" class="the-icons span3"><i class="demo-icon icon-reply-all"></i> <span class="i-name">icon-reply-all</span><span class="i-code">0xe852</span></div>
|
||||
<div title="Code: 0xe853" class="the-icons span3"><i class="demo-icon icon-eye"></i> <span class="i-name">icon-eye</span><span class="i-code">0xe853</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe854" class="the-icons span3"><i class="icon-tag"></i> <span class="i-name">icon-tag</span><span class="i-code">0xe854</span></div>
|
||||
<div title="Code: 0xe855" class="the-icons span3"><i class="icon-tags"></i> <span class="i-name">icon-tags</span><span class="i-code">0xe855</span></div>
|
||||
<div title="Code: 0xe856" class="the-icons span3"><i class="icon-lock-open-alt"></i> <span class="i-name">icon-lock-open-alt</span><span class="i-code">0xe856</span></div>
|
||||
<div title="Code: 0xe857" class="the-icons span3"><i class="icon-lock-open"></i> <span class="i-name">icon-lock-open</span><span class="i-code">0xe857</span></div>
|
||||
<div title="Code: 0xe854" class="the-icons span3"><i class="demo-icon icon-tag"></i> <span class="i-name">icon-tag</span><span class="i-code">0xe854</span></div>
|
||||
<div title="Code: 0xe855" class="the-icons span3"><i class="demo-icon icon-tags"></i> <span class="i-name">icon-tags</span><span class="i-code">0xe855</span></div>
|
||||
<div title="Code: 0xe856" class="the-icons span3"><i class="demo-icon icon-lock-open-alt"></i> <span class="i-name">icon-lock-open-alt</span><span class="i-code">0xe856</span></div>
|
||||
<div title="Code: 0xe857" class="the-icons span3"><i class="demo-icon icon-lock-open"></i> <span class="i-name">icon-lock-open</span><span class="i-code">0xe857</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe858" class="the-icons span3"><i class="icon-lock"></i> <span class="i-name">icon-lock</span><span class="i-code">0xe858</span></div>
|
||||
<div title="Code: 0xe859" class="the-icons span3"><i class="icon-home"></i> <span class="i-name">icon-home</span><span class="i-code">0xe859</span></div>
|
||||
<div title="Code: 0xe85a" class="the-icons span3"><i class="icon-info"></i> <span class="i-name">icon-info</span><span class="i-code">0xe85a</span></div>
|
||||
<div title="Code: 0xe85b" class="the-icons span3"><i class="icon-help"></i> <span class="i-name">icon-help</span><span class="i-code">0xe85b</span></div>
|
||||
<div title="Code: 0xe858" class="the-icons span3"><i class="demo-icon icon-lock"></i> <span class="i-name">icon-lock</span><span class="i-code">0xe858</span></div>
|
||||
<div title="Code: 0xe859" class="the-icons span3"><i class="demo-icon icon-home"></i> <span class="i-name">icon-home</span><span class="i-code">0xe859</span></div>
|
||||
<div title="Code: 0xe85a" class="the-icons span3"><i class="demo-icon icon-info"></i> <span class="i-name">icon-info</span><span class="i-code">0xe85a</span></div>
|
||||
<div title="Code: 0xe85b" class="the-icons span3"><i class="demo-icon icon-help"></i> <span class="i-name">icon-help</span><span class="i-code">0xe85b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe85c" class="the-icons span3"><i class="icon-search"></i> <span class="i-name">icon-search</span><span class="i-code">0xe85c</span></div>
|
||||
<div title="Code: 0xe85d" class="the-icons span3"><i class="icon-flapping"></i> <span class="i-name">icon-flapping</span><span class="i-code">0xe85d</span></div>
|
||||
<div title="Code: 0xe85e" class="the-icons span3"><i class="icon-rewind"></i> <span class="i-name">icon-rewind</span><span class="i-code">0xe85e</span></div>
|
||||
<div title="Code: 0xe85f" class="the-icons span3"><i class="icon-chart-line"></i> <span class="i-name">icon-chart-line</span><span class="i-code">0xe85f</span></div>
|
||||
<div title="Code: 0xe85c" class="the-icons span3"><i class="demo-icon icon-search"></i> <span class="i-name">icon-search</span><span class="i-code">0xe85c</span></div>
|
||||
<div title="Code: 0xe85d" class="the-icons span3"><i class="demo-icon icon-flapping"></i> <span class="i-name">icon-flapping</span><span class="i-code">0xe85d</span></div>
|
||||
<div title="Code: 0xe85e" class="the-icons span3"><i class="demo-icon icon-rewind"></i> <span class="i-name">icon-rewind</span><span class="i-code">0xe85e</span></div>
|
||||
<div title="Code: 0xe85f" class="the-icons span3"><i class="demo-icon icon-chart-line"></i> <span class="i-name">icon-chart-line</span><span class="i-code">0xe85f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe860" class="the-icons span3"><i class="icon-bell-off"></i> <span class="i-name">icon-bell-off</span><span class="i-code">0xe860</span></div>
|
||||
<div title="Code: 0xe861" class="the-icons span3"><i class="icon-bell-off-empty"></i> <span class="i-name">icon-bell-off-empty</span><span class="i-code">0xe861</span></div>
|
||||
<div title="Code: 0xe862" class="the-icons span3"><i class="icon-plug"></i> <span class="i-name">icon-plug</span><span class="i-code">0xe862</span></div>
|
||||
<div title="Code: 0xe863" class="the-icons span3"><i class="icon-eye-off"></i> <span class="i-name">icon-eye-off</span><span class="i-code">0xe863</span></div>
|
||||
<div title="Code: 0xe860" class="the-icons span3"><i class="demo-icon icon-bell-off"></i> <span class="i-name">icon-bell-off</span><span class="i-code">0xe860</span></div>
|
||||
<div title="Code: 0xe861" class="the-icons span3"><i class="demo-icon icon-bell-off-empty"></i> <span class="i-name">icon-bell-off-empty</span><span class="i-code">0xe861</span></div>
|
||||
<div title="Code: 0xe862" class="the-icons span3"><i class="demo-icon icon-plug"></i> <span class="i-name">icon-plug</span><span class="i-code">0xe862</span></div>
|
||||
<div title="Code: 0xe863" class="the-icons span3"><i class="demo-icon icon-eye-off"></i> <span class="i-name">icon-eye-off</span><span class="i-code">0xe863</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe864" class="the-icons span3"><i class="icon-reschedule"></i> <span class="i-name">icon-reschedule</span><span class="i-code">0xe864</span></div>
|
||||
<div title="Code: 0xe865" class="the-icons span3"><i class="icon-cw"></i> <span class="i-name">icon-cw</span><span class="i-code">0xe865</span></div>
|
||||
<div title="Code: 0xe866" class="the-icons span3"><i class="icon-host"></i> <span class="i-name">icon-host</span><span class="i-code">0xe866</span></div>
|
||||
<div title="Code: 0xe867" class="the-icons span3"><i class="icon-thumbs-up"></i> <span class="i-name">icon-thumbs-up</span><span class="i-code">0xe867</span></div>
|
||||
<div title="Code: 0xe864" class="the-icons span3"><i class="demo-icon icon-reschedule"></i> <span class="i-name">icon-reschedule</span><span class="i-code">0xe864</span></div>
|
||||
<div title="Code: 0xe865" class="the-icons span3"><i class="demo-icon icon-cw"></i> <span class="i-name">icon-cw</span><span class="i-code">0xe865</span></div>
|
||||
<div title="Code: 0xe866" class="the-icons span3"><i class="demo-icon icon-host"></i> <span class="i-name">icon-host</span><span class="i-code">0xe866</span></div>
|
||||
<div title="Code: 0xe867" class="the-icons span3"><i class="demo-icon icon-thumbs-up"></i> <span class="i-name">icon-thumbs-up</span><span class="i-code">0xe867</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe868" class="the-icons span3"><i class="icon-thumbs-down"></i> <span class="i-name">icon-thumbs-down</span><span class="i-code">0xe868</span></div>
|
||||
<div title="Code: 0xe869" class="the-icons span3"><i class="icon-spinner"></i> <span class="i-name">icon-spinner</span><span class="i-code">0xe869</span></div>
|
||||
<div title="Code: 0xe86a" class="the-icons span3"><i class="icon-attach"></i> <span class="i-name">icon-attach</span><span class="i-code">0xe86a</span></div>
|
||||
<div title="Code: 0xe86b" class="the-icons span3"><i class="icon-keyboard"></i> <span class="i-name">icon-keyboard</span><span class="i-code">0xe86b</span></div>
|
||||
<div title="Code: 0xe868" class="the-icons span3"><i class="demo-icon icon-thumbs-down"></i> <span class="i-name">icon-thumbs-down</span><span class="i-code">0xe868</span></div>
|
||||
<div title="Code: 0xe869" class="the-icons span3"><i class="demo-icon icon-spinner"></i> <span class="i-name">icon-spinner</span><span class="i-code">0xe869</span></div>
|
||||
<div title="Code: 0xe86a" class="the-icons span3"><i class="demo-icon icon-attach"></i> <span class="i-name">icon-attach</span><span class="i-code">0xe86a</span></div>
|
||||
<div title="Code: 0xe86b" class="the-icons span3"><i class="demo-icon icon-keyboard"></i> <span class="i-name">icon-keyboard</span><span class="i-code">0xe86b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe86c" class="the-icons span3"><i class="icon-menu"></i> <span class="i-name">icon-menu</span><span class="i-code">0xe86c</span></div>
|
||||
<div title="Code: 0xe86d" class="the-icons span3"><i class="icon-wifi"></i> <span class="i-name">icon-wifi</span><span class="i-code">0xe86d</span></div>
|
||||
<div title="Code: 0xe86e" class="the-icons span3"><i class="icon-moon"></i> <span class="i-name">icon-moon</span><span class="i-code">0xe86e</span></div>
|
||||
<div title="Code: 0xe86f" class="the-icons span3"><i class="icon-chart-pie"></i> <span class="i-name">icon-chart-pie</span><span class="i-code">0xe86f</span></div>
|
||||
<div title="Code: 0xe86c" class="the-icons span3"><i class="demo-icon icon-menu"></i> <span class="i-name">icon-menu</span><span class="i-code">0xe86c</span></div>
|
||||
<div title="Code: 0xe86d" class="the-icons span3"><i class="demo-icon icon-wifi"></i> <span class="i-name">icon-wifi</span><span class="i-code">0xe86d</span></div>
|
||||
<div title="Code: 0xe86e" class="the-icons span3"><i class="demo-icon icon-moon"></i> <span class="i-name">icon-moon</span><span class="i-code">0xe86e</span></div>
|
||||
<div title="Code: 0xe86f" class="the-icons span3"><i class="demo-icon icon-chart-pie"></i> <span class="i-name">icon-chart-pie</span><span class="i-code">0xe86f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe870" class="the-icons span3"><i class="icon-chart-area"></i> <span class="i-name">icon-chart-area</span><span class="i-code">0xe870</span></div>
|
||||
<div title="Code: 0xe871" class="the-icons span3"><i class="icon-chart-bar"></i> <span class="i-name">icon-chart-bar</span><span class="i-code">0xe871</span></div>
|
||||
<div title="Code: 0xe872" class="the-icons span3"><i class="icon-beaker"></i> <span class="i-name">icon-beaker</span><span class="i-code">0xe872</span></div>
|
||||
<div title="Code: 0xe873" class="the-icons span3"><i class="icon-magic"></i> <span class="i-name">icon-magic</span><span class="i-code">0xe873</span></div>
|
||||
<div title="Code: 0xe870" class="the-icons span3"><i class="demo-icon icon-chart-area"></i> <span class="i-name">icon-chart-area</span><span class="i-code">0xe870</span></div>
|
||||
<div title="Code: 0xe871" class="the-icons span3"><i class="demo-icon icon-chart-bar"></i> <span class="i-name">icon-chart-bar</span><span class="i-code">0xe871</span></div>
|
||||
<div title="Code: 0xe872" class="the-icons span3"><i class="demo-icon icon-beaker"></i> <span class="i-name">icon-beaker</span><span class="i-code">0xe872</span></div>
|
||||
<div title="Code: 0xe873" class="the-icons span3"><i class="demo-icon icon-magic"></i> <span class="i-name">icon-magic</span><span class="i-code">0xe873</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe874" class="the-icons span3"><i class="icon-spin6 animate-spin"></i> <span class="i-name">icon-spin6</span><span class="i-code">0xe874</span></div>
|
||||
<div title="Code: 0xe874" class="the-icons span3"><i class="demo-icon icon-spin6 animate-spin"></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"></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"></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"></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"></i> <span class="i-name">icon-up-small</span><span class="i-code">0xe878</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></div>
|
||||
|
@ -3,10 +3,7 @@
|
||||
|
||||
namespace Icinga\Forms\Config\Resource;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Application\Platform;
|
||||
|
||||
/**
|
||||
@ -23,7 +20,9 @@ class DbResourceForm extends Form
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
@ -107,35 +106,4 @@ class DbResourceForm extends Form
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the current configuration points to a valid resource
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
if (false === static::isValidResource($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the resource configuration by trying to connect with it
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public static function isValidResource(Form $form)
|
||||
{
|
||||
$result = ResourceFactory::createResource(new ConfigObject($form->getValues()))->inspect();
|
||||
if ($result->hasError()) {
|
||||
$form->addError(sprintf($form->translate('Connectivity validation failed: %s'), $result->getError()));
|
||||
}
|
||||
|
||||
// TODO: display diagnostics in $result->toArray() to the user
|
||||
|
||||
return ! $result->hasError();
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,7 @@
|
||||
|
||||
namespace Icinga\Forms\Config\Resource;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Protocol\Ldap\LdapConnection;
|
||||
|
||||
/**
|
||||
@ -23,7 +20,9 @@ class LdapResourceForm extends Form
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
@ -132,39 +131,4 @@ class LdapResourceForm extends Form
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the current configuration points to a valid resource
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
if (false === static::isValidResource($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the resource configuration by trying to connect with it
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public static function isValidResource(Form $form)
|
||||
{
|
||||
$result = ResourceFactory::createResource(new ConfigObject($form->getValues()))->inspect();
|
||||
if ($result->hasError()) {
|
||||
$form->addError(sprintf(
|
||||
'%s (%s)',
|
||||
$form->translate('Connectivity validation failed, connection to the given resource not possible.'),
|
||||
$result->getError()
|
||||
));
|
||||
}
|
||||
|
||||
// TODO: display diagnostics in $result->toArray() to the user
|
||||
|
||||
return ! $result->hasError();
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,20 @@
|
||||
namespace Icinga\Forms\Config;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Application\Platform;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\Inspectable;
|
||||
use Icinga\Data\Inspection;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Forms\Config\Resource\DbResourceForm;
|
||||
use Icinga\Forms\Config\Resource\FileResourceForm;
|
||||
use Icinga\Forms\Config\Resource\LdapResourceForm;
|
||||
use Icinga\Forms\Config\Resource\LivestatusResourceForm;
|
||||
use Icinga\Forms\Config\Resource\SshResourceForm;
|
||||
use Icinga\Application\Platform;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
class ResourceConfigForm extends ConfigForm
|
||||
{
|
||||
@ -23,6 +28,7 @@ class ResourceConfigForm extends ConfigForm
|
||||
{
|
||||
$this->setName('form_config_resource');
|
||||
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||
$this->setValidatePartial(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,7 +147,9 @@ class ResourceConfigForm extends ConfigForm
|
||||
$resourceForm = $this->getResourceForm($this->getElement('type')->getValue());
|
||||
|
||||
if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) {
|
||||
if (method_exists($resourceForm, 'isValidResource') && false === $resourceForm::isValidResource($this)) {
|
||||
$inspection = static::inspectResource($this);
|
||||
if ($inspection !== null && $inspection->hasError()) {
|
||||
$this->error($inspection->getError());
|
||||
$this->addElement($this->getForceCreationCheckbox());
|
||||
return false;
|
||||
}
|
||||
@ -255,4 +263,103 @@ class ResourceConfigForm extends ConfigForm
|
||||
|
||||
$this->addElements($this->getResourceForm($resourceType)->createElements($formData)->getElements());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a resource by using the given form's values and return its inspection results
|
||||
*
|
||||
* @param Form $form
|
||||
*
|
||||
* @return Inspection
|
||||
*/
|
||||
public static function inspectResource(Form $form)
|
||||
{
|
||||
if ($form->getValue('type') !== 'ssh') {
|
||||
$resource = ResourceFactory::createResource(new ConfigObject($form->getValues()));
|
||||
if ($resource instanceof Inspectable) {
|
||||
return $resource->inspect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the configured resource's inspection checks and show the result, if necessary
|
||||
*
|
||||
* This will only run any validation if the user pushed the 'resource_validation' button.
|
||||
*
|
||||
* @param array $formData
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidPartial(array $formData)
|
||||
{
|
||||
if ($this->getElement('resource_validation')->isChecked() && parent::isValid($formData)) {
|
||||
$inspection = static::inspectResource($this);
|
||||
if ($inspection !== null) {
|
||||
$join = function ($e) use (& $join) {
|
||||
return is_string($e) ? $e : join("\n", array_map($join, $e));
|
||||
};
|
||||
$this->addElement(
|
||||
'note',
|
||||
'inspection_output',
|
||||
array(
|
||||
'order' => 0,
|
||||
'value' => '<strong>' . $this->translate('Validation Log') . "</strong>\n\n"
|
||||
. join("\n", array_map($join, $inspection->toArray())),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'pre', 'class' => 'log-output')),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ($inspection->hasError()) {
|
||||
$this->warning(sprintf(
|
||||
$this->translate('Failed to successfully validate the configuration: %s'),
|
||||
$inspection->getError()
|
||||
));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info($this->translate('The configuration has been successfully validated.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a submit button to this form and one to manually validate the configuration
|
||||
*
|
||||
* Calls parent::addSubmitButton() to add the submit button.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addSubmitButton()
|
||||
{
|
||||
parent::addSubmitButton()
|
||||
->getElement('btn_submit')
|
||||
->setDecorators(array('ViewHelper'));
|
||||
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'resource_validation',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
$this->addDisplayGroup(
|
||||
array('btn_submit', 'resource_validation'),
|
||||
'submit_validation',
|
||||
array(
|
||||
'decorators' => array(
|
||||
'FormElements',
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,7 @@
|
||||
|
||||
namespace Icinga\Forms\Config\UserBackend;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Authentication\User\DbUserBackend;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying database user backends
|
||||
@ -43,7 +39,9 @@ class DbBackendForm extends Form
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
@ -56,6 +54,20 @@ class DbBackendForm extends Form
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
@ -67,7 +79,7 @@ class DbBackendForm extends Form
|
||||
'description' => $this->translate(
|
||||
'The database connection to use for authenticating with this provider'
|
||||
),
|
||||
'multiOptions' => false === empty($this->resources)
|
||||
'multiOptions' => !empty($this->resources)
|
||||
? array_combine($this->resources, $this->resources)
|
||||
: array()
|
||||
)
|
||||
@ -80,49 +92,5 @@ class DbBackendForm extends Form
|
||||
'value' => 'db'
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the selected resource is a valid database user backend
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
if (false === static::isValidUserBackend($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public static function isValidUserBackend(Form $form)
|
||||
{
|
||||
$backend = new DbUserBackend(ResourceFactory::createResource($form->getResourceConfig()));
|
||||
$result = $backend->inspect();
|
||||
if ($result->hasError()) {
|
||||
$form->addError(sprintf($form->translate('Using the specified backend failed: %s'), $result->getError()));
|
||||
}
|
||||
|
||||
// TODO: display diagnostics in $result->toArray() to the user
|
||||
|
||||
return ! $result->hasError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configuration for the chosen resource
|
||||
*
|
||||
* @return ConfigObject
|
||||
*/
|
||||
public function getResourceConfig()
|
||||
{
|
||||
return ResourceFactory::getResourceConfig($this->getValue('resource'));
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,8 @@
|
||||
|
||||
namespace Icinga\Forms\Config\UserBackend;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Authentication\User\LdapUserBackend;
|
||||
use Icinga\Data\Inspection;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Exception\AuthenticationException;
|
||||
use Icinga\Authentication\User\UserBackend;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying LDAP user backends
|
||||
@ -46,7 +40,9 @@ class LdapBackendForm extends Form
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
@ -60,6 +56,20 @@ class LdapBackendForm extends Form
|
||||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others.'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
@ -72,11 +82,65 @@ class LdapBackendForm extends Form
|
||||
'description' => $this->translate(
|
||||
'The LDAP connection to use for authenticating with this provider.'
|
||||
),
|
||||
'multiOptions' => false === empty($this->resources)
|
||||
'multiOptions' => !empty($this->resources)
|
||||
? array_combine($this->resources, $this->resources)
|
||||
: array()
|
||||
)
|
||||
);
|
||||
|
||||
$baseDn = null;
|
||||
$hasAdOid = false;
|
||||
if (! $isAd && !empty($this->resources)) {
|
||||
$this->addElement(
|
||||
'button',
|
||||
'discovery_btn',
|
||||
array(
|
||||
'type' => 'submit',
|
||||
'value' => 'discovery_btn',
|
||||
'label' => $this->translate('Discover', 'A button to discover LDAP capabilities'),
|
||||
'title' => $this->translate(
|
||||
'Push to fill in the chosen connection\'s default settings.'
|
||||
),
|
||||
'decorators' => array(
|
||||
array('ViewHelper', array('separator' => '')),
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'element'))
|
||||
),
|
||||
'formnovalidate' => 'formnovalidate'
|
||||
)
|
||||
);
|
||||
$this->addDisplayGroup(
|
||||
array('resource', 'discovery_btn'),
|
||||
'connection_discovery',
|
||||
array(
|
||||
'decorators' => array(
|
||||
'FormElements',
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ($this->getElement('discovery_btn')->isChecked()) {
|
||||
$connection = ResourceFactory::create(
|
||||
isset($formData['resource']) ? $formData['resource'] : reset($this->resources)
|
||||
);
|
||||
$capabilities = $connection->bind()->getCapabilities();
|
||||
$baseDn = $capabilities->getDefaultNamingContext();
|
||||
$hasAdOid = $capabilities->isActiveDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
if ($isAd || $hasAdOid) {
|
||||
// ActiveDirectory defaults
|
||||
$userClass = 'user';
|
||||
$filter = '!(objectClass=computer)';
|
||||
$userNameAttribute = 'sAMAccountName';
|
||||
} else {
|
||||
// OpenLDAP defaults
|
||||
$userClass = 'inetOrgPerson';
|
||||
$filter = null;
|
||||
$userNameAttribute = 'uid';
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_class',
|
||||
@ -87,7 +151,7 @@ class LdapBackendForm extends Form
|
||||
'disabled' => $isAd ?: null,
|
||||
'label' => $this->translate('LDAP User Object Class'),
|
||||
'description' => $this->translate('The object class used for storing users on the LDAP server.'),
|
||||
'value' => $isAd ? 'user' : 'inetOrgPerson'
|
||||
'value' => $userClass
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
@ -96,7 +160,7 @@ class LdapBackendForm extends Form
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'allowEmpty' => true,
|
||||
'value' => $isAd ? '!(objectClass=computer)' : null,
|
||||
'value' => $filter,
|
||||
'label' => $this->translate('LDAP Filter'),
|
||||
'description' => $this->translate(
|
||||
'An additional filter to use when looking up users using the specified connection. '
|
||||
@ -139,7 +203,7 @@ class LdapBackendForm extends Form
|
||||
'description' => $this->translate(
|
||||
'The attribute name used for storing the user name on the LDAP server.'
|
||||
),
|
||||
'value' => $isAd ? 'sAMAccountName' : 'uid'
|
||||
'value' => $userNameAttribute
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
@ -154,48 +218,15 @@ class LdapBackendForm extends Form
|
||||
'text',
|
||||
'base_dn',
|
||||
array(
|
||||
'required' => false,
|
||||
'label' => $this->translate('LDAP Base DN'),
|
||||
'description' => $this->translate(
|
||||
'preserveDefault' => true,
|
||||
'required' => false,
|
||||
'label' => $this->translate('LDAP Base DN'),
|
||||
'description' => $this->translate(
|
||||
'The path where users can be found on the LDAP server. Leave ' .
|
||||
'empty to select all users available using the specified connection.'
|
||||
)
|
||||
),
|
||||
'value' => $baseDn
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the selected resource is a valid ldap user backend
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
if (false === static::isValidUserBackend($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public static function isValidUserBackend(Form $form)
|
||||
{
|
||||
/**
|
||||
* @var $result Inspection
|
||||
*/
|
||||
$result = UserBackend::create(null, new ConfigObject($form->getValues()))->inspect();
|
||||
if ($result->hasError()) {
|
||||
$form->addError($result->getError());
|
||||
}
|
||||
|
||||
// TODO: display diagnostics in $result->toArray() to the user
|
||||
|
||||
return ! $result->hasError();
|
||||
}
|
||||
}
|
||||
|
@ -4,26 +4,39 @@
|
||||
namespace Icinga\Forms\Config;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Platform;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Authentication\User\UserBackend;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\Inspectable;
|
||||
use Icinga\Data\Inspection;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Forms\Config\UserBackend\ExternalBackendForm;
|
||||
use Icinga\Forms\Config\UserBackend\DbBackendForm;
|
||||
use Icinga\Forms\Config\UserBackend\LdapBackendForm;
|
||||
use Icinga\Forms\Config\UserBackend\ExternalBackendForm;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form for managing user backends
|
||||
*/
|
||||
class UserBackendConfigForm extends ConfigForm
|
||||
{
|
||||
/**
|
||||
* The available resources split by type
|
||||
* The available user backend resources split by type
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
* The backend to load when displaying the form for the first time
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $backendToLoad;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
@ -31,20 +44,45 @@ class UserBackendConfigForm extends ConfigForm
|
||||
{
|
||||
$this->setName('form_config_authbackend');
|
||||
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||
$this->setValidatePartial(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource configuration to use
|
||||
*
|
||||
* @param Config $resources The resource configuration
|
||||
* @param Config $resourceConfig The resource configuration
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws ConfigurationError In case there are no valid resources for authentication available
|
||||
*/
|
||||
public function setResourceConfig(Config $resourceConfig)
|
||||
{
|
||||
$resources = array();
|
||||
foreach ($resourceConfig as $name => $resource) {
|
||||
$resources[strtolower($resource->type)][] = $name;
|
||||
if (in_array($resource->type, array('db', 'ldap'))) {
|
||||
$resources[$resource->type][] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($resources)) {
|
||||
$externalBackends = $this->config->toArray();
|
||||
array_walk(
|
||||
$externalBackends,
|
||||
function (& $authBackendCfg) {
|
||||
if (! isset($authBackendCfg['backend']) || $authBackendCfg['backend'] !== 'external') {
|
||||
$authBackendCfg = null;
|
||||
}
|
||||
}
|
||||
);
|
||||
if (count(array_filter($externalBackends)) > 0 && (
|
||||
$this->backendToLoad === null || !isset($externalBackends[$this->backendToLoad])
|
||||
)) {
|
||||
throw new ConfigurationError($this->translate(
|
||||
'Could not find any valid user backend resources.'
|
||||
. ' Please configure a resource for authentication first.'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$this->resources = $resources;
|
||||
@ -54,9 +92,11 @@ class UserBackendConfigForm extends ConfigForm
|
||||
/**
|
||||
* Return a form object for the given backend type
|
||||
*
|
||||
* @param string $type The backend type for which to return a form
|
||||
* @param string $type The backend type for which to return a form
|
||||
*
|
||||
* @return Form
|
||||
*
|
||||
* @throws InvalidArgumentException In case the given backend type is invalid
|
||||
*/
|
||||
public function getBackendForm($type)
|
||||
{
|
||||
@ -84,81 +124,103 @@ class UserBackendConfigForm extends ConfigForm
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a particular user backend
|
||||
* Populate the form with the given backend's config
|
||||
*
|
||||
* The backend to add is identified by the array-key `name'.
|
||||
*
|
||||
* @param array $values The values to extend the configuration with
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does already exist
|
||||
* @throws NotFoundError In case no backend with the given name is found
|
||||
*/
|
||||
public function add(array $values)
|
||||
public function load($name)
|
||||
{
|
||||
$name = isset($values['name']) ? $values['name'] : '';
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException($this->translate('User backend name missing'));
|
||||
} elseif ($this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException($this->translate('User backend already exists'));
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new NotFoundError('No user backend called "%s" found', $name);
|
||||
}
|
||||
|
||||
unset($values['name']);
|
||||
$this->config->setSection($name, $values);
|
||||
$this->backendToLoad = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a particular user backend
|
||||
* Add a new user backend
|
||||
*
|
||||
* @param string $name The name of the backend to edit
|
||||
* @param array $values The values to edit the configuration with
|
||||
* The backend to add is identified by the array-key `name'.
|
||||
*
|
||||
* @return array The edited backend configuration
|
||||
* @param array $data
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does not exist
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException In case $data does not contain a backend name
|
||||
* @throws IcingaException In case a backend with the same name already exists
|
||||
*/
|
||||
public function edit($name, array $values)
|
||||
public function add(array $data)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException($this->translate('Old user backend name missing'));
|
||||
} elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) {
|
||||
throw new InvalidArgumentException($this->translate('New user backend name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException($this->translate('Unknown user backend provided'));
|
||||
if (! isset($data['name'])) {
|
||||
throw new InvalidArgumentException('Key \'name\' missing');
|
||||
}
|
||||
|
||||
$backendConfig = $this->config->getSection($name);
|
||||
if ($newName !== $name) {
|
||||
// Only remove the old entry if it has changed as the order gets screwed when editing backend names
|
||||
$this->config->removeSection($name);
|
||||
$backendName = $data['name'];
|
||||
if ($this->config->hasSection($backendName)) {
|
||||
throw new IcingaException(
|
||||
$this->translate('A user backend with the name "%s" does already exist'),
|
||||
$backendName
|
||||
);
|
||||
}
|
||||
|
||||
unset($values['name']);
|
||||
$this->config->setSection($newName, $backendConfig->merge($values));
|
||||
return $backendConfig;
|
||||
unset($data['name']);
|
||||
$this->config->setSection($backendName, $data);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given user backend
|
||||
* Edit a user backend
|
||||
*
|
||||
* @param string $name The name of the backend to remove
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
*
|
||||
* @return array The removed backend configuration
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does not exist
|
||||
* @throws NotFoundError In case no backend with the given name is found
|
||||
*/
|
||||
public function remove($name)
|
||||
public function edit($name, array $data)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException($this->translate('user backend name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException($this->translate('Unknown user backend provided'));
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new NotFoundError('No user backend called "%s" found', $name);
|
||||
}
|
||||
|
||||
$backendConfig = $this->config->getSection($name);
|
||||
if (isset($data['name'])) {
|
||||
if ($data['name'] !== $name) {
|
||||
$this->config->removeSection($name);
|
||||
$name = $data['name'];
|
||||
}
|
||||
|
||||
unset($data['name']);
|
||||
}
|
||||
|
||||
$backendConfig->merge($data);
|
||||
foreach ($backendConfig->toArray() as $k => $v) {
|
||||
if ($v === null) {
|
||||
unset($backendConfig->$k);
|
||||
}
|
||||
}
|
||||
|
||||
$this->config->setSection($name, $backendConfig);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user backend
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function delete($name)
|
||||
{
|
||||
$this->config->removeSection($name);
|
||||
return $backendConfig;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,14 +231,12 @@ class UserBackendConfigForm extends ConfigForm
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does not exist
|
||||
* @throws NotFoundError In case no backend with the given name is found
|
||||
*/
|
||||
public function move($name, $position)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException($this->translate('User backend name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException($this->translate('Unknown user backend provided'));
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new NotFoundError('No user backend called "%s" found', $name);
|
||||
}
|
||||
|
||||
$backendOrder = $this->config->keys();
|
||||
@ -194,105 +254,9 @@ class UserBackendConfigForm extends ConfigForm
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or edit an user backend and save the configuration
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* Performs a connectivity validation using the submitted values. A checkbox is
|
||||
* added to the form to skip the check if it fails and redirection is aborted.
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) {
|
||||
$backendForm = $this->getBackendForm($this->getElement('type')->getValue());
|
||||
if (false === $backendForm::isValidUserBackend($this)) {
|
||||
$this->addElement($this->getForceCreationCheckbox());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$authBackend = $this->request->getQuery('backend');
|
||||
try {
|
||||
if ($authBackend === null) { // create new backend
|
||||
$this->add($this->getValues());
|
||||
$message = $this->translate('User backend "%s" has been successfully created');
|
||||
} else { // edit existing backend
|
||||
$this->edit($authBackend, $this->getValues());
|
||||
$message = $this->translate('User backend "%s" has been successfully changed');
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->save()) {
|
||||
Notification::success(sprintf($message, $this->getElement('name')->getValue()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the form in case an user backend is being edited
|
||||
*
|
||||
* @see Form::onRequest()
|
||||
*
|
||||
* @throws ConfigurationError In case the backend name is missing in the request or is invalid
|
||||
*/
|
||||
public function onRequest()
|
||||
{
|
||||
$authBackend = $this->request->getQuery('backend');
|
||||
if ($authBackend !== null) {
|
||||
if ($authBackend === '') {
|
||||
throw new ConfigurationError($this->translate('User backend name missing'));
|
||||
} elseif (! $this->config->hasSection($authBackend)) {
|
||||
throw new ConfigurationError($this->translate('Unknown user backend provided'));
|
||||
} elseif ($this->config->getSection($authBackend)->backend === null) {
|
||||
throw new ConfigurationError(
|
||||
sprintf($this->translate('Backend "%s" has no `backend\' setting'), $authBackend)
|
||||
);
|
||||
}
|
||||
|
||||
$configValues = $this->config->getSection($authBackend)->toArray();
|
||||
$configValues['type'] = $configValues['backend'];
|
||||
$configValues['name'] = $authBackend;
|
||||
$this->populate($configValues);
|
||||
} elseif (empty($this->resources)) {
|
||||
$externalBackends = array_filter(
|
||||
$this->config->toArray(),
|
||||
function ($authBackendCfg) {
|
||||
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'external';
|
||||
}
|
||||
);
|
||||
|
||||
if (false === empty($externalBackends)) {
|
||||
throw new ConfigurationError($this->translate('Could not find any resources for authentication'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a checkbox to be displayed at the beginning of the form
|
||||
* which allows the user to skip the connection validation
|
||||
*
|
||||
* @return Zend_Form_Element
|
||||
*/
|
||||
protected function getForceCreationCheckbox()
|
||||
{
|
||||
return $this->createElement(
|
||||
'checkbox',
|
||||
'force_creation',
|
||||
array(
|
||||
'order' => 0,
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Force Changes'),
|
||||
'description' => $this->translate('Check this box to enforce changes without connectivity validation')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
@ -302,7 +266,7 @@ class UserBackendConfigForm extends ConfigForm
|
||||
if (isset($this->resources['db'])) {
|
||||
$backendTypes['db'] = $this->translate('Database');
|
||||
}
|
||||
if (isset($this->resources['ldap']) && ($backendType === 'ldap' || Platform::extensionLoaded('ldap'))) {
|
||||
if (isset($this->resources['ldap'])) {
|
||||
$backendTypes['ldap'] = 'LDAP';
|
||||
$backendTypes['msldap'] = 'ActiveDirectory';
|
||||
}
|
||||
@ -336,21 +300,186 @@ class UserBackendConfigForm extends ConfigForm
|
||||
)
|
||||
);
|
||||
|
||||
if (isset($formData['force_creation']) && $formData['force_creation']) {
|
||||
if (isset($formData['skip_validation']) && $formData['skip_validation']) {
|
||||
// In case another error occured and the checkbox was displayed before
|
||||
$this->addElement($this->getForceCreationCheckbox());
|
||||
$this->addSkipValidationCheckbox();
|
||||
}
|
||||
|
||||
$this->addElements($this->getBackendForm($backendType)->createElements($formData)->getElements());
|
||||
$this->addSubForm($this->getBackendForm($backendType)->create($formData), 'backend_form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configuration for the chosen resource
|
||||
*
|
||||
* @return ConfigObject
|
||||
* Populate the configuration of the backend to load
|
||||
*/
|
||||
public function getResourceConfig()
|
||||
public function onRequest()
|
||||
{
|
||||
return ResourceFactory::getResourceConfig($this->getValue('resource'));
|
||||
if ($this->backendToLoad) {
|
||||
$data = $this->config->getSection($this->backendToLoad)->toArray();
|
||||
$data['name'] = $this->backendToLoad;
|
||||
$data['type'] = $data['backend'];
|
||||
$this->populate($data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all form element values
|
||||
*
|
||||
* @param bool $suppressArrayNotation Ignored
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValues($suppressArrayNotation = false)
|
||||
{
|
||||
$values = parent::getValues();
|
||||
$values = array_merge($values, $values['backend_form']);
|
||||
unset($values['backend_form']);
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given values are valid
|
||||
*
|
||||
* @param array $formData The data to validate
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($formData)
|
||||
{
|
||||
if (! parent::isValid($formData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (($el = $this->getElement('skip_validation')) === null || false === $el->isChecked()) {
|
||||
$inspection = static::inspectUserBackend($this);
|
||||
if ($inspection && $inspection->hasError()) {
|
||||
$this->error($inspection->getError());
|
||||
if ($el === null) {
|
||||
$this->addSkipValidationCheckbox();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a user backend by using the given form's values and return its inspection results
|
||||
*
|
||||
* Returns null for non-inspectable backends.
|
||||
*
|
||||
* @param Form $form
|
||||
*
|
||||
* @return Inspection|null
|
||||
*/
|
||||
public static function inspectUserBackend(Form $form)
|
||||
{
|
||||
$backend = UserBackend::create(null, new ConfigObject($form->getValues()));
|
||||
if ($backend instanceof Inspectable) {
|
||||
return $backend->inspect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a checkbox to the form by which the user can skip the connection validation
|
||||
*/
|
||||
protected function addSkipValidationCheckbox()
|
||||
{
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'skip_validation',
|
||||
array(
|
||||
'order' => 0,
|
||||
'ignore' => true,
|
||||
'required' => true,
|
||||
'label' => $this->translate('Skip Validation'),
|
||||
'description' => $this->translate(
|
||||
'Check this box to enforce changes without validating that authentication is possible.'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the configured backend's inspection checks and show the result, if necessary
|
||||
*
|
||||
* This will only run any validation if the user pushed the 'backend_validation' button.
|
||||
*
|
||||
* @param array $formData
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidPartial(array $formData)
|
||||
{
|
||||
if ($this->getElement('backend_validation')->isChecked() && parent::isValid($formData)) {
|
||||
$inspection = static::inspectUserBackend($this);
|
||||
if ($inspection !== null) {
|
||||
$join = function ($e) use (& $join) {
|
||||
return is_string($e) ? $e : join("\n", array_map($join, $e));
|
||||
};
|
||||
$this->addElement(
|
||||
'note',
|
||||
'inspection_output',
|
||||
array(
|
||||
'order' => 0,
|
||||
'value' => '<strong>' . $this->translate('Validation Log') . "</strong>\n\n"
|
||||
. join("\n", array_map($join, $inspection->toArray())),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'pre', 'class' => 'log-output')),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ($inspection->hasError()) {
|
||||
$this->warning(sprintf(
|
||||
$this->translate('Failed to successfully validate the configuration: %s'),
|
||||
$inspection->getError()
|
||||
));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info($this->translate('The configuration has been successfully validated.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a submit button to this form and one to manually validate the configuration
|
||||
*
|
||||
* Calls parent::addSubmitButton() to add the submit button.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addSubmitButton()
|
||||
{
|
||||
parent::addSubmitButton()
|
||||
->getElement('btn_submit')
|
||||
->setDecorators(array('ViewHelper'));
|
||||
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'backend_validation',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
$this->addDisplayGroup(
|
||||
array('btn_submit', 'backend_validation'),
|
||||
'submit_validation',
|
||||
array(
|
||||
'decorators' => array(
|
||||
'FormElements',
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,9 @@
|
||||
|
||||
namespace Icinga\Forms\Config;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
class UserBackendReorderForm extends ConfigForm
|
||||
{
|
||||
@ -29,7 +29,9 @@ class UserBackendReorderForm extends ConfigForm
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
@ -39,8 +41,6 @@ class UserBackendReorderForm extends ConfigForm
|
||||
|
||||
/**
|
||||
* Update the user backend order and save the configuration
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
@ -55,8 +55,8 @@ class UserBackendReorderForm extends ConfigForm
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
} catch (NotFoundError $_) {
|
||||
Notification::error(sprintf($this->translate('User backend "%s" not found'), $backendName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -205,10 +205,7 @@ class PreferenceForm extends Form
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Save to the Preferences'),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'div'))
|
||||
)
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -219,10 +216,7 @@ class PreferenceForm extends Form
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Save for the current Session'),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'div'))
|
||||
)
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -54,6 +54,7 @@ $iframeClass = $isIframe ? ' iframe' : '';
|
||||
<div id="layout" class="default-layout<?php if ($showFullscreen): ?> fullscreen-layout<?php endif ?>">
|
||||
<?= $this->render('body.phtml') ?>
|
||||
</div>
|
||||
<iframe id="fileupload-frame-target" name="fileupload-frame-target"></iframe>
|
||||
<!--[if IE 8]>
|
||||
<script type="text/javascript" src="<?= $this->href($ie8jsfile) ?>"></script>
|
||||
<![endif]-->
|
||||
|
10
application/layouts/scripts/wrapped.phtml
Normal file
10
application/layouts/scripts/wrapped.phtml
Normal 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>
|
@ -1,8 +1,6 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use \Zend_View_Helper_FormElement;
|
||||
|
||||
/**
|
||||
* Helper to generate a "datetime" element
|
||||
*/
|
||||
|
@ -1,6 +0,0 @@
|
||||
<div class="controls">
|
||||
<?= $this->tabs->showOnlyCloseButton() ?>
|
||||
</div>
|
||||
<div class="content">
|
||||
<?= $form; ?>
|
||||
</div>
|
@ -1,6 +0,0 @@
|
||||
<div class="controls">
|
||||
<?= $this->tabs->showOnlyCloseButton() ?>
|
||||
</div>
|
||||
<div class="content">
|
||||
<?= $form; ?>
|
||||
</div>
|
@ -33,7 +33,7 @@
|
||||
</td>
|
||||
<td data-base-target="_self">
|
||||
<?php if ($i > 0): ?>
|
||||
<button type="submit" name="backend_newpos" value="<?= sprintf(
|
||||
<button type="submit" name="backend_newpos" class="icon-only" value="<?= sprintf(
|
||||
'%s|%s',
|
||||
$backendNames[$i],
|
||||
$i - 1
|
||||
@ -43,11 +43,11 @@
|
||||
$this->translate('Move user backend %s upwards'),
|
||||
$backendNames[$i]
|
||||
); ?>">
|
||||
<?= $this->icon('up-big'); ?>
|
||||
<?= $this->icon('up-small'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if ($i + 1 < count($backendNames)): ?>
|
||||
<button type="submit" name="backend_newpos" value="<?= sprintf(
|
||||
<button type="submit" name="backend_newpos" class="icon-only" value="<?= sprintf(
|
||||
'%s|%s',
|
||||
$backendNames[$i],
|
||||
$i + 1
|
||||
@ -57,7 +57,7 @@
|
||||
$this->translate('Move user backend %s downwards'),
|
||||
$backendNames[$i]
|
||||
); ?>">
|
||||
<?= $this->icon('down-big'); ?>
|
||||
<?= $this->icon('down-small'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
@ -46,8 +46,6 @@ Requires: %{name}-vendor-HTMLPurifier
|
||||
Requires: %{name}-vendor-JShrink
|
||||
Requires: %{name}-vendor-lessphp
|
||||
Requires: %{name}-vendor-Parsedown
|
||||
Requires: %{zend}
|
||||
Obsoletes: %{name}-vendor-zend
|
||||
|
||||
|
||||
%description
|
||||
@ -84,6 +82,10 @@ Requires: %{php}-gd %{php}-intl
|
||||
%{?fedora:Requires: php-pecl-imagick}
|
||||
%{?rhel:Requires: php-pecl-imagick}
|
||||
%{?suse_version:Requires: %{php}-gettext %{php}-json %{php}-openssl %{php}-posix}
|
||||
Requires: %{zend}
|
||||
Obsoletes: %{name}-vendor-zend
|
||||
Requires: %{zend}-Db-Adapter-Pdo-Mysql
|
||||
Requires: %{zend}-Db-Adapter-Pdo-Pgsql
|
||||
|
||||
%description -n php-Icinga
|
||||
Icinga Web 2 PHP library
|
||||
|
@ -8,6 +8,7 @@ use Icinga\Data\ConfigObject;
|
||||
use Icinga\Application\Logger\Writer\FileWriter;
|
||||
use Icinga\Application\Logger\Writer\SyslogWriter;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
||||
/**
|
||||
* Logger
|
||||
@ -226,13 +227,7 @@ class Logger
|
||||
$messages = array();
|
||||
$error = $message;
|
||||
do {
|
||||
$messages[] = sprintf(
|
||||
'%s in %s:%d with message: %s',
|
||||
get_class($error),
|
||||
$error->getFile(),
|
||||
$error->getLine(),
|
||||
$error->getMessage()
|
||||
);
|
||||
$messages[] = IcingaException::describe($error);
|
||||
} while ($error = $error->getPrevious());
|
||||
$message = implode(' <- ', $messages);
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
|
||||
$insp->write($this->ds->inspect());
|
||||
try {
|
||||
$users = $this->select()->where('is_active', true)->count();
|
||||
if ($users > 1) {
|
||||
if ($users >= 1) {
|
||||
$insp->write(sprintf('%s active users', $users));
|
||||
} else {
|
||||
return $insp->error('0 active users', $users);
|
||||
|
@ -4,6 +4,7 @@
|
||||
namespace Icinga\Cli;
|
||||
|
||||
use Icinga\Application\ApplicationBootstrap as App;
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Cli\Params;
|
||||
use Icinga\Cli\Screen;
|
||||
@ -265,7 +266,8 @@ class Loader
|
||||
if ($obj && $obj instanceof Command && $obj->showTrace()) {
|
||||
echo $this->formatTrace($e->getTrace());
|
||||
}
|
||||
$this->fail($e->getMessage());
|
||||
|
||||
$this->fail(IcingaException::describe($e));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,7 @@ class Inspection
|
||||
if ($entry instanceof Inspection) {
|
||||
$this->log[$entry->description] = $entry->toArray();
|
||||
} else {
|
||||
Logger::debug($entry);
|
||||
$this->log[] = $entry;
|
||||
}
|
||||
}
|
||||
@ -77,7 +78,8 @@ class Inspection
|
||||
if (isset($this->error)) {
|
||||
throw new ProgrammingError('Inspection object used after error');
|
||||
}
|
||||
$this->write($entry);
|
||||
Logger::error($entry);
|
||||
$this->log[] = $entry;
|
||||
$this->error = $entry;
|
||||
return $this;
|
||||
}
|
||||
|
9
library/Icinga/Data/Paginatable.php
Normal file
9
library/Icinga/Data/Paginatable.php
Normal 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 {};
|
||||
|
@ -3,6 +3,4 @@
|
||||
|
||||
namespace Icinga\Data;
|
||||
|
||||
use Countable;
|
||||
|
||||
interface QueryInterface extends Fetchable, Filterable, Limitable, Sortable, Countable {};
|
||||
interface QueryInterface extends Fetchable, Filterable, Paginatable, Sortable {};
|
||||
|
14
library/Icinga/Data/SortRules.php
Normal file
14
library/Icinga/Data/SortRules.php
Normal 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();
|
||||
}
|
@ -40,4 +40,24 @@ class IcingaException extends Exception
|
||||
$e = new ReflectionClass(get_called_class());
|
||||
return $e->newInstanceArgs($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the given exception formatted as one-liner
|
||||
*
|
||||
* The format used is: %class% in %path%:%line% with message: %message%
|
||||
*
|
||||
* @param Exception $exception
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function describe(Exception $exception)
|
||||
{
|
||||
return sprintf(
|
||||
'%s in %s:%d with message: %s',
|
||||
get_class($exception),
|
||||
$exception->getFile(),
|
||||
$exception->getLine(),
|
||||
$exception->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ class LdapConnection implements Selectable, Inspectable
|
||||
public function bind()
|
||||
{
|
||||
if ($this->bound) {
|
||||
return;
|
||||
return $this;
|
||||
}
|
||||
|
||||
$ds = $this->getConnection();
|
||||
@ -332,6 +332,7 @@ class LdapConnection implements Selectable, Inspectable
|
||||
}
|
||||
|
||||
$this->bound = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,7 +78,7 @@ abstract class Repository implements Selectable
|
||||
protected $filterColumns;
|
||||
|
||||
/**
|
||||
* The default sort rules to be applied on a query
|
||||
* The sort rules to be applied on a query
|
||||
*
|
||||
* This may be initialized by concrete repository implementations, in the following format
|
||||
* <pre><code>
|
||||
@ -284,7 +284,7 @@ abstract class Repository implements Selectable
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default sort rules to be applied on a query
|
||||
* Return the sort rules to be applied on a query
|
||||
*
|
||||
* Calls $this->initializeSortRules() in case $this->sortRules is null.
|
||||
*
|
||||
|
@ -9,12 +9,13 @@ use Icinga\Application\Benchmark;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\QueryInterface;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\SortRules;
|
||||
use Icinga\Exception\QueryException;
|
||||
|
||||
/**
|
||||
* Query class supposed to mediate between a repository and its datasource's query
|
||||
*/
|
||||
class RepositoryQuery implements QueryInterface, Iterator
|
||||
class RepositoryQuery implements QueryInterface, SortRules, Iterator
|
||||
{
|
||||
/**
|
||||
* The repository being used
|
||||
@ -212,6 +213,16 @@ class RepositoryQuery implements QueryInterface, Iterator
|
||||
return $this->query->getFilter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sort rules being applied on this query
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSortRules()
|
||||
{
|
||||
return $this->repository->getSortRules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a sort rule for this query
|
||||
*
|
||||
@ -226,7 +237,7 @@ class RepositoryQuery implements QueryInterface, Iterator
|
||||
*/
|
||||
public function order($field = null, $direction = null, $ignoreDefault = false)
|
||||
{
|
||||
$sortRules = $this->repository->getSortRules();
|
||||
$sortRules = $this->getSortRules();
|
||||
if ($field === null) {
|
||||
// Use first available sort rule as default
|
||||
if (empty($sortRules)) {
|
||||
|
@ -37,13 +37,13 @@ class Controller extends ModuleActionController
|
||||
return;
|
||||
}
|
||||
|
||||
if (($sort = $request->getPost('sort'))) {
|
||||
if (($sort = $request->getPost('sort')) || ($direction = $request->getPost('dir'))) {
|
||||
$url = Url::fromRequest();
|
||||
$url->setParam('sort', $sort);
|
||||
if (($dir = $request->getPost('dir'))) {
|
||||
$url->setParam('dir', $dir);
|
||||
if ($sort) {
|
||||
$url->setParam('sort', $sort);
|
||||
$url->remove('dir');
|
||||
} else {
|
||||
$url->removeParam('dir');
|
||||
$url->setParam('dir', $direction);
|
||||
}
|
||||
|
||||
$this->redirectNow($url);
|
||||
|
@ -96,6 +96,9 @@ class ActionController extends Zend_Controller_Action
|
||||
if ($this->rerenderLayout = $request->getUrl()->shift('renderLayout')) {
|
||||
$this->xhrLayout = 'body';
|
||||
}
|
||||
if ($request->getUrl()->shift('_disableLayout')) {
|
||||
$this->_helper->layout()->disableLayout();
|
||||
}
|
||||
|
||||
if ($this->requiresLogin()) {
|
||||
$this->redirectToLogin(Url::fromRequest());
|
||||
@ -455,11 +458,11 @@ class ActionController extends Zend_Controller_Action
|
||||
foreach ($notifications->getMessages() as $m) {
|
||||
$notificationList[] = rawurlencode($m->type . ' ' . $m->message);
|
||||
}
|
||||
$resp->setHeader('X-Icinga-Notification', implode('&', $notificationList));
|
||||
$resp->setHeader('X-Icinga-Notification', implode('&', $notificationList), true);
|
||||
}
|
||||
|
||||
if ($this->reloadCss) {
|
||||
$resp->setHeader('X-Icinga-CssReload', 'now');
|
||||
$resp->setHeader('X-Icinga-CssReload', 'now', true);
|
||||
}
|
||||
|
||||
if ($this->view->title) {
|
||||
@ -469,18 +472,19 @@ class ActionController extends Zend_Controller_Action
|
||||
}
|
||||
$resp->setHeader(
|
||||
'X-Icinga-Title',
|
||||
rawurlencode($this->view->title . ' :: Icinga Web')
|
||||
rawurlencode($this->view->title . ' :: Icinga Web'),
|
||||
true
|
||||
);
|
||||
} else {
|
||||
$resp->setHeader('X-Icinga-Title', rawurlencode('Icinga Web'));
|
||||
$resp->setHeader('X-Icinga-Title', rawurlencode('Icinga Web'), true);
|
||||
}
|
||||
|
||||
if ($this->rerenderLayout) {
|
||||
$this->getResponse()->setHeader('X-Icinga-Container', 'layout');
|
||||
$this->getResponse()->setHeader('X-Icinga-Container', 'layout', true);
|
||||
}
|
||||
|
||||
if ($this->autorefreshInterval !== null) {
|
||||
$resp->setHeader('X-Icinga-Refresh', $this->autorefreshInterval);
|
||||
$resp->setHeader('X-Icinga-Refresh', $this->autorefreshInterval, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,13 +3,13 @@
|
||||
|
||||
namespace Icinga\Web;
|
||||
|
||||
use LogicException;
|
||||
use Zend_Config;
|
||||
use Zend_Form;
|
||||
use Zend_Form_Element;
|
||||
use Zend_View_Interface;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Authentication\Manager;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Security\SecurityException;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Web\Form\ErrorLabeller;
|
||||
@ -84,7 +84,7 @@ class Form extends Zend_Form
|
||||
/**
|
||||
* The url to redirect to upon success
|
||||
*
|
||||
* @var string|Url
|
||||
* @var Url
|
||||
*/
|
||||
protected $redirectUrl;
|
||||
|
||||
@ -160,6 +160,13 @@ class Form extends Zend_Form
|
||||
*/
|
||||
protected $notifications;
|
||||
|
||||
/**
|
||||
* The hints of this form
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $hints;
|
||||
|
||||
/**
|
||||
* Whether the Autosubmit decorator should be applied to this form
|
||||
*
|
||||
@ -222,12 +229,12 @@ class Form extends Zend_Form
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws LogicException If the callback is not callable
|
||||
* @throws ProgrammingError If the callback is not callable
|
||||
*/
|
||||
public function setOnSuccess($onSuccess)
|
||||
{
|
||||
if (! is_callable($onSuccess)) {
|
||||
throw new LogicException('The option `onSuccess\' is not callable');
|
||||
throw new ProgrammingError('The option `onSuccess\' is not callable');
|
||||
}
|
||||
$this->onSuccess = $onSuccess;
|
||||
return $this;
|
||||
@ -262,9 +269,17 @@ class Form extends Zend_Form
|
||||
* @param string|Url $url The url to redirect to
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws ProgrammingError In case $url is neither a string nor a instance of Icinga\Web\Url
|
||||
*/
|
||||
public function setRedirectUrl($url)
|
||||
{
|
||||
if (is_string($url)) {
|
||||
$url = Url::fromPath($url, array(), $this->getRequest());
|
||||
} elseif (! $url instanceof Url) {
|
||||
throw new ProgrammingError('$url must be a string or instance of Icinga\Web\Url');
|
||||
}
|
||||
|
||||
$this->redirectUrl = $url;
|
||||
return $this;
|
||||
}
|
||||
@ -272,14 +287,16 @@ class Form extends Zend_Form
|
||||
/**
|
||||
* Return the url to redirect to upon success
|
||||
*
|
||||
* @return string|Url
|
||||
* @return Url
|
||||
*/
|
||||
public function getRedirectUrl()
|
||||
{
|
||||
if ($this->redirectUrl === null) {
|
||||
$url = Url::fromRequest(array(), $this->getRequest());
|
||||
// Be sure to remove all form dependent params because we do not want to submit it again
|
||||
$this->redirectUrl = $url->without(array_keys($this->getElements()));
|
||||
$this->redirectUrl = $this->getRequest()->getUrl();
|
||||
if ($this->getMethod() === 'get') {
|
||||
// Be sure to remove all form dependent params because we do not want to submit it again
|
||||
$this->redirectUrl = $this->redirectUrl->without(array_keys($this->getElements()));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->redirectUrl;
|
||||
@ -566,6 +583,49 @@ class Form extends Zend_Form
|
||||
return $this->notifications;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the hints for this form
|
||||
*
|
||||
* @param array $hints
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setHints(array $hints)
|
||||
{
|
||||
$this->hints = $hints;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a hint for this form
|
||||
*
|
||||
* If $hint is an array the second value should be an
|
||||
* array as well containing additional HTML properties.
|
||||
*
|
||||
* @param string|array $hint
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addHint($hint)
|
||||
{
|
||||
$this->hints[] = $hint;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hints of this form
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHints()
|
||||
{
|
||||
if ($this->hints === null) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $this->hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the Autosubmit decorator should be applied to this form
|
||||
*
|
||||
@ -600,22 +660,26 @@ class Form extends Zend_Form
|
||||
*/
|
||||
public function create(array $formData = array())
|
||||
{
|
||||
if (false === $this->created) {
|
||||
if (! $this->created) {
|
||||
$this->createElements($formData);
|
||||
$this->addFormIdentification()
|
||||
->addCsrfCounterMeasure()
|
||||
->addSubmitButton();
|
||||
|
||||
// Use Form::getAttrib() instead of Form::getAction() here because we want to explicitly check against
|
||||
// null. Form::getAction() would return the empty string '' if the action is not set.
|
||||
// For not setting the action attribute use Form::setAction(''). This is required for for the
|
||||
// accessibility's enable/disable auto-refresh mechanic
|
||||
if ($this->getAttrib('action') === null) {
|
||||
// Use Form::getAttrib() instead of Form::getAction() here because we want to explicitly check against
|
||||
// null. Form::getAction() would return the empty string '' if the action is not set.
|
||||
// For not setting the action attribute use Form::setAction(''). This is required for for the
|
||||
// accessibility's enable/disable auto-refresh mechanic
|
||||
$action = $this->getRequest()->getUrl();
|
||||
if ($this->getMethod() === 'get') {
|
||||
$action = $action->without(array_keys($this->getElements()));
|
||||
}
|
||||
|
||||
// TODO(el): Re-evalute this necessity. JavaScript could use the container's URL if there's no action set.
|
||||
// We MUST set an action as JS gets confused otherwise, if
|
||||
// this form is being displayed in an additional column
|
||||
$this->setAction(Url::fromRequest()->without(array_keys($this->getElements())));
|
||||
$this->setAction($action);
|
||||
}
|
||||
|
||||
$this->created = true;
|
||||
@ -862,7 +926,7 @@ class Form extends Zend_Form
|
||||
*/
|
||||
public function addFormIdentification()
|
||||
{
|
||||
if (false === $this->uidDisabled && $this->getElement($this->uidElementName) === null) {
|
||||
if (! $this->uidDisabled && $this->getElement($this->uidElementName) === null) {
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
$this->uidElementName,
|
||||
@ -884,7 +948,7 @@ class Form extends Zend_Form
|
||||
*/
|
||||
public function addCsrfCounterMeasure()
|
||||
{
|
||||
if (false === $this->tokenDisabled && $this->getElement($this->tokenElementName) === null) {
|
||||
if (! $this->tokenDisabled && $this->getElement($this->tokenElementName) === null) {
|
||||
$this->addElement(new CsrfCounterMeasure($this->tokenElementName));
|
||||
}
|
||||
|
||||
@ -946,12 +1010,20 @@ class Form extends Zend_Form
|
||||
|
||||
$formData = $this->getRequestData();
|
||||
if ($this->getUidDisabled() || $this->wasSent($formData)) {
|
||||
if (($frameUpload = (bool) $request->getUrl()->shift('_frameUpload', false))) {
|
||||
$this->getView()->layout()->setLayout('wrapped');
|
||||
}
|
||||
|
||||
$this->populate($formData); // Necessary to get isSubmitted() to work
|
||||
if (! $this->getSubmitLabel() || $this->isSubmitted()) {
|
||||
if ($this->isValid($formData)
|
||||
&& (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $this))
|
||||
|| ($this->onSuccess === null && false !== $this->onSuccess()))) {
|
||||
$this->getResponse()->redirectAndExit($this->getRedirectUrl());
|
||||
if (! $frameUpload) {
|
||||
$this->getResponse()->redirectAndExit($this->getRedirectUrl());
|
||||
} else {
|
||||
$this->getView()->layout()->redirectUrl = $this->getRedirectUrl()->getAbsoluteUrl();
|
||||
}
|
||||
}
|
||||
} elseif ($this->getValidatePartial()) {
|
||||
// The form can't be processed but we may want to show validation errors though
|
||||
@ -1087,10 +1159,11 @@ class Form extends Zend_Form
|
||||
->addDecorator('HtmlTag', array('tag' => 'div', 'class' => 'header'));
|
||||
}
|
||||
|
||||
$this->addDecorator('FormErrors', array('onlyCustomFormErrors' => true))
|
||||
$this->addDecorator('FormDescriptions')
|
||||
->addDecorator('FormNotifications')
|
||||
->addDecorator('FormDescriptions')
|
||||
->addDecorator('FormErrors', array('onlyCustomFormErrors' => true))
|
||||
->addDecorator('FormElements')
|
||||
->addDecorator('FormHints')
|
||||
//->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
|
||||
->addDecorator('Form');
|
||||
}
|
||||
|
@ -7,35 +7,10 @@ use Zend_Form_Decorator_Abstract;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Decorator to add a list of descriptions at the top of a form
|
||||
*
|
||||
* The description for required form elements is automatically being handled.
|
||||
* Decorator to add a list of descriptions at the top or bottom of a form
|
||||
*/
|
||||
class FormDescriptions extends Zend_Form_Decorator_Abstract
|
||||
{
|
||||
/**
|
||||
* A list of element class names to be ignored when detecting which message to use to describe required elements
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $blacklist;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($options = null)
|
||||
{
|
||||
parent::__construct($options);
|
||||
$this->blacklist = array(
|
||||
'Zend_Form_Element_Hidden',
|
||||
'Zend_Form_Element_Submit',
|
||||
'Zend_Form_Element_Button',
|
||||
'Icinga\Web\Form\Element\Note',
|
||||
'Icinga\Web\Form\Element\Button',
|
||||
'Icinga\Web\Form\Element\CsrfCounterMeasure'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render form descriptions
|
||||
*
|
||||
@ -55,18 +30,7 @@ class FormDescriptions extends Zend_Form_Decorator_Abstract
|
||||
return $content;
|
||||
}
|
||||
|
||||
$descriptions = $this->recurseForm($form, $entirelyRequired);
|
||||
if ($entirelyRequired) {
|
||||
$descriptions[] = $form->getView()->translate(
|
||||
'All fields are required and must be filled in to complete the form.'
|
||||
);
|
||||
} elseif ($entirelyRequired === false) {
|
||||
$descriptions[] = $form->getView()->translate(sprintf(
|
||||
'Required fields are marked with %s and must be filled in to complete the form.',
|
||||
$form->getRequiredCue()
|
||||
));
|
||||
}
|
||||
|
||||
$descriptions = $this->recurseForm($form);
|
||||
if (empty($descriptions)) {
|
||||
return $content;
|
||||
}
|
||||
@ -92,53 +56,15 @@ class FormDescriptions extends Zend_Form_Decorator_Abstract
|
||||
/**
|
||||
* Recurse the given form and return the descriptions for it and all of its subforms
|
||||
*
|
||||
* @param Form $form The form to recurse
|
||||
* @param mixed $entirelyRequired Set by reference, true means all elements in the hierarchy are
|
||||
* required, false only a partial subset and null none at all
|
||||
* @param bool $elementsPassed Whether there were any elements passed during the recursion until now
|
||||
* @param Form $form The form to recurse
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function recurseForm(Form $form, & $entirelyRequired = null, $elementsPassed = false)
|
||||
protected function recurseForm(Form $form)
|
||||
{
|
||||
$requiredLabels = array();
|
||||
if ($form->getRequiredCue() !== null) {
|
||||
$partiallyRequired = $partiallyOptional = false;
|
||||
foreach ($form->getElements() as $element) {
|
||||
if (! in_array($element->getType(), $this->blacklist)) {
|
||||
if (! $element->isRequired()) {
|
||||
$partiallyOptional = true;
|
||||
if ($entirelyRequired) {
|
||||
$entirelyRequired = false;
|
||||
}
|
||||
} else {
|
||||
$partiallyRequired = true;
|
||||
if (($label = $element->getDecorator('label')) !== false) {
|
||||
$requiredLabels[] = $label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! $elementsPassed) {
|
||||
$elementsPassed = $partiallyRequired || $partiallyOptional;
|
||||
if ($entirelyRequired === null && $partiallyRequired) {
|
||||
$entirelyRequired = ! $partiallyOptional;
|
||||
}
|
||||
} elseif ($entirelyRequired === null && $partiallyRequired) {
|
||||
$entirelyRequired = false;
|
||||
}
|
||||
}
|
||||
|
||||
$descriptions = array($form->getDescriptions());
|
||||
foreach ($form->getSubForms() as $subForm) {
|
||||
$descriptions[] = $this->recurseForm($subForm, $entirelyRequired, $elementsPassed);
|
||||
}
|
||||
|
||||
if ($entirelyRequired) {
|
||||
foreach ($requiredLabels as $label) {
|
||||
$label->setRequiredSuffix('');
|
||||
}
|
||||
$descriptions[] = $this->recurseForm($subForm);
|
||||
}
|
||||
|
||||
return call_user_func_array('array_merge', $descriptions);
|
||||
|
142
library/Icinga/Web/Form/Decorator/FormHints.php
Normal file
142
library/Icinga/Web/Form/Decorator/FormHints.php
Normal 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);
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ namespace Icinga\Web\Form;
|
||||
use BadMethodCallException;
|
||||
use Zend_Translate_Adapter;
|
||||
use Zend_Validate_NotEmpty;
|
||||
use Zend_Validate_File_MimeType;
|
||||
use Icinga\Web\Form\Validator\DateTimeValidator;
|
||||
use Icinga\Web\Form\Validator\ReadablePathValidator;
|
||||
use Icinga\Web\Form\Validator\WritablePathValidator;
|
||||
@ -42,10 +43,15 @@ class ErrorLabeller extends Zend_Translate_Adapter
|
||||
$label = $element->getLabel() ?: $element->getName();
|
||||
|
||||
return array(
|
||||
Zend_Validate_NotEmpty::IS_EMPTY => sprintf(t('%s is required and must not be empty'), $label),
|
||||
WritablePathValidator::NOT_WRITABLE => sprintf(t('%s is not writable', 'config.path'), $label),
|
||||
WritablePathValidator::DOES_NOT_EXIST => sprintf(t('%s does not exist', 'config.path'), $label),
|
||||
ReadablePathValidator::NOT_READABLE => sprintf(t('%s is not readable', 'config.path'), $label),
|
||||
Zend_Validate_NotEmpty::IS_EMPTY => sprintf(t('%s is required and must not be empty'), $label),
|
||||
Zend_Validate_File_MimeType::FALSE_TYPE => sprintf(
|
||||
t('%s (%%value%%) has a false MIME type of "%%type%%"'),
|
||||
$label
|
||||
),
|
||||
Zend_Validate_File_MimeType::NOT_DETECTED => sprintf(t('%s (%%value%%) has no MIME type'), $label),
|
||||
WritablePathValidator::NOT_WRITABLE => sprintf(t('%s is not writable', 'config.path'), $label),
|
||||
WritablePathValidator::DOES_NOT_EXIST => sprintf(t('%s does not exist', 'config.path'), $label),
|
||||
ReadablePathValidator::NOT_READABLE => sprintf(t('%s is not readable', 'config.path'), $label),
|
||||
DateTimeValidator::INVALID_DATETIME_FORMAT => sprintf(
|
||||
t('%s not in the expected format: %%value%%'),
|
||||
$label
|
||||
|
@ -8,7 +8,6 @@ use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use RegexIterator;
|
||||
use RecursiveRegexIterator;
|
||||
use Zend_Controller_Front;
|
||||
use Icinga\Application\Icinga;
|
||||
use lessc;
|
||||
|
||||
@ -31,8 +30,6 @@ class LessCompiler
|
||||
*/
|
||||
private $lessc;
|
||||
|
||||
private $baseUrl;
|
||||
|
||||
private $source;
|
||||
|
||||
/**
|
||||
@ -44,6 +41,17 @@ class LessCompiler
|
||||
$this->lessc = new lessc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the extendend import functionality
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function disableExtendedImport()
|
||||
{
|
||||
$this->lessc->importDisabled = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function compress()
|
||||
{
|
||||
$this->lessc->setPreserveComments(false);
|
||||
|
@ -118,7 +118,13 @@ class MenuRenderer extends RecursiveIteratorIterator
|
||||
try {
|
||||
return $child->getRenderer()->render($child);
|
||||
} catch (Exception $e) {
|
||||
Logger::error('Could not invoke custom renderer. Exception: '. $e->getMessage());
|
||||
Logger::error(
|
||||
'Could not invoke custom menu renderer. %s in %s:%d with message: %s',
|
||||
get_class($e),
|
||||
$e->getFile(),
|
||||
$e->getLine(),
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,6 +99,7 @@ class StyleSheet
|
||||
}
|
||||
|
||||
$less = new LessCompiler();
|
||||
$less->disableExtendedImport();
|
||||
foreach ($lessFiles as $file) {
|
||||
$less->addFile($file);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
namespace Icinga\Web\Widget;
|
||||
|
||||
use Icinga\Data\QueryInterface;
|
||||
use Icinga\Data\Paginatable;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
|
||||
/**
|
||||
@ -14,7 +14,7 @@ class Paginator extends AbstractWidget
|
||||
/**
|
||||
* The query the paginator widget is created for
|
||||
*
|
||||
* @var QueryInterface
|
||||
* @var Paginatable
|
||||
*/
|
||||
protected $query;
|
||||
|
||||
@ -28,11 +28,11 @@ class Paginator extends AbstractWidget
|
||||
/**
|
||||
* Set the query to create the paginator widget for
|
||||
*
|
||||
* @param QueryInterface $query
|
||||
* @param Paginatable $query
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setQuery(QueryInterface $query)
|
||||
public function setQuery(Paginatable $query)
|
||||
{
|
||||
$this->query = $query;
|
||||
return $this;
|
||||
|
@ -3,30 +3,26 @@
|
||||
|
||||
namespace Icinga\Web\Widget;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Data\Sortable;
|
||||
use Icinga\Data\SortRules;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Data\Sortable;
|
||||
use Icinga\Application\Icinga;
|
||||
|
||||
/**
|
||||
* SortBox widget
|
||||
*
|
||||
* The "SortBox" Widget allows you to create a generic sort input for sortable views. It automatically creates a form
|
||||
* containing a select box with all sort options and a dropbox with the sort direction. It also handles automatic
|
||||
* submission of sorting changes and draws an additional submit button when JavaScript is disabled.
|
||||
* The "SortBox" Widget allows you to create a generic sort input for sortable views. It automatically creates a select
|
||||
* box with all sort options and a dropbox with the sort direction. It also handles automatic submission of sorting
|
||||
* changes and draws an additional submit button when JavaScript is disabled.
|
||||
*
|
||||
* The constructor takes an string for the component name and an array containing the select options, where the key is
|
||||
* The constructor takes a string for the component name and an array containing the select options, where the key is
|
||||
* the value to be submitted and the value is the label that will be shown. You then should call setRequest in order
|
||||
* to make sure the form is correctly populated when a request with a sort parameter is being made.
|
||||
*
|
||||
* Example:
|
||||
* <pre><code>
|
||||
* $this->view->sortControl = new SortBox(
|
||||
* $this->getRequest()->getActionName(),
|
||||
* $columns
|
||||
* );
|
||||
* $this->view->sortControl->setRequest($this->getRequest());
|
||||
* </code></pre>
|
||||
* Call setQuery in case you'll do not want to handle URL parameters manually, but to automatically apply the user's
|
||||
* chosen sort rules on the given sortable query. This will also allow the SortBox to display the user the correct
|
||||
* default sort rules if the given query provides already some sort rules.
|
||||
*/
|
||||
class SortBox extends AbstractWidget
|
||||
{
|
||||
@ -38,25 +34,25 @@ class SortBox extends AbstractWidget
|
||||
protected $sortFields;
|
||||
|
||||
/**
|
||||
* The name of the form that will be created
|
||||
* The name used to uniquely identfy the forms being created
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* A request object used for initial form population
|
||||
* The request to fetch sort rules from
|
||||
*
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* What to apply sort parameters on
|
||||
* The query to apply sort rules on
|
||||
*
|
||||
* @var Sortable
|
||||
*/
|
||||
protected $query = null;
|
||||
protected $query;
|
||||
|
||||
/**
|
||||
* Create a SortBox with the entries from $sortFields
|
||||
@ -84,9 +80,9 @@ class SortBox extends AbstractWidget
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the parameters from the given request on this SortBox
|
||||
* Set the request to fetch sort rules from
|
||||
*
|
||||
* @param Request $request The request to use for populating the form
|
||||
* @param Request $request
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
@ -97,9 +93,11 @@ class SortBox extends AbstractWidget
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Sortable $query
|
||||
* Set the query to apply sort rules on
|
||||
*
|
||||
* @return $this
|
||||
* @param Sortable $query
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setQuery(Sortable $query)
|
||||
{
|
||||
@ -107,19 +105,54 @@ class SortBox extends AbstractWidget
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the sort rules from the given or current request on the query
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function handleRequest(Request $request = null)
|
||||
{
|
||||
if ($this->query !== null) {
|
||||
if ($request === null) {
|
||||
$request = Icinga::app()->getFrontController()->getRequest();
|
||||
}
|
||||
if ($sort = $request->getParam('sort')) {
|
||||
|
||||
if (($sort = $request->getParam('sort'))) {
|
||||
$this->query->order($sort, $request->getParam('dir'));
|
||||
} elseif (($dir = $request->getParam('dir'))) {
|
||||
$this->query->order(null, $dir);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default sort rule for the query
|
||||
*
|
||||
* @param string $column An optional column
|
||||
*
|
||||
* @return array An array of two values: $column, $direction
|
||||
*/
|
||||
protected function getSortDefaults($column = null)
|
||||
{
|
||||
$direction = null;
|
||||
if ($this->query !== null && $this->query instanceof SortRules) {
|
||||
$sortRules = $this->query->getSortRules();
|
||||
if ($column === null) {
|
||||
$column = key($sortRules);
|
||||
}
|
||||
|
||||
if ($column !== null && isset($sortRules[$column]['order'])) {
|
||||
$direction = strtoupper($sortRules[$column]['order']) === Sortable::SORT_DESC ? 'desc' : 'asc';
|
||||
}
|
||||
}
|
||||
|
||||
return array($column, $direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render this SortBox as HTML
|
||||
*
|
||||
@ -127,43 +160,68 @@ class SortBox extends AbstractWidget
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$form = new Form();
|
||||
$form->setTokenDisabled();
|
||||
$form->setName($this->name);
|
||||
$form->setAttrib('class', 'sort-control inline');
|
||||
|
||||
$form->addElement(
|
||||
$columnForm = new Form();
|
||||
$columnForm->setTokenDisabled();
|
||||
$columnForm->setName($this->name . '-column');
|
||||
$columnForm->setAttrib('class', 'inline');
|
||||
$columnForm->addElement(
|
||||
'select',
|
||||
'sort',
|
||||
array(
|
||||
'autosubmit' => true,
|
||||
'label' => $this->view()->translate('Sort by'),
|
||||
'multiOptions' => $this->sortFields
|
||||
)
|
||||
);
|
||||
$form->getElement('sort')->setDecorators(array(
|
||||
array('ViewHelper'),
|
||||
array('Label')
|
||||
));
|
||||
$form->addElement(
|
||||
'select',
|
||||
'dir',
|
||||
array(
|
||||
'autosubmit' => true,
|
||||
'multiOptions' => array(
|
||||
'asc' => 'Asc',
|
||||
'desc' => 'Desc',
|
||||
),
|
||||
'multiOptions' => $this->sortFields,
|
||||
'decorators' => array(
|
||||
array('ViewHelper')
|
||||
array('ViewHelper'),
|
||||
array('Label')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$orderForm = new Form();
|
||||
$orderForm->setTokenDisabled();
|
||||
$orderForm->setName($this->name . '-order');
|
||||
$orderForm->setAttrib('class', 'inline');
|
||||
$orderForm->addElement(
|
||||
'select',
|
||||
'dir',
|
||||
array(
|
||||
'autosubmit' => true,
|
||||
'label' => $this->view()->translate('Direction', 'sort direction'),
|
||||
'multiOptions' => array(
|
||||
'asc' => $this->view()->translate('Ascending', 'sort direction'),
|
||||
'desc' => $this->view()->translate('Descending', 'sort direction')
|
||||
),
|
||||
'decorators' => array(
|
||||
array('ViewHelper'),
|
||||
array('Label', array('class' => 'no-js'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$column = null;
|
||||
if ($this->request) {
|
||||
$form->populate($this->request->getParams());
|
||||
$url = $this->request->getUrl();
|
||||
if ($url->hasParam('sort')) {
|
||||
$column = $url->getParam('sort');
|
||||
|
||||
if ($url->hasParam('dir')) {
|
||||
$direction = $url->getParam('dir');
|
||||
} else {
|
||||
list($_, $direction) = $this->getSortDefaults($column);
|
||||
}
|
||||
} elseif ($url->hasParam('dir')) {
|
||||
$direction = $url->getParam('dir');
|
||||
list($column, $_) = $this->getSortDefaults();
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
if ($column === null) {
|
||||
list($column, $direction) = $this->getSortDefaults();
|
||||
}
|
||||
|
||||
$columnForm->populate(array('sort' => $column));
|
||||
$orderForm->populate(array('dir' => $direction));
|
||||
return '<div class="sort-control">' . $columnForm . $orderForm . '</div>';
|
||||
}
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ EOT;
|
||||
|
||||
private function renderRefreshTab()
|
||||
{
|
||||
$url = Url::fromRequest()->without('renderLayout');
|
||||
$url = Icinga::app()->getFrontController()->getRequest()->getUrl();
|
||||
$tab = $this->get($this->getActiveName());
|
||||
|
||||
if ($tab !== null) {
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use \Zend_Controller_Action_Exception;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Module\Doc\DocController;
|
||||
|
||||
@ -25,10 +24,7 @@ class Doc_IcingawebController extends DocController
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
$this->translate('Documentation for Icinga Web 2 is not available'),
|
||||
404
|
||||
);
|
||||
$this->httpNotFound($this->translate('Documentation for Icinga Web 2 is not available'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use \Zend_Controller_Action_Exception;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Module\Doc\DocController;
|
||||
use Icinga\Module\Doc\Exception\DocException;
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use \Zend_Controller_Action_Exception;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Module\Doc\DocController;
|
||||
use Icinga\Module\Doc\DocParser;
|
||||
|
@ -9,6 +9,7 @@ class Monitoring_TacticalController extends MonitoringController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->setAutorefreshInterval(15);
|
||||
$this->getTabs()->add(
|
||||
'tactical_overview',
|
||||
array(
|
||||
|
@ -16,7 +16,7 @@ abstract class CommandForm extends Form
|
||||
/**
|
||||
* Monitoring backend
|
||||
*
|
||||
* @var Backend
|
||||
* @var MonitoringBackend
|
||||
*/
|
||||
protected $backend;
|
||||
|
||||
@ -36,7 +36,7 @@ abstract class CommandForm extends Form
|
||||
/**
|
||||
* Get the monitoring backend
|
||||
*
|
||||
* @return Backend
|
||||
* @return MonitoringBackend
|
||||
*/
|
||||
public function getBackend()
|
||||
{
|
||||
|
@ -13,8 +13,7 @@ use Icinga\Web\Notification;
|
||||
class DeleteCommentCommandForm extends CommandForm
|
||||
{
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Zend_Form::init() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
@ -22,8 +21,7 @@ class DeleteCommentCommandForm extends CommandForm
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData = array())
|
||||
{
|
||||
@ -59,8 +57,7 @@ class DeleteCommentCommandForm extends CommandForm
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::addSubmitButton() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addSubmitButton()
|
||||
{
|
||||
@ -81,8 +78,7 @@ class DeleteCommentCommandForm extends CommandForm
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||
|
||||
use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand;
|
||||
use \Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
/**
|
||||
@ -20,8 +20,7 @@ class DeleteCommentsCommandForm extends CommandForm
|
||||
protected $comments;
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Zend_Form::init() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
@ -29,8 +28,7 @@ class DeleteCommentsCommandForm extends CommandForm
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData = array())
|
||||
{
|
||||
@ -45,8 +43,7 @@ class DeleteCommentsCommandForm extends CommandForm
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSubmitLabel()
|
||||
{
|
||||
@ -54,8 +51,7 @@ class DeleteCommentsCommandForm extends CommandForm
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
@ -76,9 +72,9 @@ class DeleteCommentsCommandForm extends CommandForm
|
||||
/**
|
||||
* Set the comments to be deleted upon success
|
||||
*
|
||||
* @param array $comments
|
||||
* @param array $comments
|
||||
*
|
||||
* @return this fluent interface
|
||||
* @return $this
|
||||
*/
|
||||
public function setComments(array $comments)
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||
|
||||
use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
|
||||
use \Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
/**
|
||||
@ -13,17 +13,15 @@ use Icinga\Web\Notification;
|
||||
class DeleteDowntimeCommandForm extends CommandForm
|
||||
{
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Zend_Form::init() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setAttrib('class', 'inline');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData = array())
|
||||
{
|
||||
@ -57,10 +55,9 @@ class DeleteDowntimeCommandForm extends CommandForm
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::addSubmitButton() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addSubmitButton()
|
||||
{
|
||||
@ -79,10 +76,9 @@ class DeleteDowntimeCommandForm extends CommandForm
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
@ -90,7 +86,7 @@ class DeleteDowntimeCommandForm extends CommandForm
|
||||
$cmd->setDowntimeId($this->getElement('downtime_id')->getValue());
|
||||
$cmd->setIsService($this->getElement('downtime_is_service')->getValue());
|
||||
$this->getTransport($this->request)->send($cmd);
|
||||
|
||||
|
||||
$redirect = $this->getElement('redirect')->getValue();
|
||||
if (! empty($redirect)) {
|
||||
$this->setRedirectUrl($redirect);
|
||||
|
@ -4,7 +4,7 @@
|
||||
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||
|
||||
use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
|
||||
use \Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
/**
|
||||
@ -18,10 +18,9 @@ class DeleteDowntimesCommandForm extends CommandForm
|
||||
* @var array
|
||||
*/
|
||||
protected $downtimes;
|
||||
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Zend_Form::init() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
@ -29,8 +28,7 @@ class DeleteDowntimesCommandForm extends CommandForm
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData = array())
|
||||
{
|
||||
@ -43,19 +41,17 @@ class DeleteDowntimesCommandForm extends CommandForm
|
||||
));
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSubmitLabel()
|
||||
{
|
||||
return $this->translatePlural('Remove', 'Remove All', count($this->downtimes));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
@ -72,13 +68,13 @@ class DeleteDowntimesCommandForm extends CommandForm
|
||||
Notification::success($this->translate('Deleting downtime.'));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the downtimes to be deleted upon success
|
||||
*
|
||||
* @param type $downtimes
|
||||
* @param array $downtimes
|
||||
*
|
||||
* @return $this
|
||||
* @return $this
|
||||
*/
|
||||
public function setDowntimes(array $downtimes)
|
||||
{
|
||||
|
@ -109,7 +109,10 @@ class BackendConfigForm extends ConfigForm
|
||||
|
||||
$backendName = $data['name'];
|
||||
if ($this->config->hasSection($backendName)) {
|
||||
throw new IcingaException('A monitoring backend with the name "%s" does already exist', $backendName);
|
||||
throw new IcingaException(
|
||||
$this->translate('A monitoring backend with the name "%s" does already exist'),
|
||||
$backendName
|
||||
);
|
||||
}
|
||||
|
||||
unset($data['name']);
|
||||
@ -309,10 +312,15 @@ class BackendConfigForm extends ConfigForm
|
||||
return false;
|
||||
}
|
||||
|
||||
$resourceConfig = ResourceFactory::getResourceConfig($this->getValue('resource'));
|
||||
if (! self::isValidIdoSchema($this, $resourceConfig) || !self::isValidIdoInstance($this, $resourceConfig)) {
|
||||
$this->addSkipValidationCheckbox();
|
||||
return false;
|
||||
if (($el = $this->getElement('skip_validation')) === null || false === $el->isChecked()) {
|
||||
$resourceConfig = ResourceFactory::getResourceConfig($this->getValue('resource'));
|
||||
if (! self::isValidIdoSchema($this, $resourceConfig) || !self::isValidIdoInstance($this, $resourceConfig)) {
|
||||
if ($el === null) {
|
||||
$this->addSkipValidationCheckbox();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -95,7 +95,10 @@ class InstanceConfigForm extends ConfigForm
|
||||
|
||||
$instanceName = $data['name'];
|
||||
if ($this->config->hasSection($instanceName)) {
|
||||
throw new IcingaException('A monitoring instance with the name "%s" does already exist', $instanceName);
|
||||
throw new IcingaException(
|
||||
$this->translate('A monitoring instance with the name "%s" does already exist'),
|
||||
$instanceName
|
||||
);
|
||||
}
|
||||
|
||||
unset($data['name']);
|
||||
|
@ -3,9 +3,7 @@
|
||||
|
||||
namespace Icinga\Module\Monitoring\Forms;
|
||||
|
||||
use Icinga\Data\Filter\FilterNot;
|
||||
use Icinga\Web\Url;
|
||||
use \Zend_Form;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
|
||||
@ -15,7 +13,7 @@ use Icinga\Data\Filter\Filter;
|
||||
class EventOverviewForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
@ -28,7 +26,7 @@ class EventOverviewForm extends Form
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@
|
||||
namespace Icinga\Module\Monitoring\Forms\Setup;
|
||||
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Forms\Config\ResourceConfigForm;
|
||||
use Icinga\Forms\Config\Resource\DbResourceForm;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Module\Monitoring\Forms\Config\BackendConfigForm;
|
||||
@ -71,13 +72,17 @@ class IdoResourcePage extends Form
|
||||
}
|
||||
|
||||
if (! isset($formData['skip_validation']) || !$formData['skip_validation']) {
|
||||
$configObject = new ConfigObject($this->getValues());
|
||||
if (! DbResourceForm::isValidResource($this, $configObject)) {
|
||||
$inspection = ResourceConfigForm::inspectResource($this);
|
||||
if ($inspection !== null && $inspection->hasError()) {
|
||||
$this->error($inspection->getError());
|
||||
$this->addSkipValidationCheckbox($this->translate(
|
||||
'Check this to not to validate connectivity with the given database server.'
|
||||
));
|
||||
return false;
|
||||
} elseif (
|
||||
}
|
||||
|
||||
$configObject = new ConfigObject($this->getValues());
|
||||
if (
|
||||
! BackendConfigForm::isValidIdoSchema($this, $configObject)
|
||||
|| !BackendConfigForm::isValidIdoInstance($this, $configObject)
|
||||
) {
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
namespace Icinga\Module\Monitoring\Forms;
|
||||
|
||||
use \Zend_Form;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
|
||||
@ -13,7 +12,7 @@ use Icinga\Data\Filter\Filter;
|
||||
class StatehistoryForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
@ -56,7 +55,7 @@ class StatehistoryForm extends Form
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
|
@ -60,5 +60,8 @@ class ProgramstatusQuery extends IdoQuery
|
||||
if (version_compare($this->getIdoVersion(), '1.11.8', '<')) {
|
||||
$this->columnMap['programstatus']['program_version'] = '(NULL)';
|
||||
}
|
||||
if (version_compare($this->getIdoVersion(), '1.8', '<')) {
|
||||
$this->columnMap['programstatus']['disable_notif_expire_time'] = '(NULL)';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,13 +60,13 @@ class DeleteCommentCommand extends IcingaCommand
|
||||
/**
|
||||
* Set whether the command affects a service
|
||||
*
|
||||
* @param boolean $value The value, defaults to true
|
||||
* @param bool $isService
|
||||
*
|
||||
* @return this fluent interface
|
||||
* @return $this
|
||||
*/
|
||||
public function setIsService($value = true)
|
||||
public function setIsService($isService = true)
|
||||
{
|
||||
$this->isService = (bool) $value;
|
||||
$this->isService = (bool) $isService;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -27,17 +27,20 @@ class DeleteDowntimeCommand extends IcingaCommand
|
||||
/**
|
||||
* Set if this command affects a service
|
||||
*
|
||||
* @param type $value
|
||||
* @param bool $isService
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setIsService($value = true)
|
||||
public function setIsService($isService = true)
|
||||
{
|
||||
$this->isService = (bool) $value;
|
||||
$this->isService = (bool) $isService;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return whether the command affects a service
|
||||
*
|
||||
* @return type
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsService()
|
||||
{
|
||||
|
@ -3,9 +3,20 @@
|
||||
|
||||
namespace Icinga\Module\Monitoring\Command\Transport;
|
||||
|
||||
use Icinga\Module\Monitoring\Command\IcingaCommand;
|
||||
|
||||
/**
|
||||
* Interface for Icinga command transports
|
||||
*/
|
||||
interface CommandTransportInterface
|
||||
{
|
||||
/**
|
||||
* Send an Icinga command over the Icinga command transport
|
||||
*
|
||||
* @param IcingaCommand $command The command to send
|
||||
* @param int|null $now Timestamp of the command or null for now
|
||||
*
|
||||
* @throws \Icinga\Module\Monitoring\Exception\CommandTransportException If sending the Icinga command failed
|
||||
*/
|
||||
public function send(IcingaCommand $command, $now = null);
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ use Exception;
|
||||
use RuntimeException;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Module\Monitoring\Command\Exception\TransportException;
|
||||
use Icinga\Module\Monitoring\Command\IcingaCommand;
|
||||
use Icinga\Module\Monitoring\Command\Renderer\IcingaCommandFileCommandRenderer;
|
||||
use Icinga\Module\Monitoring\Exception\CommandTransportException;
|
||||
use Icinga\Util\File;
|
||||
|
||||
/**
|
||||
@ -104,7 +104,7 @@ class LocalCommandFile implements CommandTransportInterface
|
||||
* @param int|null $now
|
||||
*
|
||||
* @throws ConfigurationError
|
||||
* @throws TransportException
|
||||
* @throws CommandTransportException
|
||||
*/
|
||||
public function send(IcingaCommand $command, $now = null)
|
||||
{
|
||||
@ -129,7 +129,7 @@ class LocalCommandFile implements CommandTransportInterface
|
||||
// Assume RuntimeException thrown by SplFileObject in the format: __METHOD__ . "({$filename}): Message"
|
||||
$message = substr($message, $pos + 1);
|
||||
}
|
||||
throw new TransportException(
|
||||
throw new CommandTransportException(
|
||||
'Can\'t send external Icinga command to the local command file "%s": %s',
|
||||
$this->path,
|
||||
$message
|
||||
|
@ -6,9 +6,9 @@ namespace Icinga\Module\Monitoring\Command\Transport;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Module\Monitoring\Command\Exception\TransportException;
|
||||
use Icinga\Module\Monitoring\Command\IcingaCommand;
|
||||
use Icinga\Module\Monitoring\Command\Renderer\IcingaCommandFileCommandRenderer;
|
||||
use Icinga\Module\Monitoring\Exception\CommandTransportException;
|
||||
|
||||
/**
|
||||
* A remote Icinga command file
|
||||
@ -224,7 +224,7 @@ class RemoteCommandFile implements CommandTransportInterface
|
||||
* @param int|null $now
|
||||
*
|
||||
* @throws ConfigurationError
|
||||
* @throws TransportException
|
||||
* @throws CommandTransportException
|
||||
*/
|
||||
public function send(IcingaCommand $command, $now = null)
|
||||
{
|
||||
@ -260,7 +260,7 @@ class RemoteCommandFile implements CommandTransportInterface
|
||||
);
|
||||
exec($ssh, $output, $status);
|
||||
if ($status !== 0) {
|
||||
throw new TransportException(
|
||||
throw new CommandTransportException(
|
||||
'Can\'t send external Icinga command: %s',
|
||||
implode(' ', $output)
|
||||
);
|
||||
|
@ -36,8 +36,10 @@ class Customvar extends DataView
|
||||
{
|
||||
return array(
|
||||
'varname' => array(
|
||||
'varname' => self::SORT_ASC,
|
||||
'varvalue' => self::SORT_ASC,
|
||||
'columns' => array(
|
||||
'varname',
|
||||
'varvalue'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ namespace Icinga\Module\Monitoring\DataView;
|
||||
|
||||
use IteratorAggregate;
|
||||
use Icinga\Data\QueryInterface;
|
||||
use Icinga\Data\SortRules;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\Filter\FilterMatch;
|
||||
use Icinga\Data\PivotTable;
|
||||
@ -18,7 +19,7 @@ use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
/**
|
||||
* A read-only view of an underlying query
|
||||
*/
|
||||
abstract class DataView implements QueryInterface, IteratorAggregate
|
||||
abstract class DataView implements QueryInterface, SortRules, IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* The query used to populate the view
|
||||
|
@ -49,8 +49,7 @@ class EventHistory extends DataView
|
||||
{
|
||||
return array(
|
||||
'timestamp' => array(
|
||||
'columns' => array('timestamp'),
|
||||
'order' => 'DESC'
|
||||
'order' => self::SORT_DESC
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Module\Monitoring\Command\Exception;
|
||||
namespace Icinga\Module\Monitoring\Exception;
|
||||
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
||||
/**
|
||||
* Exception thrown if a command was not sent
|
||||
*/
|
||||
class TransportException extends IcingaException
|
||||
class CommandTransportException extends IcingaException
|
||||
{
|
||||
}
|
@ -3,41 +3,50 @@
|
||||
|
||||
namespace Icinga\Module\Monitoring\Web\Menu;
|
||||
|
||||
use Icinga\Web\Menu as Menu;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use Icinga\Web\Menu;
|
||||
use Icinga\Web\Menu\MenuItemRenderer;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
|
||||
class BackendAvailabilityMenuItemRenderer extends MenuItemRenderer
|
||||
{
|
||||
/**
|
||||
* Checks whether the monitoring backend is running or not
|
||||
* Get whether or not the monitoring backend is currently running
|
||||
*
|
||||
* @return mixed
|
||||
* @return bool
|
||||
*/
|
||||
protected function isCurrentlyRunning()
|
||||
{
|
||||
return MonitoringBackend::instance()->select()->from(
|
||||
'programstatus',
|
||||
array(
|
||||
'is_currently_running'
|
||||
$programStatus = MonitoringBackend::instance()
|
||||
->select()
|
||||
->from(
|
||||
'programstatus',
|
||||
array('is_currently_running')
|
||||
)
|
||||
)->getQuery()->fetchRow()->is_currently_running;
|
||||
->fetchRow();
|
||||
return $programStatus !== false ? (bool) $programStatus : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see MenuItemRenderer::render()
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(Menu $menu)
|
||||
{
|
||||
return $this->getBadge() . $this->createLink($menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the problem badge HTML
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getBadge()
|
||||
{
|
||||
if (! (bool)$this->isCurrentlyRunning()) {
|
||||
if (! $this->isCurrentlyRunning()) {
|
||||
return sprintf(
|
||||
'<div title="%s" class="badge-container"><span class="badge badge-critical">%s</span></div>',
|
||||
mt('monitoring', 'monitoring backend is not running'),
|
||||
'<div title="%s" class="badge-container"><span class="badge badge-critical">%d</span></div>',
|
||||
sprintf(
|
||||
mt('monitoring', 'Monitoring backend %s is not running'), MonitoringBackend::instance()->getName()
|
||||
),
|
||||
1
|
||||
);
|
||||
}
|
||||
@ -51,10 +60,12 @@ class BackendAvailabilityMenuItemRenderer extends MenuItemRenderer
|
||||
*/
|
||||
public function getSummary()
|
||||
{
|
||||
if (! (bool)$this->isCurrentlyRunning()) {
|
||||
if (! $this->isCurrentlyRunning()) {
|
||||
return array(
|
||||
'problems' => 1,
|
||||
'title' => mt('monitoring', 'monitoring backend is not running')
|
||||
'problems' => 1,
|
||||
'title' => sprintf(
|
||||
mt('monitoring', 'Monitoring backend %s is not running'), MonitoringBackend::instance()->getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
@ -89,9 +89,6 @@ class AdminAccountPage extends Form
|
||||
}
|
||||
|
||||
if (count($choices) > 1) {
|
||||
$this->addDescription($this->translate(
|
||||
'Below are several options you can choose from for how to define the desired account.'
|
||||
));
|
||||
$this->addElement(
|
||||
'select',
|
||||
'user_type',
|
||||
@ -99,6 +96,7 @@ class AdminAccountPage extends Form
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('Type Of Definition'),
|
||||
'description' => $this->translate('Choose how to define the desired account.'),
|
||||
'multiOptions' => $choices,
|
||||
'value' => $choice
|
||||
)
|
||||
@ -124,7 +122,7 @@ class AdminAccountPage extends Form
|
||||
'label' => $this->translate('Username'),
|
||||
'description' => $this->translate(
|
||||
'Define the initial administrative account by providing a username that reflects'
|
||||
. ' a user created later or one that is authenticated using external mechanisms'
|
||||
. ' a user created later or one that is authenticated using external mechanisms.'
|
||||
)
|
||||
)
|
||||
);
|
||||
@ -139,7 +137,7 @@ class AdminAccountPage extends Form
|
||||
'label' => $this->translate('Username'),
|
||||
'description' => sprintf(
|
||||
$this->translate(
|
||||
'Choose a user reported by the %s backend as the initial administrative account',
|
||||
'Choose a user reported by the %s backend as the initial administrative account.',
|
||||
'setup.admin'
|
||||
),
|
||||
$this->backendConfig['backend'] === 'db'
|
||||
@ -159,7 +157,7 @@ class AdminAccountPage extends Form
|
||||
'required' => true,
|
||||
'label' => $this->translate('Username'),
|
||||
'description' => $this->translate(
|
||||
'Enter the username to be used when creating an initial administrative account'
|
||||
'Enter the username to be used when creating an initial administrative account.'
|
||||
)
|
||||
)
|
||||
);
|
||||
@ -170,7 +168,9 @@ class AdminAccountPage extends Form
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => $this->translate('Password'),
|
||||
'description' => $this->translate('Enter the password to assign to the newly created account')
|
||||
'description' => $this->translate(
|
||||
'Enter the password to assign to the newly created account.'
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
@ -181,7 +181,7 @@ class AdminAccountPage extends Form
|
||||
'renderPassword' => true,
|
||||
'label' => $this->translate('Repeat password'),
|
||||
'description' => $this->translate(
|
||||
'Please repeat the password given above to avoid typing errors'
|
||||
'Please repeat the password given above to avoid typing errors.'
|
||||
),
|
||||
'validators' => array(
|
||||
array('identical', false, array('new_user_password'))
|
||||
|
@ -3,11 +3,12 @@
|
||||
|
||||
namespace Icinga\Module\Setup\Forms;
|
||||
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Forms\Config\UserBackendConfigForm;
|
||||
use Icinga\Forms\Config\UserBackend\DbBackendForm;
|
||||
use Icinga\Forms\Config\UserBackend\LdapBackendForm;
|
||||
use Icinga\Forms\Config\UserBackend\ExternalBackendForm;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Wizard page to define authentication backend specific details
|
||||
@ -66,14 +67,14 @@ class AuthBackendPage extends Form
|
||||
$this->setRequiredCue(null);
|
||||
$backendForm = new DbBackendForm();
|
||||
$backendForm->setRequiredCue(null);
|
||||
$backendForm->createElements($formData)->removeElement('resource');
|
||||
$backendForm->create($formData)->removeElement('resource');
|
||||
$this->addDescription($this->translate(
|
||||
'As you\'ve chosen to use a database for authentication all you need '
|
||||
. 'to do now is defining a name for your first authentication backend.'
|
||||
));
|
||||
} elseif ($this->config['type'] === 'ldap') {
|
||||
$backendForm = new LdapBackendForm();
|
||||
$backendForm->createElements($formData)->removeElement('resource');
|
||||
$backendForm->create($formData)->removeElement('resource');
|
||||
$this->addDescription($this->translate(
|
||||
'Before you are able to authenticate using the LDAP connection defined earlier you need to'
|
||||
. ' provide some more information so that Icinga Web 2 is able to locate account details.'
|
||||
@ -97,15 +98,30 @@ class AuthBackendPage extends Form
|
||||
);
|
||||
} else { // $this->config['type'] === 'external'
|
||||
$backendForm = new ExternalBackendForm();
|
||||
$backendForm->createElements($formData);
|
||||
$backendForm->create($formData);
|
||||
$this->addDescription($this->translate(
|
||||
'You\'ve chosen to authenticate using a web server\'s mechanism so it may be necessary'
|
||||
. ' to adjust usernames before any permissions, restrictions, etc. are being applied.'
|
||||
));
|
||||
}
|
||||
|
||||
$this->addElements($backendForm->getElements());
|
||||
$this->getElement('name')->setValue('icingaweb2');
|
||||
$backendForm->getElement('name')->setValue('icingaweb2');
|
||||
$this->addSubForm($backendForm, 'backend_form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all form element values
|
||||
*
|
||||
* @param bool $suppressArrayNotation Ignored
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValues($suppressArrayNotation = false)
|
||||
{
|
||||
$values = parent::getValues();
|
||||
$values = array_merge($values, $values['backend_form']);
|
||||
unset($values['backend_form']);
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,11 +133,11 @@ class AuthBackendPage extends Form
|
||||
*/
|
||||
public function isValid($data)
|
||||
{
|
||||
if (false === parent::isValid($data)) {
|
||||
if (! parent::isValid($data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->config['type'] === 'ldap' && ( !isset($data['skip_validation']) || $data['skip_validation'] == 0)) {
|
||||
if ($this->config['type'] === 'ldap' && (! isset($data['skip_validation']) || $data['skip_validation'] == 0)) {
|
||||
$self = clone $this;
|
||||
$self->addElement(
|
||||
'text',
|
||||
@ -130,7 +146,9 @@ class AuthBackendPage extends Form
|
||||
'value' => $this->getResourceConfig()
|
||||
)
|
||||
);
|
||||
if (! LdapBackendForm::isValidUserBackend($self)) {
|
||||
$inspection = UserBackendConfigForm::inspectUserBackend($self);
|
||||
if ($inspection && $inspection->hasError()) {
|
||||
$this->error($inspection->getError());
|
||||
$this->addSkipValidationCheckbox();
|
||||
return false;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
namespace Icinga\Module\Setup\Forms;
|
||||
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Forms\Config\ResourceConfigForm;
|
||||
use Icinga\Forms\Config\Resource\LdapResourceForm;
|
||||
|
||||
/**
|
||||
@ -65,12 +66,14 @@ class LdapResourcePage extends Form
|
||||
*/
|
||||
public function isValid($data)
|
||||
{
|
||||
if (false === parent::isValid($data)) {
|
||||
if (! parent::isValid($data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (false === isset($data['skip_validation']) || $data['skip_validation'] == 0) {
|
||||
if (false === LdapResourceForm::isValidResource($this)) {
|
||||
if (! isset($data['skip_validation']) || $data['skip_validation'] == 0) {
|
||||
$inspection = ResourceConfigForm::inspectResource($this);
|
||||
if ($inspection !== null && $inspection->hasError()) {
|
||||
$this->error($inspection->getError());
|
||||
$this->addSkipValidationCheckbox();
|
||||
return false;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
form.sort-control {
|
||||
div.sort-control {
|
||||
.dontprint;
|
||||
float: right;
|
||||
|
||||
@ -15,7 +15,13 @@ form.sort-control {
|
||||
}
|
||||
|
||||
select[name=dir] {
|
||||
width: 5em;
|
||||
width: 8em;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
html.no-js div.sort-control form {
|
||||
display: table;
|
||||
margin-left: auto;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input, select {
|
||||
input, select, textarea {
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
@ -44,10 +44,19 @@ input[type=submit] {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
border: 2px solid #ddd;
|
||||
border: 1px solid;
|
||||
border-color: @colorPetrol;
|
||||
background: @colorPetrol;
|
||||
outline: 0;
|
||||
|
||||
&[disabled] {
|
||||
background-color: #666;
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
&:hover[disabled], &:active[disabled], &:focus[disabled] {
|
||||
background-color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
input[type=submit]:hover, a.button:hover, input[type=submit]:focus {
|
||||
@ -87,10 +96,6 @@ button::-moz-focus-inner {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select::-moz-focus-inner {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
@ -190,7 +195,8 @@ form ul.form-notifications {
|
||||
}
|
||||
|
||||
form div.element {
|
||||
margin: 0.5em 0;
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
form label {
|
||||
@ -200,6 +206,14 @@ form label {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
form div.element > * {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
form dt {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
select, input[type=text], textarea {
|
||||
width: 20em;
|
||||
display: inline-block;
|
||||
@ -259,3 +273,76 @@ form ul.descriptions {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
form ul.hints {
|
||||
.non-list-like-list;
|
||||
padding: 0.5em 0.5em 0 0.5em;
|
||||
|
||||
li {
|
||||
font-size: 0.8em;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.control-group {
|
||||
& > * {
|
||||
float: left;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
div.element {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: ".";
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
button, .button-like {
|
||||
font-size: 0.9em;
|
||||
font-weight: bold;
|
||||
outline: 0;
|
||||
color: #fff;
|
||||
padding: 0.2em;
|
||||
border: 1px solid;
|
||||
border-color: @colorPetrol;
|
||||
background: @colorPetrol;
|
||||
|
||||
&[disabled] {
|
||||
background-color: #666;
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
background-color: #333;
|
||||
border-color: #333;
|
||||
cursor: pointer;
|
||||
|
||||
&[disabled] {
|
||||
background-color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
&.icon-only {
|
||||
font-size: 1.5em;
|
||||
padding: 0;
|
||||
border: none;
|
||||
color: inherit;
|
||||
background-color: transparent;
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.button-like {
|
||||
cursor: default;
|
||||
text-decoration: none;
|
||||
}
|
@ -47,6 +47,10 @@ html {
|
||||
}
|
||||
}
|
||||
|
||||
#fileupload-frame-target {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#responsive-debug {
|
||||
font-size: 0.9em;
|
||||
font-family: Courier new, monospace;
|
||||
@ -401,3 +405,13 @@ html {
|
||||
padding-top: 0em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
// Hide non-javascript elements if javascript is enabled
|
||||
html.js *.no-js {
|
||||
.sr-only;
|
||||
}
|
||||
|
||||
// Hide javascript elements if javascript is disabled
|
||||
html.no-js *.js {
|
||||
.sr-only;
|
||||
}
|
@ -12,6 +12,15 @@ p code {
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
pre.log-output {
|
||||
padding: 0.5em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 2em;
|
||||
max-height: 12em;
|
||||
overflow: auto;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #39a;
|
||||
}
|
||||
@ -104,7 +113,7 @@ table.benchmark {
|
||||
.info-box {
|
||||
padding: 0.5em;
|
||||
border: 1px solid lightgrey;
|
||||
background-color: #fbfcc5;
|
||||
background-color: #f2f4fd;
|
||||
}
|
||||
|
||||
/* Action table */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user