Merge branch 'master' into bugfix/Improve-tooltip-descriptions-8110
Conflicts: modules/monitoring/application/views/scripts/hosts/show.phtml
This commit is contained in:
commit
868295110a
|
@ -1,7 +1,8 @@
|
|||
---
|
||||
icingaweb2::config: /etc/icingaweb
|
||||
icingaweb2::log: /var/log/icingaweb/icingaweb.log
|
||||
icingaweb2::web_path: icingaweb
|
||||
icingaweb2::db_user: icingaweb
|
||||
icingaweb2::db_pass: icingaweb
|
||||
icingaweb2::db_name: icingaweb
|
||||
icingaweb2::config: /etc/icingaweb2
|
||||
icingaweb2::log: /var/log/icingaweb2/icingaweb2.log
|
||||
icingaweb2::web_path: icingaweb2
|
||||
icingaweb2::db_user: icingaweb2
|
||||
icingaweb2::db_pass: icingaweb2
|
||||
icingaweb2::db_name: icingaweb2
|
||||
icingaweb2::group: icingaweb2
|
||||
|
|
|
@ -13,5 +13,5 @@ node default {
|
|||
source => 'puppet:////vagrant/.puppet/files/etc/profile.d/env.sh'
|
||||
}
|
||||
@user { vagrant: ensure => present }
|
||||
User <| title == vagrant |> { groups +> icingaweb }
|
||||
User <| title == vagrant |> { groups +> hiera('icingaweb2::group') }
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ class icinga2_pgsql {
|
|||
password => 'icinga2',
|
||||
schemafile => '/usr/share/icinga2-ido-pgsql/schema/pgsql.sql',
|
||||
}
|
||||
-> icinga2::feature { 'ido-pgsql':
|
||||
source => 'puppet:///modules/icinga2_pgsql',
|
||||
}
|
||||
# Because Icinga 2 does not handle more than one IDO connection properly, The ido-pgsql will not be enabled by default.
|
||||
# -> icinga2::feature { 'ido-pgsql':
|
||||
# source => 'puppet:///modules/icinga2_pgsql',
|
||||
# }
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
class icingaweb2::config (
|
||||
$config = hiera('icingaweb2::config')
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$web_group = hiera('icingaweb2::group')
|
||||
) {
|
||||
group { 'icingaweb':
|
||||
group { $web_group:
|
||||
ensure => present,
|
||||
}
|
||||
|
||||
file { [ "${config}", "${config}/enabledModules", "${config}/modules", "${config}/preferences" ]:
|
||||
ensure => directory,
|
||||
owner => 'root',
|
||||
group => 'icingaweb',
|
||||
group => $web_group,
|
||||
mode => '2770',
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
define icingaweb2::config::general (
|
||||
$source,
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$replace = true
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$web_group = hiera('icingaweb2::group'),
|
||||
$replace = true
|
||||
) {
|
||||
include icingaweb2::config
|
||||
|
||||
file { "${config}/${name}.ini":
|
||||
content => template("${source}/${name}.ini.erb"),
|
||||
owner => 'root',
|
||||
group => 'icingaweb',
|
||||
group => $web_group,
|
||||
mode => 0660,
|
||||
replace => $replace,
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
define icingaweb2::config::module (
|
||||
$module,
|
||||
$source,
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$replace = true
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$web_group = hiera('icingaweb2::group'),
|
||||
$replace = true
|
||||
) {
|
||||
include icingaweb2::config
|
||||
|
||||
|
@ -10,7 +11,7 @@ define icingaweb2::config::module (
|
|||
file { "${config}/modules/${module}":
|
||||
ensure => directory,
|
||||
owner => 'root',
|
||||
group => 'icingaweb',
|
||||
group => $web_group,
|
||||
mode => '2770',
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +19,7 @@ define icingaweb2::config::module (
|
|||
file { "${config}/modules/${module}/${name}.ini":
|
||||
source => "${source}/modules/${module}/${name}.ini",
|
||||
owner => 'root',
|
||||
group => 'icingaweb',
|
||||
group => $web_group,
|
||||
mode => 0660,
|
||||
replace => $replace,
|
||||
}
|
||||
|
|
|
@ -71,6 +71,11 @@ local icinga icinga trust
|
|||
host icinga icinga 127.0.0.1/32 trust
|
||||
host icinga icinga ::1/128 trust
|
||||
|
||||
# icinga2
|
||||
local icinga2 icinga2 trust
|
||||
host icinga2 icinga2 127.0.0.1/32 trust
|
||||
host icinga2 icinga2 ::1/128 trust
|
||||
|
||||
# icinga_unittest
|
||||
local icinga_unittest icinga_unittest trust
|
||||
host icinga_unittest icinga_unittest 127.0.0.1/32 trust
|
||||
|
@ -81,6 +86,11 @@ local icingaweb icingaweb trust
|
|||
host icingaweb icingaweb 127.0.0.1/32 trust
|
||||
host icingaweb icingaweb ::1/128 trust
|
||||
|
||||
# icingaweb2
|
||||
local <%= scope.function_hiera(['icingaweb2::db_user']) %> <%= scope.function_hiera(['icingaweb2::db_user']) %> trust
|
||||
host <%= scope.function_hiera(['icingaweb2::db_user']) %> <%= scope.function_hiera(['icingaweb2::db_user']) %> 127.0.0.1/32 trust
|
||||
host <%= scope.function_hiera(['icingaweb2::db_user']) %> <%= scope.function_hiera(['icingaweb2::db_user']) %> ::1/128 trust
|
||||
|
||||
# "local" is for Unix domain socket connections only
|
||||
local all all ident
|
||||
# IPv4 local connections:
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
# Class: php_imagick
|
||||
#
|
||||
# This class installs the ImageMagick PHP module.
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
# Actions:
|
||||
#
|
||||
# Requires:
|
||||
#
|
||||
# php
|
||||
#
|
||||
# Sample Usage:
|
||||
#
|
||||
# include php_imagick
|
||||
#
|
||||
class php_imagick {
|
||||
include php
|
||||
|
||||
$php_imagick = $::operatingsystem ? {
|
||||
/(Debian|Ubuntu)/ => 'php5-imagick',
|
||||
/(RedHat|CentOS|Fedora)/ => 'php-pecl-imagick',
|
||||
/(SLES|OpenSuSE)/ => 'php5-imagick',
|
||||
}
|
||||
|
||||
package { $php_imagick:
|
||||
ensure => latest,
|
||||
}
|
||||
}
|
|
@ -1,13 +1,15 @@
|
|||
class icingaweb2_dev (
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$log = hiera('icingaweb2::log'),
|
||||
$web_path = hiera('icingaweb2::web_path'),
|
||||
$db_user = hiera('icingaweb2::db_user'),
|
||||
$db_pass = hiera('icingaweb2::db_pass'),
|
||||
$db_name = hiera('icingaweb2::db_name'),
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$log = hiera('icingaweb2::log'),
|
||||
$web_path = hiera('icingaweb2::web_path'),
|
||||
$db_user = hiera('icingaweb2::db_user'),
|
||||
$db_pass = hiera('icingaweb2::db_pass'),
|
||||
$db_name = hiera('icingaweb2::db_name'),
|
||||
$web_group = hiera('icingaweb2::group'),
|
||||
) {
|
||||
include apache
|
||||
include php
|
||||
include php_imagick
|
||||
include icingaweb2::config
|
||||
include icingacli
|
||||
include icinga_packages
|
||||
|
@ -19,7 +21,7 @@ class icingaweb2_dev (
|
|||
}
|
||||
|
||||
# TODO(el): icinga-gui is not a icingaweb2_dev package
|
||||
package { [ 'php-pdo', 'php-ldap', 'php-phpunit-PHPUnit', 'icinga-gui' ]:
|
||||
package { [ 'php-gd', 'php-intl', 'php-pdo', 'php-ldap', 'php-phpunit-PHPUnit', 'icinga-gui' ]:
|
||||
ensure => latest,
|
||||
notify => Service['apache'],
|
||||
require => Class['icinga_packages'],
|
||||
|
@ -28,7 +30,7 @@ class icingaweb2_dev (
|
|||
Exec { path => '/usr/local/bin:/usr/bin:/bin' }
|
||||
|
||||
# TODO(el): Enabling/disabling modules should be a resource
|
||||
User <| alias == apache |> { groups +> 'icingaweb' }
|
||||
User <| alias == apache |> { groups +> $web_group }
|
||||
-> exec { 'enable-monitoring-module':
|
||||
command => 'icingacli module enable monitoring',
|
||||
user => 'apache',
|
||||
|
@ -50,7 +52,7 @@ class icingaweb2_dev (
|
|||
file { $log_dir:
|
||||
ensure => directory,
|
||||
owner => 'root',
|
||||
group => 'icingaweb',
|
||||
group => $web_group,
|
||||
mode => '2775'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[autologin]
|
||||
backend = autologin
|
||||
backend = external
|
||||
|
||||
[icingaweb-mysql]
|
||||
backend = db
|
||||
|
|
263
README.md
263
README.md
|
@ -2,267 +2,26 @@
|
|||
|
||||
## Table of Contents
|
||||
|
||||
0. [General Information](#general information)
|
||||
0. [About](#about)
|
||||
1. [Installation](#installation)
|
||||
2. [Support](#support)
|
||||
3. [Vagrant - Virtual development environment](#vagrant)
|
||||
|
||||
## General Information
|
||||
## About
|
||||
|
||||
`Icinga Web 2` is the next generation monitoring web interface, framework
|
||||
and CLI tool developed by the [Icinga Project](https://www.icinga.org/community/team/).
|
||||
**Icinga Web 2** is the next generation open source monitoring web interface, framework
|
||||
and command-line interface developed by the [Icinga Project](https://www.icinga.org/), supporting Icinga 2,
|
||||
Icinga Core and any other monitoring backend compatible with the Livestatus Protocol.
|
||||
|
||||
Responsive and fast, rewritten from scratch supporting multiple backends and
|
||||
providing a CLI tool. Compatible with Icinga Core 2.x and 1.x.
|
||||
|
||||
Check the Icinga website for some [insights](https://www.icinga.org/icinga/screenshots/icinga-web-2/).
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> `Icinga Web 2` is still in development and not meant for production deployment.
|
||||
> Watch the [development roadmap](https://dev.icinga.org/projects/icingaweb2/roadmap)
|
||||
> and [Icinga website](https://www.icinga.org/) for release schedule updates!
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
Please navigate to [doc/installation.md](doc/installation.md) for updated details.
|
||||
For installing Icinga Web 2 please read [doc/installation.md](doc/installation.md).
|
||||
|
||||
## Support
|
||||
|
||||
Please head over to the [community support channels](https://www.icinga.org/icinga/faq/get-help/)
|
||||
in case of questions, bugs, etc.
|
||||
|
||||
Please make sure to provide the following details:
|
||||
|
||||
* OS, distribution, version
|
||||
* PHP and/or MySQL/PostgreSQL version
|
||||
* Which browser and its version
|
||||
* Screenshot and problem description
|
||||
|
||||
|
||||
## Vagrant
|
||||
|
||||
### Requirements
|
||||
|
||||
* Vagrant 1.2+
|
||||
* Virtualbox 4.2.16+
|
||||
* a fairly powerful hardware (quad core, 4gb ram, fast hdd)
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> The deployment of the virtual machine is tested against Vagrant starting with version 1.2.
|
||||
> Unfortunately older versions will not work.
|
||||
|
||||
### General
|
||||
|
||||
The Icinga Web 2 project ships with a Vagrant virtual machine that integrates
|
||||
the source code with various services and example data in a controlled
|
||||
environment. This enables developers and users to test Livestatus, status.dat,
|
||||
MySQL and PostgreSQL backends as well as the LDAP authentication. All you
|
||||
have to do is install Vagrant and run:
|
||||
|
||||
vagrant up
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> The first boot of the vm takes a fairly long time because
|
||||
> you'll download a plain CentOS base box and Vagrant will automatically
|
||||
> provision the environment on the first go.
|
||||
|
||||
After you should be able to browse [localhost:8080/icingaweb](http://localhost:8080/icingaweb).
|
||||
|
||||
### Environment
|
||||
|
||||
**Forwarded ports**:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Proctocol</th>
|
||||
<th>Local port (virtual machine host)</th>
|
||||
<th>Remote port (the virtual machine)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SSH</td>
|
||||
<td>2222</td>
|
||||
<td>22</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>HTTP</td>
|
||||
<td>8080</td>
|
||||
<td>80</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
**Installed packages**:
|
||||
|
||||
* Apache2 with PHP enabled
|
||||
* PHP with MySQL and PostgreSQL libraries
|
||||
* MySQL server and client software
|
||||
* PostgreSQL server and client software
|
||||
* [Icinga prerequisites](http://docs.icinga.org/latest/en/quickstart-idoutils.html#installpackages)
|
||||
* OpenLDAP servers and clients
|
||||
|
||||
**Installed users and groups**:
|
||||
|
||||
* User icinga with group icinga and icinga-cmd
|
||||
* Webserver user added to group icinga-cmd
|
||||
|
||||
**Installed software**:
|
||||
|
||||
* Icinga with IDOUtils using a MySQL database
|
||||
* Icinga with IDOUtils using a PostgreSQL database
|
||||
* Icinga 2
|
||||
|
||||
**Installed files**:
|
||||
|
||||
* `/usr/share/icinga/htpasswd.users` account information for logging into the Icinga classic web interface for both icinga instances
|
||||
* `/usr/lib64/nagios/plugins` Monitoring Plugins for all Icinga instances
|
||||
|
||||
#### Icinga with IDOUtils using a MySQL database
|
||||
|
||||
**Installation path**: `/usr/local/icinga-mysql`
|
||||
|
||||
**Services**:
|
||||
|
||||
* `icinga-mysql`
|
||||
* `ido2db-mysql`
|
||||
|
||||
Connect to the **icinga mysql database** using the following command:
|
||||
|
||||
mysql -u icinga -p icinga icinga
|
||||
|
||||
Access the **Classic UI** (CGIs) via [localhost:8080/icinga-mysql](http://localhost:8080/icinga-mysql).
|
||||
For **logging into** the Icinga classic web interface use user *icingaadmin* with password *icinga*.
|
||||
|
||||
#### Icinga with IDOUtils using a PostgreSQL database
|
||||
|
||||
**Installation path**: `/usr/local/icinga-pgsql`
|
||||
|
||||
**Services**:
|
||||
|
||||
* `icinga-pgsql`
|
||||
* `ido2db-pgsql`
|
||||
|
||||
Connect to the **icinga mysql database** using the following command:
|
||||
|
||||
sudo -u postgres psql -U icinga -d icinga
|
||||
|
||||
Access the **Classic UI** (CGIs) via [localhost:8080/icinga-pgsql](http://localhost:8080/icinga-pgsql).
|
||||
For **logging into** the Icinga classic web interface use user *icingaadmin* with password *icinga*.
|
||||
|
||||
#### Monitoring Test Config
|
||||
|
||||
Test config is added to both the MySQL and PostgreSQL Icinga instance utilizing the Perl module
|
||||
**Monitoring::Generator::TestConfig** to generate test config to **/usr/local/share/misc/monitoring_test_config**
|
||||
which is then copied to **<instance>/etc/conf.d/test_config/**.
|
||||
Configuration can be adjusted and recreated with **/usr/local/share/misc/monitoring_test_config/recreate.pl**.
|
||||
**Note** that you have to run
|
||||
|
||||
vagrant provision
|
||||
|
||||
in the host after any modification to the script just mentioned.
|
||||
|
||||
#### MK Livestatus
|
||||
|
||||
MK Livestatus is added to the Icinga installation using a MySQL database.
|
||||
|
||||
**Installation path**:
|
||||
|
||||
* `/usr/local/icinga-mysql/bin/unixcat`
|
||||
* `/usr/local/icinga-mysql/lib/mk-livestatus/livecheck`
|
||||
* `/usr/local/icinga-mysql/lib/mk-livestatus/livestatus.o`
|
||||
* `/usr/local/icinga-mysql/etc/modules/mk-livestatus.cfg`
|
||||
* `/usr/local/icinga-mysql/var/rw/live`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
echo "GET hosts" | /usr/local/icinga-mysql/bin/unixcat /usr/local/icinga-mysql/var/rw/live
|
||||
|
||||
#### LDAP example data
|
||||
|
||||
The environment includes a openldap server with example data. *Domain* suffix is **dc=icinga,dc=org**.
|
||||
Administrator (*rootDN*) of the slapd configuration database is **cn=admin,cn=config** and the
|
||||
administrator (*rootDN*) of our database instance is **cn=admin,dc=icinga,dc=org**. Both share
|
||||
the *password* `admin`.
|
||||
|
||||
Examples to query the slapd configuration database:
|
||||
|
||||
ldapsearch -x -W -LLL -D cn=admin,cn=config -b cn=config dn
|
||||
ldapsearch -Y EXTERNAL -H ldapi:/// -LLL -b cn=config dn
|
||||
|
||||
Examples to query our database instance:
|
||||
|
||||
ldapsearch -x -W -LLL -D cn=admin,dc=icinga,dc=org -b dc=icinga,dc=org dn
|
||||
ldapsearch -Y EXTERNAL -H ldapi:/// -LLL -b dc=icinga,dc=org dn
|
||||
|
||||
This is what the **dc=icinga,dc=org** *DIT* looks like:
|
||||
|
||||
> dn: dc=icinga,dc=org
|
||||
>
|
||||
> dn: ou=people,dc=icinga,dc=org
|
||||
>
|
||||
> dn: ou=groups,dc=icinga,dc=org
|
||||
>
|
||||
> dn: cn=Users,ou=groups,dc=icinga,dc=org
|
||||
> cn: Users
|
||||
> uniqueMember: cn=Jon Doe,ou=people,dc=icinga,dc=org
|
||||
> uniqueMember: cn=Jane Smith,ou=people,dc=icinga,dc=org
|
||||
> uniqueMember: cn=John Q. Public,ou=people,dc=icinga,dc=org
|
||||
> uniqueMember: cn=Richard Roe,ou=people,dc=icinga,dc=org
|
||||
>
|
||||
> dn: cn=John Doe,ou=people,dc=icinga,dc=org
|
||||
> cn: John Doe
|
||||
> uid: jdoe
|
||||
>
|
||||
> dn: cn=Jane Smith,ou=people,dc=icinga,dc=org
|
||||
> cn: Jane Smith
|
||||
> uid: jsmith
|
||||
>
|
||||
> dn: cn=John Q. Public,ou=people,dc=icinga,dc=org
|
||||
> cn: John Q. Public
|
||||
> uid: jqpublic
|
||||
>
|
||||
> dn: cn=Richard Roe,ou=people,dc=icinga,dc=org
|
||||
> cn: Richard Roe
|
||||
> uid: rroe
|
||||
|
||||
All users share the password `password`.
|
||||
|
||||
#### Testing the code
|
||||
|
||||
All software required to run tests is installed in the virtual machine.
|
||||
In order to run all tests you have to execute the following commands:
|
||||
|
||||
vagrant ssh -c /vagrant/test/php/runtests
|
||||
vagrant ssh -c /vagrant/test/php/checkswag
|
||||
vagrant ssh -c /vagrant/test/js/runtests
|
||||
vagrant ssh -c /vagrant/test/js/checkswag
|
||||
vagrant ssh -c /vagrant/test/frontend/runtests
|
||||
|
||||
`runtests` will execute unit and regression tests and `checkswag` will report
|
||||
code style issues.
|
||||
|
||||
#### Icinga 2
|
||||
|
||||
Installed from the Icinga [snapshot package repository](http://packages.icinga.org/epel/).
|
||||
The configuration is located in `/etc/icinga2`.
|
||||
|
||||
**Example usage**:
|
||||
|
||||
/etc/init.d/icinga2 (start|stop|restart|reload)
|
||||
|
||||
|
||||
## Log into Icinga Web 2
|
||||
|
||||
If you've configure LDAP as authentication backend (which is the default) use the following login credentials:
|
||||
|
||||
> **Username**: jdoe
|
||||
> **Password**: password
|
||||
|
||||
Have a look at [LDAP example data](#ldap example data) for more accounts.
|
||||
|
||||
Using MySQL as backend:
|
||||
|
||||
> **Username**: icingaadmin
|
||||
> **Password**: icinga
|
||||
If you come across problems at some time, the [community support channels](https://support.icinga.org/)
|
||||
are good places to ask for advice from other users and give some in return.
|
||||
|
||||
For status updates check the [Icinga website](https://www.icinga.org/) and the
|
||||
[Icinga Web 2 development roadmap](https://dev.icinga.org/projects/icingaweb2/roadmap).
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
VAGRANTFILE_API_VERSION = "2"
|
||||
VAGRANT_REQUIRED_VERSION = "1.5.0"
|
||||
|
||||
# Require 1.2.x at least
|
||||
if ! defined? Vagrant.require_version
|
||||
if Gem::Version.new(Vagrant::VERSION) < Gem::Version.new(VAGRANT_REQUIRED_VERSION)
|
||||
puts "Vagrant >= " + VAGRANT_REQUIRED_VERSION + " required. Your version is " + Vagrant::VERSION
|
||||
|
|
|
@ -4,16 +4,17 @@
|
|||
|
||||
# namespace Icinga\Application\Controllers;
|
||||
|
||||
use Icinga\Authentication\Backend\AutoLoginBackend;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Forms\Authentication\LoginForm;
|
||||
use Icinga\Authentication\AuthChain;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Authentication\AuthChain;
|
||||
use Icinga\Authentication\Backend\ExternalBackend;
|
||||
use Icinga\Exception\AuthenticationException;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
use Icinga\Forms\Authentication\LoginForm;
|
||||
use Icinga\User;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
|
@ -33,10 +34,12 @@ class AuthenticationController extends ActionController
|
|||
*/
|
||||
public function loginAction()
|
||||
{
|
||||
if (@file_exists(Config::resolvePath('setup.token')) && !@file_exists(Config::resolvePath('config.ini'))) {
|
||||
$icinga = Icinga::app();
|
||||
if ($icinga->setupTokenExists() && $icinga->requiresSetup()) {
|
||||
$this->redirectNow(Url::fromPath('setup'));
|
||||
}
|
||||
|
||||
$triedOnlyExternalAuth = null;
|
||||
$auth = $this->Auth();
|
||||
$this->view->form = $form = new LoginForm();
|
||||
$this->view->title = $this->translate('Icingaweb Login');
|
||||
|
@ -80,7 +83,7 @@ class AuthenticationController extends ActionController
|
|||
}
|
||||
|
||||
foreach ($chain as $backend) {
|
||||
if ($backend instanceof AutoLoginBackend) {
|
||||
if ($backend instanceof ExternalBackend) {
|
||||
continue;
|
||||
}
|
||||
++$backendsTried;
|
||||
|
@ -124,7 +127,8 @@ class AuthenticationController extends ActionController
|
|||
} elseif ($request->isGet()) {
|
||||
$user = new User('');
|
||||
foreach ($chain as $backend) {
|
||||
if ($backend instanceof AutoLoginBackend) {
|
||||
$triedOnlyExternalAuth = $triedOnlyExternalAuth === null;
|
||||
if ($backend instanceof ExternalBackend) {
|
||||
$authenticated = $backend->authenticate($user);
|
||||
if ($authenticated === true) {
|
||||
$auth->setAuthenticated($user);
|
||||
|
@ -132,6 +136,8 @@ class AuthenticationController extends ActionController
|
|||
Url::fromPath(Url::fromRequest()->getParam('redirect', 'dashboard'))
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$triedOnlyExternalAuth = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +145,8 @@ class AuthenticationController extends ActionController
|
|||
$this->view->errorInfo = $e->getMessage();
|
||||
}
|
||||
|
||||
$this->view->configMissing = is_dir(Config::$configDir) === false;
|
||||
$this->view->requiresExternalAuth = $triedOnlyExternalAuth && !$auth->isAuthenticated();
|
||||
$this->view->requiresSetup = Icinga::app()->requiresSetup();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,6 @@ use Icinga\Web\Url;
|
|||
use Icinga\Web\Widget\Tab;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Forms\PreferenceForm;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\User\Preferences\PreferencesStore;
|
||||
|
||||
/**
|
||||
|
@ -40,14 +39,13 @@ class PreferenceController extends BasePreferenceController
|
|||
public function indexAction()
|
||||
{
|
||||
$storeConfig = Config::app()->getSection('preferences');
|
||||
if ($storeConfig->isEmpty()) {
|
||||
throw new ConfigurationError(t('You need to configure how to store preferences first.'));
|
||||
}
|
||||
|
||||
$user = $this->getRequest()->getUser();
|
||||
$form = new PreferenceForm();
|
||||
$form->setPreferences($user->getPreferences());
|
||||
$form->setStore(PreferencesStore::create($storeConfig, $user));
|
||||
if ($storeConfig->get('store', 'ini') !== 'none') {
|
||||
$form->setStore(PreferencesStore::create($storeConfig, $user));
|
||||
}
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# fontello-ifont font files moved
|
||||
|
||||
New target is: public/font
|
||||
|
||||
The font directory has been moved to the public structure because of
|
||||
Internet Explorer version 8 compatibility. The common way for browsers is to
|
||||
include the binary embeded font type in the javascript. IE8 falls back and
|
||||
include one of the provided font sources. Therefore it is important to have
|
||||
the font files available public and exported by the HTTP server.
|
|
@ -18,7 +18,7 @@ class LoginForm extends Form
|
|||
public function init()
|
||||
{
|
||||
$this->setName('form_login');
|
||||
$this->setSubmitLabel(t('Login'));
|
||||
$this->setSubmitLabel($this->translate('Login'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,8 +31,8 @@ class LoginForm extends Form
|
|||
'username',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Username'),
|
||||
'placeholder' => t('Please enter your username...'),
|
||||
'label' => $this->translate('Username'),
|
||||
'placeholder' => $this->translate('Please enter your username...'),
|
||||
'class' => false === isset($formData['username']) ? 'autofocus' : ''
|
||||
)
|
||||
);
|
||||
|
@ -41,8 +41,8 @@ class LoginForm extends Form
|
|||
'password',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Password'),
|
||||
'placeholder' => t('...and your password'),
|
||||
'label' => $this->translate('Password'),
|
||||
'placeholder' => $this->translate('...and your password'),
|
||||
'class' => isset($formData['username']) ? 'autofocus' : ''
|
||||
)
|
||||
);
|
||||
|
|
|
@ -53,8 +53,8 @@ class DbBackendForm extends Form
|
|||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Backend Name'),
|
||||
'description' => t(
|
||||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
),
|
||||
)
|
||||
|
@ -64,8 +64,10 @@ class DbBackendForm extends Form
|
|||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Connection'),
|
||||
'description' => t('The database connection to use for authenticating with this provider'),
|
||||
'label' => $this->translate('Database Connection'),
|
||||
'description' => $this->translate(
|
||||
'The database connection to use for authenticating with this provider'
|
||||
),
|
||||
'multiOptions' => false === empty($this->resources)
|
||||
? array_combine($this->resources, $this->resources)
|
||||
: array()
|
||||
|
@ -107,11 +109,11 @@ class DbBackendForm extends Form
|
|||
try {
|
||||
$dbUserBackend = new DbUserBackend(ResourceFactory::createResource($form->getResourceConfig()));
|
||||
if ($dbUserBackend->count() < 1) {
|
||||
$form->addError(t('No users found under the specified database backend'));
|
||||
$form->addError($form->translate('No users found under the specified database backend'));
|
||||
return false;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$form->addError(sprintf(t('Using the specified backend failed: %s'), $e->getMessage()));
|
||||
$form->addError(sprintf($form->translate('Using the specified backend failed: %s'), $e->getMessage()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,16 +8,16 @@ use Zend_Validate_Callback;
|
|||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying autologin authentication backends
|
||||
* Form class for adding/modifying authentication backends of type "external"
|
||||
*/
|
||||
class AutologinBackendForm extends Form
|
||||
class ExternalBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend_autologin');
|
||||
$this->setName('form_config_authbackend_external');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,8 +30,8 @@ class AutologinBackendForm extends Form
|
|||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Backend Name'),
|
||||
'description' => t(
|
||||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
|
@ -52,9 +52,11 @@ class AutologinBackendForm extends Form
|
|||
'text',
|
||||
'strip_username_regexp',
|
||||
array(
|
||||
'label' => t('Filter Pattern'),
|
||||
'description' => t('The regular expression to use to strip specific parts off from usernames. Leave empty if you do not want to strip off anything'),
|
||||
'value' => '/\@[^$]+$/',
|
||||
'label' => $this->translate('Filter Pattern'),
|
||||
'description' => $this->translate(
|
||||
'The regular expression to use to strip specific parts off from usernames.'
|
||||
. ' Leave empty if you do not want to strip off anything'
|
||||
),
|
||||
'validators' => array(
|
||||
new Zend_Validate_Callback(function ($value) {
|
||||
return @preg_match($value, '') !== false;
|
||||
|
@ -67,7 +69,7 @@ class AutologinBackendForm extends Form
|
|||
'backend',
|
||||
array(
|
||||
'disabled' => true,
|
||||
'value' => 'autologin'
|
||||
'value' => 'external'
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -77,7 +79,7 @@ class AutologinBackendForm extends Form
|
|||
/**
|
||||
* Validate the configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* Returns always true as autologin backends are just "passive" backends. (The webserver authenticates users.)
|
||||
* Returns always true as backends of type "external" are just "passive" backends.
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
|
@ -54,8 +54,8 @@ class LdapBackendForm extends Form
|
|||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Backend Name'),
|
||||
'description' => t(
|
||||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
)
|
||||
)
|
||||
|
@ -65,8 +65,8 @@ class LdapBackendForm extends Form
|
|||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('LDAP Resource'),
|
||||
'description' => t('The resource to use for authenticating with this provider'),
|
||||
'label' => $this->translate('LDAP Resource'),
|
||||
'description' => $this->translate('The resource to use for authenticating with this provider'),
|
||||
'multiOptions' => false === empty($this->resources)
|
||||
? array_combine($this->resources, $this->resources)
|
||||
: array()
|
||||
|
@ -77,8 +77,8 @@ class LdapBackendForm extends Form
|
|||
'user_class',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('LDAP User Object Class'),
|
||||
'description' => t('The object class used for storing users on the ldap server'),
|
||||
'label' => $this->translate('LDAP User Object Class'),
|
||||
'description' => $this->translate('The object class used for storing users on the ldap server'),
|
||||
'value' => 'inetOrgPerson'
|
||||
)
|
||||
);
|
||||
|
@ -87,8 +87,10 @@ class LdapBackendForm extends Form
|
|||
'user_name_attribute',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('LDAP User Name Attribute'),
|
||||
'description' => t('The attribute name used for storing the user name on the ldap server'),
|
||||
'label' => $this->translate('LDAP User Name Attribute'),
|
||||
'description' => $this->translate(
|
||||
'The attribute name used for storing the user name on the ldap server'
|
||||
),
|
||||
'value' => 'uid'
|
||||
)
|
||||
);
|
||||
|
@ -105,9 +107,11 @@ class LdapBackendForm extends Form
|
|||
'base_dn',
|
||||
array(
|
||||
'required' => false,
|
||||
'label' => t('Base DN'),
|
||||
'description' => t('The path where users can be found on the ldap server. ' .
|
||||
' Leave empty to select all users available on the specified resource.')
|
||||
'label' => $this->translate('Base DN'),
|
||||
'description' => $this->translate(
|
||||
'The path where users can be found on the ldap server. Leave ' .
|
||||
'empty to select all users available on the specified resource.'
|
||||
)
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
|
@ -146,7 +150,7 @@ class LdapBackendForm extends Form
|
|||
$form->addError($e->getMessage());
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
$form->addError(sprintf(t('Unable to validate authentication: %s'), $e->getMessage()));
|
||||
$form->addError(sprintf($form->translate('Unable to validate authentication: %s'), $e->getMessage()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ use Icinga\Data\ResourceFactory;
|
|||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Forms\Config\Authentication\DbBackendForm;
|
||||
use Icinga\Forms\Config\Authentication\LdapBackendForm;
|
||||
use Icinga\Forms\Config\Authentication\AutologinBackendForm;
|
||||
use Icinga\Forms\Config\Authentication\ExternalBackendForm;
|
||||
|
||||
class AuthenticationBackendConfigForm extends ConfigForm
|
||||
{
|
||||
|
@ -31,7 +31,7 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend');
|
||||
$this->setSubmitLabel(t('Save Changes'));
|
||||
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,10 +67,10 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
} elseif ($type === 'ldap') {
|
||||
$form = new LdapBackendForm();
|
||||
$form->setResources(isset($this->resources['ldap']) ? $this->resources['ldap'] : array());
|
||||
} elseif ($type === 'autologin') {
|
||||
$form = new AutologinBackendForm();
|
||||
} elseif ($type === 'external') {
|
||||
$form = new ExternalBackendForm();
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf(t('Invalid backend type "%s" provided'), $type));
|
||||
throw new InvalidArgumentException(sprintf($this->translate('Invalid backend type "%s" provided'), $type));
|
||||
}
|
||||
|
||||
return $form;
|
||||
|
@ -91,9 +91,9 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
{
|
||||
$name = isset($values['name']) ? $values['name'] : '';
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Authentication backend name missing'));
|
||||
throw new InvalidArgumentException($this->translate('Authentication backend name missing'));
|
||||
} elseif ($this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Authentication backend already exists'));
|
||||
throw new InvalidArgumentException($this->translate('Authentication backend already exists'));
|
||||
}
|
||||
|
||||
unset($values['name']);
|
||||
|
@ -114,11 +114,11 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
public function edit($name, array $values)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Old authentication backend name missing'));
|
||||
throw new InvalidArgumentException($this->translate('Old authentication backend name missing'));
|
||||
} elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) {
|
||||
throw new InvalidArgumentException(t('New authentication backend name missing'));
|
||||
throw new InvalidArgumentException($this->translate('New authentication backend name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Unknown authentication backend provided'));
|
||||
throw new InvalidArgumentException($this->translate('Unknown authentication backend provided'));
|
||||
}
|
||||
|
||||
$backendConfig = $this->config->getSection($name);
|
||||
|
@ -144,9 +144,9 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
public function remove($name)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Authentication backend name missing'));
|
||||
throw new InvalidArgumentException($this->translate('Authentication backend name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Unknown authentication backend provided'));
|
||||
throw new InvalidArgumentException($this->translate('Unknown authentication backend provided'));
|
||||
}
|
||||
|
||||
$backendConfig = $this->config->getSection($name);
|
||||
|
@ -167,9 +167,9 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
public function move($name, $position)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Authentication backend name missing'));
|
||||
throw new InvalidArgumentException($this->translate('Authentication backend name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Unknown authentication backend provided'));
|
||||
throw new InvalidArgumentException($this->translate('Unknown authentication backend provided'));
|
||||
}
|
||||
|
||||
$backendOrder = $this->config->keys();
|
||||
|
@ -208,10 +208,10 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
try {
|
||||
if ($authBackend === null) { // create new backend
|
||||
$this->add($this->getValues());
|
||||
$message = t('Authentication backend "%s" has been successfully created');
|
||||
$message = $this->translate('Authentication backend "%s" has been successfully created');
|
||||
} else { // edit existing backend
|
||||
$this->edit($authBackend, $this->getValues());
|
||||
$message = t('Authentication backend "%s" has been successfully changed');
|
||||
$message = $this->translate('Authentication backend "%s" has been successfully changed');
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
|
@ -237,11 +237,13 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
$authBackend = $this->request->getQuery('auth_backend');
|
||||
if ($authBackend !== null) {
|
||||
if ($authBackend === '') {
|
||||
throw new ConfigurationError(t('Authentication backend name missing'));
|
||||
throw new ConfigurationError($this->translate('Authentication backend name missing'));
|
||||
} elseif (! $this->config->hasSection($authBackend)) {
|
||||
throw new ConfigurationError(t('Unknown authentication backend provided'));
|
||||
throw new ConfigurationError($this->translate('Unknown authentication backend provided'));
|
||||
} elseif ($this->config->getSection($authBackend)->backend === null) {
|
||||
throw new ConfigurationError(sprintf(t('Backend "%s" has no `backend\' setting'), $authBackend));
|
||||
throw new ConfigurationError(
|
||||
sprintf($this->translate('Backend "%s" has no `backend\' setting'), $authBackend)
|
||||
);
|
||||
}
|
||||
|
||||
$configValues = $this->config->getSection($authBackend)->toArray();
|
||||
|
@ -249,15 +251,15 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
$configValues['name'] = $authBackend;
|
||||
$this->populate($configValues);
|
||||
} elseif (empty($this->resources)) {
|
||||
$autologinBackends = array_filter(
|
||||
$externalBackends = array_filter(
|
||||
$this->config->toArray(),
|
||||
function ($authBackendCfg) {
|
||||
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'autologin';
|
||||
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'external';
|
||||
}
|
||||
);
|
||||
|
||||
if (false === empty($autologinBackends)) {
|
||||
throw new ConfigurationError(t('Could not find any resources for authentication'));
|
||||
if (false === empty($externalBackends)) {
|
||||
throw new ConfigurationError($this->translate('Could not find any resources for authentication'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -276,8 +278,8 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
array(
|
||||
'order' => 0,
|
||||
'ignore' => true,
|
||||
'label' => t('Force Changes'),
|
||||
'description' => t('Check this box to enforce changes without connectivity validation')
|
||||
'label' => $this->translate('Force Changes'),
|
||||
'description' => $this->translate('Check this box to enforce changes without connectivity validation')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -291,20 +293,20 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
$backendType = isset($formData['type']) ? $formData['type'] : null;
|
||||
|
||||
if (isset($this->resources['db'])) {
|
||||
$backendTypes['db'] = t('Database');
|
||||
$backendTypes['db'] = $this->translate('Database');
|
||||
}
|
||||
if (isset($this->resources['ldap']) && ($backendType === 'ldap' || Platform::extensionLoaded('ldap'))) {
|
||||
$backendTypes['ldap'] = 'LDAP';
|
||||
}
|
||||
|
||||
$autologinBackends = array_filter(
|
||||
$externalBackends = array_filter(
|
||||
$this->config->toArray(),
|
||||
function ($authBackendCfg) {
|
||||
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'autologin';
|
||||
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'external';
|
||||
}
|
||||
);
|
||||
if ($backendType === 'autologin' || empty($autologinBackends)) {
|
||||
$backendTypes['autologin'] = t('Autologin');
|
||||
if ($backendType === 'external' || empty($externalBackends)) {
|
||||
$backendTypes['external'] = $this->translate('External');
|
||||
}
|
||||
|
||||
if ($backendType === null) {
|
||||
|
@ -318,8 +320,10 @@ class AuthenticationBackendConfigForm extends ConfigForm
|
|||
'ignore' => true,
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('Backend Type'),
|
||||
'description' => t('The type of the resource to use for this authenticaton provider'),
|
||||
'label' => $this->translate('Backend Type'),
|
||||
'description' => $this->translate(
|
||||
'The type of the resource to use for this authenticaton provider'
|
||||
),
|
||||
'multiOptions' => $backendTypes
|
||||
)
|
||||
);
|
||||
|
|
|
@ -52,7 +52,7 @@ class AuthenticationBackendReorderForm extends ConfigForm
|
|||
|
||||
try {
|
||||
if ($configForm->move($backendName, $position)->save()) {
|
||||
Notification::success(t('Authentication order updated!'));
|
||||
Notification::success($this->translate('Authentication order updated!'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -4,10 +4,8 @@
|
|||
|
||||
namespace Icinga\Forms\Config\General;
|
||||
|
||||
use DateTimeZone;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
|
||||
|
@ -33,10 +31,10 @@ class ApplicationConfigForm extends Form
|
|||
'text',
|
||||
'global_module_path',
|
||||
array(
|
||||
'label' => t('Module Path'),
|
||||
'label' => $this->translate('Module Path'),
|
||||
'required' => true,
|
||||
'value' => implode(':', Icinga::app()->getModuleManager()->getModuleDirs()),
|
||||
'description' => t(
|
||||
'description' => $this->translate(
|
||||
'Contains the directories that will be searched for available modules, separated by '
|
||||
. 'colons. Modules that don\'t exist in these directories can still be symlinked in '
|
||||
. 'the module folder, but won\'t show up in the list of disabled modules.'
|
||||
|
@ -46,19 +44,19 @@ class ApplicationConfigForm extends Form
|
|||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'preferences_type',
|
||||
'preferences_store',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('User Preference Storage Type'),
|
||||
'label' => $this->translate('User Preference Storage Type'),
|
||||
'multiOptions' => array(
|
||||
'ini' => t('File System (INI Files)'),
|
||||
'db' => t('Database'),
|
||||
'null' => t('Don\'t Store Preferences')
|
||||
'ini' => $this->translate('File System (INI Files)'),
|
||||
'db' => $this->translate('Database'),
|
||||
'none' => $this->translate('Don\'t Store Preferences')
|
||||
)
|
||||
)
|
||||
);
|
||||
if (isset($formData['preferences_type']) && $formData['preferences_type'] === 'db') {
|
||||
if (isset($formData['preferences_store']) && $formData['preferences_store'] === 'db') {
|
||||
$backends = array();
|
||||
foreach (ResourceFactory::getResourceConfigs()->toArray() as $name => $resource) {
|
||||
if ($resource['type'] === 'db') {
|
||||
|
@ -72,7 +70,7 @@ class ApplicationConfigForm extends Form
|
|||
array(
|
||||
'required' => true,
|
||||
'multiOptions' => $backends,
|
||||
'label' => t('Database Connection')
|
||||
'label' => $this->translate('Database Connection')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
namespace Icinga\Forms\Config\General;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Form\Validator\WritablePathValidator;
|
||||
|
@ -31,12 +30,12 @@ class LoggingConfigForm extends Form
|
|||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('Logging Type'),
|
||||
'description' => t('The type of logging to utilize.'),
|
||||
'label' => $this->translate('Logging Type'),
|
||||
'description' => $this->translate('The type of logging to utilize.'),
|
||||
'multiOptions' => array(
|
||||
'syslog' => 'Syslog',
|
||||
'file' => t('File', 'app.config.logging.type'),
|
||||
'none' => t('None', 'app.config.logging.type')
|
||||
'file' => $this->translate('File', 'app.config.logging.type'),
|
||||
'none' => $this->translate('None', 'app.config.logging.type')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -47,13 +46,13 @@ class LoggingConfigForm extends Form
|
|||
'logging_level',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Logging Level'),
|
||||
'description' => t('The maximum logging level to emit.'),
|
||||
'label' => $this->translate('Logging Level'),
|
||||
'description' => $this->translate('The maximum logging level to emit.'),
|
||||
'multiOptions' => array(
|
||||
Logger::$levels[Logger::ERROR] => t('Error', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::WARNING] => t('Warning', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::INFO] => t('Information', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::DEBUG] => t('Debug', 'app.config.logging.level')
|
||||
Logger::$levels[Logger::ERROR] => $this->translate('Error', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::WARNING] => $this->translate('Warning', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::INFO] => $this->translate('Information', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::DEBUG] => $this->translate('Debug', 'app.config.logging.level')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -65,9 +64,11 @@ class LoggingConfigForm extends Form
|
|||
'logging_application',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Application Prefix'),
|
||||
'description' => t('The name of the application by which to prefix syslog messages.'),
|
||||
'value' => 'icingaweb',
|
||||
'label' => $this->translate('Application Prefix'),
|
||||
'description' => $this->translate(
|
||||
'The name of the application by which to prefix syslog messages.'
|
||||
),
|
||||
'value' => 'icingaweb2',
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
|
@ -91,8 +92,8 @@ class LoggingConfigForm extends Form
|
|||
// 'logging_facility',
|
||||
// array(
|
||||
// 'required' => true,
|
||||
// 'label' => t('Facility'),
|
||||
// 'description' => t('The syslog facility to utilize.'),
|
||||
// 'label' => $this->translate('Facility'),
|
||||
// 'description' => $this->translate('The syslog facility to utilize.'),
|
||||
// 'multiOptions' => array(
|
||||
// 'user' => 'LOG_USER'
|
||||
// )
|
||||
|
@ -104,9 +105,9 @@ class LoggingConfigForm extends Form
|
|||
'logging_file',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('File path'),
|
||||
'description' => t('The full path to the log file to write messages to.'),
|
||||
'value' => $this->getDefaultLogDir(),
|
||||
'label' => $this->translate('File path'),
|
||||
'description' => $this->translate('The full path to the log file to write messages to.'),
|
||||
'value' => '/var/log/icingaweb2/icingaweb2.log',
|
||||
'validators' => array(new WritablePathValidator())
|
||||
)
|
||||
);
|
||||
|
@ -114,14 +115,4 @@ class LoggingConfigForm extends Form
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default logging directory for type 'file'
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultLogDir()
|
||||
{
|
||||
return realpath(Icinga::app()->getApplicationDir('../var/log/icingaweb.log'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class GeneralConfigForm extends ConfigForm
|
|||
public function init()
|
||||
{
|
||||
$this->setName('form_config_general');
|
||||
$this->setSubmitLabel(t('Save Changes'));
|
||||
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,7 +52,7 @@ class GeneralConfigForm extends ConfigForm
|
|||
}
|
||||
|
||||
if ($this->save()) {
|
||||
Notification::success(t('New configuration has successfully been stored'));
|
||||
Notification::success($this->translate('New configuration has successfully been stored'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ class DbResourceForm extends Form
|
|||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'description' => t('The unique name of this resource')
|
||||
'label' => $this->translate('Resource Name'),
|
||||
'description' => $this->translate('The unique name of this resource')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -50,8 +50,8 @@ class DbResourceForm extends Form
|
|||
'db',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Type'),
|
||||
'description' => t('The type of SQL database'),
|
||||
'label' => $this->translate('Database Type'),
|
||||
'description' => $this->translate('The type of SQL database'),
|
||||
'multiOptions' => $dbChoices
|
||||
)
|
||||
);
|
||||
|
@ -60,8 +60,8 @@ class DbResourceForm extends Form
|
|||
'host',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Host'),
|
||||
'description' => t('The hostname of the database'),
|
||||
'label' => $this->translate('Host'),
|
||||
'description' => $this->translate('The hostname of the database'),
|
||||
'value' => 'localhost'
|
||||
)
|
||||
);
|
||||
|
@ -70,8 +70,8 @@ class DbResourceForm extends Form
|
|||
'port',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Port'),
|
||||
'description' => t('The port to use'),
|
||||
'label' => $this->translate('Port'),
|
||||
'description' => $this->translate('The port to use'),
|
||||
'value' => 3306
|
||||
)
|
||||
);
|
||||
|
@ -80,8 +80,8 @@ class DbResourceForm extends Form
|
|||
'dbname',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Name'),
|
||||
'description' => t('The name of the database to use')
|
||||
'label' => $this->translate('Database Name'),
|
||||
'description' => $this->translate('The name of the database to use')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -89,8 +89,8 @@ class DbResourceForm extends Form
|
|||
'username',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Username'),
|
||||
'description' => t('The user name to use for authentication')
|
||||
'label' => $this->translate('Username'),
|
||||
'description' => $this->translate('The user name to use for authentication')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -99,8 +99,8 @@ class DbResourceForm extends Form
|
|||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Password'),
|
||||
'description' => t('The password to use for authentication')
|
||||
'label' => $this->translate('Password'),
|
||||
'description' => $this->translate('The password to use for authentication')
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -132,7 +132,9 @@ class DbResourceForm extends Form
|
|||
$resource = ResourceFactory::createResource(new ConfigObject($form->getValues()));
|
||||
$resource->getConnection()->getConnection();
|
||||
} catch (Exception $e) {
|
||||
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
$form->addError(
|
||||
$form->translate('Connectivity validation failed, connection to the given resource not possible.')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ class FileResourceForm extends Form
|
|||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'description' => t('The unique name of this resource')
|
||||
'label' => $this->translate('Resource Name'),
|
||||
'description' => $this->translate('The unique name of this resource')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -39,8 +39,8 @@ class FileResourceForm extends Form
|
|||
'filename',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'description' => t('The filename to fetch information from'),
|
||||
'label' => $this->translate('Filepath'),
|
||||
'description' => $this->translate('The filename to fetch information from'),
|
||||
'validators' => array(new ReadablePathValidator())
|
||||
)
|
||||
);
|
||||
|
@ -49,8 +49,8 @@ class FileResourceForm extends Form
|
|||
'fields',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Pattern'),
|
||||
'description' => t('The regular expression by which to identify columns')
|
||||
'label' => $this->translate('Pattern'),
|
||||
'description' => $this->translate('The regular expression by which to identify columns')
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -32,8 +32,8 @@ class LdapResourceForm extends Form
|
|||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'description' => t('The unique name of this resource')
|
||||
'label' => $this->translate('Resource Name'),
|
||||
'description' => $this->translate('The unique name of this resource')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -41,8 +41,10 @@ class LdapResourceForm extends Form
|
|||
'hostname',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Host'),
|
||||
'description' => t('The hostname or address of the LDAP server to use for authentication'),
|
||||
'label' => $this->translate('Host'),
|
||||
'description' => $this->translate(
|
||||
'The hostname or address of the LDAP server to use for authentication'
|
||||
),
|
||||
'value' => 'localhost'
|
||||
)
|
||||
);
|
||||
|
@ -51,8 +53,8 @@ class LdapResourceForm extends Form
|
|||
'port',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Port'),
|
||||
'description' => t('The port of the LDAP server to use for authentication'),
|
||||
'label' => $this->translate('Port'),
|
||||
'description' => $this->translate('The port of the LDAP server to use for authentication'),
|
||||
'value' => 389
|
||||
)
|
||||
);
|
||||
|
@ -61,8 +63,10 @@ class LdapResourceForm extends Form
|
|||
'root_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Root DN'),
|
||||
'description' => t('Only the root and its child nodes will be accessible on this resource.')
|
||||
'label' => $this->translate('Root DN'),
|
||||
'description' => $this->translate(
|
||||
'Only the root and its child nodes will be accessible on this resource.'
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -70,8 +74,8 @@ class LdapResourceForm extends Form
|
|||
'bind_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Bind DN'),
|
||||
'description' => t('The user dn to use for querying the ldap server')
|
||||
'label' => $this->translate('Bind DN'),
|
||||
'description' => $this->translate('The user dn to use for querying the ldap server')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -80,8 +84,8 @@ class LdapResourceForm extends Form
|
|||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Bind Password'),
|
||||
'description' => t('The password to use for querying the ldap server')
|
||||
'label' => $this->translate('Bind Password'),
|
||||
'description' => $this->translate('The password to use for querying the ldap server')
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -119,7 +123,9 @@ class LdapResourceForm extends Form
|
|||
throw new Exception();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
$form->addError(
|
||||
$form->translate('Connectivity validation failed, connection to the given resource not possible.')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,8 +33,8 @@ class LivestatusResourceForm extends Form
|
|||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'description' => t('The unique name of this resource')
|
||||
'label' => $this->translate('Resource Name'),
|
||||
'description' => $this->translate('The unique name of this resource')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -42,9 +42,9 @@ class LivestatusResourceForm extends Form
|
|||
'socket',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Socket'),
|
||||
'description' => t('The path to your livestatus socket used for querying monitoring data'),
|
||||
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/rw/livestatus')
|
||||
'label' => $this->translate('Socket'),
|
||||
'description' => $this->translate('The path to your livestatus socket used for querying monitoring data'),
|
||||
'value' => '/var/run/icinga2/cmd/livestatus'
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -75,8 +75,10 @@ class LivestatusResourceForm extends Form
|
|||
try {
|
||||
$resource = ResourceFactory::createResource(new ConfigObject($form->getValues()));
|
||||
$resource->connect()->disconnect();
|
||||
} catch (Exception $e) {
|
||||
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
} catch (Exception $_) {
|
||||
$form->addError(
|
||||
$form->translate('Connectivity validation failed, connection to the given resource not possible.')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class ResourceConfigForm extends ConfigForm
|
|||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource');
|
||||
$this->setSubmitLabel(t('Save Changes'));
|
||||
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,7 +43,7 @@ class ResourceConfigForm extends ConfigForm
|
|||
} elseif ($type === 'file') {
|
||||
return new FileResourceForm();
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf(t('Invalid resource type "%s" provided'), $type));
|
||||
throw new InvalidArgumentException(sprintf($this->translate('Invalid resource type "%s" provided'), $type));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,9 +62,9 @@ class ResourceConfigForm extends ConfigForm
|
|||
{
|
||||
$name = isset($values['name']) ? $values['name'] : '';
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Resource name missing'));
|
||||
throw new InvalidArgumentException($this->translate('Resource name missing'));
|
||||
} elseif ($this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Resource already exists'));
|
||||
throw new InvalidArgumentException($this->translate('Resource already exists'));
|
||||
}
|
||||
|
||||
unset($values['name']);
|
||||
|
@ -85,11 +85,11 @@ class ResourceConfigForm extends ConfigForm
|
|||
public function edit($name, array $values)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Old resource name missing'));
|
||||
throw new InvalidArgumentException($this->translate('Old resource name missing'));
|
||||
} elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) {
|
||||
throw new InvalidArgumentException(t('New resource name missing'));
|
||||
throw new InvalidArgumentException($this->translate('New resource name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Unknown resource provided'));
|
||||
throw new InvalidArgumentException($this->translate('Unknown resource provided'));
|
||||
}
|
||||
|
||||
$resourceConfig = $this->config->getSection($name);
|
||||
|
@ -111,9 +111,9 @@ class ResourceConfigForm extends ConfigForm
|
|||
public function remove($name)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Resource name missing'));
|
||||
throw new InvalidArgumentException($this->translate('Resource name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Unknown resource provided'));
|
||||
throw new InvalidArgumentException($this->translate('Unknown resource provided'));
|
||||
}
|
||||
|
||||
$resourceConfig = $this->config->getSection($name);
|
||||
|
@ -143,10 +143,10 @@ class ResourceConfigForm extends ConfigForm
|
|||
try {
|
||||
if ($resource === null) { // create new resource
|
||||
$this->add($this->getValues());
|
||||
$message = t('Resource "%s" has been successfully created');
|
||||
$message = $this->translate('Resource "%s" has been successfully created');
|
||||
} else { // edit existing resource
|
||||
$this->edit($resource, $this->getValues());
|
||||
$message = t('Resource "%s" has been successfully changed');
|
||||
$message = $this->translate('Resource "%s" has been successfully changed');
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
|
@ -172,9 +172,9 @@ class ResourceConfigForm extends ConfigForm
|
|||
$resource = $this->request->getQuery('resource');
|
||||
if ($resource !== null) {
|
||||
if ($resource === '') {
|
||||
throw new ConfigurationError(t('Resource name missing'));
|
||||
throw new ConfigurationError($this->translate('Resource name missing'));
|
||||
} elseif (! $this->config->hasSection($resource)) {
|
||||
throw new ConfigurationError(t('Unknown resource provided'));
|
||||
throw new ConfigurationError($this->translate('Unknown resource provided'));
|
||||
}
|
||||
|
||||
$configValues = $this->config->getSection($resource)->toArray();
|
||||
|
@ -197,8 +197,8 @@ class ResourceConfigForm extends ConfigForm
|
|||
array(
|
||||
'order' => 0,
|
||||
'ignore' => true,
|
||||
'label' => t('Force Changes'),
|
||||
'description' => t('Check this box to enforce changes without connectivity validation')
|
||||
'label' => $this->translate('Force Changes'),
|
||||
'description' => $this->translate('Check this box to enforce changes without connectivity validation')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -211,14 +211,14 @@ class ResourceConfigForm extends ConfigForm
|
|||
$resourceType = isset($formData['type']) ? $formData['type'] : 'db';
|
||||
|
||||
$resourceTypes = array(
|
||||
'file' => t('File'),
|
||||
'file' => $this->translate('File'),
|
||||
'livestatus' => 'Livestatus',
|
||||
);
|
||||
if ($resourceType === 'ldap' || Platform::extensionLoaded('ldap')) {
|
||||
$resourceTypes['ldap'] = 'LDAP';
|
||||
}
|
||||
if ($resourceType === 'db' || Platform::hasMysqlSupport() || Platform::hasPostgresqlSupport()) {
|
||||
$resourceTypes['db'] = t('SQL Database');
|
||||
$resourceTypes['db'] = $this->translate('SQL Database');
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
|
@ -227,8 +227,8 @@ class ResourceConfigForm extends ConfigForm
|
|||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('Resource Type'),
|
||||
'description' => t('The type of resource'),
|
||||
'label' => $this->translate('Resource Type'),
|
||||
'description' => $this->translate('The type of resource'),
|
||||
'multiOptions' => $resourceTypes,
|
||||
'value' => $resourceType
|
||||
)
|
||||
|
|
|
@ -17,6 +17,6 @@ class ConfirmRemovalForm extends Form
|
|||
public function init()
|
||||
{
|
||||
$this->setName('form_confirm_removal');
|
||||
$this->setSubmitLabel(t('Confirm Removal'));
|
||||
$this->setSubmitLabel($this->translate('Confirm Removal'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class DashletForm extends Form
|
|||
{
|
||||
$this->setName('form_dashboard_addurl');
|
||||
if (! $this->getSubmitLabel()) {
|
||||
$this->setSubmitLabel(t('Add To Dashboard'));
|
||||
$this->setSubmitLabel($this->translate('Add To Dashboard'));
|
||||
}
|
||||
$this->setAction(URL::fromRequest());
|
||||
}
|
||||
|
@ -66,9 +66,10 @@ class DashletForm extends Form
|
|||
'url',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Url'),
|
||||
'description' =>
|
||||
t('Enter url being loaded in the dashlet. You can paste the full URL, including filters.')
|
||||
'label' => $this->translate('Url'),
|
||||
'description' => $this->translate(
|
||||
'Enter url being loaded in the dashlet. You can paste the full URL, including filters.'
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -76,8 +77,8 @@ class DashletForm extends Form
|
|||
'dashlet',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Dashlet Title'),
|
||||
'description' => t('Enter a title for the dashlet.')
|
||||
'label' => $this->translate('Dashlet Title'),
|
||||
'description' => $this->translate('Enter a title for the dashlet.')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -95,9 +96,8 @@ class DashletForm extends Form
|
|||
'pane',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t("New Dashboard Title"),
|
||||
'description' =>
|
||||
t('Enter a title for the new pane.')
|
||||
'label' => $this->translate("New Dashboard Title"),
|
||||
'description' => $this->translate('Enter a title for the new pane.')
|
||||
)
|
||||
);
|
||||
} else {
|
||||
|
@ -106,10 +106,9 @@ class DashletForm extends Form
|
|||
'pane',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Dashboard'),
|
||||
'label' => $this->translate('Dashboard'),
|
||||
'multiOptions' => $panes,
|
||||
'description' =>
|
||||
t('Select a pane you want to add the dashlet.')
|
||||
'description' => $this->translate('Select a pane you want to add the dashlet.')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -119,9 +118,9 @@ class DashletForm extends Form
|
|||
'create_new_pane',
|
||||
array(
|
||||
'required' => false,
|
||||
'label' => t('New dashboard'),
|
||||
'label' => $this->translate('New dashboard'),
|
||||
'class' => 'autosubmit',
|
||||
'description' => t('Check this box if you want to add the dashlet to a new dashboard')
|
||||
'description' => $this->translate('Check this box if you want to add the dashlet to a new dashboard')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ class LdapDiscoveryForm extends Form
|
|||
'domain',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Search Domain'),
|
||||
'description' => t('Search this domain for records of available servers.'),
|
||||
'label' => $this->translate('Search Domain'),
|
||||
'description' => $this->translate('Search this domain for records of available servers.'),
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -36,7 +36,7 @@ class LdapDiscoveryForm extends Form
|
|||
'note',
|
||||
'additional_description',
|
||||
array(
|
||||
'value' => t('No Ldap servers found on this domain.'
|
||||
'value' => $this->translate('No Ldap servers found on this domain.'
|
||||
. ' You can try to specify host and port and try again, or just skip this step and '
|
||||
. 'configure the server manually.'
|
||||
)
|
||||
|
@ -47,8 +47,8 @@ class LdapDiscoveryForm extends Form
|
|||
'hostname',
|
||||
array(
|
||||
'required' => false,
|
||||
'label' => t('Host'),
|
||||
'description' => t('IP or host name to search.'),
|
||||
'label' => $this->translate('Host'),
|
||||
'description' => $this->translate('IP or hostname to search.'),
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -57,8 +57,8 @@ class LdapDiscoveryForm extends Form
|
|||
'port',
|
||||
array(
|
||||
'required' => false,
|
||||
'label' => t('Port'),
|
||||
'description' => t('Port', 389),
|
||||
'label' => $this->translate('Port'),
|
||||
'description' => $this->translate('Port', 389),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ class PreferenceForm extends Form
|
|||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
$this->preferences = new Preferences($this->store->load());
|
||||
$this->preferences = new Preferences($this->store ? $this->store->load() : array());
|
||||
|
||||
$webPreferences = $this->preferences->get('icingaweb', array());
|
||||
foreach ($this->getValues() as $key => $value) {
|
||||
|
@ -103,11 +103,11 @@ class PreferenceForm extends Form
|
|||
Session::getSession()->user->setPreferences($this->preferences);
|
||||
|
||||
try {
|
||||
if ($this->getElement('btn_submit_preferences')->isChecked()) {
|
||||
if ($this->store && $this->getElement('btn_submit_preferences')->isChecked()) {
|
||||
$this->save();
|
||||
Notification::success(t('Preferences successfully saved'));
|
||||
Notification::success($this->translate('Preferences successfully saved'));
|
||||
} else {
|
||||
Notification::success(t('Preferences successfully saved for the current session'));
|
||||
Notification::success($this->translate('Preferences successfully saved for the current session'));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Logger::error($e);
|
||||
|
@ -142,13 +142,13 @@ class PreferenceForm extends Form
|
|||
public function createElements(array $formData)
|
||||
{
|
||||
$languages = array();
|
||||
$languages['autodetect'] = sprintf(t('Browser (%s)', 'preferences.form'), $this->getLocale());
|
||||
$languages['autodetect'] = sprintf($this->translate('Browser (%s)', 'preferences.form'), $this->getLocale());
|
||||
foreach (Translator::getAvailableLocaleCodes() as $language) {
|
||||
$languages[$language] = $language;
|
||||
}
|
||||
|
||||
$tzList = array();
|
||||
$tzList['autodetect'] = sprintf(t('Browser (%s)', 'preferences.form'), $this->getDefaultTimezone());
|
||||
$tzList['autodetect'] = sprintf($this->translate('Browser (%s)', 'preferences.form'), $this->getDefaultTimezone());
|
||||
foreach (DateTimeZone::listIdentifiers() as $tz) {
|
||||
$tzList[$tz] = $tz;
|
||||
}
|
||||
|
@ -158,8 +158,8 @@ class PreferenceForm extends Form
|
|||
'language',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Your Current Language'),
|
||||
'description' => t('Use the following language to display texts and messages'),
|
||||
'label' => $this->translate('Your Current Language'),
|
||||
'description' => $this->translate('Use the following language to display texts and messages'),
|
||||
'multiOptions' => $languages,
|
||||
'value' => substr(setlocale(LC_ALL, 0), 0, 5)
|
||||
)
|
||||
|
@ -170,8 +170,8 @@ class PreferenceForm extends Form
|
|||
'timezone',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Your Current Timezone'),
|
||||
'description' => t('Use the following timezone for dates and times'),
|
||||
'label' => $this->translate('Your Current Timezone'),
|
||||
'description' => $this->translate('Use the following timezone for dates and times'),
|
||||
'multiOptions' => $tzList,
|
||||
'value' => $this->getDefaultTimezone()
|
||||
)
|
||||
|
@ -182,29 +182,31 @@ class PreferenceForm extends Form
|
|||
'show_benchmark',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Use benchmark')
|
||||
'label' => $this->translate('Use benchmark')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'btn_submit_preferences',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => t('Save to the Preferences'),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'div'))
|
||||
if ($this->store) {
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'btn_submit_preferences',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Save to the Preferences'),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'div'))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'btn_submit_session',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => t('Save for the current Session'),
|
||||
'label' => $this->translate('Save for the current Session'),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'div'))
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Icinga\Forms\Security;
|
|||
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use Zend_Form_Element;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Util\String;
|
||||
|
@ -18,14 +19,14 @@ class RoleForm extends ConfigForm
|
|||
/**
|
||||
* Provided permissions by currently loaded modules
|
||||
*
|
||||
* @var array
|
||||
* @type array
|
||||
*/
|
||||
protected $providedPermissions = array();
|
||||
protected $providedPermissions = array('*' => '*');
|
||||
|
||||
/**
|
||||
* Provided restrictions by currently loaded modules
|
||||
*
|
||||
* @var array
|
||||
* @type array
|
||||
*/
|
||||
protected $providedRestrictions = array();
|
||||
|
||||
|
@ -35,14 +36,26 @@ class RoleForm extends ConfigForm
|
|||
*/
|
||||
public function init()
|
||||
{
|
||||
$helper = new Zend_Form_Element('bogus');
|
||||
foreach (Icinga::app()->getModuleManager()->getLoadedModules() as $module) {
|
||||
foreach ($module->getProvidedPermissions() as $permission) {
|
||||
/** @var object $permission */
|
||||
/** @type object $permission */
|
||||
$this->providedPermissions[$permission->name] = $permission->name . ': ' . $permission->description;
|
||||
}
|
||||
foreach ($module->getProvidedRestrictions() as $restriction) {
|
||||
/** @var object $restriction */
|
||||
$this->providedRestrictions[$restriction->name] = $restriction->description;
|
||||
/** @type object $restriction */
|
||||
$name = $helper->filterName($restriction->name); // Zend only permits alphanumerics, the underscore,
|
||||
// the circumflex and any ASCII character in range
|
||||
// \x7f to \xff (127 to 255)
|
||||
while (isset($this->providedRestrictions[$name])) {
|
||||
// Because Zend_Form_Element::filterName() replaces any not permitted character with the empty
|
||||
// string we may have duplicate names, e.g. 're/striction' and 'restriction'
|
||||
$name .= '_';
|
||||
}
|
||||
$this->providedRestrictions[$name] = array(
|
||||
'description' => $restriction->description,
|
||||
'name' => $restriction->name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,8 +72,8 @@ class RoleForm extends ConfigForm
|
|||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Role Name'),
|
||||
'description' => t('The name of the role'),
|
||||
'label' => $this->translate('Role Name'),
|
||||
'description' => $this->translate('The name of the role'),
|
||||
'ignore' => true
|
||||
),
|
||||
),
|
||||
|
@ -68,35 +81,37 @@ class RoleForm extends ConfigForm
|
|||
'textarea',
|
||||
'users',
|
||||
array(
|
||||
'label' => t('Users'),
|
||||
'description' => t('Comma-separated list of users that are assigned to the role')
|
||||
'label' => $this->translate('Users'),
|
||||
'description' => $this->translate('Comma-separated list of users that are assigned to the role')
|
||||
),
|
||||
),
|
||||
array(
|
||||
'textarea',
|
||||
'groups',
|
||||
array(
|
||||
'label' => t('Groups'),
|
||||
'description' => t('Comma-separated list of groups that are assigned to the role')
|
||||
'label' => $this->translate('Groups'),
|
||||
'description' => $this->translate('Comma-separated list of groups that are assigned to the role')
|
||||
),
|
||||
),
|
||||
array(
|
||||
'multiselect',
|
||||
'permissions',
|
||||
array(
|
||||
'label' => t('Permissions Set'),
|
||||
'description' => t('The permissions to grant. You may select more than one permission'),
|
||||
'label' => $this->translate('Permissions Set'),
|
||||
'description' => $this->translate(
|
||||
'The permissions to grant. You may select more than one permission'
|
||||
),
|
||||
'multiOptions' => $this->providedPermissions
|
||||
)
|
||||
)
|
||||
));
|
||||
foreach ($this->providedRestrictions as $name => $description) {
|
||||
foreach ($this->providedRestrictions as $name => $spec) {
|
||||
$this->addElement(
|
||||
'text',
|
||||
$name,
|
||||
array(
|
||||
'label' => $name,
|
||||
'description' => $description
|
||||
'label' => $spec['name'],
|
||||
'description' => $spec['description']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -120,7 +135,7 @@ class RoleForm extends ConfigForm
|
|||
}
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
t('Can\'t load role \'%s\'. Role does not exist'),
|
||||
$this->translate('Can\'t load role \'%s\'. Role does not exist'),
|
||||
$name
|
||||
));
|
||||
}
|
||||
|
@ -129,6 +144,15 @@ class RoleForm extends ConfigForm
|
|||
? String::trimSplit($role['permissions'])
|
||||
: null;
|
||||
$role['name'] = $name;
|
||||
$restrictions = array();
|
||||
foreach ($this->providedRestrictions as $name => $spec) {
|
||||
if (isset($role[$spec['name']])) {
|
||||
// Translate restriction names to filtered element names
|
||||
$restrictions[$name] = $role[$spec['name']];
|
||||
unset($role[$spec['name']]);
|
||||
}
|
||||
}
|
||||
$role = array_merge($role, $restrictions);
|
||||
$this->populate($role);
|
||||
return $this;
|
||||
}
|
||||
|
@ -152,7 +176,7 @@ class RoleForm extends ConfigForm
|
|||
}
|
||||
if ($this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
t('Can\'t add role \'%s\'. Role already exists'),
|
||||
$this->translate('Can\'t add role \'%s\'. Role already exists'),
|
||||
$name
|
||||
));
|
||||
}
|
||||
|
@ -178,7 +202,7 @@ class RoleForm extends ConfigForm
|
|||
}
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
t('Can\'t remove role \'%s\'. Role does not exist'),
|
||||
$this->translate('Can\'t remove role \'%s\'. Role does not exist'),
|
||||
$name
|
||||
));
|
||||
}
|
||||
|
@ -211,7 +235,7 @@ class RoleForm extends ConfigForm
|
|||
} else {
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
t('Can\'t update role \'%s\'. Role does not exist'),
|
||||
$this->translate('Can\'t update role \'%s\'. Role does not exist'),
|
||||
$name
|
||||
));
|
||||
}
|
||||
|
@ -230,6 +254,15 @@ class RoleForm extends ConfigForm
|
|||
if (isset($values['permissions'])) {
|
||||
$values['permissions'] = implode(', ', $values['permissions']);
|
||||
}
|
||||
$restrictions = array();
|
||||
foreach ($this->providedRestrictions as $name => $spec) {
|
||||
if (isset($values[$name])) {
|
||||
// Translate filtered element names to restriction names
|
||||
$restrictions[$spec['name']] = $values[$name];
|
||||
unset($values[$name]);
|
||||
}
|
||||
}
|
||||
$values = array_merge($values, $restrictions);
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Menu;
|
||||
use Icinga\Web\MenuRenderer;
|
||||
use Icinga\Web\Widget\SearchDashboard;
|
||||
|
||||
// Don't render a menu for unauthenticated users unless menu is auth aware
|
||||
if (! $this->auth()->isAuthenticated()) {
|
||||
|
@ -11,15 +10,16 @@ if (! $this->auth()->isAuthenticated()) {
|
|||
}
|
||||
|
||||
?>
|
||||
<div
|
||||
id="menu" data-last-update="<?= (time() - 14) ?>000" data-base-target="_main" class="container" data-icinga-url="<?=$this->href('layout/menu');?>"
|
||||
data-icinga-refresh="15"
|
||||
>
|
||||
<? if (SearchDashboard::search('dummy')->getPane('search')->hasDashlets()): ?>
|
||||
<form action="<?= $this->href('search') ?>" method="get" role="search">
|
||||
<input type="text" name="q" class="search autofocus" placeholder="<?= $this->translate('Search...') ?>"
|
||||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
|
||||
</form>
|
||||
<? endif; ?>
|
||||
<?= new MenuRenderer(Menu::load(), Url::fromRequest()->without('renderLayout')->getRelativeUrl()); ?>
|
||||
<div id="menu" data-last-update="<?= (time() - 14) ?>000" data-base-target="_main" class="container"
|
||||
data-icinga-url="<?= $this->href('layout/menu') ?>" data-icinga-refresh="15">
|
||||
<?= $this->partial(
|
||||
'layout/menu.phtml',
|
||||
'default',
|
||||
array(
|
||||
'menuRenderer' => new MenuRenderer(
|
||||
Menu::load(),
|
||||
Url::fromRequest()->without('renderLayout')->getRelativeUrl()
|
||||
)
|
||||
)
|
||||
) ?>
|
||||
</div>
|
||||
|
|
|
@ -57,7 +57,7 @@ class Zend_View_Helper_FormDateTime extends Zend_View_Helper_FormElement
|
|||
$type = $attribs['local'] === true ? 'datetime-local' : 'datetime';
|
||||
unset($attribs['local']); // Unset local to not render it again in $this->_htmlAttribs($attribs)
|
||||
$html5 = sprintf(
|
||||
'<input type="%s" name="%s" id="%s" value="%s"%s%s%s%s%s',
|
||||
'<input type="%s" name="%s" id="%s" step="1" value="%s"%s%s%s%s%s',
|
||||
$type,
|
||||
$this->view->escape($name),
|
||||
$this->view->escape($id),
|
||||
|
|
|
@ -1,11 +1,28 @@
|
|||
<div id="login">
|
||||
<div class="logo">
|
||||
<div class="image">
|
||||
<img class="fade-in one" src="<?= $this->baseUrl('img/logo_icinga_big.png') ?>" alt="<?= t('The Icinga logo') ?>" >
|
||||
<img class="fade-in one" src="<?= $this->baseUrl('img/logo_icinga_big.png'); ?>" alt="<?= $this->translate('The Icinga logo'); ?>" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="form" data-base-target="layout">
|
||||
<h1>Welcome to Icinga Web 2</h1>
|
||||
<?php if ($requiresSetup): ?>
|
||||
<p class="config-note"><?= sprintf(
|
||||
$this->translate(
|
||||
'It appears that you did not configure Icinga Web 2 yet so it\'s not possible to log in without any defined '
|
||||
. 'authentication method. Please define a authentication method by following the instructions in the'
|
||||
. ' %1$sdocumentation%3$s or by using our %2$sweb-based setup-wizard%3$s.'
|
||||
),
|
||||
'<a href="http://docs.icinga.org/" title="' . $this->translate('Icinga Web 2 Documentation') . '">', // TODO: More exact documentation link..
|
||||
'<a href="' . $this->href('setup') . '" title="' . $this->translate('Icinga Web 2 Setup-Wizard') . '">',
|
||||
'</a>'
|
||||
); ?></p>
|
||||
<?php elseif ($requiresExternalAuth): ?>
|
||||
<p class="info-box"><span class="icon-info"></span><?= $this->translate(
|
||||
'You\'re currently not authenticated using any of the web server\'s authentication mechanisms.'
|
||||
. ' Make sure you\'ll configure such, otherwise you\'ll not be able to login.'
|
||||
); ?></p>
|
||||
<?php endif ?>
|
||||
<h1><?= $this->translate('Welcome to Icinga Web 2'); ?></h1>
|
||||
<?php
|
||||
/* TODO: remove this as soon as notifications and forms are ready */
|
||||
if (isset($this->errorInfo)): ?>
|
||||
|
@ -14,18 +31,6 @@
|
|||
</div>
|
||||
<?php endif ?>
|
||||
<?= $this->form ?>
|
||||
<div class="footer">Icinga Web 2 © 2013-2014<br><a href="https://www.icinga.org">The Icinga Project</a></div>
|
||||
<?php if ($configMissing): ?>
|
||||
<div class="config-note"><?= sprintf(
|
||||
t(
|
||||
'You seem not to have Icinga Web 2 configured yet so it\'s not possible to log in without any defined '
|
||||
. 'authentication method. Please define a authentication method by following the instructions in the'
|
||||
. ' %1$sdocumentation%3$s or by using our %2$sweb-based setup-wizard%3$s.'
|
||||
),
|
||||
'<a href="http://docs.icinga.org/" title="Icinga Web 2 Documentation">', // TODO: Documentation link
|
||||
'<a href="' . $this->href('setup') . '" title="Icinga Web 2 Setup-Wizard">',
|
||||
'</a>'
|
||||
); ?></div>
|
||||
<?php endif ?>
|
||||
<div class="footer">Icinga Web 2 © 2013-2015<br><a href="https://www.icinga.org"><?= $this->translate('The Icinga Project'); ?></a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="controls">
|
||||
<div class="controls" data-base-target="_main">
|
||||
<?= $tabs; ?>
|
||||
</div>
|
||||
<div class="content" data-base-target="_next">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="controls">
|
||||
<div class="controls" data-base-target="_main">
|
||||
<?= $this->tabs->render($this); ?>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
<div class="controls">
|
||||
<?= $this->tabs->render($this); ?>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<?php $errors = $this->form->getErrorMessages(); ?>
|
||||
|
||||
<?php if (isset($this->messageBox)): ?>
|
||||
<?= $this->messageBox->render() ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($this->successMessage): ?>
|
||||
<div>
|
||||
<i class="icinga-icon-success"></i>
|
||||
<strong><?= $this->escape($this->successMessage); ?></strong>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($errors)) : ?>
|
||||
<div>
|
||||
<h4>Errors occured when trying to save the project.</h4>
|
||||
<p>
|
||||
The following errors occured when trying to save the configuration:
|
||||
</p>
|
||||
<ul>
|
||||
<?php foreach($errors as $error): ?>
|
||||
<li><?= $this->escape($error) ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
<?= $this->form ?>
|
||||
</div>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="controls">
|
||||
<div class="controls" data-base-target="_right">
|
||||
<?= $this->tabs ?>
|
||||
<h1><?= $this->escape($module->getTitle()) ?></h1>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="controls">
|
||||
<div class="controls" data-base-target="_main">
|
||||
<?= $tabs; ?>
|
||||
</div>
|
||||
<div class="content" data-base-target="_next">
|
||||
|
|
|
@ -5,7 +5,7 @@ use Icinga\Web\Widget\SearchDashboard;
|
|||
<? if (SearchDashboard::search('dummy')->getPane('search')->hasDashlets()): ?>
|
||||
<form action="<?= $this->href('search') ?>" method="get" role="search">
|
||||
<input
|
||||
type="text" name="q" class="search autofocus" placeholder="<?= $this->translate('Search...') ?>"
|
||||
type="text" name="q" class="search" placeholder="<?= $this->translate('Search...') ?>"
|
||||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
/>
|
||||
</form>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="controls">
|
||||
<div class="controls" data-base-target="_main">
|
||||
<?= $tabs ?>
|
||||
<h1><?= $this->translate('Roles') ?></h1>
|
||||
</div>
|
||||
|
@ -30,7 +30,7 @@
|
|||
<td>
|
||||
<?php
|
||||
// TODO(el): $role->without(...) or $role->shift(...) would be nice!
|
||||
$restrictions = $role;
|
||||
$restrictions = clone $role;
|
||||
unset($restrictions['users']);
|
||||
unset($restrictions['groups']);
|
||||
unset($restrictions['permissions']);
|
||||
|
|
|
@ -24,7 +24,7 @@ For delegating authentication to the web server simply add `autologin` to your a
|
|||
|
||||
````
|
||||
[autologin]
|
||||
backend = autologin
|
||||
backend = external
|
||||
````
|
||||
|
||||
If your web server is not configured for authentication though the `autologin` section has no effect.
|
||||
|
|
|
@ -1,90 +1,83 @@
|
|||
# Externel Authentication
|
||||
# External Authentication
|
||||
|
||||
It is possible to use the authentication mechanism of the webserver,
|
||||
instead of using the internal authentication-manager to
|
||||
authenticate users. This might be useful if you only have very few users, and
|
||||
user management over *.htaccess* is sufficient, or if you must use some other
|
||||
authentication mechanism that is only available through your webserver.
|
||||
It is possible to utilize the authentication mechanism of the webserver instead
|
||||
of the internal authentication of Icinga Web 2 to authenticate users. This might
|
||||
be useful if you only have very few users and user management over **.htaccess**
|
||||
is not sufficient or if you are required to use some other authentication
|
||||
mechanism that is only available by utilizing the webserver.
|
||||
|
||||
When external authentication is used, Icingaweb will entrust the
|
||||
complete authentication process to the external authentication provider (the webserver):
|
||||
The provider should take care of authenticating the user and declining
|
||||
all requests with invalid or missing credentials. When the authentication
|
||||
was succesful, it should provide the authenticated users name to its php-module
|
||||
and Icingaweb will assume that the user is authorized to access the page.
|
||||
Because of this it is very important that the webservers authentication is
|
||||
configured correctly, as wrong configuration could lead to unauthorized
|
||||
access to the site, or a broken login-process.
|
||||
Icinga Web 2 will entrust the complete authentication process to the
|
||||
authentication provider of the webserver, if external authentication is used.
|
||||
So it is very important that the webserver's authentication is configured
|
||||
correctly as wrong configuration might lead to unauthorized access or a
|
||||
malfunction in the login-process.
|
||||
|
||||
## Using External Authentication
|
||||
|
||||
## Use External Authentication
|
||||
External authentication in Icinga Web 2 requires the following preparations:
|
||||
|
||||
Using external authentication in Icingaweb requires two steps to work:
|
||||
1. The external authentication must be set up properly to correctly
|
||||
authenticate users
|
||||
2. Icinga Web 2 must be configured to use external authentication
|
||||
|
||||
1. The external authentication must be set up correctly to always
|
||||
authenticate the users.
|
||||
2. Icingaweb must be configured to use the external authentication.
|
||||
### Preparing the External Authentication Provider
|
||||
|
||||
This step depends heavily on the used webserver and authentication mechanism you
|
||||
want to use. It is not possible to cover all possibillities and you should
|
||||
probably read the documentation for your webserver to get detailed instructions
|
||||
on how to set up authentication properly.
|
||||
|
||||
### Prepare the External Authentication Provider
|
||||
|
||||
This step depends heavily on the used webserver and authentication
|
||||
mechanism you want to use. It is not possible to cover all possibillities
|
||||
and you should probably read the documentation for your webserver for
|
||||
detailed instructions on how to set up authentication properly.
|
||||
|
||||
In general, you need to make sure that:
|
||||
|
||||
- All routes require authentication
|
||||
- Only permitted users are allowed to authenticate
|
||||
In general you need to make sure that:
|
||||
|
||||
- All routes require authentication
|
||||
- Only permitted users are allowed to authenticate
|
||||
|
||||
#### Example Configuration for Apache and HTTPDigestAuthentication
|
||||
|
||||
The following example will show how to enable external authentication in Apache using
|
||||
*HTTP Digest Authentication*.
|
||||
The following example will show how to enable external authentication in Apache
|
||||
using *HTTP Digest Authentication*.
|
||||
|
||||
##### Create users
|
||||
##### Creating users
|
||||
|
||||
To create users for a digest authentication we can use the tool *htdigest*.
|
||||
We choose *.icingawebdigest* as a name for the created file, containing
|
||||
the user credentials.
|
||||
To create users for digest authentication you can use the tool *htdigest*. In
|
||||
this example **.icingawebdigest** is the name of the file containing the user
|
||||
credentials.
|
||||
|
||||
This command will create a new file with the user *jdoe*. *htdigest*
|
||||
will prompt you for your password, after it has been executed. If you
|
||||
want to add more users to the file you need to ommit the *-c* parameter
|
||||
in all further commands to avoInid the file to be overwritten.
|
||||
This command creates a new file with the user *jdoe*. *htdigest* will prompt
|
||||
you for a password. If you want to add more users to the file you need to omit
|
||||
the *-c* parameter in all following commands to not to overwrite the file.
|
||||
|
||||
````
|
||||
sudo htdigest -c /etc/icingaweb2/.icingawebdigest "Icinga Web 2" jdoe
|
||||
````
|
||||
|
||||
sudo htdigest -c /etc/httpd/conf.d/.icingawebdigest "Icingaweb 2" jdoe
|
||||
##### Configuring the Webserver
|
||||
|
||||
The webserver should require authentication for all public Icinga Web 2 files.
|
||||
|
||||
##### Set up authentication
|
||||
````
|
||||
<Directory "/usr/share/icingaweb2/public">
|
||||
AuthType digest
|
||||
AuthName "Icinga Web 2"
|
||||
AuthDigestProvider file
|
||||
AuthUserFile /etc/icingaweb2/.icingawebdigest
|
||||
Require valid-user
|
||||
</Directory>
|
||||
````
|
||||
|
||||
The webserver should require authentication for all public icingaweb files.
|
||||
### Preparing Icinga Web 2
|
||||
|
||||
Once external authentication is set up correctly you need to configure Icinga
|
||||
Web 2. In case you already completed the setup wizard it is likely that you are
|
||||
now finished.
|
||||
|
||||
<Directory "/var/www/html/icingaweb">
|
||||
AuthType digest
|
||||
AuthName "Icingaweb 2"
|
||||
AuthDigestProvider file
|
||||
AuthUserFile /etc/httpd/conf.d/.icingawebdigest
|
||||
Require valid-user
|
||||
</Directory>
|
||||
To get Icinga Web 2 to use external authentication the file
|
||||
**config/authentication.ini** is required. Just add the following section
|
||||
called "autologin", or any name of your choice, and save your changes:
|
||||
|
||||
|
||||
### Prepare Icingaweb
|
||||
````
|
||||
[autologin]
|
||||
backend = external
|
||||
````
|
||||
|
||||
When the external authentication is set up correctly, we need
|
||||
to configure IcingaWeb to use it as an authentication source. The
|
||||
configuration key *authenticationMode* in the section *global* defines
|
||||
if the authentication should be handled internally or externally. Since
|
||||
we want to delegate the authentication to the Webserver we choose
|
||||
"external" as the new value:
|
||||
|
||||
|
||||
[global]
|
||||
; ...
|
||||
authenticationMode = "external"
|
||||
; ...
|
||||
|
||||
Congratulations! You are now logged in when visiting Icinga Web 2.
|
|
@ -6,7 +6,7 @@ system and distribution you are running. But it is also possible to install Icin
|
|||
## <a id="installation-requirements"></a> Installing Requirements
|
||||
|
||||
* A web server, e.g. Apache or nginx
|
||||
* PHP >= 5.3.0
|
||||
* PHP >= 5.3.0 w/ gettext and OpenSSL support
|
||||
* MySQL or PostgreSQL PHP libraries when using a database for authentication or storing user preferences into a database
|
||||
* LDAP PHP library when using Active Directory or LDAP for authentication
|
||||
* Icinga 1.x w/ Livestatus or IDO, Icinga 2 w/ Livestatus or IDO feature enabled
|
||||
|
@ -26,7 +26,7 @@ repository either via git or http protocol using the following URLs:
|
|||
* http://git.icinga.org/icingaweb2.git
|
||||
|
||||
There is also a browsable version available at
|
||||
[gi.icinga.org](https://git.icinga.org/?p=icingaweb2.git;a=summary "Icinga Web 2 Git Repository").
|
||||
[git.icinga.org](https://git.icinga.org/?p=icingaweb2.git;a=summary "Icinga Web 2 Git Repository").
|
||||
This version also offers snapshots for easy download which you can use if you do not have git present on your system.
|
||||
|
||||
````
|
||||
|
@ -38,25 +38,73 @@ git clone git://git.icinga.org/icingaweb2.git
|
|||
Choose a target directory and move Icinga Web 2 there.
|
||||
|
||||
````
|
||||
mv icingaweb2 /usr/share/icingaweb
|
||||
mv icingaweb2 /usr/share/icingaweb2
|
||||
````
|
||||
|
||||
**Step 3: Configuring the Web Server**
|
||||
|
||||
Use `icingacli` to generate web server configuration for either Apache or nginx.
|
||||
|
||||
*Apache*
|
||||
|
||||
Apache:
|
||||
````
|
||||
./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb/public
|
||||
./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public
|
||||
````
|
||||
|
||||
*nginx*
|
||||
|
||||
nginx:
|
||||
````
|
||||
./bin/icingacli setup config webserver nginx --document-root /usr/share/icingaweb/public
|
||||
./bin/icingacli setup config webserver nginx --document-root /usr/share/icingaweb2/public
|
||||
````
|
||||
|
||||
**Step 4: Web Setup**
|
||||
**Step 4: Preparing Web Setup**
|
||||
|
||||
Visit Icinga Web 2 in your browser and complete installation using the web setup.
|
||||
Because both web and CLI must have access to configuration and logs, permissions will be managed using a special
|
||||
system group. The web server user and CLI user have to be added to this system group.
|
||||
|
||||
Add the system group `icingaweb2` in the first place.
|
||||
|
||||
Fedora, RHEL, CentOS, SLES and OpenSUSE:
|
||||
````
|
||||
groupadd -r icingaweb2
|
||||
````
|
||||
|
||||
Debian and Ubuntu:
|
||||
````
|
||||
addgroup --system icingaweb2
|
||||
````
|
||||
|
||||
Add your web server's user to the system group `icingaweb2`:
|
||||
|
||||
Fedora, RHEL and CentOS:
|
||||
````
|
||||
usermod -a -G icingaweb2 apache
|
||||
````
|
||||
|
||||
SLES and OpenSUSE:
|
||||
````
|
||||
usermod -G icingaweb2 wwwrun
|
||||
````
|
||||
|
||||
Debian and Ubuntu:
|
||||
````
|
||||
usermod -a -G icingaweb2 wwwrun
|
||||
````
|
||||
|
||||
Use `icingacli` to create the configuration directory which defaults to **/etc/icingaweb2**:
|
||||
````
|
||||
./bin/icingacli setup config directory
|
||||
````
|
||||
|
||||
When using the web setup you are required to authenticate using a token. In order to generate a token use the
|
||||
`icingacli`:
|
||||
````
|
||||
./bin/icingacli setup token create
|
||||
````
|
||||
|
||||
In case you do not remember the token you can show it using the `icingacli`:
|
||||
````
|
||||
./bin/icingacli setup token show
|
||||
````
|
||||
|
||||
**Step 5: Web Setup**
|
||||
|
||||
Visit Icinga Web 2 in your browser and complete installation using the web setup: /icingaweb2/setup
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
# Vagrant
|
||||
|
||||
## Requirements
|
||||
|
||||
* Vagrant >= version 1.5
|
||||
* VirtualBox or Parallels
|
||||
|
||||
> **Note:** The deployment of the virtual machine is tested against Vagrant starting with version 1.5.
|
||||
> Unfortunately older versions will not work.
|
||||
|
||||
## General
|
||||
|
||||
The Icinga Web 2 project ships with a Vagrant virtual machine that integrates
|
||||
the source code with various services and example data in a controlled
|
||||
environment. This enables developers and users to test Livestatus,
|
||||
MySQL and PostgreSQL backends as well as the LDAP authentication. All you
|
||||
have to do is install Vagrant and run:
|
||||
|
||||
````
|
||||
vagrant up
|
||||
````
|
||||
|
||||
> **Note:** The first boot of the vm takes a fairly long time because
|
||||
> you'll download a plain CentOS base box and Vagrant will automatically
|
||||
> provision the environment on the first go.
|
||||
|
||||
After you should be able to browse [localhost:8080/icingaweb2](http://localhost:8080/icingaweb2).
|
||||
|
||||
## Log into Icinga Web 2
|
||||
|
||||
Both LDAP and a MySQL are configured as authentication backend. Please use one of the following login credentials:
|
||||
|
||||
> LDAP:
|
||||
>> **Username**: `jdoe`
|
||||
|
||||
>> **Password**: `password`
|
||||
|
||||
>MySQL:
|
||||
>> **Username**: `icingaadmin`
|
||||
|
||||
>> **Password**: `icinga`
|
||||
|
||||
|
||||
|
||||
## Testing the Source Code
|
||||
|
||||
All software required to run tests is installed in the virtual machine.
|
||||
In order to run all tests you have to execute the following command:
|
||||
|
||||
````
|
||||
vagrant ssh -c "icingacli test php unit"
|
||||
````
|
428
icingaweb2.spec
428
icingaweb2.spec
|
@ -1,237 +1,271 @@
|
|||
#/**
|
||||
# * This file is part of Icinga Web 2.
|
||||
# *
|
||||
# * Icinga Web 2 - Head for multiple monitoring backends.
|
||||
# * Copyright (C) 2014 Icinga Development Team
|
||||
# *
|
||||
# * This program is free software; you can redistribute it and/or
|
||||
# * modify it under the terms of the GNU General Public License
|
||||
# * as published by the Free Software Foundation; either version 2
|
||||
# * of the License, or (at your option) any later version.
|
||||
# *
|
||||
# * This program is distributed in the hope that it will be useful,
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# * GNU General Public License for more details.
|
||||
# *
|
||||
# * You should have received a copy of the GNU General Public License
|
||||
# * along with this program; if not, write to the Free Software
|
||||
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
# *
|
||||
# * @copyright 2014 Icinga Development Team <info@icinga.org>
|
||||
# * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
|
||||
# * @author Icinga Development Team <info@icinga.org>
|
||||
# *
|
||||
# */
|
||||
%define revision 1.beta2
|
||||
|
||||
%define revision 1
|
||||
|
||||
%define configdir %{_sysconfdir}/%{name}
|
||||
%define sharedir %{_datadir}/%{name}
|
||||
%define prefixdir %{_datadir}/%{name}
|
||||
%define usermodparam -a -G
|
||||
%define logdir %{_localstatedir}/log/%{name}
|
||||
%define docdir %{sharedir}/doc
|
||||
|
||||
%if "%{_vendor}" == "suse"
|
||||
%define phpname php5
|
||||
%define phpzendname php5-ZendFramework
|
||||
%define apache2modphpname apache2-mod_php5
|
||||
%endif
|
||||
# SLE 11 = 1110
|
||||
%if 0%{?suse_version} == 1110
|
||||
%define phpname php53
|
||||
%define apache2modphpname apache2-mod_php53
|
||||
%define usermodparam -A
|
||||
%endif
|
||||
|
||||
%if "%{_vendor}" == "redhat"
|
||||
%define phpname php
|
||||
%define phpzendname php-ZendFramework
|
||||
%endif
|
||||
|
||||
# el5 requires newer php53 rather than php (5.1)
|
||||
%if 0%{?el5} || 0%{?rhel} == 5 || "%{?dist}" == ".el5"
|
||||
%define phpname php53
|
||||
%endif
|
||||
|
||||
%if "%{_vendor}" == "suse"
|
||||
%define apacheconfdir %{_sysconfdir}/apache2/conf.d
|
||||
%define apacheuser wwwrun
|
||||
%define apachegroup www
|
||||
%define extcmdfile %{_localstatedir}/run/icinga2/cmd/icinga.cmd
|
||||
%define livestatussocket %{_localstatedir}/run/icinga2/cmd/livestatus
|
||||
%endif
|
||||
%if "%{_vendor}" == "redhat"
|
||||
%define apacheconfdir %{_sysconfdir}/httpd/conf.d
|
||||
%define apacheuser apache
|
||||
%define apachegroup apache
|
||||
%define extcmdfile %{_localstatedir}/run/icinga2/cmd/icinga.cmd
|
||||
%define livestatussocket %{_localstatedir}/run/icinga2/cmd/livestatus
|
||||
%endif
|
||||
|
||||
Summary: Open Source host, service and network monitoring Web UI
|
||||
Name: icingaweb2
|
||||
Version: 0.0.1
|
||||
Version: 2.0.0
|
||||
Release: %{revision}%{?dist}
|
||||
License: GPLv2
|
||||
Summary: Icinga Web 2
|
||||
Group: Applications/System
|
||||
URL: http://www.icinga.org
|
||||
License: GPL
|
||||
URL: https://icinga.org
|
||||
Source0: https://github.com/Icinga/%{name}/archive/v%{version}.tar.gz
|
||||
BuildArch: noarch
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}
|
||||
Packager: Icinga Team <info@icinga.org>
|
||||
|
||||
%if "%{_vendor}" == "suse"
|
||||
AutoReqProv: Off
|
||||
%if 0%{?fedora} || 0%{?rhel}
|
||||
%define wwwconfigdir %{_sysconfdir}/httpd/conf.d
|
||||
%define wwwuser apache
|
||||
%if 0%{?rhel} == 5
|
||||
%define php php53
|
||||
%define php_cli php53-cli
|
||||
%else
|
||||
%define php php
|
||||
%define php_cli php-cli
|
||||
%endif
|
||||
%if 0%{?rhel} == 6
|
||||
%define zend php-ZendFramework
|
||||
%else
|
||||
%define zend %{name}-vendor-Zend
|
||||
%endif
|
||||
%endif
|
||||
|
||||
Source: icingaweb2-%{version}.tar.gz
|
||||
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
|
||||
|
||||
BuildRequires: %{phpname} >= 5.3.0
|
||||
BuildRequires: %{phpname}-devel >= 5.3.0
|
||||
BuildRequires: %{phpname}-ldap
|
||||
BuildRequires: %{phpname}-pdo
|
||||
BuildRequires: %{phpzendname}
|
||||
%if "%{_vendor}" != "suse"
|
||||
BuildRequires: %{phpzendname}-Db-Adapter-Pdo
|
||||
BuildRequires: %{phpzendname}-Db-Adapter-Pdo-Mysql
|
||||
BuildRequires: %{phpzendname}-Db-Adapter-Pdo-Pgsql
|
||||
%if 0%{?suse_version}
|
||||
%define wwwconfigdir %{_sysconfdir}/apache2/conf.d
|
||||
%define wwwuser wwwrun
|
||||
%define zend php5-ZendFramework
|
||||
%if 0%{?suse_version} == 1110
|
||||
%define php php53
|
||||
Requires: apache2-mod_php53
|
||||
%else
|
||||
%define php php5
|
||||
Requires: apache2-mod_php5
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if "%{_vendor}" == "redhat"
|
||||
%endif
|
||||
%if "%{_vendor}" == "suse"
|
||||
Requires: %{phpname}-devel >= 5.3.0
|
||||
BuildRequires: %{phpname}-json
|
||||
BuildRequires: %{phpname}-sockets
|
||||
BuildRequires: %{phpname}-dom
|
||||
%endif
|
||||
|
||||
Requires: %{phpname} >= 5.3.0
|
||||
Requires: %{phpzendname}
|
||||
Requires: %{phpname}-ldap
|
||||
Requires: %{phpname}-pdo
|
||||
%if "%{_vendor}" == "redhat"
|
||||
Requires: %{phpname}-common
|
||||
Requires: %{phpzendname}-Db-Adapter-Pdo
|
||||
Requires: %{phpzendname}-Db-Adapter-Pdo-Mysql
|
||||
Requires: php-pear
|
||||
%endif
|
||||
%if "%{_vendor}" == "suse"
|
||||
Requires: %{phpname}-pear
|
||||
Requires: %{phpname}-dom
|
||||
Requires: %{phpname}-tokenizer
|
||||
Requires: %{phpname}-gettext
|
||||
Requires: %{phpname}-ctype
|
||||
Requires: %{phpname}-json
|
||||
Requires: %{apache2modphpname}
|
||||
%endif
|
||||
|
||||
Requires: php-Icinga
|
||||
Requires(pre): shadow-utils
|
||||
Requires: %{name}-common = %{version}-%{release}
|
||||
Requires: php-Icinga = %{version}-%{release}
|
||||
Requires: %{name}-vendor-dompdf
|
||||
Requires: %{name}-vendor-HTMLPurifier
|
||||
Requires: %{name}-vendor-JShrink
|
||||
Requires: %{name}-vendor-lessphp
|
||||
Requires: %{name}-vendor-Parsedown
|
||||
Requires: %{zend}
|
||||
|
||||
|
||||
%description
|
||||
Icinga Web 2 for Icinga 2 or Icinga 1.x using multiple backends
|
||||
for example DB IDO.
|
||||
Icinga Web 2
|
||||
|
||||
%package -n icingacli
|
||||
Summary: Icinga CLI
|
||||
Group: Applications/System
|
||||
Requires: %{name} = %{version}-%{release}
|
||||
Requires: php-Icinga
|
||||
|
||||
%description -n icingacli
|
||||
Icinga CLI using php-Icinga Icinga Web 2 backend.
|
||||
%define basedir %{_datadir}/%{name}
|
||||
%define bindir %{_bindir}
|
||||
%define configdir %{_sysconfdir}/%{name}
|
||||
%define logdir %{_localstatedir}/log/%{name}
|
||||
%define phpdir %{_datadir}/php
|
||||
%define icingawebgroup icingaweb2
|
||||
%define docsdir %{_datadir}/doc/%{name}
|
||||
|
||||
|
||||
%package common
|
||||
Summary: Common files for Icinga Web 2 and the Icinga CLI
|
||||
Group: Applications/System
|
||||
|
||||
%description common
|
||||
Common files for Icinga Web 2 and the Icinga CLI
|
||||
|
||||
|
||||
%package -n php-Icinga
|
||||
Summary: Icinga Web 2 PHP Libraries
|
||||
Group: Applications/System
|
||||
Requires: %{name} = %{version}-%{release}
|
||||
Requires: %{phpname} >= 5.3.0
|
||||
Requires: %{phpzendname}
|
||||
|
||||
Summary: Icinga Web 2 PHP library
|
||||
Group: Development/Libraries
|
||||
Requires: %{php} >= 5.3.0
|
||||
Requires: %{php}-gd %{php}-intl
|
||||
%{?fedora:Requires: php-pecl-imagick}
|
||||
%{?rhel:Requires: php-pecl-imagick}
|
||||
%{?suse_version:Requires: %{php}-gettext %{php}-openssl php5-imagick}
|
||||
|
||||
%description -n php-Icinga
|
||||
Icinga Web 2 PHP Libraries required by the web frontend and cli tool.
|
||||
Icinga Web 2 PHP library
|
||||
|
||||
|
||||
%package -n icingacli
|
||||
Summary: Icinga CLI
|
||||
Group: Applications/System
|
||||
Requires: %{name}-common = %{version}-%{release}
|
||||
Requires: php-Icinga = %{version}-%{release}
|
||||
%{?fedora:Requires: %{php_cli} >= 5.3.0 bash-completion}
|
||||
%{?rhel:Requires: %{php_cli} >= 5.3.0 bash-completion}
|
||||
%{?suse_version:Requires: %{php} >= 5.3.0}
|
||||
|
||||
%description -n icingacli
|
||||
Icinga CLI
|
||||
|
||||
|
||||
%package vendor-dompdf
|
||||
Version: 0.6.1
|
||||
Release: 1%{?dist}
|
||||
Summary: Icinga Web 2 vendor library dompdf
|
||||
Group: Development/Libraries
|
||||
Requires: %{php} >= 5.3.0
|
||||
|
||||
%description vendor-dompdf
|
||||
Icinga Web 2 vendor library dompdf
|
||||
|
||||
|
||||
%package vendor-HTMLPurifier
|
||||
Version: 4.6.0
|
||||
Release: 1%{?dist}
|
||||
Summary: Icinga Web 2 vendor library HTMLPurifier
|
||||
Group: Development/Libraries
|
||||
Requires: %{php} >= 5.3.0
|
||||
|
||||
%description vendor-HTMLPurifier
|
||||
Icinga Web 2 vendor library HTMLPurifier
|
||||
|
||||
|
||||
%package vendor-JShrink
|
||||
Version: 1.0.1
|
||||
Release: 1%{?dist}
|
||||
Summary: Icinga Web 2 vendor library JShrink
|
||||
Group: Development/Libraries
|
||||
Requires: %{php} >= 5.3.0
|
||||
|
||||
%description vendor-JShrink
|
||||
Icinga Web 2 vendor library JShrink
|
||||
|
||||
|
||||
%package vendor-lessphp
|
||||
Version: 0.4.0
|
||||
Release: 1%{?dist}
|
||||
Summary: Icinga Web 2 vendor library lessphp
|
||||
Group: Development/Libraries
|
||||
Requires: %{php} >= 5.3.0
|
||||
|
||||
%description vendor-lessphp
|
||||
Icinga Web 2 vendor library lessphp
|
||||
|
||||
|
||||
%package vendor-Parsedown
|
||||
Version: 1.0.0
|
||||
Release: 1%{?dist}
|
||||
Summary: Icinga Web 2 vendor library Parsedown
|
||||
Group: Development/Libraries
|
||||
Requires: %{php} >= 5.3.0
|
||||
|
||||
%description vendor-Parsedown
|
||||
Icinga Web 2 vendor library Parsedown
|
||||
|
||||
|
||||
%package vendor-Zend
|
||||
Version: 1.12.9
|
||||
Release: 1%{?dist}
|
||||
Summary: Icinga Web 2 vendor library Zend Framework
|
||||
Group: Development/Libraries
|
||||
Requires: %{php} >= 5.3.0
|
||||
|
||||
%description vendor-Zend
|
||||
Icinga Web 2 vendor library Zend
|
||||
|
||||
|
||||
%prep
|
||||
#VERSION=0.0.1; git archive --format=tar --prefix=icingaweb2-$VERSION/ HEAD | gzip >icingaweb2-$VERSION.tar.gz
|
||||
%setup -q -n %{name}-%{version}
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
|
||||
%install
|
||||
[ "%{buildroot}" != "/" ] && [ -d "%{buildroot}" ] && rm -rf %{buildroot}
|
||||
|
||||
# prepare configuration for sub packages
|
||||
|
||||
# install rhel apache config
|
||||
install -D -m0644 packages/files/apache/icingaweb.conf %{buildroot}/%{apacheconfdir}/icingaweb.conf
|
||||
|
||||
# install public, library, modules
|
||||
%{__mkdir} -p %{buildroot}/%{sharedir}
|
||||
%{__mkdir} -p %{buildroot}/%{logdir}
|
||||
%{__mkdir} -p %{buildroot}/%{docdir}
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/dashboard
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/modules
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/modules/monitoring
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/enabledModules
|
||||
|
||||
# make sure to install local icingacli for setup wizard token generation & webserver config
|
||||
%{__cp} -r application doc library modules public bin %{buildroot}/%{sharedir}/
|
||||
|
||||
# enable the monitoring module by default
|
||||
ln -s %{sharedir}/modules/monitoring %{buildroot}/%{_sysconfdir}/%{name}/enabledModules/monitoring
|
||||
## config
|
||||
|
||||
# symlink icingacli
|
||||
mkdir -p %{buildroot}/usr/bin
|
||||
ln -sf %{sharedir}/bin/icingacli %{buildroot}/usr/bin/icingacli
|
||||
rm -rf %{buildroot}
|
||||
mkdir -p %{buildroot}/{%{basedir}/{modules,library,public},%{bindir},%{configdir}/modules/setup,%{logdir},%{phpdir},%{wwwconfigdir},%{_sysconfdir}/bash_completion.d,%{docsdir}}
|
||||
cp -prv application doc %{buildroot}/%{basedir}
|
||||
cp -pv etc/bash_completion.d/icingacli %{buildroot}/%{_sysconfdir}/bash_completion.d/icingacli
|
||||
cp -prv modules/{monitoring,setup} %{buildroot}/%{basedir}/modules
|
||||
cp -prv library/Icinga %{buildroot}/%{phpdir}
|
||||
cp -prv library/vendor %{buildroot}/%{basedir}/library
|
||||
cp -prv public/{css,img,js,error_norewrite.html} %{buildroot}/%{basedir}/public
|
||||
cp -pv packages/files/apache/icingaweb2.conf %{buildroot}/%{wwwconfigdir}/icingaweb2.conf
|
||||
cp -pv packages/files/bin/icingacli %{buildroot}/%{bindir}
|
||||
cp -pv packages/files/public/index.php %{buildroot}/%{basedir}/public
|
||||
cp -prv etc/schema %{buildroot}/%{docsdir}
|
||||
cp -prv packages/files/config/modules/setup %{buildroot}/%{configdir}/modules/
|
||||
|
||||
%pre
|
||||
# Add apacheuser in the icingacmd group
|
||||
# If the group exists, add the apacheuser in the icingacmd group.
|
||||
# It is not neccessary that icinga2-web is installed on the same system as
|
||||
# icinga and only on systems with icinga installed the icingacmd
|
||||
# group exists. In all other cases the user used for ssh access has
|
||||
# to be added to the icingacmd group on the remote icinga server.
|
||||
getent group icingacmd > /dev/null
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
%{_sbindir}/usermod %{usermodparam} icingacmd %{apacheuser}
|
||||
fi
|
||||
|
||||
%preun
|
||||
|
||||
%post
|
||||
getent group icingacmd >/dev/null || groupadd -r icingacmd
|
||||
%if 0%{?suse_version}
|
||||
usermod -G icingacmd,%{icingawebgroup} %{wwwuser}
|
||||
%else
|
||||
usermod -a -G icingacmd,%{icingawebgroup} %{wwwuser}
|
||||
%endif
|
||||
exit 0
|
||||
|
||||
%clean
|
||||
[ "%{buildroot}" != "/" ] && [ -d "%{buildroot}" ] && rm -rf %{buildroot}
|
||||
rm -rf %{buildroot}
|
||||
|
||||
%files
|
||||
# main dirs
|
||||
%defattr(-,root,root)
|
||||
%doc etc/schema doc packages/RPM.md
|
||||
%attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/public
|
||||
%attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/modules
|
||||
# configs
|
||||
%{basedir}/application/controllers
|
||||
%{basedir}/application/fonts
|
||||
%{basedir}/application/forms
|
||||
%{basedir}/application/layouts
|
||||
%{basedir}/application/views
|
||||
%{basedir}/doc
|
||||
%{basedir}/modules
|
||||
%{basedir}/public
|
||||
%{wwwconfigdir}/icingaweb2.conf
|
||||
%attr(2775,root,%{icingawebgroup}) %dir %{logdir}
|
||||
%{docsdir}
|
||||
%docdir %{docsdir}
|
||||
%attr(2770,root,%{icingawebgroup}) %config(noreplace) %dir %{configdir}/modules/setup
|
||||
%attr(0660,root,%{icingawebgroup}) %config(noreplace) %{configdir}/modules/setup/config.ini
|
||||
|
||||
|
||||
%pre common
|
||||
getent group %{icingawebgroup} >/dev/null || groupadd -r %{icingawebgroup}
|
||||
exit 0
|
||||
|
||||
%files common
|
||||
%defattr(-,root,root)
|
||||
%config(noreplace) %attr(-,root,root) %{apacheconfdir}/icingaweb.conf
|
||||
%config(noreplace) %attr(-,%{apacheuser},%{apachegroup}) %{configdir}
|
||||
# logs
|
||||
%attr(2775,%{apacheuser},%{apachegroup}) %dir %{logdir}
|
||||
# shipped docs
|
||||
%attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/doc
|
||||
%{basedir}/application/locale
|
||||
%dir %{basedir}/modules
|
||||
%attr(2770,root,%{icingawebgroup}) %config(noreplace) %dir %{configdir}
|
||||
%attr(2770,root,%{icingawebgroup}) %config(noreplace) %dir %{configdir}/modules
|
||||
|
||||
|
||||
%files -n php-Icinga
|
||||
%attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/application
|
||||
%attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/library
|
||||
%defattr(-,root,root)
|
||||
%{phpdir}/Icinga
|
||||
|
||||
|
||||
%files -n icingacli
|
||||
%attr(0755,root,root) /usr/bin/icingacli
|
||||
%attr(0755,root,root) %{sharedir}/bin/icingacli
|
||||
%attr(0755,root,root) %{sharedir}/bin/license_writer.py
|
||||
%defattr(-,root,root)
|
||||
%{basedir}/application/clicommands
|
||||
%{_sysconfdir}/bash_completion.d/icingacli
|
||||
%attr(0755,root,root) %{bindir}/icingacli
|
||||
|
||||
%changelog
|
||||
|
||||
%files vendor-dompdf
|
||||
%defattr(-,root,root)
|
||||
%{basedir}/library/vendor/dompdf
|
||||
|
||||
|
||||
%files vendor-HTMLPurifier
|
||||
%defattr(-,root,root)
|
||||
%{basedir}/library/vendor/HTMLPurifier
|
||||
|
||||
|
||||
%files vendor-JShrink
|
||||
%defattr(-,root,root)
|
||||
%{basedir}/library/vendor/JShrink
|
||||
|
||||
|
||||
%files vendor-lessphp
|
||||
%defattr(-,root,root)
|
||||
%{basedir}/library/vendor/lessphp
|
||||
|
||||
|
||||
%files vendor-Parsedown
|
||||
%defattr(-,root,root)
|
||||
%{basedir}/library/vendor/Parsedown
|
||||
|
||||
|
||||
%files vendor-Zend
|
||||
%defattr(-,root,root)
|
||||
%{basedir}/library/vendor/Zend
|
||||
|
|
|
@ -113,6 +113,13 @@ abstract class ApplicationBootstrap
|
|||
*/
|
||||
protected $isWeb = false;
|
||||
|
||||
/**
|
||||
* Whether Icinga Web 2 requires setup
|
||||
*
|
||||
* @type bool
|
||||
*/
|
||||
protected $requiresSetup = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
|
@ -133,7 +140,7 @@ abstract class ApplicationBootstrap
|
|||
if (array_key_exists('ICINGAWEB_CONFIGDIR', $_SERVER)) {
|
||||
$configDir = $_SERVER['ICINGAWEB_CONFIGDIR'];
|
||||
} else {
|
||||
$configDir = '/etc/icingaweb';
|
||||
$configDir = '/etc/icingaweb2';
|
||||
}
|
||||
}
|
||||
$canonical = realpath($configDir);
|
||||
|
@ -333,7 +340,7 @@ abstract class ApplicationBootstrap
|
|||
/**
|
||||
* Setup Icinga auto loader
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setupAutoloader()
|
||||
{
|
||||
|
@ -366,7 +373,7 @@ abstract class ApplicationBootstrap
|
|||
/**
|
||||
* Setup module manager
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupModuleManager()
|
||||
{
|
||||
|
@ -378,25 +385,10 @@ abstract class ApplicationBootstrap
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all core modules
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
protected function loadCoreModules()
|
||||
{
|
||||
try {
|
||||
$this->moduleManager->loadCoreModules();
|
||||
} catch (NotReadableError $e) {
|
||||
Logger::error(new IcingaException('Cannot load core modules. An exception was thrown:', $e));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all enabled modules
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function loadEnabledModules()
|
||||
{
|
||||
|
@ -408,10 +400,47 @@ abstract class ApplicationBootstrap
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the setup module if Icinga Web 2 requires setup or the setup token exists
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function loadSetupModuleIfNecessary()
|
||||
{
|
||||
if (! @file_exists($this->config->resolvePath('authentication.ini'))) {
|
||||
$this->requiresSetup = true;
|
||||
$this->moduleManager->loadModule('setup');
|
||||
} elseif ($this->setupTokenExists()) {
|
||||
// Load setup module but do not require setup
|
||||
$this->moduleManager->loadModule('setup');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether Icinga Web 2 requires setup
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function requiresSetup()
|
||||
{
|
||||
return $this->requiresSetup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the setup token exists
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setupTokenExists()
|
||||
{
|
||||
return @file_exists($this->config->resolvePath('setup.token'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup default logging
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupLogging()
|
||||
{
|
||||
|
@ -428,7 +457,7 @@ abstract class ApplicationBootstrap
|
|||
/**
|
||||
* Load Configuration
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function loadConfig()
|
||||
{
|
||||
|
@ -447,7 +476,7 @@ abstract class ApplicationBootstrap
|
|||
/**
|
||||
* Error handling configuration
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupErrorHandling()
|
||||
{
|
||||
|
@ -473,7 +502,7 @@ abstract class ApplicationBootstrap
|
|||
/**
|
||||
* Set up logger
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupLogger()
|
||||
{
|
||||
|
@ -490,7 +519,7 @@ abstract class ApplicationBootstrap
|
|||
/**
|
||||
* Set up the resource factory
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
protected function setupResourceFactory()
|
||||
{
|
||||
|
|
|
@ -44,7 +44,7 @@ class Cli extends ApplicationBootstrap
|
|||
->setupLogger()
|
||||
->setupResourceFactory()
|
||||
->setupModuleManager()
|
||||
->loadCoreModules();
|
||||
->loadSetupModuleIfNecessary();
|
||||
}
|
||||
|
||||
protected function setupLogging()
|
||||
|
|
|
@ -279,7 +279,7 @@ class Config implements Countable, Iterator
|
|||
*
|
||||
* @param string $file The file to parse
|
||||
*
|
||||
* @throws NotReadableError When the file does not exist or cannot be read
|
||||
* @throws NotReadableError When the file cannot be read
|
||||
*/
|
||||
public static function fromIni($file)
|
||||
{
|
||||
|
@ -292,7 +292,7 @@ class Config implements Countable, Iterator
|
|||
$config = new static(new ConfigObject(parse_ini_file($filepath, true)));
|
||||
$config->setConfigFile($filepath);
|
||||
return $config;
|
||||
} else {
|
||||
} elseif (@file_exists($filepath)) {
|
||||
throw new NotReadableError(t('Cannot read config file "%s". Permission denied'), $filepath);
|
||||
}
|
||||
|
||||
|
@ -322,7 +322,7 @@ class Config implements Countable, Iterator
|
|||
*/
|
||||
public static function app($configname = 'config', $fromDisk = false)
|
||||
{
|
||||
if (!isset(self::$app[$configname]) || $fromDisk) {
|
||||
if (! isset(self::$app[$configname]) || $fromDisk) {
|
||||
self::$app[$configname] = static::fromIni(static::resolvePath($configname . '.ini'));
|
||||
}
|
||||
|
||||
|
@ -341,12 +341,12 @@ class Config implements Countable, Iterator
|
|||
*/
|
||||
public static function module($modulename, $configname = 'config', $fromDisk = false)
|
||||
{
|
||||
if (!isset(self::$modules[$modulename])) {
|
||||
if (! isset(self::$modules[$modulename])) {
|
||||
self::$modules[$modulename] = array();
|
||||
}
|
||||
|
||||
$moduleConfigs = self::$modules[$modulename];
|
||||
if (!isset($moduleConfigs[$configname]) || $fromDisk) {
|
||||
if (! isset($moduleConfigs[$configname]) || $fromDisk) {
|
||||
$moduleConfigs[$configname] = static::fromIni(
|
||||
static::resolvePath('modules/' . $modulename . '/' . $configname . '.ini')
|
||||
);
|
||||
|
|
|
@ -6,10 +6,8 @@ namespace Icinga\Application;
|
|||
|
||||
require_once dirname(__FILE__) . '/ApplicationBootstrap.php';
|
||||
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
|
||||
/**
|
||||
* Use this if you want to make use of Icinga funtionality in other web projects
|
||||
* Use this if you want to make use of Icinga functionality in other web projects
|
||||
*
|
||||
* Usage example:
|
||||
* <code>
|
||||
|
|
|
@ -68,18 +68,6 @@ class Manager
|
|||
*/
|
||||
private $modulePaths = array();
|
||||
|
||||
/**
|
||||
* The core modules
|
||||
*
|
||||
* Core modules do not need to be enabled to load and cannot be disabled
|
||||
* by the user. This must not be writable programmatically!
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $coreModules = array(
|
||||
'setup'
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a new instance of the module manager
|
||||
*
|
||||
|
@ -170,21 +158,7 @@ class Manager
|
|||
}
|
||||
|
||||
/**
|
||||
* Try to set all core modules in loaded state
|
||||
*
|
||||
* @return self
|
||||
* @see Manager::loadModule()
|
||||
*/
|
||||
public function loadCoreModules()
|
||||
{
|
||||
foreach ($this->coreModules as $name) {
|
||||
$this->loadModule($name);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to set all enabled modules in loaded state
|
||||
* Try to set all enabled modules in loaded sate
|
||||
*
|
||||
* @return self
|
||||
* @see Manager::loadModule()
|
||||
|
@ -239,8 +213,6 @@ class Manager
|
|||
'Cannot enable module "%s". Module is not installed.',
|
||||
$name
|
||||
);
|
||||
} elseif (in_array($name, $this->coreModules)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
clearstatcache(true);
|
||||
|
@ -458,7 +430,7 @@ class Manager
|
|||
}
|
||||
|
||||
$installed = $this->listInstalledModules();
|
||||
foreach (array_diff($installed, $this->coreModules) as $name) {
|
||||
foreach ($installed as $name) {
|
||||
$info[$name] = (object) array(
|
||||
'name' => $name,
|
||||
'path' => $this->installedBaseDirs[$name],
|
||||
|
|
|
@ -759,15 +759,15 @@ class Module
|
|||
protected function registerAutoloader()
|
||||
{
|
||||
$moduleName = ucfirst($this->getName());
|
||||
|
||||
$moduleLibraryDir = $this->getLibDir(). '/'. $moduleName;
|
||||
if (is_dir($this->getBaseDir()) && is_dir($this->getLibDir()) && is_dir($moduleLibraryDir)) {
|
||||
if (is_dir($moduleLibraryDir)) {
|
||||
$this->app->getLoader()->registerNamespace('Icinga\\Module\\' . $moduleName, $moduleLibraryDir);
|
||||
if (is_dir($this->getFormDir())) {
|
||||
$this->app->getLoader()->registerNamespace(
|
||||
'Icinga\\Module\\' . $moduleName. '\\Forms',
|
||||
$this->getFormDir()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$moduleFormDir = $this->getFormDir();
|
||||
if (is_dir($moduleFormDir)) {
|
||||
$this->app->getLoader()->registerNamespace('Icinga\\Module\\' . $moduleName. '\\Forms', $moduleFormDir);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
|
|
@ -104,7 +104,7 @@ class Web extends ApplicationBootstrap
|
|||
->setupZendMvc()
|
||||
->setupFormNamespace()
|
||||
->setupModuleManager()
|
||||
->loadCoreModules()
|
||||
->loadSetupModuleIfNecessary()
|
||||
->loadEnabledModules()
|
||||
->setupRoute()
|
||||
->setupPagination();
|
||||
|
|
|
@ -87,9 +87,16 @@ class DbUserBackend extends UserBackend
|
|||
*/
|
||||
protected function getPasswordHash($username)
|
||||
{
|
||||
$stmt = $this->conn->getDbAdapter()->prepare(
|
||||
'SELECT password_hash FROM icingaweb_user WHERE name = :name AND active = 1'
|
||||
);
|
||||
if ($this->conn->getDbType() === 'pgsql') {
|
||||
// Since PostgreSQL version 9.0 the default value for bytea_output is 'hex' instead of 'escape'
|
||||
$stmt = $this->conn->getDbAdapter()->prepare(
|
||||
'SELECT ENCODE(password_hash, \'escape\') FROM icingaweb_user WHERE name = :name AND active = 1'
|
||||
);
|
||||
} else {
|
||||
$stmt = $this->conn->getDbAdapter()->prepare(
|
||||
'SELECT password_hash FROM icingaweb_user WHERE name = :name AND active = 1'
|
||||
);
|
||||
}
|
||||
$stmt->execute(array(':name' => $username));
|
||||
$stmt->bindColumn(1, $lob, PDO::PARAM_LOB);
|
||||
$stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
|
|
@ -11,7 +11,7 @@ use Icinga\User;
|
|||
/**
|
||||
* Test login with external authentication mechanism, e.g. Apache
|
||||
*/
|
||||
class AutoLoginBackend extends UserBackend
|
||||
class ExternalBackend extends UserBackend
|
||||
{
|
||||
/**
|
||||
* Regexp expression to strip values from a username
|
||||
|
@ -21,7 +21,7 @@ class AutoLoginBackend extends UserBackend
|
|||
private $stripUsernameRegexp;
|
||||
|
||||
/**
|
||||
* Create new autologin backend
|
||||
* Create new authentication backend of type "external"
|
||||
*
|
||||
* @param ConfigObject $config
|
||||
*/
|
||||
|
@ -33,7 +33,7 @@ class AutoLoginBackend extends UserBackend
|
|||
/**
|
||||
* Count the available users
|
||||
*
|
||||
* Autologin backends will always return 1
|
||||
* Authenticaton backends of type "external" will always return 1
|
||||
*
|
||||
* @return int
|
||||
*/
|
|
@ -213,7 +213,7 @@ class LdapUserBackend extends UserBackend
|
|||
*/
|
||||
public function count()
|
||||
{
|
||||
return $this->conn->count($this->selectUsers());
|
||||
return $this->selectUsers()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -63,7 +63,7 @@ class Manager
|
|||
);
|
||||
$config = new Config();
|
||||
}
|
||||
if ($config->hasSection('preferences')) {
|
||||
if ($config->get('preferences', 'store', 'ini') !== 'none') {
|
||||
$preferencesConfig = $config->getSection('preferences');
|
||||
try {
|
||||
$preferencesStore = PreferencesStore::create(
|
||||
|
@ -165,6 +165,7 @@ class Manager
|
|||
*/
|
||||
public function hasPermission($permission)
|
||||
{
|
||||
return true;
|
||||
if (! $this->isAuthenticated()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace Icinga\Authentication;
|
||||
|
||||
use Countable;
|
||||
use Icinga\Authentication\Backend\AutoLoginBackend;
|
||||
use Icinga\Authentication\Backend\ExternalBackend;
|
||||
use Icinga\Authentication\Backend\DbUserBackend;
|
||||
use Icinga\Authentication\Backend\LdapUserBackend;
|
||||
use Icinga\Data\ConfigObject;
|
||||
|
@ -69,8 +69,8 @@ abstract class UserBackend implements Countable
|
|||
);
|
||||
}
|
||||
$backendType = strtolower($backendType);
|
||||
if ($backendType === 'autologin') {
|
||||
$backend = new AutoLoginBackend($backendConfig);
|
||||
if ($backendType === 'external') {
|
||||
$backend = new ExternalBackend($backendConfig);
|
||||
$backend->setName($name);
|
||||
return $backend;
|
||||
}
|
||||
|
|
|
@ -78,24 +78,23 @@ class Axis implements Drawable
|
|||
private $yUnit = null;
|
||||
|
||||
/**
|
||||
* If the displayed labels should be aligned horizontally or diagonally
|
||||
* The minimum amount of units each step must take up
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $labelRotationStyle = self::LABEL_ROTATE_DIAGONAL;
|
||||
public $minUnitsPerStep = 80;
|
||||
|
||||
/**
|
||||
* Set the label rotation style for the horizontal axis
|
||||
* The minimum amount of units each tick must take up
|
||||
*
|
||||
* <ul>
|
||||
* <li><b>LABEL_ROTATE_HORIZONTAL</b>: Labels will be displayed horizontally </li>
|
||||
* <li><b>LABEL_ROTATE_DIAGONAL</b>: Labels will be rotated by 45° </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param $style The rotation mode
|
||||
* @var int
|
||||
*/
|
||||
public function setHorizontalLabelRotationStyle($style)
|
||||
{
|
||||
$this->labelRotationStyle = $style;
|
||||
}
|
||||
public $minUnitsPerTick = 15;
|
||||
|
||||
/**
|
||||
* If the displayed labels should be aligned horizontally or diagonally
|
||||
*/
|
||||
protected $labelRotationStyle = self::LABEL_ROTATE_HORIZONTAL;
|
||||
|
||||
/**
|
||||
* Inform the axis about an added dataset
|
||||
|
@ -160,58 +159,74 @@ class Axis implements Drawable
|
|||
*/
|
||||
private function renderHorizontalAxis(RenderContext $ctx, DOMElement $group)
|
||||
{
|
||||
$steps = $this->ticksPerX($this->xUnit->getTicks(), $ctx->getNrOfUnitsX(), $this->minUnitsPerStep);
|
||||
$ticks = $this->ticksPerX($this->xUnit->getTicks(), $ctx->getNrOfUnitsX(), $this->minUnitsPerTick);
|
||||
|
||||
// Steps should always be ticks
|
||||
if ($ticks !== $steps) {
|
||||
$steps = $ticks * 5;
|
||||
}
|
||||
|
||||
// Check whether there is enough room for regular labels
|
||||
$labelRotationStyle = $this->labelRotationStyle;
|
||||
if ($this->labelsOversized($this->xUnit, 6)) {
|
||||
$labelRotationStyle = self::LABEL_ROTATE_DIAGONAL;
|
||||
}
|
||||
|
||||
/*
|
||||
$line = new Line(0, 100, 100, 100);
|
||||
$line->setStrokeWidth(2);
|
||||
$group->appendChild($line->toSvg($ctx));
|
||||
*/
|
||||
|
||||
// contains the approximate end position of the last label
|
||||
$lastLabelEnd = -1;
|
||||
$shift = 0;
|
||||
|
||||
$i = 0;
|
||||
foreach ($this->xUnit as $label => $pos) {
|
||||
if ($this->labelRotationStyle === self::LABEL_ROTATE_HORIZONTAL) {
|
||||
// If the last label would overlap this label we shift the y axis a bit
|
||||
if ($lastLabelEnd > $pos) {
|
||||
$shift = ($shift + 5) % 10;
|
||||
} else {
|
||||
$shift = 0;
|
||||
|
||||
if ($i % $ticks === 0) {
|
||||
/*
|
||||
$tick = new Line($pos, 100, $pos, 101);
|
||||
$group->appendChild($tick->toSvg($ctx));
|
||||
*/
|
||||
}
|
||||
|
||||
if ($i % $steps === 0) {
|
||||
if ($labelRotationStyle === self::LABEL_ROTATE_HORIZONTAL) {
|
||||
// If the last label would overlap this label we shift the y axis a bit
|
||||
if ($lastLabelEnd > $pos) {
|
||||
$shift = ($shift + 5) % 10;
|
||||
} else {
|
||||
$shift = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$labelField = new Text($pos + 0.5, ($this->xLabel ? 107 : 105) + $shift, $label);
|
||||
if ($labelRotationStyle === self::LABEL_ROTATE_HORIZONTAL) {
|
||||
$labelField->setAlignment(Text::ALIGN_MIDDLE)
|
||||
->setFontSize('2.5em');
|
||||
} else {
|
||||
$labelField->setFontSize('2.5em');
|
||||
}
|
||||
|
||||
if ($labelRotationStyle === self::LABEL_ROTATE_DIAGONAL) {
|
||||
$labelField = new Rotator($labelField, 45);
|
||||
}
|
||||
$labelField = $labelField->toSvg($ctx);
|
||||
|
||||
$group->appendChild($labelField);
|
||||
|
||||
if ($this->drawYGrid) {
|
||||
$bgLine = new Line($pos, 0, $pos, 100);
|
||||
$bgLine->setStrokeWidth(0.5)
|
||||
->setStrokeColor('#BFBFBF');
|
||||
$group->appendChild($bgLine->toSvg($ctx));
|
||||
}
|
||||
$lastLabelEnd = $pos + strlen($label) * 1.2;
|
||||
}
|
||||
|
||||
$tick = new Line($pos, 100, $pos, 102);
|
||||
$group->appendChild($tick->toSvg($ctx));
|
||||
|
||||
$labelField = new Text($pos + 0.5, ($this->xLabel ? 107 : 105) + $shift, $label);
|
||||
if ($this->labelRotationStyle === self::LABEL_ROTATE_HORIZONTAL) {
|
||||
$labelField->setAlignment(Text::ALIGN_MIDDLE)
|
||||
->setFontSize('1.8em');
|
||||
} else {
|
||||
$labelField->setFontSize('2.5em');
|
||||
}
|
||||
|
||||
if ($this->labelRotationStyle === self::LABEL_ROTATE_DIAGONAL) {
|
||||
$labelField = new Rotator($labelField, 45);
|
||||
}
|
||||
$labelField = $labelField->toSvg($ctx);
|
||||
|
||||
$group->appendChild($labelField);
|
||||
|
||||
if ($this->drawYGrid) {
|
||||
$bgLine = new Line($pos, 0, $pos, 100);
|
||||
$bgLine->setStrokeWidth(0.5)
|
||||
->setStrokeColor('#232');
|
||||
$group->appendChild($bgLine->toSvg($ctx));
|
||||
}
|
||||
$lastLabelEnd = $pos + strlen($label) * 1.2;
|
||||
}
|
||||
|
||||
// render the label for this axis
|
||||
if ($this->xLabel) {
|
||||
$axisLabel = new Text(50, 104, $this->xLabel);
|
||||
$axisLabel->setFontSize('2em')
|
||||
->setFontWeight('bold')
|
||||
->setAlignment(Text::ALIGN_MIDDLE);
|
||||
$group->appendChild($axisLabel->toSvg($ctx));
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,34 +238,59 @@ class Axis implements Drawable
|
|||
*/
|
||||
private function renderVerticalAxis(RenderContext $ctx, DOMElement $group)
|
||||
{
|
||||
$steps = $this->ticksPerX($this->yUnit->getTicks(), $ctx->getNrOfUnitsY(), $this->minUnitsPerStep);
|
||||
$ticks = $this->ticksPerX($this->yUnit->getTicks(), $ctx->getNrOfUnitsY(), $this->minUnitsPerTick);
|
||||
|
||||
// Steps should always be ticks
|
||||
if ($ticks !== $steps) {
|
||||
$steps = $ticks * 5;
|
||||
}
|
||||
/*
|
||||
$line = new Line(0, 0, 0, 100);
|
||||
$line->setStrokeWidth(2);
|
||||
$group->appendChild($line->toSvg($ctx));
|
||||
*/
|
||||
|
||||
$i = 0;
|
||||
foreach ($this->yUnit as $label => $pos) {
|
||||
$pos = 100 - $pos;
|
||||
$tick = new Line(0, $pos, -1, $pos);
|
||||
$group->appendChild($tick->toSvg($ctx));
|
||||
|
||||
$labelField = new Text(-0.5, $pos+0.5, $label);
|
||||
$labelField->setFontSize('1.8em')
|
||||
->setAlignment(Text::ALIGN_END);
|
||||
|
||||
$group->appendChild($labelField->toSvg($ctx));
|
||||
if ($this->drawXGrid) {
|
||||
$bgLine = new Line(0, $pos, 100, $pos);
|
||||
$bgLine->setStrokeWidth(0.5)
|
||||
->setStrokeColor('#343');
|
||||
$group->appendChild($bgLine->toSvg($ctx));
|
||||
if ($i % $ticks === 0) {
|
||||
// draw a tick
|
||||
//$tick = new Line(0, $pos, -1, $pos);
|
||||
//$group->appendChild($tick->toSvg($ctx));
|
||||
}
|
||||
|
||||
if ($i % $steps === 0) {
|
||||
// draw a step
|
||||
$labelField = new Text(-0.5, $pos + 0.5, $label);
|
||||
$labelField->setFontSize('2.5em')
|
||||
->setAlignment(Text::ALIGN_END);
|
||||
|
||||
$group->appendChild($labelField->toSvg($ctx));
|
||||
if ($this->drawXGrid) {
|
||||
$bgLine = new Line(0, $pos, 100, $pos);
|
||||
$bgLine->setStrokeWidth(0.5)
|
||||
->setStrokeColor('#BFBFBF');
|
||||
$group->appendChild($bgLine->toSvg($ctx));
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ($this->yLabel) {
|
||||
$axisLabel = new Text(-8, 50, $this->yLabel);
|
||||
if ($this->yLabel || $this->xLabel) {
|
||||
if ($this->yLabel && $this->xLabel) {
|
||||
$txt = $this->yLabel . ' / ' . $this->xLabel;
|
||||
} else if ($this->xLabel) {
|
||||
$txt = $this->xLabel;
|
||||
} else {
|
||||
$txt = $this->yLabel;
|
||||
}
|
||||
|
||||
$axisLabel = new Text(50, -3, $txt);
|
||||
$axisLabel->setFontSize('2em')
|
||||
->setFontWeight('bold')
|
||||
->setAlignment(Text::ALIGN_MIDDLE);
|
||||
$axisLabel = new Rotator($axisLabel, 90);
|
||||
|
||||
$group->appendChild($axisLabel->toSvg($ctx));
|
||||
}
|
||||
|
@ -416,4 +456,32 @@ class Axis implements Drawable
|
|||
$this->renderVerticalAxis($ctx, $group);
|
||||
return $group;
|
||||
}
|
||||
|
||||
protected function ticksPerX($ticks, $units, $min)
|
||||
{
|
||||
$per = 1;
|
||||
while ($per * $units / $ticks < $min) {
|
||||
$per++;
|
||||
}
|
||||
return $per;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether at least one label of the given Axis
|
||||
* is bigger than the given maxLength
|
||||
*
|
||||
* @param AxisUnit $axis The axis that contains the labels that will be checked
|
||||
*
|
||||
* @return boolean Whether at least one label is bigger than maxLength
|
||||
*/
|
||||
private function labelsOversized(AxisUnit $axis, $maxLength = 5)
|
||||
{
|
||||
$oversized = false;
|
||||
foreach ($axis as $label => $pos) {
|
||||
if (strlen($label) > $maxLength) {
|
||||
$oversized = true;
|
||||
}
|
||||
}
|
||||
return $oversized;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ class BarGraph extends Styleable implements Drawable
|
|||
*
|
||||
* @var int
|
||||
*/
|
||||
private $barWidth = 4;
|
||||
private $barWidth = 3;
|
||||
|
||||
/**
|
||||
* The dataset to use for this bar graph
|
||||
|
@ -122,6 +122,14 @@ class BarGraph extends Styleable implements Drawable
|
|||
$doc = $ctx->getDocument();
|
||||
$group = $doc->createElement('g');
|
||||
$idx = 0;
|
||||
|
||||
if (count($this->dataSet) > 15) {
|
||||
$this->barWidth = 2;
|
||||
}
|
||||
if (count($this->dataSet) > 25) {
|
||||
$this->barWidth = 1;
|
||||
}
|
||||
|
||||
foreach ($this->dataSet as $x => $point) {
|
||||
// add white background bar, to prevent other bars from altering transparency effects
|
||||
$bar = $this->drawSingleBar($point, $idx++, 'white', $this->strokeWidth, $idx)->toSvg($ctx);
|
||||
|
|
|
@ -45,6 +45,13 @@ class LineGraph extends Styleable implements Drawable
|
|||
*/
|
||||
public $strokeWidth = 5;
|
||||
|
||||
/**
|
||||
* The size of the displayed dots
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $dotWith = 0;
|
||||
|
||||
/**
|
||||
* Create a new LineGraph displaying the given dataset
|
||||
*
|
||||
|
@ -138,8 +145,8 @@ class LineGraph extends Styleable implements Drawable
|
|||
$group = $path->toSvg($ctx);
|
||||
if ($this->showDataPoints === true) {
|
||||
foreach ($this->dataset as $point) {
|
||||
$dot = new Circle($point[0], $point[1], $this->strokeWidth*5);
|
||||
$dot->setFill('black');
|
||||
$dot = new Circle($point[0], $point[1], $this->dotWith);
|
||||
$dot->setFill($this->strokeColor);
|
||||
|
||||
$group->appendChild($dot->toSvg($ctx));
|
||||
}
|
||||
|
|
|
@ -66,13 +66,14 @@ class Legend implements Drawable
|
|||
$outer->getLayout()->setPadding(2, 2, 2, 2);
|
||||
$nrOfColumns = 4;
|
||||
|
||||
$leftstep = 100 / $nrOfColumns;
|
||||
$topstep = 10 / $nrOfColumns + 2;
|
||||
|
||||
$top = 0;
|
||||
$left = 0;
|
||||
$lastLabelEndPos = -1;
|
||||
foreach ($this->dataset as $color => $text) {
|
||||
$leftstep = 100 / $nrOfColumns + strlen($text);
|
||||
|
||||
// Make sure labels don't overlap each other
|
||||
while ($lastLabelEndPos >= $left) {
|
||||
$left += $leftstep;
|
||||
|
|
|
@ -61,7 +61,7 @@ class Circle extends Styleable implements Drawable
|
|||
$circle = $ctx->getDocument()->createElement('circle');
|
||||
$circle->setAttribute('cx', Format::formatSVGNumber($coords[0]));
|
||||
$circle->setAttribute('cy', Format::formatSVGNumber($coords[1]));
|
||||
$circle->setAttribute('r', 5);
|
||||
$circle->setAttribute('r', $this->radius);
|
||||
$circle->setAttribute('style', $this->getStyle());
|
||||
$this->applyAttributes($circle);
|
||||
return $circle;
|
||||
|
|
|
@ -9,13 +9,14 @@ use Iterator;
|
|||
/**
|
||||
* Base class for Axis Units
|
||||
*
|
||||
* An AxisUnit takes a set of values and places them on a given range
|
||||
*
|
||||
* Concrete subclasses must implement the iterator interface, with
|
||||
* getCurrent returning the axis relative position and getValue the label
|
||||
* that will be displayed
|
||||
*/
|
||||
interface AxisUnit extends Iterator
|
||||
{
|
||||
|
||||
/**
|
||||
* Add a dataset to this AxisUnit, required for dynamic min and max vlaues
|
||||
*
|
||||
|
@ -46,4 +47,11 @@ interface AxisUnit extends Iterator
|
|||
* @param int $max The new maximum value
|
||||
*/
|
||||
public function setMax($max);
|
||||
|
||||
/**
|
||||
* Get the amount of ticks of this axis
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTicks();
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ namespace Icinga\Chart\Unit;
|
|||
*/
|
||||
class LinearUnit implements AxisUnit
|
||||
{
|
||||
|
||||
/**
|
||||
* The minimum value to display
|
||||
*
|
||||
|
@ -43,7 +42,7 @@ class LinearUnit implements AxisUnit
|
|||
*
|
||||
* @var int
|
||||
*/
|
||||
private $nrOfTicks = 10;
|
||||
protected $nrOfTicks = 10;
|
||||
|
||||
/**
|
||||
* The currently displayed tick
|
||||
|
@ -95,45 +94,13 @@ class LinearUnit implements AxisUnit
|
|||
if (!$this->staticMin) {
|
||||
$this->min = min($this->min, $datapoints[0]);
|
||||
}
|
||||
if (!$this->staticMin || !$this->staticMax) {
|
||||
$this->updateMaxValue();
|
||||
}
|
||||
$this->currentTick = 0;
|
||||
$this->currentValue = $this->min;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the range depending on the current values of min, max and nrOfTicks
|
||||
*/
|
||||
private function updateMaxValue()
|
||||
{
|
||||
$this->max = $this->calculateTickRange($this->max - $this->min, $this->nrOfTicks) *
|
||||
$this->nrOfTicks + $this->min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the minimum tick range that is necessary to display the given value range
|
||||
* correctly
|
||||
*
|
||||
* @param int range The range to display
|
||||
* @param int ticks The amount of ticks to use
|
||||
*
|
||||
* @return int The value for each tick
|
||||
*/
|
||||
private function calculateTickRange($range, $ticks)
|
||||
{
|
||||
$factor = 1;
|
||||
$steps = array(1, 2, 5);
|
||||
$step = 0;
|
||||
while ($range / ($factor * $steps[$step]) > $ticks) {
|
||||
$step++;
|
||||
if ($step === count($steps)) {
|
||||
$step = 0;
|
||||
$factor *= 10;
|
||||
}
|
||||
if ($this->max === $this->min) {
|
||||
$this->max = $this->min + 10;
|
||||
}
|
||||
return $steps[$step] * $factor;
|
||||
$this->nrOfTicks = $this->max - $this->min;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,7 +116,7 @@ class LinearUnit implements AxisUnit
|
|||
} elseif ($value > $this->max) {
|
||||
return 100;
|
||||
} else {
|
||||
return 100 * ($value - $this->min) / $this->max - $this->min;
|
||||
return 100 * ($value - $this->min) / $this->nrOfTicks;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,7 +178,6 @@ class LinearUnit implements AxisUnit
|
|||
if ($max !== null) {
|
||||
$this->max = $max;
|
||||
$this->staticMax = true;
|
||||
$this->updateMaxValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,7 +191,6 @@ class LinearUnit implements AxisUnit
|
|||
if ($min !== null) {
|
||||
$this->min = $min;
|
||||
$this->staticMin = true;
|
||||
$this->updateMaxValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,4 +213,14 @@ class LinearUnit implements AxisUnit
|
|||
{
|
||||
return $this->max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of ticks necessary to display this AxisUnit
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTicks()
|
||||
{
|
||||
return $this->nrOfTicks;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Chart\Unit;
|
||||
|
||||
/**
|
||||
* Logarithmic tick distribution over the axis
|
||||
*
|
||||
* This class does not use the actual logarithm, but a slightly altered version called the
|
||||
* Log-Modulo transformation. This is necessary, since a regular logarithmic scale is not able to display negative
|
||||
* values and zero-points. See <a href="http://blogs.sas.com/content/iml/2014/07/14/log-transformation-of-pos-neg>
|
||||
* this article </a> for a more detailed description.
|
||||
*/
|
||||
class LogarithmicUnit implements AxisUnit
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $base;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $currentTick;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $minExp;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $maxExp;
|
||||
|
||||
/**
|
||||
* True when the minimum value is static and isn't affected by the data set
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $staticMin = false;
|
||||
|
||||
/**
|
||||
* True when the maximum value is static and isn't affected by the data set
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $staticMax = false;
|
||||
|
||||
/**
|
||||
* Create and initialize this AxisUnit
|
||||
*
|
||||
* @param int $nrOfTicks The number of ticks to use
|
||||
*/
|
||||
public function __construct($base = 10)
|
||||
{;
|
||||
$this->base = $base;
|
||||
$this->minExp = PHP_INT_MAX;
|
||||
$this->maxExp = ~PHP_INT_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a dataset and calculate the minimum and maximum value for this AxisUnit
|
||||
*
|
||||
* @param array $dataset The dataset to add
|
||||
* @param int $idx The idx (0 for x, 1 for y)
|
||||
*
|
||||
* @return self Fluent interface
|
||||
*/
|
||||
public function addValues(array $dataset, $idx = 0)
|
||||
{
|
||||
$datapoints = array();
|
||||
|
||||
foreach ($dataset['data'] as $points) {
|
||||
$datapoints[] = $points[$idx];
|
||||
}
|
||||
if (empty($datapoints)) {
|
||||
return $this;
|
||||
}
|
||||
sort($datapoints);
|
||||
if (!$this->staticMax) {
|
||||
$this->maxExp = max($this->maxExp, $this->logCeil($datapoints[count($datapoints) - 1]));
|
||||
}
|
||||
if (!$this->staticMin) {
|
||||
$this->minExp = min($this->minExp, $this->logFloor($datapoints[0]));
|
||||
}
|
||||
$this->currentTick = 0;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the absolute value to an axis relative value
|
||||
*
|
||||
* @param int $value The absolute coordinate from the data set
|
||||
* @return float|int The axis relative coordinate (between 0 and 100)
|
||||
*/
|
||||
public function transform($value)
|
||||
{
|
||||
if ($value < $this->pow($this->minExp)) {
|
||||
return 0;
|
||||
} elseif ($value > $this->pow($this->maxExp)) {
|
||||
return 100;
|
||||
} else {
|
||||
return 100 * ($this->log($value) - $this->minExp) / $this->getTicks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the position of the current tick
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->currentTick * (100 / $this->getTicks());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the next tick and tick value
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
++ $this->currentTick;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the label for the current tick
|
||||
*
|
||||
* @return string The label for the current tick
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
$currentBase = $this->currentTick + $this->minExp;
|
||||
if (abs($currentBase) > 4) {
|
||||
return $this->base . 'E' . $currentBase;
|
||||
}
|
||||
return (string) intval($this->pow($currentBase));
|
||||
}
|
||||
|
||||
/**
|
||||
* True when we're at a valid tick (iterator interface)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->currentTick >= 0 && $this->currentTick < $this->getTicks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the current tick and label value
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->currentTick = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a log-modulo transformation
|
||||
*
|
||||
* @param $value The value to transform
|
||||
*
|
||||
* @return double The transformed value
|
||||
*/
|
||||
protected function log($value)
|
||||
{
|
||||
$sign = $value > 0 ? 1 : -1;
|
||||
return $sign * log1p($sign * $value) / log($this->base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the biggest exponent necessary to display the given data point
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
protected function logCeil($value)
|
||||
{
|
||||
return ceil($this->log($value)) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the smallest exponent necessary to display the given data point
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
protected function logFloor($value)
|
||||
{
|
||||
return floor($this->log($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverse function to the log-modulo transformation
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return double
|
||||
*/
|
||||
protected function pow($value)
|
||||
{
|
||||
if ($value == 0) {
|
||||
return 0;
|
||||
}
|
||||
$sign = $value > 0 ? 1 : -1;
|
||||
return $sign * (pow($this->base, $sign * $value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the axis minimum value to a fixed value
|
||||
*
|
||||
* @param int $min The new minimum value
|
||||
*/
|
||||
public function setMin($min)
|
||||
{
|
||||
$this->minExp = $this->logFloor($min);
|
||||
$this->staticMin = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the axis maximum value to a fixed value
|
||||
*
|
||||
* @param int $max The new maximum value
|
||||
*/
|
||||
public function setMax($max)
|
||||
{
|
||||
$this->maxExp = $this->logCeil($max);
|
||||
$this->staticMax = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current minimum value of the axis
|
||||
*
|
||||
* @return int The minimum set for this axis
|
||||
*/
|
||||
public function getMin()
|
||||
{
|
||||
return $this->pow($this->minExp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current maximum value of the axis
|
||||
*
|
||||
* @return int The maximum set for this axis
|
||||
*/
|
||||
public function getMax()
|
||||
{
|
||||
return $this->pow($this->maxExp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of ticks necessary to display this AxisUnit
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTicks()
|
||||
{
|
||||
return $this->maxExp - $this->minExp;
|
||||
}
|
||||
}
|
|
@ -118,4 +118,14 @@ class StaticAxis implements AxisUnit
|
|||
{
|
||||
return reset($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of ticks of this axis
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTicks()
|
||||
{
|
||||
return count($this->items);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@ abstract class Command
|
|||
{
|
||||
protected $app;
|
||||
protected $docs;
|
||||
|
||||
/**
|
||||
* @type Params
|
||||
*/
|
||||
protected $params;
|
||||
protected $screen;
|
||||
protected $isVerbose;
|
||||
|
@ -124,7 +128,7 @@ abstract class Command
|
|||
|
||||
public function fail($msg)
|
||||
{
|
||||
throw new IcingaException('%s', $msg);
|
||||
throw new IcingaException($msg);
|
||||
}
|
||||
|
||||
public function getDefaultActionName()
|
||||
|
|
|
@ -8,6 +8,11 @@ use Icinga\Data\Filter\Filter;
|
|||
|
||||
/**
|
||||
* Interface for filtering a result set
|
||||
*
|
||||
* @deprecated(EL): addFilter and applyFilter do the same in all usages.
|
||||
* addFilter could be replaced w/ getFilter()->add(). We must no require classes implementing this interface to
|
||||
* implement redundant methods over and over again. This interface must be moved to the namespace Icinga\Data\Filter.
|
||||
* It lacks documentation.
|
||||
*/
|
||||
interface Filterable
|
||||
{
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\File;
|
||||
|
||||
use FilterIterator;
|
||||
use Iterator;
|
||||
|
||||
/**
|
||||
* Iterator over files having a specific file extension
|
||||
*
|
||||
* Usage example:
|
||||
* <code>
|
||||
* <?php
|
||||
*
|
||||
* namespace Icinga\Example;
|
||||
*
|
||||
* use RecursiveDirectoryIterator;
|
||||
* use RecursiveIteratorIterator;
|
||||
* use Icinga\File\FileExtensionFilterIterator;
|
||||
*
|
||||
* $markdownFiles = new FileExtensionFilterIterator(
|
||||
* new RecursiveIteratorIterator(
|
||||
* new RecursiveDirectoryIterator(__DIR__),
|
||||
* RecursiveIteratorIterator::SELF_FIRST
|
||||
* ),
|
||||
* 'md'
|
||||
* );
|
||||
* </code>
|
||||
*/
|
||||
class FileExtensionFilterIterator extends FilterIterator
|
||||
{
|
||||
/**
|
||||
* The extension to filter for
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
protected $extension;
|
||||
|
||||
/**
|
||||
* Create a new FileExtensionFilterIterator
|
||||
*
|
||||
* @param Iterator $iterator Apply filter to this iterator
|
||||
* @param string $extension The file extension to filter for. The file extension may not contain the leading dot
|
||||
*/
|
||||
public function __construct(Iterator $iterator, $extension)
|
||||
{
|
||||
$this->extension = '.' . ltrim(strtolower((string) $extension), '.');
|
||||
parent::__construct($iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept files which match the file extension to filter for
|
||||
*
|
||||
* @return bool Whether the current element of the iterator is acceptable
|
||||
* through this filter
|
||||
*/
|
||||
public function accept()
|
||||
{
|
||||
$current = $this->current();
|
||||
/* @var $current \SplFileInfo */
|
||||
if (! $current->isFile()) {
|
||||
return false;
|
||||
}
|
||||
// SplFileInfo::getExtension() is only available since PHP 5 >= 5.3.6
|
||||
$filename = $current->getFilename();
|
||||
$sfx = substr($filename, -strlen($this->extension));
|
||||
return $sfx === false ? false : strtolower($sfx) === $this->extension;
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ class IniWriter extends Zend_Config_Writer_FileAbstract
|
|||
*
|
||||
* @var int
|
||||
*/
|
||||
public static $fileMode = 0664;
|
||||
public static $fileMode = 0660;
|
||||
|
||||
/**
|
||||
* Create a new INI writer
|
||||
|
@ -90,11 +90,9 @@ class IniWriter extends Zend_Config_Writer_FileAbstract
|
|||
|
||||
if ($setMode) {
|
||||
$mode = isset($this->options['filemode']) ? $this->options['filemode'] : static::$fileMode;
|
||||
$old = umask(0); // Make sure that the mode we're going to set doesn't get mangled
|
||||
if (is_int($mode) && false === @chmod($filePath, $mode)) {
|
||||
throw new Zend_Config_Exception(sprintf('Failed to set file mode "%o" on file "%s"', $mode, $filePath));
|
||||
}
|
||||
umask($old);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,7 +232,7 @@ class IniWriter extends Zend_Config_Writer_FileAbstract
|
|||
|
||||
/**
|
||||
* Getter for filename
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFilename()
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}
|
||||
|
||||
namespace Icinga\File;
|
||||
|
||||
use FilterIterator;
|
||||
|
||||
/**
|
||||
* Iterator over non-empty files
|
||||
*
|
||||
* Usage example:
|
||||
* <code>
|
||||
* <?php
|
||||
*
|
||||
* namespace Icinga\Example;
|
||||
*
|
||||
* use RecursiveDirectoryIterator;
|
||||
* use RecursiveIteratorIterator;
|
||||
* use Icinga\File\NonEmptyFilterIterator;
|
||||
*
|
||||
* $nonEmptyFiles = new NonEmptyFileIterator(
|
||||
* new RecursiveIteratorIterator(
|
||||
* new RecursiveDirectoryIterator(__DIR__),
|
||||
* RecursiveIteratorIterator::SELF_FIRST
|
||||
* )
|
||||
* );
|
||||
* </code>
|
||||
*/
|
||||
class NonEmptyFileIterator extends FilterIterator
|
||||
{
|
||||
/**
|
||||
* Accept non-empty files
|
||||
*
|
||||
* @return bool Whether the current element of the iterator is acceptable
|
||||
* through this filter
|
||||
*/
|
||||
public function accept()
|
||||
{
|
||||
$current = $this->current();
|
||||
/** @type $current \SplFileInfo */
|
||||
if (! $current->isFile()
|
||||
|| $current->getSize() === 0
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
namespace Icinga\Protocol\Ldap;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Protocol\Ldap\Exception as LdapException;
|
||||
use Icinga\Application\Platform;
|
||||
use Icinga\Application\Config;
|
||||
|
@ -97,6 +98,9 @@ class Connection
|
|||
protected $namingContexts;
|
||||
protected $discoverySuccess = false;
|
||||
|
||||
protected $lastResult;
|
||||
protected $pageCookie;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
|
@ -238,7 +242,8 @@ class Connection
|
|||
*/
|
||||
public function fetchRow($query, $fields = array())
|
||||
{
|
||||
// TODO: This is ugly, make it better!
|
||||
$query = clone $query;
|
||||
$query->limit(1);
|
||||
$results = $this->fetchAll($query, $fields);
|
||||
return array_shift($results);
|
||||
}
|
||||
|
@ -250,44 +255,56 @@ class Connection
|
|||
*/
|
||||
public function count(Query $query)
|
||||
{
|
||||
$results = $this->runQuery($query, '+');
|
||||
if (! $results) {
|
||||
return 0;
|
||||
$this->connect();
|
||||
$this->bind();
|
||||
|
||||
$count = 0;
|
||||
$results = $this->runQuery($query);
|
||||
while (! empty($results)) {
|
||||
$count += ldap_count_entries($this->ds, $results);
|
||||
$results = $this->runQuery($query);
|
||||
}
|
||||
return ldap_count_entries($this->ds, $results);
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function fetchAll($query, $fields = array())
|
||||
public function fetchAll(Query $query, $fields = array())
|
||||
{
|
||||
$offset = null;
|
||||
$limit = null;
|
||||
$this->connect();
|
||||
$this->bind();
|
||||
|
||||
$offset = $limit = null;
|
||||
if ($query->hasLimit()) {
|
||||
$offset = $query->getOffset();
|
||||
$limit = $query->getLimit();
|
||||
$limit = $query->getLimit();
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$entries = array();
|
||||
$results = $this->runQuery($query, $fields);
|
||||
if (! $results) {
|
||||
return array();
|
||||
}
|
||||
$entry = ldap_first_entry($this->ds, $results);
|
||||
$count = 0;
|
||||
while ($entry) {
|
||||
if (($offset === null || $offset <= $count)
|
||||
&& ($limit === null || ($offset + $limit) >= $count)
|
||||
) {
|
||||
$attrs = ldap_get_attributes($this->ds, $entry);
|
||||
$entries[ldap_get_dn($this->ds, $entry)]
|
||||
= $this->cleanupAttributes($attrs);
|
||||
while (! empty($results)) {
|
||||
$entry = ldap_first_entry($this->ds, $results);
|
||||
while ($entry) {
|
||||
$count++;
|
||||
if (
|
||||
($offset === null || $offset <= $count)
|
||||
&& ($limit === null || $limit > count($entries))
|
||||
) {
|
||||
$entries[ldap_get_dn($this->ds, $entry)] = $this->cleanupAttributes(
|
||||
ldap_get_attributes($this->ds, $entry)
|
||||
);
|
||||
}
|
||||
|
||||
$entry = ldap_next_entry($this->ds, $entry);
|
||||
}
|
||||
$count++;
|
||||
$entry = ldap_next_entry($this->ds, $entry);
|
||||
|
||||
$results = $this->runQuery($query, $fields);
|
||||
}
|
||||
ldap_free_result($results);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
public function cleanupAttributes(& $attrs)
|
||||
protected function cleanupAttributes($attrs)
|
||||
{
|
||||
$clean = (object) array();
|
||||
for ($i = 0; $i < $attrs['count']; $i++) {
|
||||
|
@ -303,26 +320,55 @@ class Connection
|
|||
return $clean;
|
||||
}
|
||||
|
||||
protected function runQuery($query, $fields)
|
||||
protected function runQuery(Query $query, $fields = array())
|
||||
{
|
||||
$this->connect();
|
||||
$this->bind();
|
||||
if ($query instanceof Query) {
|
||||
$fields = $query->listFields();
|
||||
if ($query->getUsePagedResults() && version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||
if ($this->pageCookie === null) {
|
||||
$this->pageCookie = '';
|
||||
} else {
|
||||
try {
|
||||
ldap_control_paged_result_response($this->ds, $this->lastResult, $this->pageCookie);
|
||||
} catch (Exception $e) {
|
||||
$this->pageCookie = '';
|
||||
Logger::debug(
|
||||
'Unable to request paged LDAP results. Does the server allow paged search requests? (%s)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
ldap_free_result($this->lastResult);
|
||||
if (! $this->pageCookie) {
|
||||
$this->pageCookie = $this->lastResult = null;
|
||||
// Abandon the paged search request so that subsequent requests succeed
|
||||
ldap_control_paged_result($this->ds, 0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Does not matter whether we'll use a valid page size here,
|
||||
// as the server applies its hard limit in case its too high
|
||||
ldap_control_paged_result(
|
||||
$this->ds,
|
||||
$query->hasLimit() ? $query->getLimit() : 500,
|
||||
true,
|
||||
$this->pageCookie
|
||||
);
|
||||
} elseif ($this->lastResult !== null) {
|
||||
ldap_free_result($this->lastResult);
|
||||
$this->lastResult = null;
|
||||
return false;
|
||||
}
|
||||
// WARNING:
|
||||
// We do not support pagination right now, and there is no chance to
|
||||
// do so for PHP < 5.4. Warnings about "Sizelimit exceeded" will
|
||||
// therefore not be hidden right now.
|
||||
|
||||
$base = $query->hasBase() ? $query->getBase() : $this->root_dn;
|
||||
$results = @ldap_search(
|
||||
$this->ds,
|
||||
$base,
|
||||
$query->create(),
|
||||
$fields,
|
||||
empty($fields) ? $query->listFields() : $fields,
|
||||
0, // Attributes and values
|
||||
0 // No limit - at least where possible
|
||||
$query->hasLimit() ? $query->getOffset() + $query->getLimit() : 0 // No limit - at least where possible
|
||||
);
|
||||
|
||||
if ($results === false) {
|
||||
if (ldap_errno($this->ds) === self::LDAP_NO_SUCH_OBJECT) {
|
||||
return false;
|
||||
|
@ -336,12 +382,12 @@ class Connection
|
|||
)
|
||||
);
|
||||
}
|
||||
$list = array();
|
||||
if ($query instanceof Query) {
|
||||
foreach ($query->getSortColumns() as $col) {
|
||||
ldap_sort($this->ds, $results, $col[0]);
|
||||
}
|
||||
|
||||
foreach ($query->getSortColumns() as $col) {
|
||||
ldap_sort($this->ds, $results, $col[0]);
|
||||
}
|
||||
|
||||
$this->lastResult = $results;
|
||||
return $results;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ class Query
|
|||
protected $sort_columns = array();
|
||||
protected $count;
|
||||
protected $base;
|
||||
protected $usePagedResults = true;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -61,6 +62,17 @@ class Query
|
|||
return $this->base;
|
||||
}
|
||||
|
||||
public function setUsePagedResults($state = true)
|
||||
{
|
||||
$this->usePagedResults = (bool) $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUsePagedResults()
|
||||
{
|
||||
return $this->usePagedResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count result set, ignoring limits
|
||||
*
|
||||
|
|
|
@ -197,8 +197,8 @@ class User
|
|||
*/
|
||||
public function setPermissions(array $permissions)
|
||||
{
|
||||
natcasesort($permissions);
|
||||
if (! empty($permissions)) {
|
||||
natcasesort($permissions);
|
||||
$this->permissions = array_combine($permissions, $permissions);
|
||||
}
|
||||
return $this;
|
||||
|
|
|
@ -26,7 +26,7 @@ use Icinga\Data\Db\DbConnection;
|
|||
* // Create a INI store
|
||||
* $store = PreferencesStore::create(
|
||||
* new ConfigObject(
|
||||
* 'type' => 'ini',
|
||||
* 'store' => 'ini',
|
||||
* 'config_path' => '/path/to/preferences'
|
||||
* ),
|
||||
* $user // Instance of \Icinga\User
|
||||
|
@ -117,13 +117,7 @@ abstract class PreferencesStore
|
|||
*/
|
||||
public static function create(ConfigObject $config, User $user)
|
||||
{
|
||||
if (($type = $config->type) === null) {
|
||||
throw new ConfigurationError(
|
||||
'Preferences configuration is missing the type directive'
|
||||
);
|
||||
}
|
||||
|
||||
$type = ucfirst(strtolower($type));
|
||||
$type = ucfirst(strtolower($config->get('store', 'ini')));
|
||||
$storeClass = 'Icinga\\User\\Preferences\\Store\\' . $type . 'Store';
|
||||
if (!class_exists($storeClass)) {
|
||||
throw new ConfigurationError(
|
||||
|
|
|
@ -36,4 +36,22 @@ class String
|
|||
{
|
||||
return str_replace(' ', '', ucwords(str_replace($separator, ' ', strtolower($name))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ellipsis when a string is longer than max length
|
||||
*
|
||||
* @param string $string
|
||||
* @param int $maxLength
|
||||
* @param string $ellipsis
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function ellipsis($string, $maxLength, $ellipsis = '...')
|
||||
{
|
||||
if (strlen($string) > $maxLength) {
|
||||
return substr($string, 0, $maxLength - strlen($ellipsis)) . $ellipsis;
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace Icinga\Web\Controller;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Authentication\Manager as AuthManager;
|
||||
use Icinga\Authentication\Manager;
|
||||
use Icinga\Application\Benchmark;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
@ -47,6 +47,11 @@ class ActionController extends Zend_Controller_Action
|
|||
|
||||
private $xhrLayout = 'inline';
|
||||
|
||||
/**
|
||||
* Authentication manager
|
||||
*
|
||||
* @type \Icinga\Authentication\Manager|null
|
||||
*/
|
||||
private $auth;
|
||||
|
||||
protected $params;
|
||||
|
@ -101,6 +106,49 @@ class ActionController extends Zend_Controller_Action
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the authentication manager
|
||||
*
|
||||
* @return Manager
|
||||
*/
|
||||
public function Auth()
|
||||
{
|
||||
if ($this->auth === null) {
|
||||
$this->auth = Manager::getInstance();
|
||||
}
|
||||
return $this->auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current user has the given permission
|
||||
*
|
||||
* @param string $permission Name of the permission
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasPermission($permission)
|
||||
{
|
||||
return $this->Auth()->hasPermission($permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if user lacks the given permission
|
||||
*
|
||||
* @param string $name Permission name
|
||||
* @throws Exception
|
||||
*/
|
||||
public function assertPermission($name)
|
||||
{
|
||||
if (! $this->Auth()->hasPermission($name)) {
|
||||
// TODO: Shall this be an Auth Exception? Or a 404?
|
||||
throw new IcingaException(
|
||||
'Auth error, no permission for "%s"',
|
||||
$name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function Config($file = null)
|
||||
{
|
||||
if ($file === null) {
|
||||
|
@ -110,14 +158,6 @@ class ActionController extends Zend_Controller_Action
|
|||
}
|
||||
}
|
||||
|
||||
public function Auth()
|
||||
{
|
||||
if ($this->auth === null) {
|
||||
$this->auth = AuthManager::getInstance();
|
||||
}
|
||||
return $this->auth;
|
||||
}
|
||||
|
||||
public function Window()
|
||||
{
|
||||
if ($this->window === null) {
|
||||
|
@ -146,6 +186,22 @@ class ActionController extends Zend_Controller_Action
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond with HTTP 405 if the current request's method is not one of the given methods
|
||||
*
|
||||
* @param string $httpMethod Unlimited number of allowed HTTP methods
|
||||
*
|
||||
* @throws \Zend_Controller_Action_Exception If the request method is not one of the given methods
|
||||
*/
|
||||
public function assertHttpMethod($httpMethod)
|
||||
{
|
||||
$httpMethods = array_flip(array_map('strtoupper', func_get_args()));
|
||||
if (! isset($httpMethods[$this->getRequest()->getMethod()])) {
|
||||
$this->getResponse()->setHeader('Allow', implode(', ', array_keys($httpMethods)));
|
||||
throw new \Zend_Controller_Action_Exception($this->translate('Method Not Allowed'), 405);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return restriction information for an eventually authenticated user
|
||||
*
|
||||
|
@ -157,34 +213,6 @@ class ActionController extends Zend_Controller_Action
|
|||
return $this->Auth()->getRestrictions($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user currently authenticated has the given permission
|
||||
*
|
||||
* @param string $name Permission name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasPermission($name)
|
||||
{
|
||||
return $this->Auth()->hasPermission($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception if user lacks the given permission
|
||||
*
|
||||
* @param string $name Permission name
|
||||
* @throws Exception
|
||||
*/
|
||||
public function assertPermission($name)
|
||||
{
|
||||
if (! $this->Auth()->hasPermission($name)) {
|
||||
// TODO: Shall this be an Auth Exception? Or a 404?
|
||||
throw new IcingaException(
|
||||
'Auth error, no permission for "%s"',
|
||||
$name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the controller requires a login. That is when the controller requires authentication and the
|
||||
* user is currently not authenticated
|
||||
|
@ -270,7 +298,7 @@ class ActionController extends Zend_Controller_Action
|
|||
/**
|
||||
* Redirect to the login path
|
||||
*
|
||||
* @param string $afterLogin The action to call when the login was successful. Defaults to '/index/welcome'
|
||||
* @param Url $afterLogin The action to call when the login was successful. Defaults to '/index/welcome'
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
|
|
@ -512,7 +512,7 @@ class Form extends Zend_Form
|
|||
|
||||
$el = parent::createElement($type, $name, $options);
|
||||
|
||||
if (($description = $el->getDescription()) !== null && ($label = $el->getDecorator('label')) !== null) {
|
||||
if (($description = $el->getDescription()) !== null && ($label = $el->getDecorator('label')) !== false) {
|
||||
$label->setOptions(array(
|
||||
'title' => $description,
|
||||
'class' => 'has-feedback'
|
||||
|
@ -805,6 +805,24 @@ class Form extends Zend_Form
|
|||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the translation domain for this form
|
||||
*
|
||||
* The returned translation domain is either determined based on this form's qualified name or it is the default
|
||||
* 'icinga' domain
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTranslationDomain()
|
||||
{
|
||||
$parts = explode('\\', get_called_class());
|
||||
if ($parts[1] === 'Module') {
|
||||
// Assume format Icinga\Module\ModuleName\Forms\...
|
||||
return strtolower($parts[2]);
|
||||
}
|
||||
return 'icinga';
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a string
|
||||
*
|
||||
|
@ -815,7 +833,7 @@ class Form extends Zend_Form
|
|||
*/
|
||||
protected function translate($text, $context = null)
|
||||
{
|
||||
return Translator::translate($text, $this->request->getModuleName(), $context);
|
||||
return Translator::translate($text, $this->getTranslationDomain(), $context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -834,7 +852,7 @@ class Form extends Zend_Form
|
|||
$textSingular,
|
||||
$textPlural,
|
||||
$number,
|
||||
$this->request->getModuleName(),
|
||||
$this->getTranslationDomain(),
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
|
|
@ -43,12 +43,6 @@ class LessCompiler
|
|||
{
|
||||
require_once 'lessphp/lessc.inc.php';
|
||||
$this->lessc = new lessc();
|
||||
|
||||
$this->lessc->setVariables(
|
||||
array(
|
||||
'baseurl' => '\'' . Zend_Controller_Front::getInstance()->getBaseUrl(). '\''
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function compress()
|
||||
|
|
|
@ -248,7 +248,8 @@ class Menu implements RecursiveIterator
|
|||
|
||||
$section->add(t('Logout'), array(
|
||||
'url' => 'authentication/logout',
|
||||
'priority' => 700
|
||||
'priority' => 700,
|
||||
'renderer' => 'ForeignMenuItemRenderer'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -366,7 +367,7 @@ class Menu implements RecursiveIterator
|
|||
/**
|
||||
* Return the url of this menu
|
||||
*
|
||||
* @return string
|
||||
* @return Url
|
||||
*/
|
||||
public function getUrl()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Web\Menu;
|
||||
|
||||
use Icinga\Web\Menu;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
* A menu item with a link that surpasses the regular navigation link behavior
|
||||
*/
|
||||
class ForeignMenuItemRenderer implements MenuItemRenderer {
|
||||
|
||||
public function render(Menu $menu)
|
||||
{
|
||||
return sprintf(
|
||||
'<a href="%s" target="_self">%s%s<span></span></a>',
|
||||
$menu->getUrl() ?: '#',
|
||||
$menu->getIcon() ? '<img src="' . Url::fromPath($menu->getIcon()) . '" class="icon" /> ' : '',
|
||||
htmlspecialchars($menu->getTitle())
|
||||
);
|
||||
}
|
||||
}
|
|
@ -78,8 +78,9 @@ class PhpSession extends Session
|
|||
}
|
||||
}
|
||||
|
||||
if (!is_writable(session_save_path())) {
|
||||
throw new ConfigurationError('Can\'t save session');
|
||||
$sessionSavePath = session_save_path();
|
||||
if (session_module_name() === 'files' && !is_writable($sessionSavePath)) {
|
||||
throw new ConfigurationError("Can't save session, path '$sessionSavePath' is not writable.");
|
||||
}
|
||||
|
||||
if ($this->exists()) {
|
||||
|
|
|
@ -96,6 +96,7 @@ class StyleSheet
|
|||
$cache->send($cacheFile);
|
||||
return;
|
||||
}
|
||||
|
||||
$less = new LessCompiler();
|
||||
foreach ($lessFiles as $file) {
|
||||
$less->addFile($file);
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
|
||||
namespace Icinga\Web;
|
||||
|
||||
use Closure;
|
||||
use Zend_View_Abstract;
|
||||
use Icinga\Authentication\Manager;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Util\Translator;
|
||||
use Zend_View_Abstract;
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* Icinga view
|
||||
|
@ -36,6 +37,13 @@ class View extends Zend_View_Abstract
|
|||
*/
|
||||
private $helperFunctions = array();
|
||||
|
||||
/**
|
||||
* Authentication manager
|
||||
*
|
||||
* @type \Icinga\Authentication\Manager|null
|
||||
*/
|
||||
private $auth;
|
||||
|
||||
/**
|
||||
* Create a new view object
|
||||
*
|
||||
|
@ -154,6 +162,31 @@ class View extends Zend_View_Abstract
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authentication manager
|
||||
*
|
||||
* @return Manager
|
||||
*/
|
||||
public function Auth()
|
||||
{
|
||||
if ($this->auth === null) {
|
||||
$this->auth = Manager::getInstance();
|
||||
}
|
||||
return $this->auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current user has the given permission
|
||||
*
|
||||
* @param string $permission Name of the permission
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasPermission($permission)
|
||||
{
|
||||
return $this->Auth()->hasPermission($permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to include the view script in a scope that only allows public
|
||||
* members.
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
namespace Icinga\Web\View;
|
||||
|
||||
use Icinga\Util\String;
|
||||
|
||||
$this->addHelperFunction('ellipsis', function ($string, $maxLength, $ellipsis = '...') {
|
||||
return String::ellipsis($string, $maxLength, $ellipsis);
|
||||
});
|
|
@ -5,6 +5,7 @@
|
|||
namespace Icinga\Web\Widget\Chart;
|
||||
|
||||
use Icinga\Chart\PieChart;
|
||||
use Icinga\Module\Monitoring\Plugin\PerfdataSet;
|
||||
use Icinga\Web\Widget\AbstractWidget;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Util\Format;
|
||||
|
@ -28,36 +29,23 @@ class InlinePie extends AbstractWidget
|
|||
const NUMBER_FORMAT_RATIO = 'ratio';
|
||||
|
||||
/**
|
||||
* The template string used for rendering this widget
|
||||
* The template string used for rendering this widget
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $template =<<<'EOD'
|
||||
<span
|
||||
class="sparkline"
|
||||
sparkTitle="{title}"
|
||||
sparkWidth="{width}"
|
||||
sparkHeight="{height}"
|
||||
sparkBorderWidth="{borderWidth}"
|
||||
sparkBorderColor="{borderColor}"
|
||||
sparkTooltipChartTitle="{title}"
|
||||
style="{style}"
|
||||
labels="{labels}"
|
||||
formatted="{formatted}"
|
||||
hideEmptyLabel={hideEmptyLabel}
|
||||
values="{data}"
|
||||
tooltipFormat="{tooltipFormat}"
|
||||
sparkSliceColors="[{colors}]"
|
||||
sparkType="pie"></span>
|
||||
<noscript>
|
||||
<img class="inlinepie"
|
||||
title="{title}" src="{url}" style="position: relative; top: 10px; width: {width}px; height: {height}px; {style}"
|
||||
data-icinga-colors="{colors}" data-icinga-values="{data}"
|
||||
/>
|
||||
</noscript>
|
||||
<span sparkType="pie" class="sparkline {class}" {title} {size} sparkSliceColors="[{colors}]" values="{data}">
|
||||
</span>
|
||||
{noscript}
|
||||
EOD;
|
||||
|
||||
private $noscript =<<<'EOD'
|
||||
<noscript>
|
||||
<img class="inlinepie {class}" {title} src="{url}" data-icinga-colors="{colors}" data-icinga-values="{data}"/>
|
||||
</noscript>
|
||||
EOD;
|
||||
|
||||
|
||||
/**
|
||||
* @var Url
|
||||
*/
|
||||
|
@ -68,35 +56,7 @@ EOD;
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
private $colors = array('#44bb77', '#ffaa44', '#ff5566', '#ddccdd');
|
||||
|
||||
/**
|
||||
* The width of the rendered chart
|
||||
*
|
||||
* @var int The value in px
|
||||
*/
|
||||
private $width = 16;
|
||||
|
||||
/**
|
||||
* The height of the rendered chart
|
||||
*
|
||||
* @var int The value in px
|
||||
*/
|
||||
private $height = 16;
|
||||
|
||||
/**
|
||||
* PieChart border width
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
private $borderWidth = 1;
|
||||
|
||||
/**
|
||||
* The color of the border
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $borderColor = '#fff';
|
||||
private $colors = array('#049BAF', '#ffaa44', '#ff5566', '#ddccdd');
|
||||
|
||||
/**
|
||||
* The title of the chart
|
||||
|
@ -106,11 +66,9 @@ EOD;
|
|||
private $title;
|
||||
|
||||
/**
|
||||
* The style for the HtmlElement
|
||||
*
|
||||
* @var string
|
||||
* @var
|
||||
*/
|
||||
private $style = '';
|
||||
private $size;
|
||||
|
||||
/**
|
||||
* The data displayed by the pie-chart
|
||||
|
@ -120,45 +78,9 @@ EOD;
|
|||
private $data;
|
||||
|
||||
/**
|
||||
* The labels to display for each data set
|
||||
*
|
||||
* @var array
|
||||
* @var
|
||||
*/
|
||||
private $labels = array();
|
||||
|
||||
/**
|
||||
* If the tooltip for the "empty" area should be hidden
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $hideEmptyLabel = false;
|
||||
|
||||
/**
|
||||
* The format string used to display tooltips
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $tooltipFormat = '<b>{{title}}</b></br> {{label}}: {{formatted}} ({{percent}}%)';
|
||||
|
||||
/**
|
||||
* The number format used to render numeric values in tooltips
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $format = self::NUMBER_FORMAT_NONE;
|
||||
|
||||
/**
|
||||
* Set if the tooltip for the empty area should be hidden
|
||||
*
|
||||
* @param bool $hide Whether to hide the empty area
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setHideEmptyLabel($hide = true)
|
||||
{
|
||||
$this->hideEmptyLabel = $hide;
|
||||
return $this;
|
||||
}
|
||||
private $class = '';
|
||||
|
||||
/**
|
||||
* Set the data to be displayed.
|
||||
|
@ -175,24 +97,36 @@ EOD;
|
|||
}
|
||||
|
||||
/**
|
||||
* The labels to be displayed in the pie-chart
|
||||
* Set the size of the inline pie
|
||||
*
|
||||
* @param mixed $label The label of the displayed value, or null for no labels
|
||||
* @param int $size Sets both, the height and width
|
||||
*
|
||||
* @return $this
|
||||
* @return $this
|
||||
*/
|
||||
public function setLabel($label)
|
||||
public function setSize($size = null)
|
||||
{
|
||||
if (is_array($label)) {
|
||||
$this->url->setParam('labels', implode(',', array_keys($label)));
|
||||
} elseif ($label != null) {
|
||||
$labelArr = array($label, $label, $label, '');
|
||||
$this->url->setParam('labels', implode(',', $labelArr));
|
||||
$label = $labelArr;
|
||||
} else {
|
||||
$this->url->removeKey('labels');
|
||||
}
|
||||
$this->labels = $label;
|
||||
$this->size = $size;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not display the NoScript fallback html
|
||||
*/
|
||||
public function disableNoScript()
|
||||
{
|
||||
$this->noscript = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class to define the
|
||||
*
|
||||
* @param $class
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSparklineClass($class)
|
||||
{
|
||||
$this->class = $class;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -214,105 +148,6 @@ EOD;
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the used number format
|
||||
*
|
||||
* @param $format string 'bytes' or 'time'
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setNumberFormat($format)
|
||||
{
|
||||
$this->format = $format;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A format string used to render the content of the piechart tooltips
|
||||
*
|
||||
* Placeholders using curly braces '{FOO}' are replace with their specific values. The format
|
||||
* String may contain HTML-Markup. The available replaceable values are:
|
||||
* <ul>
|
||||
* <li><b>label</b>: The description for the current value </li>
|
||||
* <li><b>formatted</b>: A string representing the formatted value </li>
|
||||
* <li><b>value</b>: The raw (non-formatted) value used to render the piechart </li>
|
||||
* <li><b>percent</b>: The percentage of the current value </li>
|
||||
* </ul>
|
||||
* Note: Changes will only affect JavaScript sparklines and not the SVG charts used for fallback
|
||||
*
|
||||
* @param $format
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTooltipFormat($format)
|
||||
{
|
||||
$this->tooltipFormat = $format;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the height
|
||||
*
|
||||
* @param $height
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setHeight($height)
|
||||
{
|
||||
$this->height = $height;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border width of the pie chart
|
||||
*
|
||||
* @param float $width Width in px
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBorderWidth($width)
|
||||
{
|
||||
$this->borderWidth = $width;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the color of the pie chart border
|
||||
*
|
||||
* @param string $col The color string
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBorderColor($col)
|
||||
{
|
||||
$this->borderColor = $col;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width
|
||||
*
|
||||
* @param $width
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setWidth($width)
|
||||
{
|
||||
$this->width = $width;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the styling of the created HtmlElement
|
||||
*
|
||||
* @param string $style
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setStyle($style)
|
||||
{
|
||||
$this->style = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the title of the displayed Data
|
||||
*
|
||||
|
@ -322,7 +157,7 @@ EOD;
|
|||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
$this->title = 'title="' . htmlspecialchars($title) . '"';
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -335,13 +170,10 @@ EOD;
|
|||
*/
|
||||
public function __construct(array $data, $title, $colors = null)
|
||||
{
|
||||
$this->title = $title;
|
||||
$this->setTitle($title);
|
||||
$this->url = Url::fromPath('svg/chart.php');
|
||||
if (array_key_exists('data', $data)) {
|
||||
$this->data = $data['data'];
|
||||
if (array_key_exists('labels', $data)) {
|
||||
$this->labels = $data['labels'];
|
||||
}
|
||||
if (array_key_exists('colors', $data)) {
|
||||
$this->colors = $data['colors'];
|
||||
}
|
||||
|
@ -354,21 +186,6 @@ EOD;
|
|||
$this->setColors($this->colors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a serialization containing the current label array
|
||||
*
|
||||
* @return string A serialized array of labels
|
||||
*/
|
||||
private function createLabelString ()
|
||||
{
|
||||
$labels = $this->labels;
|
||||
foreach ($labels as $key => $label) {
|
||||
$labels[$key] = str_replace('|', '', $label);
|
||||
}
|
||||
return isset($this->labels) && is_array($this->labels) ? implode('|', $this->labels) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders this widget via the given view and returns the
|
||||
* HTML as a string
|
||||
|
@ -382,11 +199,11 @@ EOD;
|
|||
$pie->alignTopLeft();
|
||||
$pie->disableLegend();
|
||||
$pie->drawPie(array(
|
||||
'data' => $this->data, 'colors' => $this->colors, 'labels' => $this->labels
|
||||
'data' => $this->data, 'colors' => $this->colors
|
||||
));
|
||||
|
||||
try {
|
||||
$png = $pie->toPng($this->width, $this->height);
|
||||
$png = $pie->toPng($this->size, $this->size);
|
||||
return '<img class="inlinepie" src="data:image/png;base64,' . base64_encode($png) . '" />';
|
||||
} catch (IcingaException $_) {
|
||||
return '';
|
||||
|
@ -394,17 +211,17 @@ EOD;
|
|||
}
|
||||
|
||||
$template = $this->template;
|
||||
// TODO: Check whether we are XHR and don't send
|
||||
$template = str_replace('{noscript}', $this->noscript, $template);
|
||||
$template = str_replace('{url}', $this->url, $template);
|
||||
$template = str_replace('{class}', $this->class, $template);
|
||||
|
||||
// style
|
||||
$template = str_replace('{width}', $this->width, $template);
|
||||
$template = str_replace('{height}', $this->height, $template);
|
||||
$template = str_replace('{title}', htmlspecialchars($this->title), $template);
|
||||
$template = str_replace('{style}', $this->style, $template);
|
||||
$template = str_replace('{size}',
|
||||
isset($this->size) ? 'sparkWidth="' . $this->size . '" sparkHeight="' . $this->size . '" ' : '', $template);
|
||||
$template = str_replace('{title}', $this->title, $template);
|
||||
|
||||
$template = str_replace('{colors}', implode(',', $this->colors), $template);
|
||||
$template = str_replace('{borderWidth}', $this->borderWidth, $template);
|
||||
$template = str_replace('{borderColor}', $this->borderColor, $template);
|
||||
$template = str_replace('{hideEmptyLabel}', $this->hideEmptyLabel ? 'true' : 'false', $template);
|
||||
|
||||
// Locale-ignorant string cast. Please. Do. NOT. Remove. This. Again.
|
||||
// Problem is that implode respects locales when casting floats. This means
|
||||
|
@ -414,38 +231,7 @@ EOD;
|
|||
$data[] = sprintf('%F', $dat);
|
||||
}
|
||||
|
||||
// values
|
||||
$formatted = array();
|
||||
foreach ($this->data as $key => $value) {
|
||||
$formatted[$key] = $this->formatValue($value);
|
||||
}
|
||||
$template = str_replace('{data}', htmlspecialchars(implode(',', $data)), $template);
|
||||
$template = str_replace('{formatted}', htmlspecialchars(implode('|', $formatted)), $template);
|
||||
$template = str_replace('{labels}', htmlspecialchars($this->createLabelString()), $template);
|
||||
$template = str_replace('{tooltipFormat}', $this->tooltipFormat, $template);
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the given value depending on the current value of numberFormat
|
||||
*
|
||||
* @param float $value The value to format
|
||||
*
|
||||
* @return string The formatted value
|
||||
*/
|
||||
private function formatValue($value)
|
||||
{
|
||||
if ($this->format === self::NUMBER_FORMAT_NONE) {
|
||||
return (string)$value;
|
||||
} elseif ($this->format === self::NUMBER_FORMAT_BYTES) {
|
||||
return Format::bytes($value);
|
||||
} elseif ($this->format === self::NUMBER_FORMAT_TIME) {
|
||||
return Format::duration($value);
|
||||
} elseif ($this->format === self::NUMBER_FORMAT_RATIO) {
|
||||
return $value;
|
||||
} else {
|
||||
Logger::warning('Unknown format string "' . $this->format . '" for InlinePie, value not formatted.');
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,6 +218,25 @@ EOT;
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a tab
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
unset($this->tabs[$name]);
|
||||
if (($dropdownIndex = array_search($name, $this->dropdownTabs)) !== false) {
|
||||
array_splice($this->dropdownTabs, $dropdownIndex, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a tab to the dropdown on the right side of the tab-bar.
|
||||
*
|
||||
|
|
|
@ -39,6 +39,13 @@ class Wizard
|
|||
*/
|
||||
const BTN_PREV = 'btn_prev';
|
||||
|
||||
/**
|
||||
* This wizard's parent
|
||||
*
|
||||
* @var Wizard
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* The name of the wizard's current page
|
||||
*
|
||||
|
@ -71,19 +78,55 @@ class Wizard
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this wizard's parent or null in case it has none
|
||||
*
|
||||
* @return Wizard|null
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this wizard's parent
|
||||
*
|
||||
* @param Wizard $wizard The parent wizard
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setParent(Wizard $wizard)
|
||||
{
|
||||
$this->parent = $wizard;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pages being part of this wizard
|
||||
*
|
||||
* In case this is a nested wizard a flattened array of all contained pages is returned.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPages()
|
||||
{
|
||||
return $this->pages;
|
||||
$pages = array();
|
||||
foreach ($this->pages as $page) {
|
||||
if ($page instanceof self) {
|
||||
$pages = array_merge($pages, $page->getPages());
|
||||
} else {
|
||||
$pages[] = $page;
|
||||
}
|
||||
}
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the page with the given name
|
||||
*
|
||||
* Note that it's also possible to retrieve a nested wizard's page by using this method.
|
||||
*
|
||||
* @param string $name The name of the page to return
|
||||
*
|
||||
* @return null|Form The page or null in case there is no page with the given name
|
||||
|
@ -98,22 +141,31 @@ class Wizard
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a new page to this wizard
|
||||
* Add a new page or wizard to this wizard
|
||||
*
|
||||
* @param Form $page The page to add to the wizard
|
||||
* @param Form|Wizard $page The page or wizard to add to the wizard
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addPage(Form $page)
|
||||
public function addPage($page)
|
||||
{
|
||||
if (! $page instanceof Form && ! $page instanceof self) {
|
||||
throw InvalidArgumentException(
|
||||
'The $page argument must be an instance of Icinga\Web\Form '
|
||||
. 'or Icinga\Web\Wizard but is of type: ' . get_class($page)
|
||||
);
|
||||
} elseif ($page instanceof self) {
|
||||
$page->setParent($this);
|
||||
}
|
||||
|
||||
$this->pages[] = $page;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple pages to this wizard
|
||||
* Add multiple pages or wizards to this wizard
|
||||
*
|
||||
* @param array $pages The pages to add to the wizard
|
||||
* @param array $pages The pages or wizards to add to the wizard
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
|
@ -148,6 +200,10 @@ class Wizard
|
|||
*/
|
||||
public function getCurrentPage()
|
||||
{
|
||||
if ($this->parent) {
|
||||
return $this->parent->getCurrentPage();
|
||||
}
|
||||
|
||||
if ($this->currentPage === null) {
|
||||
$this->assertHasPages();
|
||||
$pages = $this->getPages();
|
||||
|
@ -202,6 +258,10 @@ class Wizard
|
|||
{
|
||||
$page = $this->getCurrentPage();
|
||||
|
||||
if (($wizard = $this->findWizard($page)) !== null) {
|
||||
return $wizard->handleRequest($request);
|
||||
}
|
||||
|
||||
if ($request === null) {
|
||||
$request = $page->getRequest();
|
||||
}
|
||||
|
@ -238,6 +298,39 @@ class Wizard
|
|||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the wizard for the given page or null if its not part of a wizard
|
||||
*
|
||||
* @param Form $page The page to return its wizard for
|
||||
*
|
||||
* @return Wizard|null
|
||||
*/
|
||||
protected function findWizard(Form $page)
|
||||
{
|
||||
foreach ($this->getWizards() as $wizard) {
|
||||
if ($wizard->getPage($page->getName()) === $page) {
|
||||
return $wizard;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this wizard's child wizards
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getWizards()
|
||||
{
|
||||
$wizards = array();
|
||||
foreach ($this->pages as $pageOrWizard) {
|
||||
if ($pageOrWizard instanceof self) {
|
||||
$wizards[] = $pageOrWizard;
|
||||
}
|
||||
}
|
||||
|
||||
return $wizards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the request data based on given form's request method
|
||||
*
|
||||
|
@ -264,6 +357,10 @@ class Wizard
|
|||
*/
|
||||
protected function getRequestedPage(array $requestData)
|
||||
{
|
||||
if ($this->parent) {
|
||||
return $this->parent->getRequestedPage($requestData);
|
||||
}
|
||||
|
||||
if (isset($requestData[static::BTN_NEXT])) {
|
||||
return $requestData[static::BTN_NEXT];
|
||||
} elseif (isset($requestData[static::BTN_PREV])) {
|
||||
|
@ -280,6 +377,10 @@ class Wizard
|
|||
*/
|
||||
protected function getDirection(Request $request = null)
|
||||
{
|
||||
if ($this->parent) {
|
||||
return $this->parent->getDirection($request);
|
||||
}
|
||||
|
||||
$currentPage = $this->getCurrentPage();
|
||||
|
||||
if ($request === null) {
|
||||
|
@ -299,7 +400,7 @@ class Wizard
|
|||
/**
|
||||
* Return the new page to set as current page
|
||||
*
|
||||
* Permission is checked by verifying that the requested page's previous page has page data available.
|
||||
* Permission is checked by verifying that the requested page or its previous page has page data available.
|
||||
* The requested page is automatically permitted without any checks if the origin page is its previous
|
||||
* page or one that occurs later in order.
|
||||
*
|
||||
|
@ -312,11 +413,15 @@ class Wizard
|
|||
*/
|
||||
protected function getNewPage($requestedPage, Form $originPage)
|
||||
{
|
||||
if ($this->parent) {
|
||||
return $this->parent->getNewPage($requestedPage, $originPage);
|
||||
}
|
||||
|
||||
if (($page = $this->getPage($requestedPage)) !== null) {
|
||||
$permitted = true;
|
||||
|
||||
$pages = $this->getPages();
|
||||
if (($index = array_search($page, $pages, true)) > 0) {
|
||||
if (! $this->hasPageData($requestedPage) && ($index = array_search($page, $pages, true)) > 0) {
|
||||
$previousPage = $pages[$index - 1];
|
||||
if ($originPage === null || ($previousPage->getName() !== $originPage->getName()
|
||||
&& array_search($originPage, $pages, true) < $index))
|
||||
|
@ -335,6 +440,36 @@ class Wizard
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next or previous page based on the given one
|
||||
*
|
||||
* @param Form $page The page to skip
|
||||
*
|
||||
* @return Form
|
||||
*/
|
||||
protected function skipPage(Form $page)
|
||||
{
|
||||
if ($this->parent) {
|
||||
return $this->parent->skipPage($page);
|
||||
}
|
||||
|
||||
if ($this->hasPageData($page->getName())) {
|
||||
$pageData = & $this->getPageData();
|
||||
unset($pageData[$page->getName()]);
|
||||
}
|
||||
|
||||
$pages = $this->getPages();
|
||||
if ($this->getDirection() === static::FORWARD) {
|
||||
$nextPage = $pages[array_search($page, $pages, true) + 1];
|
||||
$newPage = $this->getNewPage($nextPage->getName(), $page);
|
||||
} else { // $this->getDirection() === static::BACKWARD
|
||||
$previousPage = $pages[array_search($page, $pages, true) - 1];
|
||||
$newPage = $this->getNewPage($previousPage->getName(), $page);
|
||||
}
|
||||
|
||||
return $newPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given page is this wizard's last page
|
||||
*
|
||||
|
@ -344,10 +479,27 @@ class Wizard
|
|||
*/
|
||||
protected function isLastPage(Form $page)
|
||||
{
|
||||
if ($this->parent) {
|
||||
return $this->parent->isLastPage($page);
|
||||
}
|
||||
|
||||
$pages = $this->getPages();
|
||||
return $page->getName() === end($pages)->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether all of this wizard's pages were visited by the user
|
||||
*
|
||||
* The base implementation just verifies that the very last page has page data available.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isComplete()
|
||||
{
|
||||
$pages = $this->getPages();
|
||||
return $this->hasPageData($pages[count($pages) - 1]->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this wizard has been completed
|
||||
*
|
||||
|
@ -421,6 +573,10 @@ class Wizard
|
|||
*/
|
||||
public function getSession()
|
||||
{
|
||||
if ($this->parent) {
|
||||
return $this->parent->getSession();
|
||||
}
|
||||
|
||||
return Session::getSession()->getNamespace(get_class($this));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,3 +4,4 @@ DESTINATION=.
|
|||
wget -O ${FILENAME}.tar.gz https://github.com/erusev/parsedown/archive/${RELEASE}.tar.gz
|
||||
tar xfz ${FILENAME}.tar.gz -C $DESTINATION/ --strip-components 1 $FILENAME/Parsedown.php $FILENAME/LICENSE.txt
|
||||
chmod 644 $DESTINATION/Parsedown.php
|
||||
mv LICENSE.txt LICENSE
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
curl https://codeload.github.com/dompdf/dompdf/tar.gz/v0.6.1 -o dompdf-0.6.1.tar.gz
|
||||
tar xzf dompdf-0.6.1.tar.gz --strip-components 1 dompdf-0.6.1/{include/*.php,lib,dompdf*.php,LICENSE.LGPL}
|
||||
rm dompdf-0.6.1.tar.gz
|
||||
mv LICENSE.LGPL LICENSE
|
||||
|
||||
curl https://codeload.github.com/PhenX/php-font-lib/tar.gz/0.3.1 -o php-font-lib-0.3.1.tar.gz
|
||||
mkdir lib/php-font-lib/classes
|
||||
|
|
|
@ -8,12 +8,36 @@ use Icinga\Module\Doc\DocController;
|
|||
|
||||
class Doc_IcingawebController extends DocController
|
||||
{
|
||||
/**
|
||||
* Get the path to Icinga Web 2's documentation
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws Zend_Controller_Action_Exception If Icinga Web 2's documentation is not available
|
||||
*/
|
||||
protected function getPath()
|
||||
{
|
||||
$path = Icinga::app()->getBaseDir('doc');
|
||||
if (is_dir($path)) {
|
||||
return $path;
|
||||
}
|
||||
if (($path = $this->Config()->get('documentation', 'icingaweb2')) !== null) {
|
||||
if (is_dir($path)) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
$this->translate('Documentation for Icinga Web 2 is not available'),
|
||||
404
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View the toc of Icinga Web 2's documentation
|
||||
*/
|
||||
public function tocAction()
|
||||
{
|
||||
return $this->renderToc(Icinga::app()->getApplicationDir('/../doc'), 'Icinga Web 2', 'doc/icingaweb/chapter');
|
||||
$this->renderToc($this->getPath(), 'Icinga Web 2', 'doc/icingaweb/chapter');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,12 +50,12 @@ class Doc_IcingawebController extends DocController
|
|||
$chapterId = $this->getParam('chapterId');
|
||||
if ($chapterId === null) {
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
$this->translate('Missing parameter \'chapterId\''),
|
||||
sprintf($this->translate('Missing parameter \'%s\''), 'chapterId'),
|
||||
404
|
||||
);
|
||||
}
|
||||
return $this->renderChapter(
|
||||
Icinga::app()->getApplicationDir('/../doc'),
|
||||
$this->renderChapter(
|
||||
$this->getPath(),
|
||||
$chapterId,
|
||||
'doc/icingaweb/toc',
|
||||
'doc/icingaweb/chapter'
|
||||
|
@ -43,6 +67,6 @@ class Doc_IcingawebController extends DocController
|
|||
*/
|
||||
public function pdfAction()
|
||||
{
|
||||
return $this->renderPdf(Icinga::app()->getApplicationDir('/../doc'), 'Icinga Web 2', 'doc/icingaweb/chapter');
|
||||
$this->renderPdf($this->getPath(), 'Icinga Web 2', 'doc/icingaweb/chapter');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,40 @@ use Icinga\Module\Doc\Exception\DocException;
|
|||
|
||||
class Doc_ModuleController extends DocController
|
||||
{
|
||||
/**
|
||||
* Get the path to a module documentation
|
||||
*
|
||||
* @param string $module The name of the module
|
||||
* @param string $default The default path
|
||||
* @param bool $suppressErrors Whether to not throw an exception if the module documentation is not
|
||||
* available
|
||||
*
|
||||
* @return string|null Path to the documentation or null if the module documentation is not
|
||||
* available and errors are suppressed
|
||||
*
|
||||
* @throws Zend_Controller_Action_Exception If the module documentation is not available and errors are not
|
||||
* suppressed
|
||||
*/
|
||||
protected function getPath($module, $default, $suppressErrors = false)
|
||||
{
|
||||
if (is_dir($default)) {
|
||||
return $default;
|
||||
}
|
||||
if (($path = $this->Config()->get('documentation', 'modules')) !== null) {
|
||||
$path = str_replace('{module}', $module, $path);
|
||||
if (is_dir($path)) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
if ($suppressErrors) {
|
||||
return null;
|
||||
}
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
sprintf($this->translate('Documentation for module \'%s\' is not available'), $module),
|
||||
404
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* List modules which are enabled and having the 'doc' directory
|
||||
*/
|
||||
|
@ -16,10 +50,10 @@ class Doc_ModuleController extends DocController
|
|||
{
|
||||
$moduleManager = Icinga::app()->getModuleManager();
|
||||
$modules = array();
|
||||
foreach (Icinga::app()->getModuleManager()->listEnabledModules() as $enabledModule) {
|
||||
$docDir = $moduleManager->getModuleDir($enabledModule, '/doc');
|
||||
if (is_dir($docDir)) {
|
||||
$modules[] = $enabledModule;
|
||||
foreach (Icinga::app()->getModuleManager()->listEnabledModules() as $module) {
|
||||
$path = $this->getPath($module, $moduleManager->getModuleDir($module, '/doc'), true);
|
||||
if ($path !== null) {
|
||||
$modules[] = $module;
|
||||
}
|
||||
}
|
||||
$this->view->modules = $modules;
|
||||
|
@ -37,7 +71,7 @@ class Doc_ModuleController extends DocController
|
|||
{
|
||||
if (empty($moduleName)) {
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
$this->translate('Missing parameter \'moduleName\''),
|
||||
sprintf($this->translate('Missing parameter \'%s\''), 'moduleName'),
|
||||
404
|
||||
);
|
||||
}
|
||||
|
@ -63,16 +97,15 @@ class Doc_ModuleController extends DocController
|
|||
*/
|
||||
public function tocAction()
|
||||
{
|
||||
$moduleName = $this->getParam('moduleName');
|
||||
$this->assertModuleEnabled($moduleName);
|
||||
$this->view->moduleName = $moduleName;
|
||||
$moduleManager = Icinga::app()->getModuleManager();
|
||||
$module = $this->getParam('moduleName');
|
||||
$this->assertModuleEnabled($module);
|
||||
$this->view->moduleName = $module;
|
||||
try {
|
||||
return $this->renderToc(
|
||||
$moduleManager->getModuleDir($moduleName, '/doc'),
|
||||
$moduleName,
|
||||
$this->renderToc(
|
||||
$this->getPath($module, Icinga::app()->getModuleManager()->getModuleDir($module, '/doc')),
|
||||
$module,
|
||||
'doc/module/chapter',
|
||||
array('moduleName' => $moduleName)
|
||||
array('moduleName' => $module)
|
||||
);
|
||||
} catch (DocException $e) {
|
||||
throw new Zend_Controller_Action_Exception($e->getMessage(), 404);
|
||||
|
@ -88,24 +121,23 @@ class Doc_ModuleController extends DocController
|
|||
*/
|
||||
public function chapterAction()
|
||||
{
|
||||
$moduleName = $this->getParam('moduleName');
|
||||
$this->assertModuleEnabled($moduleName);
|
||||
$module = $this->getParam('moduleName');
|
||||
$this->assertModuleEnabled($module);
|
||||
$chapterId = $this->getParam('chapterId');
|
||||
if ($chapterId === null) {
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
$this->translate('Missing parameter \'chapterId\''),
|
||||
sprintf($this->translate('Missing parameter \'%s\''), 'chapterId'),
|
||||
404
|
||||
);
|
||||
}
|
||||
$this->view->moduleName = $moduleName;
|
||||
$moduleManager = Icinga::app()->getModuleManager();
|
||||
$this->view->moduleName = $module;
|
||||
try {
|
||||
return $this->renderChapter(
|
||||
$moduleManager->getModuleDir($moduleName, '/doc'),
|
||||
$this->renderChapter(
|
||||
$this->getPath($module, Icinga::app()->getModuleManager()->getModuleDir($module, '/doc')),
|
||||
$chapterId,
|
||||
$this->_helper->url->url(array('moduleName' => $moduleName), 'doc/module/toc'),
|
||||
$this->_helper->url->url(array('moduleName' => $module), 'doc/module/toc'),
|
||||
'doc/module/chapter',
|
||||
array('moduleName' => $moduleName)
|
||||
array('moduleName' => $module)
|
||||
);
|
||||
} catch (DocException $e) {
|
||||
throw new Zend_Controller_Action_Exception($e->getMessage(), 404);
|
||||
|
@ -119,14 +151,13 @@ class Doc_ModuleController extends DocController
|
|||
*/
|
||||
public function pdfAction()
|
||||
{
|
||||
$moduleName = $this->getParam('moduleName');
|
||||
$this->assertModuleEnabled($moduleName);
|
||||
$moduleManager = Icinga::app()->getModuleManager();
|
||||
return $this->renderPdf(
|
||||
$moduleManager->getModuleDir($moduleName, '/doc'),
|
||||
$moduleName,
|
||||
$module = $this->getParam('moduleName');
|
||||
$this->assertModuleEnabled($module);
|
||||
$this->renderPdf(
|
||||
$this->getPath($module, Icinga::app()->getModuleManager()->getModuleDir($module, '/doc')),
|
||||
$module,
|
||||
'doc/module/chapter',
|
||||
array('moduleName' => $moduleName)
|
||||
array('moduleName' => $module)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
/* @var $this \Icinga\Application\Modules\Module */
|
||||
/** @type $this \Icinga\Application\Modules\Module */
|
||||
|
||||
$section = $this->menuSection($this->translate('Documentation'), array(
|
||||
'title' => 'Documentation',
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
# <a id="module-documentation"></a> Writing Module Documentation
|
||||
|
||||

|
||||
|
||||
Icinga Web 2 is capable of viewing your module's documentation, if the documentation is written in
|
||||
[Markdown](http://en.wikipedia.org/wiki/Markdown). Please refer to
|
||||
[Markdown Syntax Documentation](http://daringfireball.net/projects/markdown/syntax) for Markdown's formatting syntax.
|
||||
|
||||
## <a id="location"></a> Where to Put Module Documentation?
|
||||
|
||||
By default, your module's Markdown documentation files must be placed in the `doc` directory beneath your module's root
|
||||
directory, e.g.:
|
||||
|
||||
example-module/doc
|
||||
|
||||
## <a id="chapters"></a> Chapters
|
||||
|
||||
Each Markdown documentation file represents a chapter of your module's documentation. The first found heading inside
|
||||
each file is the chapter's title. The order of chapters is based on the case insensitive "Natural Order" of your files'
|
||||
names. <dfn>Natural Order</dfn> means that the file names are ordered in the way which seems natural to humans.
|
||||
It is best practice to prefix Markdown documentation file names with numbers to ensure that they appear in the correct
|
||||
order, e.g.:
|
||||
|
||||
1-about.md
|
||||
2-installation.md
|
||||
3-configuration.md
|
||||
|
||||
## <a id="toc"></a> Table Of Contents
|
||||
|
||||
The table of contents for your module's documentation is auto-generated based on all found headings inside each
|
||||
Markdown documentation file.
|
||||
|
||||
## <a id="linking"></a> Linking Between Headings
|
||||
|
||||
For linking between headings, place an anchor where you want to link to, e.g.:
|
||||
|
||||
# <a id="heading"></a> Heading
|
||||
|
||||
Please note that anchors have to be unique across all your Markdown documentation files.
|
||||
|
||||
Now you can reference the anchor either in the same or **in another** Markdown documentation file, e.g.:
|
||||
|
||||
This is a link to [Heading](#heading).
|
||||
|
||||
Other tools support linking between headings by giving the filename plus the anchor to link to, e.g.:
|
||||
|
||||
This is a link to [About/Heading](1-about.md#heading.md)
|
||||
|
||||
This syntax is also supported in Icinga Web 2.
|
||||
|
||||
## <a id="images"></a> Including Images
|
||||
|
||||
Images must placed in the `img` directory beneath your module's `public` directory, e.g.:
|
||||
|
||||
example-module/public/img/doc
|
||||
|
||||
Module images can be accessed using the following URL:
|
||||
|
||||
{baseURL}/img/{moduleName}/{file} e.g. icingaweb/img/example-module/doc/example.png
|
||||
|
||||
Markdown's image syntax is very similar to Markdown's link syntax, but prefixed with an exclamation mark, e.g.:
|
||||
|
||||

|
||||
|
||||
URLs to images inside your Markdown documentation files must be specified without the base URL, e.g.:
|
||||
|
||||

|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue