Merge branch 'master' into feature/query-interfaces-6018

Conflicts:
	modules/monitoring/library/Monitoring/Backend/Ido/Query/ContactgroupQuery.php
This commit is contained in:
Eric Lippmann 2014-05-06 18:45:12 +02:00
commit d87788b9c1
294 changed files with 7790 additions and 15997 deletions

1
.gitignore vendored
View File

@ -22,6 +22,7 @@ test/php/bin/extcmd_test
# misc test output # misc test output
test/frontend/static/public test/frontend/static/public
test/php/library/Icinga/Protocol/Statusdat/.cache
# Generated API documentation # Generated API documentation
doc/api doc/api

View File

@ -0,0 +1,9 @@
[internal_ldap_authentication]
backend = ldap
resource = internal_ldap
user_class = inetOrgPerson
user_name_attribute = uid
[internal_db_authentication]
backend = db
resource = internal_db

View File

@ -0,0 +1,35 @@
[Incidents]
title = "Current incidents"
[Incidents.Service Problems]
url = "monitoring/list/services"
service_problem = 1
limit = 10
sort = service_severity
[Incidents.Recently Recovered Services]
url = "monitoring/list/services"
sort = "service_last_state_change"
service_state = 0
limit = 10
dir = "desc"
[Incidents.Host Problems]
url = "monitoring/list/hosts"
host_problem = 1
sort = host_severity
[Landing]
title = "Landing page"
[Landing.Hostgroups]
url = "monitoring/chart/hostgroup?height=400&width=500"
[Landing.Servicegroups]
url = "monitoring/chart/servicegroup?height=360&width=450"
[Landing.Unhandled Problem Services]
url = "monitoring/list/services?service_handled=0&service_problem=1"
[Landing.Unhandled Problem Hosts]
url = "monitoring/list/hosts?host_handled=0&host_problem=1"

View File

@ -0,0 +1,25 @@
[Dashboard]
title = "Dashboard"
url = "dashboard"
icon = "img/icons/dashboard.png"
priority = 10
[System]
icon = img/icons/configuration.png
priority = 200
[System.Preferences]
title = "Preferences"
url = "preference"
priority = 200
[System.Configuration]
title = "Configuration"
url = "config"
priority = 300
[Logout]
url = "authentication/logout"
icon = img/icons/logout.png
priority = 300

View File

@ -0,0 +1,19 @@
[localdb]
type = ido
resource = "ido"
[locallive]
disabled = "1"
type = livestatus
resource = livestatus
[localfile]
disabled = "1"
type = statusdat
resource = statusdat
;[localfailsafe]
;enabled=false
;type = combo
;backends = localdb, locallive, localfile

View File

@ -0,0 +1,2 @@
[icinga]
path = "/usr/local/icinga-mysql/var/rw/icinga.cmd"

View File

@ -0,0 +1,100 @@
[Problems]
priority = 20
icon = "img/icons/error.png"
[Problems.Unhandled Hosts]
priority = 40
url = "monitoring/list/hosts?host_problem=1&host_handled=0"
[Problems.Unhandled Services]
priority = 40
url = "monitoring/list/services?service_problem=1&service_handled=0&sort=service_severity"
[Problems.Host Problems]
priority = 50
url = "monitoring/list/hosts?host_problem=1&sort=host_severity"
[Problems.Service Problems]
priority = 50
url = "monitoring/list/services?service_problem=1&sort=service_severity&dir=desc"
[Problems.Current Downtimes]
url = "monitoring/list/downtimes?downtime_is_in_effect=1"
[Overview]
priority = 30
icon = "img/icons/hostgroup.png"
[Overview.Tactical Overview]
title = "Tactical Overview"
url = "monitoring/tactical"
priority = 40
[Overview.Hosts]
title = "Hosts"
url = "monitoring/list/hosts"
priority = 50
[Overview.Services]
title = "Services"
url = "monitoring/list/services"
priority = 50
[Overview.Servicematrix]
title = "Servicematrix"
url = "monitoring/list/servicematrix"
priority = 51
[Overview.Servicegroups]
title = "Servicegroups"
url = "monitoring/list/servicegroups"
priority = 60
[Overview.Hostgroups]
title = "Hostgroups"
url = "monitoring/list/hostgroups"
priority = 60
[Overview.Contactgroups]
title = "Contactgroups"
url = "monitoring/list/contactgroups"
priority = 61
[Overview.Downtimes]
title = "Downtimes"
url = "monitoring/list/downtimes"
priority = 70
[Overview.Comments]
title = "Comments"
url = "monitoring/list/comments"
priority = 70
[History]
icon = "img/icons/history.png"
[History.Critical Events]
title = "Critical Events"
url = "monitoring/list/statehistorysummary"
priority = 50
[History.Notifications]
title = "Notifications"
url = "monitoring/list/notifications"
[History.Events]
title = "All Events"
url = "monitoring/list/eventhistory?raw_timestamp>=-2+days"
[System.Process Info]
title = "Process Info"
url = "monitoring/process/info"
priority = 120
[System.Performance Info]
title = "Performance Info"
url = "monitoring/process/performance"
priority = 130

View File

@ -0,0 +1,34 @@
[internal_db]
type = db
db = mysql
host = localhost
port = 3306
password = icingaweb
username = icingaweb
dbname = icingaweb
[ido]
type = db
db = mysql
host = localhost
port = 3306
password = icinga
username = icinga
dbname = icinga
[statusdat]
type = statusdat
status_file = /usr/local/icinga-mysql/var/status.dat
object_file = /usr/local/icinga-mysql/var/objects.cache
[livestatus]
type = livestatus
socket = /usr/local/icinga-mysql/var/rw/live
[internal_ldap]
type = ldap
hostname = localhost
port = 389
root_dn = "ou=people, dc=icinga, dc=org"
bind_dn = "cn=admin,cn=config"
bind_pw = admin

View File

@ -637,33 +637,30 @@ file { '/etc/icingaweb':
} }
file { '/etc/icingaweb/authentication.ini': file { '/etc/icingaweb/authentication.ini':
replace => 'no', source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/authentication.ini',
source => 'puppet:////vagrant/config/authentication.ini',
owner => 'apache', owner => 'apache',
group => 'apache', group => 'apache',
require => File['/etc/icingaweb'] require => File['/etc/icingaweb']
} }
file { '/etc/icingaweb/config.ini': file { '/etc/icingaweb/config.ini':
replace => 'no', ensure => file,
source => 'puppet:////vagrant/config/config.ini',
owner => 'apache', owner => 'apache',
group => 'apache', group => 'apache',
require => File['/etc/icingaweb']
} }
file { '/etc/icingaweb/menu.ini': file { '/etc/icingaweb/menu.ini':
replace => 'no', source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/menu.ini',
source => 'puppet:////vagrant/config/menu.ini',
owner => 'apache', owner => 'apache',
group => 'apache', group => 'apache',
# replace => false,
} }
file { '/etc/icingaweb/resources.ini': file { '/etc/icingaweb/resources.ini':
replace => 'no', source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/resources.ini',
source => 'puppet:////vagrant/config/resources.ini',
owner => 'apache', owner => 'apache',
group => 'apache', group => 'apache',
replace => false
} }
file { ['/etc/icingaweb/enabledModules', '/etc/icingaweb/modules', '/etc/icingaweb/modules/monitoring']: file { ['/etc/icingaweb/enabledModules', '/etc/icingaweb/modules', '/etc/icingaweb/modules/monitoring']:
@ -672,30 +669,20 @@ file { ['/etc/icingaweb/enabledModules', '/etc/icingaweb/modules', '/etc/icingaw
group => 'apache', group => 'apache',
} }
file { '/etc/icingaweb/enabledModules/monitoring':
ensure => 'link',
target => '/vagrant/modules/monitoring',
owner => 'apache',
group => 'apache',
}
file { '/etc/icingaweb/modules/monitoring/backends.ini': file { '/etc/icingaweb/modules/monitoring/backends.ini':
replace => 'no', source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/modules/monitoring/backends.ini',
source => 'puppet:////vagrant/config/modules/monitoring/backends.ini',
owner => 'apache', owner => 'apache',
group => 'apache', group => 'apache',
} }
file { '/etc/icingaweb/modules/monitoring/instances.ini': file { '/etc/icingaweb/modules/monitoring/instances.ini':
replace => 'no', source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/modules/monitoring/instances.ini',
source => 'puppet:////vagrant/config/modules/monitoring/instances.ini',
owner => 'apache', owner => 'apache',
group => 'apache', group => 'apache',
} }
file { '/etc/icingaweb/modules/monitoring/menu.ini': file { '/etc/icingaweb/modules/monitoring/menu.ini':
replace => 'no', source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/modules/monitoring/menu.ini',
source => 'puppet:////vagrant/config/modules/monitoring/menu.ini',
owner => 'apache', owner => 'apache',
group => 'apache', group => 'apache',
} }
@ -707,8 +694,11 @@ file { '/etc/icingaweb/dashboard':
} }
file { '/etc/icingaweb/dashboard/dashboard.ini': file { '/etc/icingaweb/dashboard/dashboard.ini':
replace => 'no', source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/dashboard/dashboard.ini',
source => 'puppet:////vagrant/config/dashboard/dashboard.ini',
owner => 'apache', owner => 'apache',
group => 'apache', group => 'apache',
} }
pear::package { 'deepend/Mockery':
channel => 'pear.survivethedeepend.com'
}

View File

@ -28,14 +28,23 @@ define pear::package(
$require_ = Class['pear'] $require_ = Class['pear']
} }
if $channel {
exec { "pear discover ${channel}":
command => "sudo pear channel-discover ${channel}",
unless => "pear channel-info ${channel}",
require => $require_,
before => Exec["pear install ${name}"]
}
}
exec { "pear install ${name}": exec { "pear install ${name}":
command => "pear install --alldeps ${channel}", command => "pear install --alldeps ${name}",
creates => "/usr/bin/${name}", unless => "pear list ${name}",
require => $require_ require => $require_
} }
exec { "pear upgrade ${name}": exec { "pear upgrade ${name}":
command => "pear upgrade ${channel}", command => "pear upgrade ${name}",
require => Exec["pear install ${name}"] require => Exec["pear install ${name}"]
} }
} }

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
namespace Icinga\Clicommands; namespace Icinga\Clicommands;
@ -117,3 +118,4 @@ class AutocompleteCommand extends Command
} }
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
namespace Icinga\Clicommands; namespace Icinga\Clicommands;
@ -40,3 +41,4 @@ class HelpCommand extends Command
); );
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
namespace Icinga\Clicommands; namespace Icinga\Clicommands;
@ -211,3 +212,4 @@ class ModuleCommand extends Command
$this->fail("Not implemented yet"); $this->fail("Not implemented yet");
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
namespace Icinga\Clicommands; namespace Icinga\Clicommands;
@ -44,7 +45,7 @@ class WebCommand extends Command
readlink('/proc/self/exe'), readlink('/proc/self/exe'),
$socket, $socket,
$basedir, $basedir,
$basedir . '/index.php' ICINGA_LIBDIR . '/Icinga/Application/webrouter.php'
); );
// TODO: Store webserver log, switch uid, log index.php includes, pid file // TODO: Store webserver log, switch uid, log index.php includes, pid file
@ -80,3 +81,4 @@ class WebCommand extends Command
} }
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -138,3 +139,4 @@ class AuthenticationController extends ActionController
} }
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,5 +1,5 @@
<?php <?php
// @codingStandardsIgnoreStart // @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -31,17 +31,14 @@ use \Icinga\Web\Controller\BaseConfigController;
use \Icinga\Web\Widget\Tab; use \Icinga\Web\Widget\Tab;
use \Icinga\Web\Widget\AlertMessageBox; use \Icinga\Web\Widget\AlertMessageBox;
use \Icinga\Web\Url; use \Icinga\Web\Url;
use \Icinga\Web\Hook\Configuration\ConfigurationTabBuilder;
use \Icinga\User\Message;
use \Icinga\Application\Icinga; use \Icinga\Application\Icinga;
use \Icinga\Application\Config as IcingaConfig; use \Icinga\Application\Config as IcingaConfig;
use \Icinga\Data\ResourceFactory; use \Icinga\Data\ResourceFactory;
use \Icinga\Form\Config\GeneralForm; use \Icinga\Form\Config\GeneralForm;
use \Icinga\Authentication\Manager as AuthenticationManager;
use \Icinga\Form\Config\Authentication\ReorderForm; use \Icinga\Form\Config\Authentication\ReorderForm;
use \Icinga\Form\Config\Authentication\LdapBackendForm; use \Icinga\Form\Config\Authentication\LdapBackendForm;
use \Icinga\Form\Config\Authentication\DbBackendForm; use \Icinga\Form\Config\Authentication\DbBackendForm;
use \Icinga\Form\Config\Resource\EditResourceForm; use \Icinga\Form\Config\ResourceForm;
use \Icinga\Form\Config\LoggingForm; use \Icinga\Form\Config\LoggingForm;
use \Icinga\Form\Config\ConfirmRemovalForm; use \Icinga\Form\Config\ConfirmRemovalForm;
use \Icinga\Config\PreservingIniWriter; use \Icinga\Config\PreservingIniWriter;
@ -207,36 +204,38 @@ class ConfigController extends BaseConfigController
/** /**
* Action for creating a new authentication backend * Action for creating a new authentication backend
*/ */
public function authenticationAction($showOnly = false) public function authenticationAction()
{ {
$config = IcingaConfig::app('authentication', true); $config = IcingaConfig::app('authentication', true);
$this->view->tabs->activate('authentication'); $this->view->tabs->activate('authentication');
$order = array_keys($config->toArray()); $order = array_keys($config->toArray());
$this->view->backends = array();
$this->view->messageBox = new AlertMessageBox(true); $this->view->messageBox = new AlertMessageBox(true);
foreach ($config as $backend=>$backendConfig) { $backends = array();
foreach ($order as $backend) {
$form = new ReorderForm(); $form = new ReorderForm();
$form->setName('form_reorder_backend_' . $backend); $form->setName('form_reorder_backend_' . $backend);
$form->setAuthenticationBackend($backend); $form->setBackendName($backend);
$form->setCurrentOrder($order); $form->setCurrentOrder($order);
$form->setRequest($this->_request); $form->setRequest($this->_request);
if (!$showOnly && $form->isSubmittedAndValid()) { if ($form->isSubmittedAndValid()) {
if ($this->writeAuthenticationFile($form->getReorderedConfig($config))) { if ($this->writeAuthenticationFile($form->getReorderedConfig($config))) {
$this->addSuccessMessage('Authentication Order Updated'); $this->addSuccessMessage('Authentication Order Updated');
$this->redirectNow('config/authentication'); $this->redirectNow('config/authentication');
} }
return; return;
} }
$this->view->backends[] = (object) array( $backends[] = (object) array(
'name' => $backend, 'name' => $backend,
'reorderForm' => $form 'reorderForm' => $form
); );
} }
$this->render('authentication');
$this->view->backends = $backends;
} }
/** /**
@ -398,7 +397,7 @@ class ConfigController extends BaseConfigController
{ {
$this->view->resourceTypes = $this->resourceTypes; $this->view->resourceTypes = $this->resourceTypes;
$resources = IcingaConfig::app('resources', true); $resources = IcingaConfig::app('resources', true);
$form = new EditResourceForm(); $form = new ResourceForm();
$form->setRequest($this->_request); $form->setRequest($this->_request);
if ($form->isSubmittedAndValid()) { if ($form->isSubmittedAndValid()) {
$name = $form->getName(); $name = $form->getName();
@ -430,7 +429,7 @@ class ConfigController extends BaseConfigController
$this->render('resource/modify'); $this->render('resource/modify');
return; return;
} }
$form = new EditResourceForm(); $form = new ResourceForm();
if ($this->_request->isPost() === false) { if ($this->_request->isPost() === false) {
$form->setOldName($name); $form->setOldName($name);
$form->setName($name); $form->setName($name);
@ -558,4 +557,4 @@ class ConfigController extends BaseConfigController
} }
} }
} }
// @codingStandardsIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -1,5 +1,5 @@
<?php <?php
// @codingStandardsIgnoreStart // @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -28,14 +28,16 @@
*/ */
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Web\Controller\ActionController; use \Zend_Config;
use Icinga\Web\Url; use Icinga\Web\Url;
use Icinga\Web\Widget\Dashboard;
use Icinga\Application\Config as IcingaConfig;
use Icinga\Form\Dashboard\AddUrlForm;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\NotReadableError;
use Icinga\Logger\Logger; use Icinga\Logger\Logger;
use Icinga\Config\PreservingIniWriter;
use Icinga\Application\Config as IcingaConfig;
use Icinga\Web\Widget\Dashboard;
use Icinga\Form\Dashboard\AddUrlForm;
use Icinga\Exception\NotReadableError;
use Icinga\Exception\ConfigurationError;
use Icinga\Web\Controller\ActionController;
/** /**
* Handle creation, removal and displaying of dashboards, panes and components * Handle creation, removal and displaying of dashboards, panes and components
@ -88,13 +90,19 @@ class DashboardController extends ActionController
*/ */
public function addurlAction() public function addurlAction()
{ {
$this->getTabs()->add('addurl', array( $this->getTabs()->add(
'addurl',
array(
'title' => 'Add Dashboard URL', 'title' => 'Add Dashboard URL',
'url' => Url::fromRequest() 'url' => Url::fromRequest()
))->activate('addurl'); )
)->activate('addurl');
$form = new AddUrlForm(); $form = new AddUrlForm();
$form->setRequest($this->_request); $form->setRequest($this->getRequest());
$form->setAction(Url::fromRequest()->setParams(array())->getAbsoluteUrl());
$this->view->form = $form; $this->view->form = $form;
if ($form->isSubmittedAndValid()) { if ($form->isSubmittedAndValid()) {
$dashboard = $this->getDashboard(); $dashboard = $this->getDashboard();
$dashboard->setComponentUrl( $dashboard->setComponentUrl(
@ -102,15 +110,12 @@ class DashboardController extends ActionController
$form->getValue('component'), $form->getValue('component'),
ltrim($form->getValue('url'), '/') ltrim($form->getValue('url'), '/')
); );
try {
$dashboard->store(); $configFile = IcingaConfig::app('dashboard/dashboard')->getConfigFile();
$this->redirectNow( if ($this->writeConfiguration(new Zend_Config($dashboard->toArray()), $configFile)) {
Url::fromPath('dashboard', array('pane' => $form->getValue('pane'))) $this->redirectNow(Url::fromPath('dashboard', array('pane' => $form->getValue('pane'))));
); } else {
} catch (ConfigurationError $exc) { $this->render('show-configuration');
$this->_helper->viewRenderer('show_configuration');
$this->view->exceptionMessage = $exc->getMessage();
$this->view->iniConfigurationString = $dashboard->toIni();
} }
} }
} }
@ -141,5 +146,30 @@ class DashboardController extends ActionController
*/ */
$this->view->dashboard = $dashboard; $this->view->dashboard = $dashboard;
} }
/**
* Store the given configuration as INI file
*
* @param Zend_Config $config The configuration to store
* @param string $target The path where to store the configuration
*
* @return bool Whether the configuartion has been successfully stored
*/
protected function writeConfiguration(Zend_Config $config, $target)
{
$writer = new PreservingIniWriter(array('config' => $config, 'filename' => $target));
try {
$writer->write();
} catch (Exception $e) {
Logger::error(new ConfiguationError("Cannot write dashboard to $target", 0, $e));
$this->view->iniConfigurationString = $writer->render();
$this->view->exceptionMessage = $e->getMessage();
$this->view->file = $target;
return false;
}
return true;
}
} }
// @codingStandardsIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -1,5 +1,5 @@
<?php <?php
// @codingStandardsIgnoreStart // @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -67,7 +67,7 @@ class ErrorController extends ActionController
break; break;
default: default:
$this->getResponse()->setHttpResponseCode(500); $this->getResponse()->setHttpResponseCode(500);
$this->view->title = 'Server error'; $this->view->title = 'Server error: ' . $exception->getMessage();
$this->view->message = $exception->getMessage(); $this->view->message = $exception->getMessage();
if ($this->getInvokeArg('displayExceptions') == true) { if ($this->getInvokeArg('displayExceptions') == true) {
$this->view->stackTrace = $exception->getTraceAsString(); $this->view->stackTrace = $exception->getTraceAsString();
@ -77,4 +77,4 @@ class ErrorController extends ActionController
$this->view->request = $error->request; $this->view->request = $error->request;
} }
} }
// @codingStandardsIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -26,7 +27,6 @@
* *
*/ */
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
// @codingStandardsIgnoreStart
use Icinga\Web\Controller\ActionController; use Icinga\Web\Controller\ActionController;
use Icinga\Filter\Filter; use Icinga\Filter\Filter;
@ -117,4 +117,4 @@ class FilterController extends ActionController
} }
} }
} }
// @codingStandardsIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -1,5 +1,5 @@
<?php <?php
// @codingStandardsIgnoreStart // @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -61,4 +61,4 @@ class IndexController extends ActionController
{ {
} }
} }
// @codingStandardsIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -1,5 +1,5 @@
<?php <?php
// @codingStandardsIgnoreStart // @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
@ -43,4 +43,4 @@ class LayoutController extends ActionController
$this->renderScript('parts/topbar.phtml'); $this->renderScript('parts/topbar.phtml');
} }
} }
// @codingStandardsIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -1,5 +1,5 @@
<?php <?php
// @codingStandardsIgnoreStart // @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -66,7 +66,7 @@ class ListController extends Controller
$config_ini = IcingaConfig::app()->toArray(); $config_ini = IcingaConfig::app()->toArray();
if (!in_array('logging', $config_ini) || ( if (!in_array('logging', $config_ini) || (
in_array('type', $config_ini['logging']) && in_array('type', $config_ini['logging']) &&
$config_ini['logging']['type'] === 'stream' && $config_ini['logging']['type'] === 'file' &&
in_array('target', $config_ini['logging']) && in_array('target', $config_ini['logging']) &&
file_exists($config_ini['logging']['target']) file_exists($config_ini['logging']['target'])
) )
@ -79,4 +79,4 @@ class ListController extends Controller
} }
} }
} }
// @codingStandardsIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -1,5 +1,5 @@
<?php <?php
// @codingStandardsIgnoreStart // @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -83,4 +83,4 @@ class PreferenceController extends BasePreferenceController
$this->view->form = $form; $this->view->form = $form;
} }
} }
// @codingStandardsIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -1,10 +1,5 @@
<?php <?php
/** // @codeCoverageIgnoreStart
* Icinga (http://www.icinga.org)
*
* @copyright 2014 Icinga Development Team <info@icinga.org>
* @license http://www.icinga.org/license/gpl2 GPL, version 2
*/
use Icinga\Web\Controller\ActionController; use Icinga\Web\Controller\ActionController;
use Icinga\Application\Icinga; use Icinga\Application\Icinga;
@ -50,3 +45,4 @@ class SearchController extends ActionController
$this->view->tabs = $dashboard->getTabs(); $this->view->tabs = $dashboard->getTabs();
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,5 +1,5 @@
<?php <?php
// @codingStandardsIgnoreStart // @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -185,4 +185,4 @@ class StaticController extends ActionController
$lessCompiler->printStack(); $lessCompiler->printStack();
} }
} }
// @codingStandardsIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -76,3 +77,4 @@ class LoginForm extends Form
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -30,9 +30,10 @@
namespace Icinga\Form\Config\Authentication; namespace Icinga\Form\Config\Authentication;
use \Zend_Config; use \Zend_Config;
use \Icinga\Web\Form\Decorator\HelpText; use \Zend_Form_Element_Checkbox;
use \Icinga\Data\ResourceFactory; use Icinga\Web\Form;
use \Icinga\Web\Form; use Icinga\Data\ResourceFactory;
use Icinga\Web\Form\Decorator\HelpText;
/** /**
* Base form for authentication backend forms * Base form for authentication backend forms
@ -46,21 +47,21 @@ abstract class BaseBackendForm extends Form
* *
* @var string * @var string
*/ */
private $backendName = ''; protected $backendName = '';
/** /**
* The backend configuration as a Zend_Config object * The backend configuration as a Zend_Config object
* *
* @var Zend_Config * @var Zend_Config
*/ */
private $backend; protected $backend;
/** /**
* The resources to use instead of the factory provided ones (use for testing) * The resources to use instead of the factory provided ones (use for testing)
* *
* @var Zend_Config * @var Zend_Config
*/ */
private $resources; protected $resources;
/** /**
* Set the name of the currently displayed backend * Set the name of the currently displayed backend
@ -104,7 +105,6 @@ abstract class BaseBackendForm extends Form
/** /**
* Set an alternative array of resources that should be used instead of the DBFactory resource set * Set an alternative array of resources that should be used instead of the DBFactory resource set
* (used for testing)
* *
* @param array $resources The resources to use for populating the db selection field * @param array $resources The resources to use for populating the db selection field
*/ */
@ -114,7 +114,7 @@ abstract class BaseBackendForm extends Form
} }
/** /**
* Return content of the resources.ini or previously set resources for displaying in the database selection field * Return content of the resources.ini or previously set resources
* *
* @return array * @return array
*/ */
@ -130,13 +130,13 @@ abstract class BaseBackendForm extends Form
/** /**
* Add checkbox at the beginning of the form which allows to skip logic connection validation * Add checkbox at the beginning of the form which allows to skip logic connection validation
*/ */
private function addForceCreationCheckbox() protected function addForceCreationCheckbox()
{ {
$checkbox = new \Zend_Form_Element_Checkbox( $checkbox = new Zend_Form_Element_Checkbox(
array( array(
'name' => 'backend_force_creation', 'name' => 'backend_force_creation',
'label' => 'Force Changes', 'label' => t('Force Changes'),
'helptext' => 'Check this box to enforce changes without connectivity validation', 'helptext' => t('Check this box to enforce changes without connectivity validation'),
'order' => 0 'order' => 0
) )
); );
@ -152,14 +152,14 @@ abstract class BaseBackendForm extends Form
* *
* @param array $data The form input to validate * @param array $data The form input to validate
* *
* @return bool True when validation succeeded, false if not * @return bool Whether validation succeeded or not
*/ */
public function isValid($data) public function isValid($data)
{ {
if (!parent::isValid($data)) { if (!parent::isValid($data)) {
return false; return false;
} }
if ($this->getRequest()->getPost('backend_force_creation')) { if (isset($data['backend_force_creation']) && $data['backend_force_creation']) {
return true; return true;
} }
if (!$this->isValidAuthenticationBackend()) { if (!$this->isValidAuthenticationBackend()) {
@ -183,7 +183,7 @@ abstract class BaseBackendForm extends Form
* An implementation should not throw any exception, but use the add/setErrorMessages method of * An implementation should not throw any exception, but use the add/setErrorMessages method of
* Zend_Form. If the 'backend_force_creation' checkbox is set, this method won't be called. * Zend_Form. If the 'backend_force_creation' checkbox is set, this method won't be called.
* *
* @return bool True when validation succeeded, otherwise false * @return bool Whether validation succeeded or not
*/ */
abstract public function isValidAuthenticationBackend(); abstract public function isValidAuthenticationBackend();
} }

View File

@ -29,8 +29,11 @@
namespace Icinga\Form\Config\Authentication; namespace Icinga\Form\Config\Authentication;
use \Exception;
use \Icinga\Authentication\Backend\DbUserBackend; use \Icinga\Authentication\Backend\DbUserBackend;
use \Zend_Config; use \Zend_Config;
use Icinga\Data\ResourceFactory;
use Icinga\Authentication\UserBackend;
/** /**
* Form class for adding/modifying database authentication backends * Form class for adding/modifying database authentication backends
@ -38,21 +41,23 @@ use \Zend_Config;
class DbBackendForm extends BaseBackendForm class DbBackendForm extends BaseBackendForm
{ {
/** /**
* Return a list of all database resource ready to be used as the multiOptions * Return content of the resources.ini or previously set resources
* attribute in a Zend_Form_Element_Select object
* *
* @return array * @return array
*/ */
private function getDatabaseResources() public function getResources()
{ {
$backends = array(); if ($this->resources === null) {
foreach ($this->getResources() as $resname => $resource) { $res = ResourceFactory::getResourceConfigs('db')->toArray();
if ($resource['type'] !== 'db') {
continue; foreach (array_keys($res) as $key) {
$res[$key] = $key;
} }
$backends[$resname] = $resname;
return $res;
} else {
return $this->resources;
} }
return $backends;
} }
/** /**
@ -64,15 +69,14 @@ class DbBackendForm extends BaseBackendForm
{ {
$this->setName('form_modify_backend'); $this->setName('form_modify_backend');
$name = $this->filterName($this->getBackendName()); $name = $this->filterName($this->getBackendName());
$this->addElement( $this->addElement(
'text', 'text',
'backend_' . $name . '_name', 'backend_' . $name . '_name',
array( array(
'required' => true, 'required' => true,
'allowEmpty' => false, 'allowEmpty' => false,
'label' => 'Backend Name', 'label' => t('Backend Name'),
'helptext' => 'The name of this authentication provider', 'helptext' => t('The name of this authentication provider'),
'value' => $this->getBackendName() 'value' => $this->getBackendName()
) )
); );
@ -81,12 +85,12 @@ class DbBackendForm extends BaseBackendForm
'select', 'select',
'backend_' . $name . '_resource', 'backend_' . $name . '_resource',
array( array(
'label' => 'Database Connection',
'required' => true, 'required' => true,
'allowEmpty' => false, 'allowEmpty' => false,
'helptext' => 'The database connection to use for authenticating with this provider', 'label' => t('Database Connection'),
'helptext' => t('The database connection to use for authenticating with this provider'),
'value' => $this->getBackend()->get('resource'), 'value' => $this->getBackend()->get('resource'),
'multiOptions' => $this->getDatabaseResources() 'multiOptions' => $this->getResources()
) )
); );
@ -112,53 +116,39 @@ class DbBackendForm extends BaseBackendForm
*/ */
public function getConfig() public function getConfig()
{ {
$name = $this->getBackendName(); $prefix = 'backend_' . $this->filterName($this->getBackendName()) . '_';
$prefix = 'backend_' . $this->filterName($name) . '_';
$section = $this->getValue($prefix . 'name'); $section = $this->getValue($prefix . 'name');
$cfg = array( $cfg = array(
'backend' => 'db', 'backend' => 'db',
'target' => 'user',
'resource' => $this->getValue($prefix . 'resource'), 'resource' => $this->getValue($prefix . 'resource'),
); );
return array(
$section => $cfg return array($section => $cfg);
);
} }
/** /**
* Validate the current configuration by creating a backend and requesting the user count * Validate the current configuration by creating a backend and requesting the user count
* *
* @return bool True when the backend is valid, false otherwise * @return bool Whether validation succeeded or not
*
* @see BaseBackendForm::isValidAuthenticationBackend * @see BaseBackendForm::isValidAuthenticationBackend
*/ */
public function isValidAuthenticationBackend() public function isValidAuthenticationBackend()
{ {
// @TODO fix validation of authentication backends (AK #5712)
return true;
try { try {
$name = $this->getBackendName(); $testConnection = ResourceFactory::createResource(ResourceFactory::getResourceConfig(
$dbBackend = new DbUserBackend( $this->getValue('backend_' . $this->filterName($this->getBackendName()) . '_resource')
new Zend_Config( ));
array( $dbUserBackend = new DbUserBackend($testConnection);
'backend' => 'db', if ($dbUserBackend->count() < 1) {
'target' => 'user', $this->addErrorMessage(t("No users found under the specified database backend"));
'resource' => $this->getValue('backend_' . $this->filterName($name) . '_resource'),
)
)
);
$dbBackend->connect();
if ($dbBackend->getUserCount() < 1) {
$this->addErrorMessage("No users found under the specified database backend");
return false; return false;
} }
} catch (\Exception $e) { } catch (Exception $e) {
$this->addErrorMessage("Using the specified backend failed: " . $e->getMessage()); $this->addErrorMessage(sprintf(t('Using the specified backend failed: %s'), $e->getMessage()));
return false;
} catch (\Zend_Db_Statement_Exception $e) {
$this->addErrorMessage("Using the specified backend failed: " . $e->getMessage());
return false; return false;
} }
return true; return true;
} }
} }

View File

@ -30,11 +30,10 @@
namespace Icinga\Form\Config\Authentication; namespace Icinga\Form\Config\Authentication;
use \Exception; use \Exception;
use Icinga\Data\ResourceFactory;
use \Zend_Config; use \Zend_Config;
use \Icinga\Web\Form; use Icinga\Web\Form;
use \Icinga\Authentication\Backend\LdapUserBackend; use Icinga\Data\ResourceFactory;
use \Icinga\Protocol\Ldap\Connection as LdapConnection; use Icinga\Authentication\Backend\LdapUserBackend;
/** /**
* Form for adding or modifying LDAP authentication backends * Form for adding or modifying LDAP authentication backends
@ -42,14 +41,31 @@ use \Icinga\Protocol\Ldap\Connection as LdapConnection;
class LdapBackendForm extends BaseBackendForm class LdapBackendForm extends BaseBackendForm
{ {
/** /**
* Create this form and add all required elements * Return content of the resources.ini or previously set resources
* *
* @param $options Only useful for testing purposes: * @return array
* 'resources' => All available resources. */
public function getResources()
{
if ($this->resources === null) {
$res = ResourceFactory::getResourceConfigs('ldap')->toArray();
foreach (array_keys($res) as $key) {
$res[$key] = $key;
}
return $res;
} else {
return $this->resources;
}
}
/**
* Create this form and add all required elements
* *
* @see Form::create() * @see Form::create()
*/ */
public function create($options = array()) public function create()
{ {
$this->setName('form_modify_backend'); $this->setName('form_modify_backend');
$name = $this->filterName($this->getBackendName()); $name = $this->filterName($this->getBackendName());
@ -57,12 +73,12 @@ class LdapBackendForm extends BaseBackendForm
$this->addElement( $this->addElement(
'text', 'text',
'backend_'.$name.'_name', 'backend_' . $name . '_name',
array( array(
'required' => true, 'required' => true,
'allowEmpty' => false, 'allowEmpty' => false,
'label' => 'Backend Name', 'label' => t('Backend Name'),
'helptext' => 'The name of this authentication backend', 'helptext' => t('The name of this authentication backend'),
'value' => $this->getBackendName() 'value' => $this->getBackendName()
) )
); );
@ -71,13 +87,12 @@ class LdapBackendForm extends BaseBackendForm
'select', 'select',
'backend_' . $name . '_resource', 'backend_' . $name . '_resource',
array( array(
'label' => 'Database Connection',
'required' => true, 'required' => true,
'allowEmpty' => false, 'allowEmpty' => false,
'helptext' => 'The database connection to use for authenticating with this provider', 'label' => t('LDAP Resource'),
'helptext' => t('The resource to use for authenticating with this provider'),
'value' => $this->getBackend()->get('resource'), 'value' => $this->getBackend()->get('resource'),
'multiOptions' => array_key_exists('resources', $options) ? 'multiOptions' => $this->getResources()
$options['resources'] : $this->getLdapResources()
) )
); );
@ -85,10 +100,10 @@ class LdapBackendForm extends BaseBackendForm
'text', 'text',
'backend_' . $name . '_user_class', 'backend_' . $name . '_user_class',
array( array(
'label' => 'LDAP User Object Class', 'required' => true,
'value' => $backend->get('user_class', 'inetOrgPerson'), 'label' => t('LDAP User Object Class'),
'helptext' => 'The object class used for storing users on the ldap server', 'helptext' => t('The object class used for storing users on the ldap server'),
'required' => true 'value' => $backend->get('user_class', 'inetOrgPerson')
) )
); );
@ -96,10 +111,10 @@ class LdapBackendForm extends BaseBackendForm
'text', 'text',
'backend_' . $name . '_user_name_attribute', 'backend_' . $name . '_user_name_attribute',
array( array(
'label' => 'LDAP User Name Attribute', 'required' => true,
'value' => $backend->get('user_name_attribute', 'uid'), 'label' => t('LDAP User Name Attribute'),
'helptext' => 'The attribute name used for storing the user name on the ldap server', 'helptext' => t('The attribute name used for storing the user name on the ldap server'),
'required' => true 'value' => $backend->get('user_name_attribute', 'uid')
) )
); );
@ -125,52 +140,55 @@ class LdapBackendForm extends BaseBackendForm
*/ */
public function getConfig() public function getConfig()
{ {
$name = $this->getBackendName(); $prefix = 'backend_' . $this->filterName($this->getBackendName()) . '_';
$prefix = 'backend_' . $this->filterName($name) . '_';
$section = $this->getValue($prefix . 'name'); $section = $this->getValue($prefix . 'name');
$cfg = array( $cfg = array(
'target' => 'user', 'backend' => 'ldap',
'resource' => $this->getValue($prefix . 'resource'), 'resource' => $this->getValue($prefix . 'resource'),
'user_class' => $this->getValue($prefix . 'user_class'), 'user_class' => $this->getValue($prefix . 'user_class'),
'user_name_attribute' => $this->getValue($prefix . 'user_name_attribute') 'user_name_attribute' => $this->getValue($prefix . 'user_name_attribute')
); );
return array( return array($section => $cfg);
$section => $cfg
);
} }
/** /**
* Validate the current configuration by creating a backend and requesting the user count * Validate the current configuration by creating a backend and requesting the user count
* *
* @return bool True when the backend is valid, false otherwise * @return bool Whether validation succeeded or not
*
* @see BaseBackendForm::isValidAuthenticationBacken * @see BaseBackendForm::isValidAuthenticationBacken
*/ */
public function isValidAuthenticationBackend() public function isValidAuthenticationBackend()
{ {
if (!ResourceFactory::ldapAvailable()) {
/*
* It should be possible to run icingaweb without the php ldap extension, when
* no ldap backends are needed. When the user tries to create an ldap backend
* without ldap installed we need to show him an error.
*/
$this->addErrorMessage(t('Using ldap is not possible, the php extension "ldap" is not installed.'));
return false;
}
try { try {
$cfg = $this->getConfig(); $cfg = $this->getConfig();
$backendName = 'backend_' . $this->filterName($this->getBackendName()) . '_name'; $backendName = 'backend_' . $this->filterName($this->getBackendName()) . '_name';
$backendConfig = new Zend_Config($cfg[$this->getValue($backendName)]); $backendConfig = new Zend_Config($cfg[$this->getValue($backendName)]);
$testConn = new LdapUserBackend($backendConfig); $backend = ResourceFactory::createResource(ResourceFactory::getResourceConfig($backendConfig->resource));
if ($testConn->getUserCount() === 0) { $testConn = new LdapUserBackend(
$backend,
$backendConfig->user_class,
$backendConfig->user_name_attribute
);
if ($testConn->count() === 0) {
throw new Exception('No Users Found On Directory Server'); throw new Exception('No Users Found On Directory Server');
} }
} catch (Exception $exc) { } catch (Exception $exc) {
$this->addErrorMessage( $this->addErrorMessage(
'Connection Validation Failed:' . $exc->getMessage() t('Connection Validation Failed: ' . $exc->getMessage())
); );
return false; return false;
} }
return true; return true;
} }
private function getLdapResources()
{
$res = ResourceFactory::getResourceConfigs('ldap')->toArray();
foreach ($res as $key => $value) {
$res[$key] = $key;
}
return $res;
}
} }

View File

@ -30,12 +30,10 @@
namespace Icinga\Form\Config\Authentication; namespace Icinga\Form\Config\Authentication;
use \Zend_Config; use \Zend_Config;
use \Icinga\Web\Form; use Icinga\Web\Form;
use \Icinga\Web\Url;
/** /**
* Form for modifying the authentication provider order. * Form for modifying the authentication provider order
*
*/ */
class ReorderForm extends Form class ReorderForm extends Form
{ {
@ -44,19 +42,20 @@ class ReorderForm extends Form
* *
* @var string * @var string
*/ */
private $backend = null; protected $backend;
/** /**
* The current ordering of all backends, required to determine possible changes * The current ordering of all backends, required to determine possible changes
* *
* @var array * @var array
*/ */
private $currentOrder = array(); protected $currentOrder = array();
/** /**
* Set an array with the current order of all backends * Set an array with the current order of all backends
* *
* @param array $order An array containing backend names in the order they are defined in the authentication.ini * @param array $order An array containing backend names in the order
* they are defined in the authentication.ini
*/ */
public function setCurrentOrder(array $order) public function setCurrentOrder(array $order)
{ {
@ -68,18 +67,15 @@ class ReorderForm extends Form
* *
* @param string $backend The name of the authentication backend * @param string $backend The name of the authentication backend
*/ */
public function setAuthenticationBackend($backend) public function setBackendName($backend)
{ {
$this->backend = $backend; $this->backend = $backend;
} }
/** /**
* Return the name of the currently set backend as it will appear in the forms * Return the name of the currently set backend as it will appear in the form
* *
* This calls the Zend Filtername function in order to filter specific chars * @return string The name of the backend
*
* @return string The filtered name of the backend
* @see Form::filterName()
*/ */
public function getBackendName() public function getBackendName()
{ {
@ -87,20 +83,16 @@ class ReorderForm extends Form
} }
/** /**
* Create this form. * Create this form
*
* Note: The form action will be set here to the authentication overview
* *
* @see Form::create * @see Form::create
*/ */
public function create() public function create()
{ {
$this->upForm = new Form();
$this->downForm = new Form();
if ($this->moveElementUp($this->backend, $this->currentOrder) !== $this->currentOrder) { if ($this->moveElementUp($this->backend, $this->currentOrder) !== $this->currentOrder) {
$upForm = new Form();
$this->upForm->addElement( $upForm->addElement(
'hidden', 'hidden',
'form_backend_order', 'form_backend_order',
array( array(
@ -108,7 +100,7 @@ class ReorderForm extends Form
'value' => join(',', $this->moveElementUp($this->backend, $this->currentOrder)) 'value' => join(',', $this->moveElementUp($this->backend, $this->currentOrder))
) )
); );
$this->upForm->addElement( $upForm->addElement(
'button', 'button',
'btn_' . $this->getBackendName() . '_reorder_up', 'btn_' . $this->getBackendName() . '_reorder_up',
array( array(
@ -116,13 +108,17 @@ class ReorderForm extends Form
'escape' => false, 'escape' => false,
'value' => 'btn_' . $this->getBackendName() . '_reorder_up', 'value' => 'btn_' . $this->getBackendName() . '_reorder_up',
'name' => 'btn_' . $this->getBackendName() . '_reorder_up', 'name' => 'btn_' . $this->getBackendName() . '_reorder_up',
'label' => $this->getView()->icon('up.png', 'Move up in authentication order'), 'label' => $this->getView()->icon('up.png', t('Move up in authentication order'))
) )
); );
$this->addSubForm($upForm, 'btn_reorder_up');
} }
if ($this->moveElementDown($this->backend, $this->currentOrder) !== $this->currentOrder) { if ($this->moveElementDown($this->backend, $this->currentOrder) !== $this->currentOrder) {
$this->downForm->addElement( $downForm = new Form();
$downForm->addElement(
'hidden', 'hidden',
'form_backend_order', 'form_backend_order',
array( array(
@ -130,7 +126,7 @@ class ReorderForm extends Form
'value' => join(',', $this->moveElementDown($this->backend, $this->currentOrder)) 'value' => join(',', $this->moveElementDown($this->backend, $this->currentOrder))
) )
); );
$this->downForm->addElement( $downForm->addElement(
'button', 'button',
'btn_' . $this->getBackendName() . '_reorder_down', 'btn_' . $this->getBackendName() . '_reorder_down',
array( array(
@ -138,52 +134,49 @@ class ReorderForm extends Form
'escape' => false, 'escape' => false,
'value' => 'btn_' . $this->getBackendName() . '_reorder_down', 'value' => 'btn_' . $this->getBackendName() . '_reorder_down',
'name' => 'btn_' . $this->getBackendName() . '_reorder_down', 'name' => 'btn_' . $this->getBackendName() . '_reorder_down',
'label' => $this->getView()->icon('down.png', 'Move down in authentication order'), 'label' => $this->getView()->icon('down.png', t('Move down in authentication order'))
) )
); );
$this->addSubForm($downForm, 'btn_reorder_down');
} }
$this->setAction(Url::fromPath("config/authentication", array())->getAbsoluteUrl());
} }
/** /**
* Return the result of $this->getValues but flatten the result * Return the flattened result of $this->getValues
*
* The result will be a key=>value array without subarrays
*
* @param bool $supressArrayNotation passed to getValues
* *
* @return array The currently set values * @return array The currently set values
*
* @see Form::getValues() * @see Form::getValues()
*/ */
public function getFlattenedValues($supressArrayNotation = false) protected function getFlattenedValues()
{ {
$values = parent::getValues($supressArrayNotation);
$result = array(); $result = array();
foreach ($values as $key => &$value) { foreach (parent::getValues() as $key => $value) {
if (is_array($value)) { if (is_array($value)) {
$result += $value; $result += $value;
} else { } else {
$result[$key] = $value; $result[$key] = $value;
} }
} }
return $result; return $result;
} }
/** /**
* Determine whether this form is submitted by testing the submit buttons of both subforms * Determine whether this form is submitted by testing the submit buttons of both subforms
* *
* @return bool True when the form is submitted, otherwise false * @return bool Whether the form has been submitted or not
*/ */
public function isSubmitted() public function isSubmitted()
{ {
$checkData = $this->getRequest()->getParams(); $checkData = $this->getRequest()->getParams();
return isset ($checkData['btn_' . $this->getBackendName() . '_reorder_up']) || return isset($checkData['btn_' . $this->getBackendName() . '_reorder_up']) ||
isset ($checkData['btn_' . $this->getBackendName() . '_reorder_down']); isset($checkData['btn_' . $this->getBackendName() . '_reorder_down']);
} }
/** /**
* Return the reordered configuration after a reorder button has been submited * Return the reordered configuration after a reorder button has been submitted
* *
* @param Zend_Config $config The configuration to reorder * @param Zend_Config $config The configuration to reorder
* *
@ -192,18 +185,17 @@ class ReorderForm extends Form
public function getReorderedConfig(Zend_Config $config) public function getReorderedConfig(Zend_Config $config)
{ {
$originalConfig = $config->toArray(); $originalConfig = $config->toArray();
$reordered = array();
$newOrder = $this->getFlattenedValues(); $newOrder = $this->getFlattenedValues();
$order = explode(',', $newOrder['form_backend_order']); $order = explode(',', $newOrder['form_backend_order']);
$reordered = array();
foreach ($order as $key) { foreach ($order as $key) {
if (!isset($originalConfig[$key])) { if (isset($originalConfig[$key])) {
continue;
}
$reordered[$key] = $originalConfig[$key]; $reordered[$key] = $originalConfig[$key];
} }
}
return $reordered; return $reordered;
} }
/** /**
@ -221,23 +213,22 @@ class ReorderForm extends Form
* *
* @return array The modified array * @return array The modified array
*/ */
private static function moveElementUp($key, array $array) protected static function moveElementUp($key, array $array)
{ {
$swap = null; for ($i = 0; $i < count($array) - 1; $i++) {
for ($i=0; $i<count($array)-1; $i++) { if ($array[$i + 1] === $key) {
if ($array[$i+1] !== $key) {
continue;
}
$swap = $array[$i]; $swap = $array[$i];
$array[$i] = $array[$i+1]; $array[$i] = $array[$i + 1];
$array[$i+1] = $swap; $array[$i + 1] = $swap;
return $array; return $array;
} }
}
return $array; return $array;
} }
/** /**
* Static helper for moving an element in an array one slot up, if possible * Static helper for moving an element in an array one slot down, if possible
* *
* Example: * Example:
* *
@ -251,18 +242,17 @@ class ReorderForm extends Form
* *
* @return array The modified array * @return array The modified array
*/ */
private static function moveElementDown($key, array $array) protected static function moveElementDown($key, array $array)
{ {
$swap = null; for ($i = 0; $i < count($array) - 1; $i++) {
for ($i=0; $i<count($array)-1; $i++) { if ($array[$i] === $key) {
if ($array[$i] !== $key) { $swap = $array[$i + 1];
continue; $array[$i + 1] = $array[$i];
}
$swap = $array[$i+1];
$array[$i+1] = $array[$i];
$array[$i] = $swap; $array[$i] = $swap;
return $array; return $array;
} }
}
return $array; return $array;
} }
} }

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -92,3 +93,4 @@ class ConfirmRemovalForm extends Form
); );
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -439,3 +440,4 @@ class GeneralForm extends Form
return $cfg; return $cfg;
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -30,12 +31,9 @@
namespace Icinga\Form\Config; namespace Icinga\Form\Config;
use Zend_Config; use Zend_Config;
use Zend_Form_Element_Text;
use Icinga\Application\Config;
use Icinga\Application\Icinga;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Application\Icinga;
use Icinga\Web\Form\Validator\WritablePathValidator; use Icinga\Web\Form\Validator\WritablePathValidator;
use Icinga\Web\Form\Decorator\ConditionalHidden;
/** /**
* Form class for setting the application wide logging configuration * Form class for setting the application wide logging configuration
@ -43,58 +41,13 @@ use Icinga\Web\Form\Decorator\ConditionalHidden;
class LoggingForm extends Form class LoggingForm extends Form
{ {
/** /**
* Base directory to use instead of the one provided by Icinga::app (used for testing) * Return the default logging directory for type "file"
*
* @var null
*/
private $baseDir = null;
/**
* Set a different base directory to use for default paths instead of the one provided by Icinga::app()
*
* @param string $dir The new directory to use
*/
public function setBaseDir($dir)
{
$this->baseDir = $dir;
}
/**
* Return the applications base directory or the value from a previous setBaseDir call
*
* This is used to determine the default logging paths in a manner that allows to set a different path
* during testing
* *
* @return string * @return string
*/ */
public function getBaseDir() protected function getDefaultLogDir()
{ {
if ($this->baseDir) { return realpath(Icinga::app()->getApplicationDir() . '/../var/log/icingaweb.log');
return $this->baseDir;
}
return realpath(Icinga::app()->getApplicationDir() . '/../');
}
/**
* Return true if the debug log path textfield should be displayed
*
* This is the case if the "logging_use_debug" field is autosubmitted
* and true or if it is not submitted, but the configuration for debug
* logging is set to true
*
* @param Zend_Config $config The debug section of the config.ini
*
* @return bool Whether to display the debug path field or not
*/
private function shouldDisplayDebugLog(Zend_Config $config)
{
$debugParam = $this->getRequest()->getParam('logging_debug_enable', null);
if ($debugParam !== null) {
return intval($debugParam) === 1;
} else {
return intval($config->get('enable', 0)) === 1;
}
} }
/** /**
@ -107,80 +60,95 @@ class LoggingForm extends Form
$this->setName('form_config_logging'); $this->setName('form_config_logging');
$config = $this->getConfiguration(); $config = $this->getConfiguration();
$logging = $config->logging; if (($loggingConfig = $config->logging) === null) {
$loggingConfig = new Zend_Config(array());
if ($logging === null) {
$logging = new Zend_Config(array());
} }
$debug = $logging->debug;
if ($debug === null) {
$debug = new Zend_Config(array());
}
$txtLogPath = new Zend_Form_Element_Text(
array(
'name' => 'logging_app_target',
'label' => 'Application Log Path',
'helptext' => 'The logfile to write the icingaweb debug logs to.'
. 'The webserver must be able to write at this location',
'required' => true,
'value' => $logging->get('target', $this->getBaseDir() . '/var/log/icingaweb.log')
)
);
$txtLogPath->addValidator(new WritablePathValidator());
$this->addElement($txtLogPath);
$this->addElement( $this->addElement(
'checkbox', 'checkbox',
'logging_app_verbose', 'logging_enable',
array( array(
'label' => 'Verbose Logging',
'required' => true, 'required' => true,
'helptext' => 'Check to write more verbose output to the icinga log file', 'label' => t('Logging Enabled'),
'value' => intval($logging->get('verbose', 0)) === 1 'helptext' => t('Check this to enable logging.'),
'value' => $loggingConfig->enable ? 1 : 0
) )
); );
$this->addElement( $this->addElement(
'checkbox', 'select',
'logging_debug_enable', 'logging_level',
array( array(
'label' => 'Use Debug Log',
'required' => true, 'required' => true,
'helptext' => 'Check to write a seperate debug log (Warning: This file can grow very big)', 'label' => t('Logging Level'),
'value' => $this->shouldDisplayDebugLog($debug) 'helptext' => t('The maximum loglevel to emit.'),
'value' => intval($loggingConfig->get('level', 0)),
'multiOptions' => array(
0 => t('Error'),
1 => t('Warning'),
2 => t('Information'),
3 => t('Debug')
)
) )
); );
$textLoggingDebugPath = new Zend_Form_Element_Text(
array(
'name' => 'logging_debug_target',
'label' => 'Debug Log Path',
'required' => $this->shouldDisplayDebugLog($debug),
'condition' => $this->shouldDisplayDebugLog($debug),
'value' => $debug->get('target', $this->getBaseDir() . '/var/log/icingaweb2.debug.log'),
'helptext' => 'Set the path to the debug log'
)
);
$textLoggingDebugPath->addValidator(new WritablePathValidator());
$decorator = new ConditionalHidden();
$this->addElement($textLoggingDebugPath);
$textLoggingDebugPath->addDecorator($decorator);
$this->enableAutoSubmit(array('logging_debug_enable'));
$this->addElement( $this->addElement(
'button', 'select',
'btn_submit', 'logging_type',
array( array(
'type' => 'submit', 'required' => true,
'escape' => false, 'label' => t('Logging Type'),
'value' => '1', 'helptext' => t('The type of logging to utilize.'),
'class' => 'btn btn-cta btn-common', 'value' => $loggingConfig->get('type', 'file'),
'label' => '<i class="icinga-icon-save"></i> Save Changes' 'multiOptions' => array(
'file' => t('File'),
'syslog' => 'Syslog'
)
) )
); );
$this->enableAutoSubmit(array('logging_type'));
switch ($this->getRequest()->getParam('logging_type', $loggingConfig->get('type', 'file')))
{
case 'syslog':
$this->addElement(
'text',
'logging_application',
array(
'required' => true,
'label' => t('Application Prefix'),
'helptext' => t('The name of the application by which to prefix syslog messages.'),
'value' => $loggingConfig->get('application', 'icingaweb')
)
);
$this->addElement(
'select',
'logging_facility',
array(
'required' => true,
'label' => t('Facility'),
'helptext' => t('The Syslog facility to utilize.'),
'value' => $loggingConfig->get('facility', 'LOG_USER'),
'multiOptions' => array(
'LOG_USER' => 'LOG_USER'
)
)
);
break;
case 'file':
default:
$this->addElement(
'text',
'logging_target',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('The logfile to write messages to.'),
'value' => $loggingConfig->target ? $loggingConfig->target : $this->getDefaultLogDir(),
'validators' => array(new WritablePathValidator())
)
);
}
$this->setSubmitLabel('{{SAVE_ICON}} Save Changes');
} }
/** /**
@ -190,25 +158,26 @@ class LoggingForm extends Form
*/ */
public function getConfig() public function getConfig()
{ {
$config = $this->getConfiguration();
if ($config->logging === null) {
$config->logging = new Zend_Config(array(), true);
}
if ($config->logging->debug === null) {
$config->logging->debug = new Zend_Config(array(), true);
}
$values = $this->getValues(); $values = $this->getValues();
$cfg = $config->toArray(); $cfg = $this->getConfiguration()->toArray();
$cfg['logging']['enable'] = 1; $cfg['logging']['enable'] = $values['logging_enable'] == 1;
$cfg['logging']['type'] = 'stream'; $cfg['logging']['level'] = $values['logging_level'];
$cfg['logging']['verbose'] = $values['logging_app_verbose'];
$cfg['logging']['target'] = $values['logging_app_target']; switch ($values['logging_type'])
{
case 'file':
$cfg['logging']['type'] = 'file';
$cfg['logging']['target'] = $values['logging_target'];
break;
case 'syslog':
$cfg['logging']['type'] = 'syslog';
$cfg['logging']['application'] = $values['logging_application'];
$cfg['logging']['facility'] = $values['logging_facility'];
break;
}
$cfg['logging']['debug']['enable'] = intval($values['logging_debug_enable']);
$cfg['logging']['debug']['type'] = 'stream';
$cfg['logging']['debug']['target'] = $values['logging_debug_target'];
return new Zend_Config($cfg); return new Zend_Config($cfg);
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,13 +0,0 @@
<?php
namespace Icinga\Module\Monitoring\Form\Config\Backend;
use Icinga\Module\Monitoring\Form\Config\Backend\EditResourceForm;
class CreateResourceForm extends EditResourceForm
{
public function __construct()
{
}
}

View File

@ -1,462 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2013 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 2013 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>
*
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config\Resource;
use \Zend_Config;
use Icinga\Web\Form;
use Icinga\Logger\Logger;
use Icinga\Web\Form\Decorator\HelpText;
use Icinga\Data\ResourceFactory;
/**
* Form for modifying a monitoring backend
*/
class EditResourceForm extends Form
{
/**
* The currently edited resource.
*
* @var Zend_Config
*/
private $resource;
/**
* @var string
*/
private $name = '';
/**
* @var string
*/
private $oldName = '';
/**
* Return the current resource name.
*
* @param string $name
*
* @return void|\Zend_Form
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return null|string
*/
public function getName()
{
return $this->getValue('resource_all_name');
}
/**
* Set the original name of the resource. This value is persisted using
* a hidden field.
*
* @param $name
*/
public function setOldName($name)
{
$this->oldName = $name;
}
/**
* Get the resource name that was initially set.
*/
public function getOldName()
{
return $this->getValue('resource_all_name_old');
}
private function addDbForm()
{
$this->addElement(
'select',
'resource_db_db',
array(
'label' => 'Database Type',
'value' => $this->getResource()->get('db', 'mysql'),
'required' => true,
'helptext' => 'The type of SQL database you want to create.',
'multiOptions' => array(
'mysql' => 'MySQL',
'pgsql' => 'PostgreSQL'
//'oracle' => 'Oracle'
)
)
);
$this->addElement(
'text',
'resource_db_host',
array (
'label' => 'Host',
'value' => $this->getResource()->get('host', 'localhost'),
'required' => true,
'helptext' => 'The hostname of the database.'
)
);
$this->addElement(
'text',
'resource_db_port',
array(
'label' => 'Port',
'value' => $this->getResource()->get('port', 3306),
'required' => true,
'validators' => array(
array('regex', false, '/^[0-9]+$/')
),
'helptext' => 'The port number to use.'
)
);
$this->addElement(
'text',
'resource_db_dbname',
array(
'label' => 'Database Name',
'value' => $this->getResource()->get('dbname', ''),
'required' => true,
'helptext' => 'The name of the database to use'
)
);
$this->addElement(
'text',
'resource_db_username',
array (
'label' => 'Username',
'value' => $this->getResource()->get('username', ''),
'required' => true,
'helptext' => 'The user name to use for authentication.'
)
);
$this->addElement(
'password',
'resource_db_password',
array(
'label' => 'Password',
'renderPassword' => true,
'value' => $this->getResource()->get('password', ''),
'helptext' => 'The password to use for authentication',
'required' => true
)
);
}
private function addStatusdatForm()
{
$this->addElement(
'text',
'resource_statusdat_status_file',
array(
'label' => 'Status.dat File',
'value' => $this->getResource()->get('status_file', '/usr/local/icinga/var/status.dat'),
'required' => true,
'helptext' => 'Location of your icinga status.dat file'
)
);
$this->addElement(
'text',
'resource_statusdat_object_file',
array(
'label' => 'Objects.cache File',
'value' => $this->getResource()->get('status_file', '/usr/local/icinga/var/objects.cache'),
'required' => true,
'helptext' => 'Location of your icinga objects.cache file'
)
);
}
private function addLivestatusForm()
{
$this->addElement(
'text',
'resource_livestatus_socket',
array(
'label' => 'Livestatus Socket Location',
'required' => true,
'helptext' => 'The path to your livestatus socket used for querying monitoring data',
'value' => $this->getResource()->socket,
)
);
}
private function addLdapForm()
{
$this->addElement(
'text',
'resource_ldap_hostname',
array(
'label' => 'LDAP Server Host',
'allowEmpty' => false,
'value' => $this->getResource()->get('hostname', 'localhost'),
'helptext' => 'The hostname or address of the LDAP server to use for authentication',
'required' => true
)
);
$this->addElement(
'text',
'resource_ldap_root_dn',
array(
'label' => 'LDAP Root DN',
'value' => $this->getResource()->get('root_dn', 'ou=people,dc=icinga,dc=org'),
'helptext' => 'The path where users can be found on the ldap server',
'required' => true
)
);
$this->addElement(
'text',
'resource_ldap_bind_dn',
array(
'label' => 'LDAP Bind DN',
'value' => $this->getResource()->get('bind_dn', 'cn=admin,cn=config'),
'helptext' => 'The user dn to use for querying the ldap server',
'required' => true
)
);
$this->addElement(
'password',
'resource_ldap_bind_pw',
array(
'label' => 'LDAP Bind Password',
'renderPassword' => true,
'value' => $this->getResource()->get('bind_pw', ''),
'helptext' => 'The password to use for querying the ldap server',
'required' => true
)
);
}
/**
* Set the resource configuration to edit.
*
* @param Zend_Config $resource
*/
public function setResource(Zend_Config $resource)
{
$this->resource = $resource;
}
/**
* Get the current resource configuration.
*
* @return Zend_Config
*/
public function getResource()
{
if (!isset($this->resource)) {
// Init empty resource
$this->resource = new Zend_Config(
array('type' => 'db')
);
}
return $this->resource;
}
/**
* Add a field to change the resource name and one hidden field
* to save the previous resource name.
*/
private function addNameFields()
{
$this->addElement(
'text',
'resource_all_name',
array(
'label' => 'Resource Name',
'value' => $this->name,
'helptext' => 'The unique name of this resource',
'required' => true
)
);
$this->addElement(
'hidden',
'resource_all_name_old',
array(
'value' => $this->oldName
)
);
}
/**
* Add checkbox at the beginning of the form which allows to skip logic connection validation
*/
private function addForceCreationCheckbox()
{
$checkbox = new \Zend_Form_Element_Checkbox(
array(
'name' => 'backend_force_creation',
'label' => 'Force Changes',
'helptext' => 'Check this box to enforce changes without connectivity validation',
'order' => 0
)
);
$checkbox->addDecorator(new HelpText());
$this->addElement($checkbox);
}
/**
* Add a select box for choosing the type to use for this backend
*/
private function addTypeSelectionBox()
{
$this->addElement(
'select',
'resource_type',
array(
'label' => 'Resource Type',
'value' => $this->getResource()->type,
'required' => true,
'helptext' => 'The type of resource.',
'multiOptions' => array(
'db' => 'SQL Database',
'ldap' => 'Ldap',
'statusdat' => 'Status.dat',
'livestatus' => 'Livestatus'
)
)
);
$this->enableAutoSubmit(array('resource_type'));
}
/**
* Validate this form with the Zend validation mechanism and perform a validation of the connection.
*
* If validation fails, the 'backend_force_creation' checkbox is prepended to the form to allow users to
* skip the logic connection validation.
*
* @param array $data The form input to validate
*
* @return bool True when validation succeeded, false if not
*/
public function isValid($data)
{
if (!parent::isValid($data)) {
return false;
}
if ($this->getRequest()->getPost('backend_force_creation')) {
return true;
}
if (!$this->isValidResource()) {
$this->addForceCreationCheckbox();
return false;
}
return true;
}
/**
* Test if the changed resource is a valid resource, by instantiating it and
* checking if connection is possible.
*
* @return bool True when connection to the resource is possible.
*/
private function isValidResource()
{
try {
$config = $this->getConfig();
switch ($config->type) {
case 'db':
$resource = ResourceFactory::createResource($config);
$resource->getConnection()->getConnection();
break;
case 'statusdat':
if (!file_exists($config->object_file) || !file_exists($config->status_file)) {
$this->addErrorMessage(
'Connectivity validation failed, the provided file or socket does not exist.'
);
return false;
}
break;
case 'livestatus':
// TODO: Implement check
break;
case 'ldap':
$resource = ResourceFactory::createResource($config);
$resource->connect();
break;
}
} catch (\Exception $exc) {
$this->addErrorMessage('Connectivity validation failed, connection to the given resource not possible.');
return false;
}
return true;
}
public function create()
{
$this->addNameFields();
$this->addTypeSelectionBox();
switch ($this->getRequest()->getParam('resource_type', $this->getResource()->type)) {
case 'db':
$this->addDbForm();
break;
case 'statusdat':
$this->addStatusdatForm();
break;
case 'livestatus':
$this->addLivestatusForm();
break;
case 'ldap':
$this->addLdapForm();
break;
}
$this->setSubmitLabel('{{SAVE_ICON}} Save Changes');
}
/**
* Return a configuration containing the backend settings entered in this form
*
* @return Zend_Config The updated configuration for this backend
*/
public function getConfig()
{
$values = $this->getValues();
$type = $values['resource_type'];
$result = array('type' => $type);
foreach ($values as $key => $value) {
if ($key !== 'resource_type' && $key !== 'resource_all_name' && $key !== 'resource_all_name_old') {
$configKey = explode('_', $key, 3);
if (sizeof($configKey) < 3) {
Logger::warning('EditResourceForm: invalid form key "' . $key . '" was ignored.');
continue;
}
$result[$configKey[2]] = $value;
}
}
return new Zend_Config($result);
}
}

View File

@ -0,0 +1,531 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2013 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 2013 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>
*
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config;
use Exception;
use Zend_Config;
use Zend_Form_Element_Checkbox;
use Icinga\Web\Form;
use Icinga\Data\ResourceFactory;
use Icinga\Web\Form\Element\Number;
use Icinga\Web\Form\Decorator\HelpText;
class ResourceForm extends Form
{
/**
* The resource
*
* @var Zend_Config
*/
protected $resource;
/**
* The (new) name of the resource
*
* @var string
*/
protected $name;
/**
* The old name of the resource
*
* @var string
*/
protected $oldName;
/**
* Set the current resource name
*
* @param string $name The name to set
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get the current resource name
*
* @return null|string
*/
public function getName()
{
$name = $this->getValue('resource_all_name');
if (!$name) {
return $this->name;
}
return $name;
}
/**
* Set the original name of the resource
*
* @param string $name The name to set
*/
public function setOldName($name)
{
$this->oldName = $name;
}
/**
* Get the resource name that was initially set
*
* @return null|string
*/
public function getOldName()
{
$oldName = $this->getValue('resource_all_name_old');
if (!$oldName) {
return $this->oldName;
}
return $oldName;
}
/**
* Set the resource configuration to edit.
*
* @param Zend_Config $resource The config to set
*/
public function setResource(Zend_Config $resource)
{
$this->resource = $resource;
}
/**
* Get the current resource configuration.
*
* @return Zend_Config
*/
public function getResource()
{
if (!isset($this->resource)) {
$this->resource = new Zend_Config(array('type' => 'db'));
}
return $this->resource;
}
protected function addDbForm()
{
$this->addElement(
'select',
'resource_db_db',
array(
'required' => true,
'label' => t('Database Type'),
'helptext' => t('The type of SQL database you want to create.'),
'value' => $this->getResource()->get('db', 'mysql'),
'multiOptions' => array(
'mysql' => 'MySQL',
'pgsql' => 'PostgreSQL'
//'oracle' => 'Oracle'
)
)
);
$this->addElement(
'text',
'resource_db_host',
array (
'required' => true,
'label' => t('Host'),
'helptext' => t('The hostname of the database.'),
'value' => $this->getResource()->get('host', 'localhost')
)
);
$this->addElement(
new Number(
array(
'name' => 'resource_db_port',
'required' => true,
'label' => t('Port'),
'helptext' => t('The port to use.'),
'value' => $this->getResource()->get('port', 3306)
)
)
);
$this->addElement(
'text',
'resource_db_dbname',
array(
'required' => true,
'label' => t('Database Name'),
'helptext' => t('The name of the database to use'),
'value' => $this->getResource()->get('dbname', '')
)
);
$this->addElement(
'text',
'resource_db_username',
array (
'required' => true,
'label' => t('Username'),
'helptext' => t('The user name to use for authentication.'),
'value' => $this->getResource()->get('username', '')
)
);
$this->addElement(
'password',
'resource_db_password',
array(
'required' => true,
'renderPassword' => true,
'label' => t('Password'),
'helptext' => t('The password to use for authentication'),
'value' => $this->getResource()->get('password', '')
)
);
}
protected function addStatusdatForm()
{
$this->addElement(
'text',
'resource_statusdat_status_file',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('Location of your icinga status.dat file'),
'value' => $this->getResource()->get('status_file', '/usr/local/icinga/var/status.dat')
)
);
$this->addElement(
'text',
'resource_statusdat_object_file',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('Location of your icinga objects.cache file'),
'value' => $this->getResource()->get('status_file', '/usr/local/icinga/var/objects.cache')
)
);
}
protected function addLivestatusForm()
{
$this->addElement(
'text',
'resource_livestatus_socket',
array(
'required' => true,
'label' => t('Socket'),
'helptext' => t('The path to your livestatus socket used for querying monitoring data'),
'value' => $this->getResource()->get('socket', '/usr/local/icinga/var/rw/livestatus')
)
);
}
protected function addLdapForm()
{
$this->addElement(
'text',
'resource_ldap_hostname',
array(
'required' => true,
'allowEmpty' => false,
'label' => t('Host'),
'helptext' => t('The hostname or address of the LDAP server to use for authentication'),
'value' => $this->getResource()->get('hostname', 'localhost')
)
);
$this->addElement(
'text',
'resource_ldap_root_dn',
array(
'required' => true,
'label' => t('Root DN'),
'helptext' => t('The path where users can be found on the ldap server'),
'value' => $this->getResource()->get('root_dn', 'ou=people,dc=icinga,dc=org')
)
);
$this->addElement(
'text',
'resource_ldap_bind_dn',
array(
'required' => true,
'label' => t('Bind DN'),
'helptext' => t('The user dn to use for querying the ldap server'),
'value' => $this->getResource()->get('bind_dn', 'cn=admin,cn=config')
)
);
$this->addElement(
'password',
'resource_ldap_bind_pw',
array(
'required' => true,
'renderPassword' => true,
'label' => t('Bind Password'),
'helptext' => t('The password to use for querying the ldap server'),
'value' => $this->getResource()->get('bind_pw', '')
)
);
}
protected function addFileForm()
{
$this->addElement(
'text',
'resource_file_filename',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('The filename to fetch information from'),
'value' => $this->getResource()->get('filename', '')
)
);
$this->addElement(
'text',
'resource_file_fields',
array(
'required' => true,
'label' => t('Pattern'),
'helptext' => t('The regular expression by which to identify columns'),
'value' => $this->getResource()->get('fields', '')
)
);
}
protected function addNameFields()
{
$this->addElement(
'text',
'resource_all_name',
array(
'required' => true,
'label' => t('Resource Name'),
'helptext' => t('The unique name of this resource'),
'value' => $this->getName()
)
);
$this->addElement(
'hidden',
'resource_all_name_old',
array(
'value' => $this->getOldName()
)
);
}
/**
* Add checkbox at the beginning of the form which allows to skip connection validation
*/
protected function addForceCreationCheckbox()
{
$checkbox = new Zend_Form_Element_Checkbox(
array(
'order' => 0,
'name' => 'resource_force_creation',
'label' => t('Force Changes'),
'helptext' => t('Check this box to enforce changes without connectivity validation')
)
);
$checkbox->addDecorator(new HelpText());
$this->addElement($checkbox);
}
/**
* Add a select box for choosing the type to use for this backend
*/
protected function addTypeSelectionBox()
{
$this->addElement(
'select',
'resource_type',
array(
'required' => true,
'label' => t('Resource Type'),
'helptext' => t('The type of resource'),
'value' => $this->getResource()->type,
'multiOptions' => array(
'db' => t('SQL Database'),
'ldap' => 'LDAP',
'statusdat' => 'Status.dat',
'livestatus' => 'Livestatus',
'file' => t('File')
)
)
);
$this->enableAutoSubmit(array('resource_type'));
}
/**
* Validate this form with the Zend validation mechanism and perform a validation of the connection
*
* If validation fails, the 'resource_force_creation' checkbox is prepended to the form to allow users to
* skip the connection validation
*
* @param array $data The form input to validate
*
* @return bool True when validation succeeded, false if not
*/
public function isValid($data)
{
if (!parent::isValid($data)) {
return false;
}
if (isset($data['resource_force_creation']) && $data['resource_force_creation']) {
return true;
}
if (!$this->isValidResource()) {
$this->addForceCreationCheckbox();
return false;
}
return true;
}
/**
* Test if the changed resource is a valid resource, by instantiating it and
* checking if a connection is possible
*
* @return bool True when a connection to the resource is possible
*/
public function isValidResource()
{
$config = $this->getConfig();
try {
switch ($config->type) {
case 'db':
/*
* It should be possible to run icingaweb without the pgsql or mysql extension or Zend-Pdo-Classes,
* in case they aren't actually used. When the user tries to create a resource that depends on an
* uninstalled extension, an error should be displayed.
*/
if ($config->db === 'mysql' && !ResourceFactory::mysqlAvailable()) {
$this->addErrorMessage(
t('You need to install the php extension "mysql" and the ' .
'Zend_Pdo_Mysql classes to use MySQL database resources.')
);
return false;
}
if ($config->db === 'pgsql' && !ResourceFactory::pgsqlAvailable()) {
$this->addErrorMessage(
t('You need to install the php extension "pgsql" and the ' .
'Zend_Pdo_Pgsql classes to use PostgreSQL database resources.')
);
return false;
}
$resource = ResourceFactory::createResource($config);
$resource->getConnection()->getConnection();
break;
case 'statusdat':
if (!file_exists($config->object_file) || !file_exists($config->status_file)) {
$this->addErrorMessage(
t('Connectivity validation failed, the provided file does not exist.')
);
return false;
}
break;
case 'livestatus':
$resource = ResourceFactory::createResource($config);
$resource->connect()->disconnect();
break;
case 'ldap':
$resource = ResourceFactory::createResource($config);
$resource->connect();
break;
case 'file':
if (!file_exists($config->filename)) {
$this->addErrorMessage(
t('Connectivity validation failed, the provided file does not exist.')
);
return false;
}
break;
}
} catch (Exception $e) {
$this->addErrorMessage(t('Connectivity validation failed, connection to the given resource not possible.'));
return false;
}
return true;
}
public function create()
{
$this->addNameFields();
$this->addTypeSelectionBox();
switch ($this->getRequest()->getParam('resource_type', $this->getResource()->type)) {
case 'db':
$this->addDbForm();
break;
case 'statusdat':
$this->addStatusdatForm();
break;
case 'livestatus':
$this->addLivestatusForm();
break;
case 'ldap':
$this->addLdapForm();
break;
case 'file':
$this->addFileForm();
break;
}
$this->setSubmitLabel('{{SAVE_ICON}} Save Changes');
}
/**
* Return a configuration containing the backend settings entered in this form
*
* @return Zend_Config The updated configuration for this backend
*/
public function getConfig()
{
$values = $this->getValues();
$result = array('type' => $values['resource_type']);
foreach ($values as $key => $value) {
if ($key !== 'resource_type' && $key !== 'resource_all_name' && $key !== 'resource_all_name_old') {
$configKey = explode('_', $key, 3);
if (count($configKey) === 3) {
$result[$configKey[2]] = $value;
}
}
}
return new Zend_Config($result);
}
}

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -29,7 +30,7 @@
namespace Icinga\Form\Dashboard; namespace Icinga\Form\Dashboard;
use \Icinga\Application\Config as IcingaConfig; use Icinga\Application\Config as IcingaConfig;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Web\Widget\Dashboard; use Icinga\Web\Widget\Dashboard;
use Zend_Form_Element_Text; use Zend_Form_Element_Text;
@ -39,11 +40,9 @@ use Zend_Form_Element_Select;
/** /**
* Form to add an url a dashboard pane * Form to add an url a dashboard pane
*
*/ */
class AddUrlForm extends Form class AddUrlForm extends Form
{ {
/** /**
* Add a selection box for different panes to the form * Add a selection box for different panes to the form
* *
@ -51,7 +50,6 @@ class AddUrlForm extends Form
*/ */
private function addPaneSelectionBox(Dashboard $dashboard) private function addPaneSelectionBox(Dashboard $dashboard)
{ {
$selectPane = new Zend_Form_Element_Select( $selectPane = new Zend_Form_Element_Select(
'pane', 'pane',
array( array(
@ -84,7 +82,6 @@ class AddUrlForm extends Form
/** /**
* Add a textfield for creating a new pane to this form * Add a textfield for creating a new pane to this form
*
*/ */
private function addNewPaneTextField($showExistingButton = true) private function addNewPaneTextField($showExistingButton = true)
{ {
@ -130,7 +127,6 @@ class AddUrlForm extends Form
/** /**
* Add elements to this form (used by extending classes) * Add elements to this form (used by extending classes)
*
*/ */
protected function create() protected function create()
{ {
@ -143,7 +139,7 @@ class AddUrlForm extends Form
array( array(
'label' => 'Url', 'label' => 'Url',
'required' => true, 'required' => true,
'value' => $this->getRequest()->getParam('url', null) 'value' => htmlspecialchars_decode($this->getRequest()->getParam('url', ''))
) )
); );
$elems = $dashboard->getPaneKeyTitleArray(); $elems = $dashboard->getPaneKeyTitleArray();
@ -167,6 +163,6 @@ class AddUrlForm extends Form
) )
); );
$this->setSubmitLabel("Add To Dashboard"); $this->setSubmitLabel("Add To Dashboard");
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -285,3 +286,4 @@ class GeneralForm extends Form
); );
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,34 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2013 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 2013 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>
*
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form;
class TestForm
{
}

View File

@ -1,6 +1,4 @@
<?php <?php
// @codingStandardsIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -29,10 +27,10 @@
*/ */
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
use \Icinga\Application\Icinga; use Icinga\Application\Icinga;
use \Icinga\Application\Config; use Icinga\Application\Config;
use \Icinga\Util\DateTimeFactory; use Icinga\Util\DateTimeFactory;
use \Icinga\Web\Form\Validator\DateTimeValidator; use Icinga\Web\Form\Validator\DateTimeValidator;
/** /**
* Helper to format date and time. Utilizes DateTimeFactory to ensure time zone awareness * Helper to format date and time. Utilizes DateTimeFactory to ensure time zone awareness
@ -46,7 +44,7 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
* *
* @var Zend_Controller_Request_Abstract * @var Zend_Controller_Request_Abstract
*/ */
private $request; protected $request;
/** /**
* Constructor * Constructor
@ -79,6 +77,7 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
* *
* @param int $timestamp * @param int $timestamp
* @param string $format * @param string $format
*
* @return string * @return string
*/ */
public function format($timestamp, $format) public function format($timestamp, $format)
@ -89,6 +88,7 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
} else { } else {
return $timestamp; return $timestamp;
} }
return $dt->format($format); return $dt->format($format);
} }
@ -96,6 +96,7 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
* Format date according to user's format * Format date according to user's format
* *
* @param int $timestamp A unix timestamp * @param int $timestamp A unix timestamp
*
* @return string The formatted date string * @return string The formatted date string
*/ */
public function formatDate($timestamp) public function formatDate($timestamp)
@ -107,6 +108,7 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
* Format time according to user's format * Format time according to user's format
* *
* @param int $timestamp A unix timestamp * @param int $timestamp A unix timestamp
*
* @return string The formatted time string * @return string The formatted time string
*/ */
public function formatTime($timestamp) public function formatTime($timestamp)
@ -133,7 +135,8 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
public function getDateFormat() public function getDateFormat()
{ {
return $this->request->getUser()->getPreferences()->get( return $this->request->getUser()->getPreferences()->get(
'app.dateFormat', Config::app()->global !== null ? Config::app()->global->get('dateFormat', 'd/m/Y') : 'd/m/Y' 'app.dateFormat',
Config::app()->global !== null ? Config::app()->global->get('dateFormat', 'd/m/Y') : 'd/m/Y'
); );
} }
@ -145,7 +148,8 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
public function getTimeFormat() public function getTimeFormat()
{ {
return $this->request->getUser()->getPreferences()->get( return $this->request->getUser()->getPreferences()->get(
'app.timeFormat', Config::app()->global !== null ? Config::app()->global->get('timeFormat', 'g:i A') : 'g:i A' 'app.timeFormat',
Config::app()->global !== null ? Config::app()->global->get('timeFormat', 'g:i A') : 'g:i A'
); );
} }
@ -159,5 +163,3 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
return $this->getDateFormat() . ' ' . $this->getTimeFormat(); return $this->getDateFormat() . ' ' . $this->getTimeFormat();
} }
} }
// @codingStandardsIgnoreStop

View File

@ -1,6 +1,5 @@
<?php <?php
// @codingStandardsIgnoreStart // @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -95,5 +94,4 @@ class Zend_View_Helper_FormDateTime extends Zend_View_Helper_FormElement
return $xhtml; return $xhtml;
} }
} }
// @codeCoverageIgnoreEnd
// @codingStandardsIgnoreStop

View File

@ -1,6 +1,5 @@
<?php <?php
// @codingStandardsIgnoreStart // @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -55,5 +54,4 @@ class Zend_View_Helper_FormNumber extends \Zend_View_Helper_FormText
. $this->getClosingBracket(); . $this->getClosingBracket();
} }
} }
// @codeCoverageIgnoreEnd
// @codingStandardsIgnoreStop

View File

@ -1,6 +1,5 @@
<?php <?php
// @codingStandardsIgnoreStart // @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -48,17 +47,20 @@ class Zend_View_Helper_FormTriStateCheckbox extends Zend_View_Helper_FormElement
public function formTriStateCheckbox($name, $value = null, $attribs = null) public function formTriStateCheckbox($name, $value = null, $attribs = null)
{ {
$class = ""; $class = "";
$xhtml = '<div data-icinga-component="app/triStateCheckbox" class="form-group">' $xhtml = '<div class="tristate">'
. '<div>' . ($value == 1 ? '{{ICON_ENABLED}}' : ($value === 'unchanged' ? '{{ICON_MIXED}}' : '{{ICON_DISABLED}}' )) . '</div>' . '<div>' . ($value == 1 ? ' ' : ($value === 'unchanged' ? ' ' : ' ' )) . '</div>'
. '<input class="' . $class . '" type="radio" value=1 name="' . '<input class="' . $class . '" type="radio" value=1 name="'
. $name . '" ' . ($value == 1 ? 'checked' : '') . ' ">On</input> ' . $name . '" ' . ($value == 1 ? 'checked' : '') . ' ">On</input> '
. '<input class="' . $class . '" type="radio" value=0 name="' . '<input class="' . $class . '" type="radio" value=0 name="'
. $name . '" ' . ($value == 0 ? 'checked' : '') . ' ">Off</input> '; . $name . '" ' . ($value == 0 ? 'checked' : '') . ' ">Off</input> ';
if ($value === 'unchanged') { if ($value === 'unchanged') {
$xhtml = $xhtml . '<input class="' . $class . '" type="radio" value="unchanged" name="' $xhtml = $xhtml . '<input class="' . $class . '" type="radio" value="unchanged" name="'
. $name . '" ' . 'checked "> Mixed </input>'; . $name . '" ' . 'checked "> Undefined </input>';
}; };
return $xhtml . '</div>'; return $xhtml . '</div>';
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -3,4 +3,4 @@
use Icinga\Application\Cli; use Icinga\Application\Cli;
require_once dirname(__DIR__) . '/library/Icinga/Application/Cli.php'; require_once dirname(__DIR__) . '/library/Icinga/Application/Cli.php';
Cli::start('@icingaweb_config_path@')->dispatch(); Cli::start()->dispatch();

View File

@ -16,7 +16,7 @@ timeFormat = "g:i A"
authenticationMode = "internal" authenticationMode = "internal"
[logging] [logging]
;enable = false enable = true
; Writing to a Stream ; Writing to a Stream
type = "stream" type = "stream"
; Write data to the following file ; Write data to the following file

View File

@ -50,6 +50,6 @@ bind_pw = @ldap_bindpass@
[logfile] [logfile]
type = file type = file
filename = "/vagrant/var/log/icingaweb.log" filename = "@icingaweb_log_path@/icingaweb.log"
fields = "/^(?<datetime>[0-9]{4}(-[0-9]{2}){2}T[0-9]{2}(:[0-9]{2}){2}(\\+[0-9]{2}:[0-9]{2})?) (?<loglevel>[A-Za-z]+)( \([0-9]+\))?: (?<message>.*)$/" fields = "/^(?<datetime>[0-9]{4}(-[0-9]{2}){2}T[0-9]{2}(:[0-9]{2}){2}(\\+[0-9]{2}:[0-9]{2})?) - (?<loglevel>[A-Za-z]+) - (?<message>.*)$/"
; format: PCRE ; format: PCRE

View File

@ -1,78 +0,0 @@
# Frontend component tests
Frontend tests test your code from the users perspective: By opening a specific url, executing a few clicks, strokes, etc.
and expecting something to happen. We use [CasperJS](http://casperjs.org/) for frontend testing, which is basically a
headless Webkit browser.
**NOTE**: The 1.1.0DEV version does *NOT* work at this time as the api changed. Use the stable 1.0.3 branch instead.
In order to be able to run the frontend tests, you need a running instance of icingaweb. You should make sure that you
don't need this instance after running the tests, as they could change preferences or configuration
## Writing tests
### Test bootstrap - icingawebtest.js module
The icingawebtest.js module is required for proper testing, as this module eases casperjs usage. After importing the
module with:
var icingawebtest = require('./icingawebtest');
You only need two methods for testing:
* *getTestEnv()*: This method returns a modified casperjs test environment. The difference to then normal casperjs object
is that all methods which take a URL are overloaded so you can add a relative URL if you want to (and
normally you don't want to hardcode your test URLs)
Example:
var casper = icingawebtest.getTestEnv();
* performLogin(): This calls the login page of your icingaweb instance and tries to login with the supplied credentials
icinga.performLogin();
Login is performed with the credentials from the CASPERJS_USER/CASPERJS_PASS environment (this can be set with the
./runtest --user %user% --pass %pass% arguments). The host, server and port are also represented as
CASPERJS_HOST, CASPERJS_PORT and CASPERJS_PATH environment settings. The default in runtest resembles the version that
works best in the vagrant development environment:
* The default user is 'jdoe'
* The default password is 'password'
* The host and port are localhost:80
* The default path is icinga2-web
### Writing the test code
Most tests will require you to login with the supplied credentials, this can be performed with a simple call
icinga.performLogin();
You can then start the test by calling casper.thenOpen with the page you want to work
casper.thenOpen("/mysite", function() {
// perform tests
});
### Testing
Afterwards, everything is like a normal CasperJS test, so you can wrap your assertions in a casper.then method:
// assert a specific title
casper.then(function() {
this.test.assertTitle("Just an empty page");
});
Note that asynchronous calls reuqire you to wait or provide a callback until the resource is loaded:
// waitForSelector calls callbackFn as soon as the selector returns a non-empty set
casper.waitForSelector("div#icinga-main a", callbackFn);
At the end of your test, you have to provide
casper.run(function() {
this.test.done();
});
Otherwise the tests won't be executed.

View File

@ -1,88 +0,0 @@
# Writing JavaScipt tests
JavaScript tests are executed using [mocha](http://visionmedia.github.io/mocha/) as a test framework and
[should.js](https://github.com/visionmedia/should.js/) as the assertion framework.
## Mocking require.js
As we use require.js for asynchronous dependency resolution in JavaScript, this can lead to problems in our node.js
environment. In order to avoid requirejs calls to cause issues, it has been mocked in the testlib/asyncmock.js class
and should be required in every testcase:
var rjsmock = require("requiremock.js");
rjsmock now makes dependency management comfortable and provides the following most important methods:
// remove all registered dependencies from the rjsmock cache
rjsmock.purgeDependencies();
// register the following objects underneath the following requirejs paths:
rjsmock.registerDependencies({
'icinga/container' : {
updateContainer : function() {},
createPopupContainer: function() {}
}
});
// in your js code a require(['icinga/container], function(container) {}) would now have the above mock
// object in the container variable
requireNew("icinga/util/async.js"); // requires icinga/util/async.js file - and ignores the requirejs cache
var async = rjsmock.getDefine(); // returns the last define, this way you can retrieve a specific javacript file
## Faking async responses
As we currently use the icinga/util/async.js class for all asynchronous requests, it's easy to fake responses. The asyncmock.js
class provides functions for this. To use it in your test, you first have to require it:
var asyncMock = require("asyncmock.js");
You now can use asyncMock.setNextAsyncResult((async) asyncManager, (string) resultString, (bool) fails, (object) headers) to
let the next request of the passed asyncManager object return resultString as the response, with the headers provided as the
last parameter. If fails = true, the error callback of the request will be called.
## Example test
The following example describes a complete test, (which tests whether the registerHeaderListener method in the async class works) :
var should = require("should"); // require should.js for assertions
var rjsmock = require("requiremock.js"); // use the requiremock described above
var asyncMock = require("asyncmock.js"); // Helper class to fake async requests
GLOBAL.document = $('body'); // needed when our test accesses window.document
describe('The async module', function() { // start the test scenario
it("Allows to react on specific headers", function(done) { // Start a test case - when done is called it is finished
rjsmock.purgeDependencies(); // Remove any dependency previously declared
rjsmock.registerDependencies({ // Mock icinga/container, as this is a dependency for the following include
'icinga/container' : {
updateContainer : function() {},
createPopupContainer: function() {}
}
});
requireNew("icinga/util/async.js"); // This is the file we want to test, load it and all of it's dependencies
var async = rjsmock.getDefine(); // Retrieve a reference to the loaded file
// Use asyncMock.setNextAsyncResult to let the next async request return 'result' without failing and set
// the response headers 'X-Dont-Care' and 'X-Test-Header'
asyncMock.setNextAsyncResult(async, "result", false, {
'X-Dont-Care' : 'Ignore-me',
'X-Test-Header' : 'Testme123'
});
// register a listener for results with the X-Test-Header response
async.registerHeaderListener("X-Test-Header", function(value, header) {
// test for the correct header
should.equal("Testme123", value);
// call done to mark this test as succeeded
done();
},this);
// run the faked request
var test = async.createRequest();
});
});

View File

@ -4,7 +4,7 @@
The path where you should put your PHPUnit tests should reflect the path in the sourcetree, with test/php/ prepended. So The path where you should put your PHPUnit tests should reflect the path in the sourcetree, with test/php/ prepended. So
if you're testing a file library/Icinga/My/File.php the test file should be at test/php/library/Icinga/My/File.php. This if you're testing a file library/Icinga/My/File.php the test file should be at test/php/library/Icinga/My/File.php. This
also applies for modules, where the test folder is underneath modules/myModule/test/php also applies for modules, where the tests are underneath modules/myModule/test/php
## Example test skeleton ## Example test skeleton
@ -12,13 +12,8 @@ Let's assume you're testing a class MyClass underneath the MyModule module and t
modules/mymodule/library/MyModule/Helper/MyClass.php. modules/mymodule/library/MyModule/Helper/MyClass.php.
<?php <?php
// The namespace is the same namespace as the file to test has, but with 'Test' prepended // The namespace is the same namespace as the file to test has, but with 'Tests' prepended
namespace Test\Modules\MyModule\Helper; namespace Tests\Module\MyModule\Helper;
// Require the file and maybe others. The start point is always the applications
// testss/php/ folder where the runtest executable can be found
require_once '../../mymodule/library/MyModule/Helper/MyClass.php';
class MyClassTest extends \PHPUnit_Framework_TestCase class MyClassTest extends \PHPUnit_Framework_TestCase
{ {
@ -30,28 +25,33 @@ modules/mymodule/library/MyModule/Helper/MyClass.php.
## Testing Singletons ## Testing Singletons
When test methods **modify static** class properties (which is the case when using singletons), add the PHPUnit When test methods **modify static** class properties (which is the case when using singletons), do not add the PHPUnit
[`@backupStaticAttributes enabled`](http://phpunit.de/manual/3.7/en/appendixes.annotations.html#appendixes.annotations.backupStaticAttributes) [`@backupStaticAttributes enabled`](http://phpunit.de/manual/3.7/en/appendixes.annotations.html#appendixes.annotations.backupStaticAttributes)
annotation to their [DockBlock](http://www.phpdoc.org/docs/latest/for-users/phpdoc/basic-syntax.html#what-is-a-docblock) annotation to their [DocBlock](http://www.phpdoc.org/docs/latest/for-users/phpdoc/basic-syntax.html#what-is-a-docblock)
in order to backup and restore static attributes before and after the method execution respectively. For reference you in order to backup and restore static attributes before and after the test execution respectively. Use the setUp()
should **document** that the test interacts with static attributes: and tearDown() routines instead to accomplish this task.
<?php <?php
namespace My\Test; namespace My\Test;
use \PHPUnit_Framework_TestCase; use Icinga\Test\BaseTestCase;
use My\CheesecakeFactory; use My\CheesecakeFactory;
class SingletonTest extends PHPUnit_Framework_TestCase class SingletonTest extends BaseTestCase
{ {
/** protected function setUp()
* Interact with static attributes {
* parent::setUp();
* Utilizes singleton CheesecakeFactory $this->openingHours = CheesecakeFactory::getOpeningHours();
* }
* @backupStaticAttributes enabled
*/ protected function tearDown()
{
parent::tearDown();
CheesecakeFactory::setOpeningHours($this->openingHours);
}
public function testThatInteractsWithStaticAttributes() public function testThatInteractsWithStaticAttributes()
{ {
CheesecakeFactory::setOpeningHours(24); CheesecakeFactory::setOpeningHours(24);
@ -59,79 +59,7 @@ should **document** that the test interacts with static attributes:
} }
} }
## Requirements and the dependency mess The reason to avoid using @backupStaticAttributes is the fact that if it is necessary to utilize a
singleton in your *unit* tests you probably want to rethink what you are going to test and because
### spl_autoload_register vs. require some tests are using the mock framework [`Mockery`](https://github.com/padraic/mockery) which is
using static class properties to implement its caching mechanics.
When looking at our test classes, you'll notice that we don't use PHPs autoloader to automatically load dependency, but
write 'require_once' by ourselfs. This has the following reasons:
- When writing tests, you to be aware of every dependency your testclass includes. With autoloading, it's not directly
obvious which classes are included during runtime.
- When mocking classes, you don't need to tell your autoloader to use this class instead of the one used in production
- Tests can't be run isolated without an boostrap class initializing the autoloader
### How to avoid require_once massacres: LibraryLoader
The downside of this approach is obvious: Especially when writing compoment tests you end up writing a lot of 'require'
classes. In the worst case, the PHP require_once method doesn't recognize a path to be already included and ends up
with an 'Cannot redeclare class XY' issue.
To avoid this, you should implement a LibraryLoader class for your component that handles the require_once calls.
For example, the status.dat component tests has a TestLoader class that includes all dependencies of the component:
namespace Tests\Icinga\Protocol\Statusdat;
use Test\Icinga\LibraryLoader;
require_once('library/Icinga/LibraryLoader.php');
/**
* Load all required libraries to use the statusdat
* component in integration tests
*
**/
class StatusdatTestLoader extends LibraryLoader
{
/**
* @see LibraryLoader::requireLibrary
*
**/
public static function requireLibrary()
{
// include Zend requirements
require_once 'Zend/Config.php';
require_once 'Zend/Cache.php';
require_once 'Zend/Log.php';
// retrieve the path to the icinga library
$libPath = self::getLibraryPath();
// require library dependencies
require_once($libPath."/Data/AbstractQuery.php");
require_once($libPath."/Application/Logger.php");
require_once($libPath."/Data/DatasourceInterface.php");
// shorthand for the folder where the statusdat component can be found
$statusdat = realpath($libPath."/Protocol/Statusdat/");
require_once($statusdat."/View/AccessorStrategy.php");
// ... a few more requires ...
require_once($statusdat."/Query/Group.php");
}
}
Now an component test (like tests/php/library/Icinga/Protocol/Statusdat/ReaderTest.php) can avoid the require calls and
just use the requireLibrary method:
use Icinga\Protocol\Statusdat\Reader as Reader;
// Load library at once
require_once("StatusdatTestLoader.php");
StatusdatTestLoader::requireLibrary();
**Note**: This should be used for component tests, where you want to test the combination of your classes. When testing
a single execution unit, like a method, it's often better to explicitly write your dependencies.
If you compare the first approach with the last one you will notice that, even if we produced more code in the end, our
test is more verbose in what it is doing. When someone is updating your test, he should easily see what tests are existing
and what scenarios are missing.

View File

@ -6,11 +6,10 @@ Tests for the application can be found underneath the test folder:
test/ test/
php/ PHPUnit tests for backend code php/ PHPUnit tests for backend code
js/ mocha tests for JavaScript frontend code unittests regression/ PHPUnit regression tests
frontend/ Integration tests for the frontend using casperjs
The same structure applies for modules, which also contain a toplevel test folder and suitable subtests. When you fix The same structure applies for modules, which also contain a toplevel test folder and suitable subtests. When you fix
a bug and write a regression test for it, put the test in the 'regression' and name it %DESCRIPTION%%TicketNumber% (myBug1234.js) a bug and write a regression test for it, put it in 'regression' and name it %DESCRIPTION%%TicketNumber% (myBug1234.php)
## Running tests ## Running tests

View File

@ -18,11 +18,8 @@ This list summarizes what will be described in the next few chapters:
- Your assertions should reflect one test scenario, i.e. don't write one test method that tests if something works **and** - Your assertions should reflect one test scenario, i.e. don't write one test method that tests if something works **and**
if it correctly detects errors after it works. Write one test to determine the behaviour with correct input and one that if it correctly detects errors after it works. Write one test to determine the behaviour with correct input and one that
tests the behaviour with invalid input. tests the behaviour with invalid input.
- When writing unit-tests (like function level tests), try to keep your dependencies as low as possible (best indicator herefor - Mock external components and inject them into the class you want to test. If your testsubject is not able to use mocked
is the number of require calls in your test). Mock external components and inject them into the class you want to test. If dependencies, it's often a design flaw and should be considered as a bug (and be fixed)
your testsubject is not able to use mocked dependencies, it's often a design flaw and should be considered as a bug
(and be fixed)
- When writing component tests with a lot of dependencies, wrap the require calls in a LibraryLoader subclass
## What should be tested ## What should be tested
@ -163,12 +160,6 @@ need much dependency handling. An example for a unittest would be to test the fo
A unit test for this user could, but should not look like this (we'll explain why): A unit test for this user could, but should not look like this (we'll explain why):
require_once "../../library/Icinga/MyLibrary/UserManager.php";
// needed by UserManager
require_once "../../library/Icinga/Authentication/Manager.php"
require_once "../../library/Icinga/Authentication/User.php"
// .. imagine a few more require_once
use Icinga/MyLibrary/UserManager use Icinga/MyLibrary/UserManager
class UserManagerTest extends \PHPUnit_Framework_TestCase class UserManagerTest extends \PHPUnit_Framework_TestCase
@ -196,7 +187,7 @@ A unit test for this user could, but should not look like this (we'll explain wh
$this->assertTrue($mgr->isCorrectPassword("hans", "validpasswor")); $this->assertTrue($mgr->isCorrectPassword("hans", "validpasswor"));
} }
This test has obviously a few issues: This test has a few issues:
- First, it assert a precondition to apply : A database must exist with the users jdoe and jsmith and the credentials - First, it assert a precondition to apply : A database must exist with the users jdoe and jsmith and the credentials
must match the ones provided in the test must match the ones provided in the test
@ -238,7 +229,6 @@ It would of course be best to create an Interface like UserSource which the Auth
we trust our Programmer to provide a suitable object. We now can eliminate all the AuthManager dependencies by mocking the we trust our Programmer to provide a suitable object. We now can eliminate all the AuthManager dependencies by mocking the
AuthManager (lets dumb it down to just providing an array of users): AuthManager (lets dumb it down to just providing an array of users):
require_once "../../library/Icinga/MyLibrary/UserManager.php";
use Icinga/MyLibrary/UserManager use Icinga/MyLibrary/UserManager
class AuthManagerMock class AuthManagerMock
@ -286,7 +276,6 @@ AuthManager (lets dumb it down to just providing an array of users):
Ok, we might have more code here than before, but our test is now less like prone to fail: Ok, we might have more code here than before, but our test is now less like prone to fail:
- Our test doesn't assume any preconditions to apply, like having a db server with correct users - Our test doesn't assume any preconditions to apply, like having a db server with correct users
- The require call to the AuthManager is gone, so if there's a bug in the AuthManager implementation our test is not affected
@ -368,84 +357,3 @@ Also, the assertions should get an error message that will be printed on failure
Now if something fails, we now see what has been tested via the testmethod and what caused the test to fail in the Now if something fails, we now see what has been tested via the testmethod and what caused the test to fail in the
assertion error message. You could also leave the comments and everybody knows what you are doing. assertion error message. You could also leave the comments and everybody knows what you are doing.
## Testing PHP
## Requirements and the dependency mess
### spl_autoload_register vs. require
When looking at our test classes, you'll notice that we don't use PHPs autoloader to automatically load dependency, but
write 'require_once' by ourselfs. This has the following reasons:
- When writing tests, you to be aware of every dependency your testclass includes. With autoloading, it's not directly
obvious which classes are included during runtime.
- When mocking classes, you don't need to tell your autoloader to use this class instead of the one used in production
- Tests can't be run isolated without an boostrap class initializing the autoloader
### How to avoid require_once massacres: LibraryLoader
The downside of this approach is obvious: Especially when writing compoment tests you end up writing a lot of 'require'
classes. In the worst case, the PHP require_once method doesn't recognize a path to be already included and ends up
with an 'Cannot redeclare class XY' issue.
To avoid this, you should implement a LibraryLoader class for your component that handles the require_once calls.
For example, the status.dat component tests has a TestLoader class that includes all dependencies of the component:
namespace Tests\Icinga\Protocol\Statusdat;
use Test\Icinga\LibraryLoader;
require_once('library/Icinga/LibraryLoader.php');
/**
* Load all required libraries to use the statusdat
* component in integration tests
*
**/
class StatusdatTestLoader extends LibraryLoader
{
/**
* @see LibraryLoader::requireLibrary
*
**/
public static function requireLibrary()
{
// include Zend requirements
require_once 'Zend/Config.php';
require_once 'Zend/Cache.php';
require_once 'Zend/Log.php';
// retrieve the path to the icinga library
$libPath = self::getLibraryPath();
// require library dependencies
require_once($libPath."/Data/AbstractQuery.php");
require_once($libPath."/Application/Logger.php");
require_once($libPath."/Data/DatasourceInterface.php");
// shorthand for the folder where the statusdat component can be found
$statusdat = realpath($libPath."/Protocol/Statusdat/");
require_once($statusdat."/View/AccessorStrategy.php");
// ... a few more requires ...
require_once($statusdat."/Query/Group.php");
}
}
Now an component test (like tests/php/library/Icinga/Protocol/Statusdat/ReaderTest.php) can avoid the require calls and
just use the requireLibrary method:
use Icinga\Protocol\Statusdat\Reader as Reader;
// Load library at once
require_once("StatusdatTestLoader.php");
StatusdatTestLoader::requireLibrary();
**Note**: This should be used for component tests, where you want to test the combination of your classes. When testing
a single execution unit, like a method, it's often better to explicitly write your dependencies.
If you compare the first approach with the last one you will notice that, even if we produced more code in the end, our
test is more verbose in what it is doing. When someone is updating your test, he should easily see what tests are existing
and what scenarios are missing.

View File

@ -50,29 +50,14 @@ password is queried when connecting from the local machine:
Icinga has it's own base test which lets you easily require libraries, testing database and form functionality. The class resides in Icinga has it's own base test which lets you easily require libraries, testing database and form functionality. The class resides in
library/Icinga/Test. If you write a test, just subclass BaseTestCase. library/Icinga/Test. If you write a test, just subclass BaseTestCase.
### Default test header
Before writing a test you should include the base test first
// @codingStandardsIgnoreStart
require_once realpath(__DIR__ . '/../../../../../library/Icinga/Test/BaseTestCase.php');
// @codingStandardsIgnoreEnd
Now you can simply include dependencies with predefined properties:
require_once BaseTestCase::$libDir . '/Web/Form.php';
require_once BaseTestCase::$appDir . '/forms/Config/AuthenticationForm.php';
BaseTestCase provides static variables for every directory in the project.
### Writing database tests ### Writing database tests
The base test uses the PHPUnit dataProvider annotation system to create Zend Database Adapters. Typically a The base test uses the PHPUnit dataProvider annotation system to create database connections. Typically a
database test looks like this: database test looks like this:
/** /**
* @dataProvider mysqlDb * @dataProvider mysqlDb
* @param Zend_Db_Adapter_PDO_Abstract $mysqlDb * @param Icinga\Data\Db\Connection $mysqlDb
*/ */
public function testSomethingWithMySql($mysqlDb) public function testSomethingWithMySql($mysqlDb)
{ {
@ -106,58 +91,3 @@ BaseTestCase holds method to require form libraries and create form classes base
The second parameter of createForm() can be omitted. You can set initial post request data as The second parameter of createForm() can be omitted. You can set initial post request data as
an array if needed. an array if needed.
## Writing tests for controllers
When writing tests for controllers, you can subclass the MonitoringControllerTest class underneath monitoring/test/php/testlib:
class MyTestclass extends MonitoringControllerTest
{
// test stuff
}
This class handles a lot of depenendency resolving and controller mocking. In order to test your action correctly and
without side effects, the TestFixture class allows your to define and set up your faked monitoring results in the backend
you want to test:
use Test\Monitoring\Testlib\Datasource\TestFixture;
class MyTestclass extends MonitoringControllerTest
{
public function testSomething()
{
$fixture = new TestFixture();
// adding a new critical, but acknowledged host
$fixture->addHost("hostname", 1, ObjectFlags::ACKNOWLEDGED())
// add a comment to the host (this has to be done before adding services)
->addComment("author", "comment text")
// assign to hostgroup
->addToHostgroup("myHosts")
// and add three services to this host
->addService("svc1", 0) // Service is ok
->addService("svc2", 1, ObjectFlags::PASSIVE) // service is warning and passive
->addService("svc3", 2, null, array("notes_url" => "test.html")) // critical with notes url
->addComment("author", "what a nice service comment") // add a comment to the service
->addToServicegroup("alwaysdown"); // add svc3 to servicegroup
// Create the datasource from this fixture, here in MySQL
$this->setupFixture($fixture, "mysql");
// ... do the actual testing (discussed now)
}
}
After the call to setupFixture() your backend should be ready to be tested. Setting up the controller manually would
force you to go through the whole bootstrap. To avoid this the MonitoringControllerTest class provides a 'requireController'
method which returns the Controller for you with an already set up backend using your previously defined testdata:
$controller = $this->requireController('MyController', 'mysql');
// controller is now the Zend controller instance, perform an action
$controller->myAction();
$result = $controller->view->hosts->fetchAll();
This example assumes that the controller populates the 'host' variable in the view, so now you can assert the state of
the result according to your test plan.

View File

@ -1,11 +0,0 @@
<?php
/**
*
*/
class IndexController
{
public function indexAction()
{
}
}

View File

@ -1 +0,0 @@
New module skeleton

View File

@ -1 +0,0 @@
[menu]

384
files Normal file
View File

@ -0,0 +1,384 @@
./modules/doc/application/controllers/IndexController.php
./modules/doc/application/controllers/ModuleController.php
./modules/doc/library/Doc/DocParser.php
./modules/doc/library/Doc/Controller.php
./modules/doc/library/Doc/DocException.php
./modules/doc/library/Doc/MarkdownFileIterator.php
./modules/translation/application/clicommands/CompileCommand.php
./modules/translation/application/clicommands/RefreshCommand.php
./modules/translation/library/Translation/Cli/TranslationCommand.php
./modules/translation/library/Translation/Util/GettextTranslationHelper.php
./modules/monitoring/application/forms/Config/Backend/EditBackendForm.php
./modules/monitoring/application/forms/Config/Backend/CreateBackendForm.php
./modules/monitoring/application/forms/Config/ConfirmRemovalForm.php
./modules/monitoring/application/forms/Config/Instance/CreateInstanceForm.php
./modules/monitoring/application/forms/Config/Instance/EditInstanceForm.php
./modules/monitoring/application/forms/Command/DelayNotificationForm.php
./modules/monitoring/application/forms/Command/SubmitPassiveCheckResultForm.php
./modules/monitoring/application/forms/Command/CommandForm.php
./modules/monitoring/application/forms/Command/WithChildrenCommandForm.php
./modules/monitoring/application/forms/Command/CustomNotificationForm.php
./modules/monitoring/application/forms/Command/AcknowledgeForm.php
./modules/monitoring/application/forms/Command/CommentForm.php
./modules/monitoring/application/forms/Command/MultiCommandFlagForm.php
./modules/monitoring/application/forms/Command/RescheduleNextCheckForm.php
./modules/monitoring/application/forms/Command/ScheduleDowntimeForm.php
./modules/monitoring/application/forms/Command/SingleArgumentCommandForm.php
./modules/monitoring/application/forms/Command/DisableNotificationWithExpireForm.php
./modules/monitoring/application/views/helpers/MonitoringFlags.php
./modules/monitoring/application/views/helpers/MonitoringProperties.php
./modules/monitoring/application/views/helpers/CommandForm.php
./modules/monitoring/application/views/helpers/RuntimeVariables.php
./modules/monitoring/application/views/helpers/CheckPerformance.php
./modules/monitoring/application/views/helpers/PluginOutput.php
./modules/monitoring/application/views/helpers/Perfdata.php
./modules/monitoring/application/views/helpers/_RenderServicePerfdata.php
./modules/monitoring/application/views/helpers/SelectionToolbar.php
./modules/monitoring/application/views/helpers/ContactFlags.php
./modules/monitoring/application/views/helpers/ResolveMacros.php
./modules/monitoring/application/views/helpers/MonitoringState.php
./modules/monitoring/application/views/helpers/ResolveComments.php
./modules/monitoring/application/clicommands/NrpeCommand.php
./modules/monitoring/application/clicommands/ConferenceCommand.php
./modules/monitoring/application/clicommands/ListCommand.php
./modules/monitoring/application/controllers/ShowController.php
./modules/monitoring/application/controllers/ConfigController.php
./modules/monitoring/application/controllers/MultiController.php
./modules/monitoring/application/controllers/ListController.php
./modules/monitoring/application/controllers/CommandController.php
./modules/monitoring/application/controllers/MonitoringCommands.php
./modules/monitoring/application/controllers/ChartController.php
./modules/monitoring/application/controllers/TimelineController.php
./modules/monitoring/application/controllers/TacticalController.php
./modules/monitoring/application/controllers/ProcessController.php
./modules/monitoring/library/Monitoring/DataView/Contactgroup.php
./modules/monitoring/library/Monitoring/DataView/Notification.php
./modules/monitoring/library/Monitoring/DataView/Comment.php
./modules/monitoring/library/Monitoring/DataView/Customvar.php
./modules/monitoring/library/Monitoring/DataView/EventHistory.php
./modules/monitoring/library/Monitoring/DataView/StatusSummary.php
./modules/monitoring/library/Monitoring/DataView/DataView.php
./modules/monitoring/library/Monitoring/DataView/Runtimesummary.php
./modules/monitoring/library/Monitoring/DataView/Servicegroup.php
./modules/monitoring/library/Monitoring/DataView/Runtimevariables.php
./modules/monitoring/library/Monitoring/DataView/Contact.php
./modules/monitoring/library/Monitoring/DataView/Programstatus.php
./modules/monitoring/library/Monitoring/DataView/StateHistorySummary.php
./modules/monitoring/library/Monitoring/DataView/Downtime.php
./modules/monitoring/library/Monitoring/DataView/Groupsummary.php
./modules/monitoring/library/Monitoring/DataView/Hostgroup.php
./modules/monitoring/library/Monitoring/DataView/HostStatus.php
./modules/monitoring/library/Monitoring/DataView/ServiceStatus.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/StatusdatQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/ContactgroupQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/ServicegroupsummaryQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/HostgroupQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/CommentQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/DowntimeQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/StatusSummaryQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/GroupsummaryQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/ContactQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/ServicegroupQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/HostlistQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/StatusQuery.php
./modules/monitoring/library/Monitoring/Backend/Statusdat/Query/ServicelistQuery.php
./modules/monitoring/library/Monitoring/Backend/Livestatus/Query/StatusQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/ContactgroupQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/NotificationhistoryQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/CustomvarQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/DowntimeendhistoryQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/HostgroupQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/CommentQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/DowntimeQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/StatehistoryQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/ProgramstatusQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/EventHistoryQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusSummaryQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/GroupsummaryQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/HoststatusQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/RuntimevariablesQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/CommenthistoryQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/ContactQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/StateHistorySummaryQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/AllcontactsQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/DowntimestarthistoryQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/RuntimesummaryQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusQuery.php
./modules/monitoring/library/Monitoring/Backend/Ido/Query/NotificationQuery.php
./modules/monitoring/library/Monitoring/Environment.php
./modules/monitoring/library/Monitoring/Controller.php
./modules/monitoring/library/Monitoring/Timeline/TimeEntry.php
./modules/monitoring/library/Monitoring/Timeline/TimeRange.php
./modules/monitoring/library/Monitoring/Timeline/TimeLine.php
./modules/monitoring/library/Monitoring/Object/Service.php
./modules/monitoring/library/Monitoring/Object/Host.php
./modules/monitoring/library/Monitoring/Object/AbstractObject.php
./modules/monitoring/library/Monitoring/Filter/Type/StatusFilter.php
./modules/monitoring/library/Monitoring/Filter/Registry.php
./modules/monitoring/library/Monitoring/Filter/UrlViewFilter.php
./modules/monitoring/library/Monitoring/Exception/UnsupportedBackendException.php
./modules/monitoring/library/Monitoring/Web/Widget/TimelineIntervalBox.php
./modules/monitoring/library/Monitoring/Web/Hook/TimelineProvider.php
./modules/monitoring/library/Monitoring/Web/Hook/TopBar.php
./modules/monitoring/library/Monitoring/Command/SubmitPassiveCheckresultCommand.php
./modules/monitoring/library/Monitoring/Command/AcknowledgeCommand.php
./modules/monitoring/library/Monitoring/Command/ScheduleDowntimeCommand.php
./modules/monitoring/library/Monitoring/Command/ScheduleCheckCommand.php
./modules/monitoring/library/Monitoring/Command/DisableNotificationWithExpireCommand.php
./modules/monitoring/library/Monitoring/Command/SingleArgumentCommand.php
./modules/monitoring/library/Monitoring/Command/AddCommentCommand.php
./modules/monitoring/library/Monitoring/Command/CustomNotificationCommand.php
./modules/monitoring/library/Monitoring/Command/DelayNotificationCommand.php
./modules/monitoring/library/Monitoring/Plugin.php
./modules/monitoring/library/Monitoring/Cli/CliUtils.php
./modules/monitoring/library/Monitoring/Backend.php
./modules/monitoring/library/Monitoring/Plugin/Perfdata.php
./modules/monitoring/library/Monitoring/Plugin/PerfdataSet.php
./modules/monitoring/run.php
./modules/monitoring/configuration.php
./modules/monitoring/bin/action/list.inc.php
./etc/module_skeleton/application/controllers/IndexController.php
./application/forms/Authentication/LoginForm.php
./application/forms/Config/GeneralForm.php
./application/forms/Config/Authentication/LdapBackendForm.php
./application/forms/Config/Authentication/ReorderForm.php
./application/forms/Config/Authentication/BaseBackendForm.php
./application/forms/Config/Authentication/DbBackendForm.php
./application/forms/Config/LoggingForm.php
./application/forms/Config/ConfirmRemovalForm.php
./application/forms/Config/Resource/CreateResourceForm.php
./application/forms/Config/Resource/EditResourceForm.php
./application/forms/TestForm.php
./application/forms/Dashboard/AddUrlForm.php
./application/forms/Preference/GeneralForm.php
./application/views/helpers/FormNumber.php
./application/views/helpers/DateFormat.php
./application/views/helpers/FormDateTime.php
./application/views/helpers/FormTriStateCheckbox.php
./application/views/helpers/Util.php
./application/clicommands/HelpCommand.php
./application/clicommands/ModuleCommand.php
./application/clicommands/AutocompleteCommand.php
./application/clicommands/WebCommand.php
./application/controllers/ConfigController.php
./application/controllers/ListController.php
./application/controllers/IndexController.php
./application/controllers/LayoutController.php
./application/controllers/PreferenceController.php
./application/controllers/DashboardController.php
./application/controllers/FilterController.php
./application/controllers/StaticController.php
./application/controllers/SearchController.php
./application/controllers/ErrorController.php
./application/controllers/AuthenticationController.php
./library/Icinga/Logger/Logger.php
./library/Icinga/Logger/Writer/StreamWriter.php
./library/Icinga/Logger/Writer/SyslogWriter.php
./library/Icinga/Logger/LogWriter.php
./library/Icinga/User/Preferences.php
./library/Icinga/User/Message.php
./library/Icinga/User/Preferences/Store/IniStore.php
./library/Icinga/User/Preferences/Store/DbStore.php
./library/Icinga/User/Preferences/PreferencesStore.php
./library/Icinga/Authentication/UserBackend.php
./library/Icinga/Authentication/Backend/DbUserBackend.php
./library/Icinga/Authentication/Backend/LdapUserBackend.php
./library/Icinga/Authentication/Membership.php
./library/Icinga/Authentication/Manager.php
./library/Icinga/Authentication/AdmissionLoader.php
./library/Icinga/Authentication/AuthChain.php
./library/Icinga/Data/Db/Query.php
./library/Icinga/Data/Db/TreeToSqlParser.php
./library/Icinga/Data/Db/Connection.php
./library/Icinga/Data/PivotTable.php
./library/Icinga/Data/DatasourceInterface.php
./library/Icinga/Data/DataArray/Query.php
./library/Icinga/Data/DataArray/Datasource.php
./library/Icinga/Data/ResourceFactory.php
./library/Icinga/Data/BaseQuery.php
./library/Icinga/File/Pdf.php
./library/Icinga/File/Csv.php
./library/Icinga/File/Csv/Query.php
./library/Icinga/Test/DbTest.php
./library/Icinga/Test/BaseTestCase.php
./library/Icinga/Test/FormTest.php
./library/Icinga/Protocol/Ldap/Root.php
./library/Icinga/Protocol/Ldap/Query.php
./library/Icinga/Protocol/Ldap/Exception.php
./library/Icinga/Protocol/Ldap/LdapUtils.php
./library/Icinga/Protocol/Ldap/Node.php
./library/Icinga/Protocol/Ldap/Connection.php
./library/Icinga/Protocol/File/Query.php
./library/Icinga/Protocol/File/Reader.php
./library/Icinga/Protocol/Statusdat/Parser.php
./library/Icinga/Protocol/Statusdat/Query.php
./library/Icinga/Protocol/Statusdat/Query/IQueryPart.php
./library/Icinga/Protocol/Statusdat/Query/Group.php
./library/Icinga/Protocol/Statusdat/Query/Expression.php
./library/Icinga/Protocol/Statusdat/View/AccessorStrategy.php
./library/Icinga/Protocol/Statusdat/View/MonitoringObjectList.php
./library/Icinga/Protocol/Statusdat/ObjectContainer.php
./library/Icinga/Protocol/Statusdat/Exception/ParsingException.php
./library/Icinga/Protocol/Statusdat/Reader.php
./library/Icinga/Protocol/Statusdat/IReader.php
./library/Icinga/Protocol/Statusdat/PrintableObject.php
./library/Icinga/Protocol/Statusdat/TreeToStatusdatQueryParser.php
./library/Icinga/Protocol/Statusdat/RuntimeStateContainer.php
./library/Icinga/Protocol/Nrpe/Packet.php
./library/Icinga/Protocol/Nrpe/Connection.php
./library/Icinga/Protocol/Livestatus/Query.php
./library/Icinga/Protocol/Livestatus/Connection.php
./library/Icinga/Protocol/Commandpipe/Transport/Transport.php
./library/Icinga/Protocol/Commandpipe/Transport/LocalPipe.php
./library/Icinga/Protocol/Commandpipe/Transport/SecureShell.php
./library/Icinga/Protocol/Commandpipe/Comment.php
./library/Icinga/Protocol/Commandpipe/Exception/InvalidCommandException.php
./library/Icinga/Protocol/Commandpipe/PropertyModifier.php
./library/Icinga/Protocol/Commandpipe/Command.php
./library/Icinga/Protocol/Commandpipe/CommandPipe.php
./library/Icinga/Application/Platform.php
./library/Icinga/Application/Benchmark.php
./library/Icinga/Application/functions.php
./library/Icinga/Application/LegacyWeb.php
./library/Icinga/Application/Config.php
./library/Icinga/Application/EmbeddedWeb.php
./library/Icinga/Application/ApplicationBootstrap.php
./library/Icinga/Application/Cli.php
./library/Icinga/Application/webrouter.php
./library/Icinga/Application/Modules/Module.php
./library/Icinga/Application/Modules/Manager.php
./library/Icinga/Application/Loader.php
./library/Icinga/Application/Icinga.php
./library/Icinga/Application/Web.php
./library/Icinga/Chart/Primitive/Animation.php
./library/Icinga/Chart/Primitive/Text.php
./library/Icinga/Chart/Primitive/Animatable.php
./library/Icinga/Chart/Primitive/Drawable.php
./library/Icinga/Chart/Primitive/Circle.php
./library/Icinga/Chart/Primitive/Styleable.php
./library/Icinga/Chart/Primitive/RawElement.php
./library/Icinga/Chart/Primitive/Rect.php
./library/Icinga/Chart/Primitive/Line.php
./library/Icinga/Chart/Primitive/Canvas.php
./library/Icinga/Chart/Primitive/PieSlice.php
./library/Icinga/Chart/Primitive/Path.php
./library/Icinga/Chart/Graph/LineGraph.php
./library/Icinga/Chart/Graph/StackedGraph.php
./library/Icinga/Chart/Graph/BarGraph.php
./library/Icinga/Chart/Axis.php
./library/Icinga/Chart/Palette.php
./library/Icinga/Chart/Unit/AxisUnit.php
./library/Icinga/Chart/Unit/LinearUnit.php
./library/Icinga/Chart/Unit/StaticAxis.php
./library/Icinga/Chart/Unit/CalendarUnit.php
./library/Icinga/Chart/PieChart.php
./library/Icinga/Chart/GridChart.php
./library/Icinga/Chart/SVGRenderer.php
./library/Icinga/Chart/Legend.php
./library/Icinga/Chart/Inline/PieChart.php
./library/Icinga/Chart/Inline/Inline.php
./library/Icinga/Chart/Chart.php
./library/Icinga/Chart/Render/RenderContext.php
./library/Icinga/Chart/Render/LayoutBox.php
./library/Icinga/Config/IniEditor.php
./library/Icinga/Config/PreservingIniWriter.php
./library/Icinga/User.php
./library/Icinga/Filter/Query/Tree.php
./library/Icinga/Filter/Query/Node.php
./library/Icinga/Filter/FilterAttribute.php
./library/Icinga/Filter/Type/FilterType.php
./library/Icinga/Filter/Type/BooleanFilter.php
./library/Icinga/Filter/Type/TextFilter.php
./library/Icinga/Filter/Type/TimeRangeSpecifier.php
./library/Icinga/Filter/QueryProposer.php
./library/Icinga/Filter/Registry.php
./library/Icinga/Filter/Filter.php
./library/Icinga/Filter/Filterable.php
./library/Icinga/Filter/Domain.php
./library/Icinga/Exception/NotWritableError.php
./library/Icinga/Exception/MissingParameterException.php
./library/Icinga/Exception/NotImplementedError.php
./library/Icinga/Exception/ConfigurationError.php
./library/Icinga/Exception/NotReadableError.php
./library/Icinga/Exception/SystemPermissionException.php
./library/Icinga/Exception/ProgrammingError.php
./library/Icinga/Web/JavaScript.php
./library/Icinga/Web/Notification.php
./library/Icinga/Web/MenuItem.php
./library/Icinga/Web/Widget/Dashboard.php
./library/Icinga/Web/Widget/FilterBox.php
./library/Icinga/Web/Widget/AlertMessageBox.php
./library/Icinga/Web/Widget/Tabextension/DashboardAction.php
./library/Icinga/Web/Widget/Tabextension/BasketAction.php
./library/Icinga/Web/Widget/Tabextension/Tabextension.php
./library/Icinga/Web/Widget/Tabextension/OutputFormat.php
./library/Icinga/Web/Widget/Chart/InlinePie.php
./library/Icinga/Web/Widget/Chart/HistoryColorGrid.php
./library/Icinga/Web/Widget/AbstractWidget.php
./library/Icinga/Web/Widget/FilterBadgeRenderer.php
./library/Icinga/Web/Widget/Dashboard/Component.php
./library/Icinga/Web/Widget/Dashboard/Pane.php
./library/Icinga/Web/Widget/Tabs.php
./library/Icinga/Web/Widget/Tab.php
./library/Icinga/Web/Widget/Widget.php
./library/Icinga/Web/Widget/SortBox.php
./library/Icinga/Web/Hook.php
./library/Icinga/Web/View/helpers/generic.php
./library/Icinga/Web/View/helpers/url.php
./library/Icinga/Web/View/helpers/format.php
./library/Icinga/Web/Menu.php
./library/Icinga/Web/Session.php
./library/Icinga/Web/Paginator/ScrollingStyle/SlidingWithBorder.php
./library/Icinga/Web/Paginator/Adapter/QueryAdapter.php
./library/Icinga/Web/ViewStream.php
./library/Icinga/Web/Url.php
./library/Icinga/Web/Session/SessionNamespace.php
./library/Icinga/Web/Session/Session.php
./library/Icinga/Web/Session/PhpSession.php
./library/Icinga/Web/StyleSheet.php
./library/Icinga/Web/Hook/Ticket.php
./library/Icinga/Web/Hook/Configuration/ConfigurationTabInterface.php
./library/Icinga/Web/Hook/Configuration/ConfigurationTab.php
./library/Icinga/Web/Hook/Configuration/ConfigurationTabBuilder.php
./library/Icinga/Web/Hook/TopBar.php
./library/Icinga/Web/Hook/Grapher.php
./library/Icinga/Web/Request.php
./library/Icinga/Web/View.php
./library/Icinga/Web/Widget.php
./library/Icinga/Web/Controller/ActionController.php
./library/Icinga/Web/Controller/BaseConfigController.php
./library/Icinga/Web/Controller/BasePreferenceController.php
./library/Icinga/Web/Controller/ControllerTabCollector.php
./library/Icinga/Web/LessCompiler.php
./library/Icinga/Web/Form.php
./library/Icinga/Web/Form/Element/Number.php
./library/Icinga/Web/Form/Element/DateTimePicker.php
./library/Icinga/Web/Form/Element/TriStateCheckbox.php
./library/Icinga/Web/Form/Element/Note.php
./library/Icinga/Web/Form/Decorator/ConditionalHidden.php
./library/Icinga/Web/Form/Decorator/BootstrapForm.php
./library/Icinga/Web/Form/Decorator/HelpText.php
./library/Icinga/Web/Form/Validator/DateFormatValidator.php
./library/Icinga/Web/Form/Validator/TriStateValidator.php
./library/Icinga/Web/Form/Validator/DateTimeValidator.php
./library/Icinga/Web/Form/Validator/TimeFormatValidator.php
./library/Icinga/Web/Form/Validator/WritablePathValidator.php
./library/Icinga/Web/Form/InvalidCSRFTokenException.php
./library/Icinga/Cli/Documentation/CommentParser.php
./library/Icinga/Cli/Params.php
./library/Icinga/Cli/Documentation.php
./library/Icinga/Cli/Screen/AnsiScreen.php
./library/Icinga/Cli/Loader.php
./library/Icinga/Cli/Command.php
./library/Icinga/Cli/Screen.php
./library/Icinga/Util/File.php
./library/Icinga/Util/Dimension.php
./library/Icinga/Util/DateTimeFactory.php
./library/Icinga/Util/Color.php
./library/Icinga/Util/String.php
./library/Icinga/Util/Format.php
./library/Icinga/Util/ConfigAwareFactory.php
./library/Icinga/Util/Translator.php

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -124,7 +125,7 @@ abstract class ApplicationBootstrap
/** /**
* Constructor * Constructor
*/ */
protected function __construct($configDir) protected function __construct($configDir = null)
{ {
$this->libDir = realpath(__DIR__ . '/../..'); $this->libDir = realpath(__DIR__ . '/../..');
@ -139,13 +140,23 @@ abstract class ApplicationBootstrap
define('ICINGA_APPDIR', $this->appDir); define('ICINGA_APPDIR', $this->appDir);
} }
if ($configDir === null) {
if (array_key_exists('ICINGAWEB_CONFIGDIR', $_SERVER)) {
$configDir = $_SERVER['ICINGAWEB_CONFIGDIR'];
} else if (array_key_exists('ICINGAWEB_CONFIGDIR', $_ENV)) {
$configDir = $_ENV['ICINGAWEB_CONFIGDIR'];
} else {
$configDir = '/etc/icingaweb';
}
}
$this->configDir = realpath($configDir);
$this->setupAutoloader(); $this->setupAutoloader();
$this->setupZendAutoloader(); $this->setupZendAutoloader();
Benchmark::measure('Bootstrap, autoloader registered'); Benchmark::measure('Bootstrap, autoloader registered');
Icinga::setApp($this); Icinga::setApp($this);
$this->configDir = realpath($configDir);
require_once dirname(__FILE__) . '/functions.php'; require_once dirname(__FILE__) . '/functions.php';
} }
@ -269,7 +280,7 @@ abstract class ApplicationBootstrap
* *
* @return ApplicationBootstrap * @return ApplicationBootstrap
*/ */
public static function start($configDir) public static function start($configDir = null)
{ {
$application = new static($configDir); $application = new static($configDir);
$application->bootstrap(); $application->bootstrap();
@ -364,7 +375,7 @@ abstract class ApplicationBootstrap
'level' => Logger::$ERROR, 'level' => Logger::$ERROR,
'type' => 'syslog', 'type' => 'syslog',
'facility' => 'LOG_USER', 'facility' => 'LOG_USER',
'application' => 'Icinga Web' 'application' => 'icingaweb'
) )
) )
); );
@ -446,13 +457,8 @@ abstract class ApplicationBootstrap
protected function setupTimezone() protected function setupTimezone()
{ {
$timeZoneString = $this->config->global !== null ? $this->config->global->get('timezone', 'UTC') : 'UTC'; $timeZoneString = $this->config->global !== null ? $this->config->global->get('timezone', 'UTC') : 'UTC';
try {
$tz = new DateTimeZone($timeZoneString);
} catch (Exception $e) {
throw new ConfigurationError(t('Invalid timezone') . ' "' . $timeZoneString . '"');
}
date_default_timezone_set($timeZoneString); date_default_timezone_set($timeZoneString);
DateTimeFactory::setConfig(array('timezone' => $tz)); DateTimeFactory::setConfig(array('timezone' => $timeZoneString));
return $this; return $this;
} }
@ -482,3 +488,4 @@ abstract class ApplicationBootstrap
return $this; return $this;
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -317,3 +318,4 @@ class Benchmark
{ {
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -34,8 +35,10 @@ use Icinga\Application\ApplicationBootstrap;
use Icinga\Cli\Params; use Icinga\Cli\Params;
use Icinga\Cli\Loader; use Icinga\Cli\Loader;
use Icinga\Cli\Screen; use Icinga\Cli\Screen;
use Icinga\Logger\Logger;
use Icinga\Application\Benchmark; use Icinga\Application\Benchmark;
use Icinga\Exception\ProgrammingError; use Icinga\Exception\ProgrammingError;
use Zend_Config;
require_once __DIR__ . '/ApplicationBootstrap.php'; require_once __DIR__ . '/ApplicationBootstrap.php';
@ -64,19 +67,23 @@ class Cli extends ApplicationBootstrap
->setupTimezone() ->setupTimezone()
->setupInternationalization() ->setupInternationalization()
->parseBasicParams() ->parseBasicParams()
->fixLoggingConfig()
->setupLogger() ->setupLogger()
->setupResourceFactory() ->setupResourceFactory()
->setupModuleManager(); ->setupModuleManager();
} }
protected function fixLoggingConfig() protected function setupLogging()
{ {
$conf = $this->config->logging; Logger::create(
if (! isset($conf->type) || $conf->type === 'stream') { new Zend_Config(
$conf->level = $this->verbose; array(
$conf->target = 'php://stderr'; 'enable' => true,
} 'level' => Logger::$INFO,
'type' => 'file',
'target' => 'php://stderr'
)
)
);
return $this; return $this;
} }
@ -177,3 +184,4 @@ class Cli extends ApplicationBootstrap
throw new ProgrammingError('Icinga is not running on CLI'); throw new ProgrammingError('Icinga is not running on CLI');
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -61,3 +62,4 @@ class EmbeddedWeb extends ApplicationBootstrap
->loadEnabledModules(); ->loadEnabledModules();
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -60,11 +60,13 @@ class Icinga
* Setter for an application environment * Setter for an application environment
* *
* @param ApplicationBootstrap $app * @param ApplicationBootstrap $app
* @param bool $overwrite
*
* @throws ProgrammingError * @throws ProgrammingError
*/ */
public static function setApp(ApplicationBootstrap $app) public static function setApp(ApplicationBootstrap $app, $overwrite = false)
{ {
if (self::$app !== null) { if (self::$app !== null && !$overwrite) {
throw new ProgrammingError('Cannot start Icinga twice'); throw new ProgrammingError('Cannot start Icinga twice');
} }

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -55,3 +56,4 @@ class LegacyWeb extends Web
return $this->legacyBasedir; return $this->legacyBasedir;
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,30 +1,5 @@
<?php <?php
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2013 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 2013 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>
*
*/
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Application; namespace Icinga\Application;
@ -40,6 +15,7 @@ class Loader
/** /**
* List of namespaces * List of namespaces
*
* @var array * @var array
*/ */
private $namespaces = array(); private $namespaces = array();
@ -54,14 +30,16 @@ class Loader
/** /**
* Register new namespace for directory * Register new namespace for directory
*
* @param string $namespace * @param string $namespace
* @param string $directory * @param string $directory
* @throws \Icinga\Exception\ProgrammingError *
* @throws ProgrammingError
*/ */
public function registerNamespace($namespace, $directory) public function registerNamespace($namespace, $directory)
{ {
if (!is_dir($directory)) { if (!is_dir($directory)) {
throw new ProgrammingError('Directory does not exist: '. $directory); throw new ProgrammingError('Directory does not exist: ' . $directory);
} }
$this->namespaces[$namespace] = $directory; $this->namespaces[$namespace] = $directory;
@ -69,7 +47,9 @@ class Loader
/** /**
* Test if a namespace exists * Test if a namespace exists
*
* @param string $namespace * @param string $namespace
*
* @return bool * @return bool
*/ */
public function hasNamespace($namespace) public function hasNamespace($namespace)
@ -80,9 +60,10 @@ class Loader
/** /**
* Class loader * Class loader
* *
* Ignores all but classes in the Icinga namespace. * Ignores all but classes in registered namespaces.
* *
* @param string $class * @param string $class
*
* @return boolean * @return boolean
*/ */
public function loadClass($class) public function loadClass($class)
@ -90,9 +71,8 @@ class Loader
$namespace = $this->getNamespaceForClass($class); $namespace = $this->getNamespaceForClass($class);
if ($namespace) { if ($namespace) {
$file = $this->namespaces[$namespace]. preg_replace('/^'. preg_quote($namespace). '/', '', $class); $file = $this->namespaces[$namespace] . preg_replace('/^' . preg_quote($namespace) . '/', '', $class);
$file = str_replace(self::NAMESPACE_SEPARATOR, '/', $file) . '.php';
$file = str_replace(self::NAMESPACE_SEPARATOR, '/', $file). '.php';
if (@file_exists($file)) { if (@file_exists($file)) {
require_once $file; require_once $file;
@ -109,6 +89,7 @@ class Loader
* Return is the longest match in the array found * Return is the longest match in the array found
* *
* @param string $className * @param string $className
*
* @return bool|string * @return bool|string
*/ */
private function getNamespaceForClass($className) private function getNamespaceForClass($className)
@ -116,8 +97,10 @@ class Loader
$testNamespace = ''; $testNamespace = '';
$testLength = 0; $testLength = 0;
foreach ($this->namespaces as $namespace => $directory) { foreach (array_keys($this->namespaces) as $namespace) {
$stub = preg_replace('/^'. preg_quote($namespace). '/', '', $className); $stub = preg_replace(
'/^' . preg_quote($namespace) . '(' . preg_quote(self::NAMESPACE_SEPARATOR) . '|$)/', '', $className
);
$length = strlen($className) - strlen($stub); $length = strlen($className) - strlen($stub);
if ($length > $testLength) { if ($length > $testLength) {
$testLength = $length; $testLength = $length;

View File

@ -128,10 +128,10 @@ class Manager
private function detectEnabledModules() private function detectEnabledModules()
{ {
$canonical = $this->enableDir; $canonical = $this->enableDir;
if ($canonical === false) { if ($canonical === false || ! file_exists($canonical)) {
throw new NotReadableError( // TODO: I guess the check for false has something to do with a
'Cannot read enabled modules. Module directory "' . $this->enableDir . '" does not exist' // call to realpath no longer present
); return;
} }
if (!is_dir($this->enableDir)) { if (!is_dir($this->enableDir)) {
throw new NotReadableError( throw new NotReadableError(

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -92,3 +93,4 @@ class Platform
} }
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -337,13 +338,12 @@ class Web extends ApplicationBootstrap
} }
try { try {
$tz = new DateTimeZone($userTimezone); DateTimeFactory::setConfig(array('timezone' => $userTimezone));
} catch (Exception $e) { date_default_timezone_set($userTimezone);
} catch (ConfigurationError $e) {
return parent::setupTimezone(); return parent::setupTimezone();
} }
date_default_timezone_set($userTimezone);
DateTimeFactory::setConfig(array('timezone' => $tz));
return $this; return $this;
} }
@ -372,3 +372,4 @@ class Web extends ApplicationBootstrap
return $this; return $this;
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -10,14 +10,6 @@ use Icinga\Chart\Inline\PieChart;
error_reporting(E_ALL | E_STRICT); error_reporting(E_ALL | E_STRICT);
if (array_key_exists('ICINGAWEB_CONFIGDIR', $_ENV)) {
$configDir = $_ENV['ICINGAWEB_CONFIGDIR'];
} elseif (array_key_exists('ICINGAWEB_CONFIGDIR', $_SERVER)) {
$configDir = $_SERVER['ICINGAWEB_CONFIGDIR'];
} else {
$configDir = '/etc/icingaweb';
}
if (isset($_SERVER['REQUEST_URI'])) { if (isset($_SERVER['REQUEST_URI'])) {
$ruri = $_SERVER['REQUEST_URI']; $ruri = $_SERVER['REQUEST_URI'];
} else { } else {
@ -42,7 +34,6 @@ $remove = dirname($_SERVER['PHP_SELF']);
if (substr($ruri, 0, strlen($remove)) !== $remove) { if (substr($ruri, 0, strlen($remove)) !== $remove) {
return false; return false;
} }
$ruri = ltrim(substr($ruri, strlen($remove)), '/'); $ruri = ltrim(substr($ruri, strlen($remove)), '/');
if (strpos($ruri, '?') === false) { if (strpos($ruri, '?') === false) {
@ -61,8 +52,8 @@ $special = array(
if (in_array($path, $special)) { if (in_array($path, $special)) {
require_once __DIR__ . '/EmbeddedWeb.php'; include_once __DIR__ . '/EmbeddedWeb.php';
EmbeddedWeb::start($configDir); EmbeddedWeb::start();
switch($path) { switch($path) {
@ -89,17 +80,17 @@ if (in_array($path, $special)) {
if (!array_key_exists('data', $_GET)) { if (!array_key_exists('data', $_GET)) {
return false; return false;
} }
require_once __DIR__ . '/EmbeddedWeb.php'; include __DIR__ . '/EmbeddedWeb.php';
EmbeddedWeb::start($configDir); EmbeddedWeb::start();
header('Content-Type: image/svg+xml'); header('Content-Type: image/svg+xml');
$pie = new PieChart(); $pie = new PieChart();
$pie->initFromRequest(); $pie->initFromRequest();
echo $pie->render(); echo $pie->render();
} elseif (file_exists($baseDir . $ruri) && is_file($baseDir . $ruri)) { } elseif (file_exists($baseDir . '/' . $path) && is_file($baseDir . '/' . $path)) {
return false; return false;
} else { } else {
require_once __DIR__ . '/Web.php'; include __DIR__ . '/Web.php';
Web::start($configDir)->dispatch(); Web::start()->dispatch();
} }

View File

@ -1,6 +1,6 @@
<?php <?php
namespace Icinga\Cli\Screen; namespace Icinga\Cli;
use Icinga\Cli\Screen; use Icinga\Cli\Screen;
@ -8,8 +8,6 @@ use Icinga\Cli\Screen;
class AnsiScreen extends Screen class AnsiScreen extends Screen
{ {
protected $isUtf8;
protected $fgColors = array( protected $fgColors = array(
'black' => '30', 'black' => '30',
'darkgray' => '1;30', 'darkgray' => '1;30',
@ -40,36 +38,6 @@ class AnsiScreen extends Screen
'lightgray' => '47', 'lightgray' => '47',
); );
public function __construct()
{
}
public function getColumns()
{
$cols = (int) getenv('COLUMNS');
if (! $cols) {
// stty -a ?
$cols = (int) exec('tput cols');
}
if (! $cols) {
$cols = 80;
}
return $cols;
}
public function getRows()
{
$rows = (int) getenv('ROWS');
if (! $rows) {
// stty -a ?
$rows = (int) exec('tput rows');
}
if (! $rows) {
$rows = 25;
}
return $rows;
}
public function strlen($string) public function strlen($string)
{ {
return strlen($this->stripAnsiCodes($string)); return strlen($this->stripAnsiCodes($string));
@ -80,40 +48,6 @@ class AnsiScreen extends Screen
return preg_replace('/\e\[?.*?[\@-~]/', '', $string); return preg_replace('/\e\[?.*?[\@-~]/', '', $string);
} }
public function newlines($count = 1)
{
return str_repeat("\n", $count);
}
public function center($txt)
{
$len = $this->strlen($txt);
$width = floor(($this->getColumns() + $len) / 2) - $len;
return str_repeat(' ', $width) . $txt;
}
public function hasUtf8()
{
if ($this->isUtf8 === null) {
// null should equal 0 here, however seems to equal '' on some systems:
$current = setlocale(LC_ALL, 0);
$parts = preg_split('/;/', $current);
$lc_parts = array();
foreach ($parts as $part) {
if (strpos($part, '=') === false) {
continue;
}
list($key, $val) = preg_split('/=/', $part, 2);
$lc_parts[$key] = $val;
}
$this->isUtf8 = array_key_exists('LC_CTYPE', $lc_parts)
&& preg_match('~\.UTF-8$~i', $lc_parts['LC_CTYPE']);
}
return $this->isUtf8;
}
public function clear() public function clear()
{ {
return "\033[2J" // Clear the whole screen return "\033[2J" // Clear the whole screen
@ -121,6 +55,20 @@ class AnsiScreen extends Screen
. "\033[1S"; // Scroll whole page up by 1 line (why?) . "\033[1S"; // Scroll whole page up by 1 line (why?)
} }
public function underline($text)
{
return "\033[4m"
. $text
. "\033[0m"; // Reset color codes
}
public function colorize($text, $fgColor = null, $bgColor = null)
{
return $this->startColor($fgColor, $bgColor)
. $text
. "\033[0m"; // Reset color codes
}
protected function fgColor($color) protected function fgColor($color)
{ {
if (! array_key_exists($color, $this->fgColors)) { if (! array_key_exists($color, $this->fgColors)) {
@ -163,18 +111,4 @@ class AnsiScreen extends Screen
} }
return "\033[" . implode(';', $parts) . 'm'; return "\033[" . implode(';', $parts) . 'm';
} }
public function underline($text)
{
return "\033[4m"
. $text
. "\033[0m"; // Reset color codes
}
public function colorize($text, $fgColor = null, $bgColor = null)
{
return $this->startColor($fgColor, $bgColor)
. $text
. "\033[0m"; // Reset color codes
}
} }

View File

@ -2,16 +2,102 @@
namespace Icinga\Cli; namespace Icinga\Cli;
use Icinga\Cli\Screen\AnsiScreen; use Icinga\Cli\AnsiScreen;
class Screen class Screen
{ {
protected static $instance; protected static $instance;
protected $isUtf8;
public function getColumns()
{
$cols = (int) getenv('COLUMNS');
if (! $cols) {
// stty -a ?
$cols = (int) exec('tput cols');
}
if (! $cols) {
$cols = 80;
}
return $cols;
}
public function getRows()
{
$rows = (int) getenv('ROWS');
if (! $rows) {
// stty -a ?
$rows = (int) exec('tput rows');
}
if (! $rows) {
$rows = 25;
}
return $rows;
}
public function strlen($string)
{
return strlen($string);
}
public function newlines($count = 1)
{
return str_repeat("\n", $count);
}
public function center($txt)
{
$len = $this->strlen($txt);
$width = floor(($this->getColumns() + $len) / 2) - $len;
return str_repeat(' ', $width) . $txt;
}
public function hasUtf8()
{
if ($this->isUtf8 === null) {
// null should equal 0 here, however seems to equal '' on some systems:
$current = setlocale(LC_ALL, 0);
$parts = preg_split('/;/', $current);
$lc_parts = array();
foreach ($parts as $part) {
if (strpos($part, '=') === false) {
continue;
}
list($key, $val) = preg_split('/=/', $part, 2);
$lc_parts[$key] = $val;
}
$this->isUtf8 = array_key_exists('LC_CTYPE', $lc_parts)
&& preg_match('~\.UTF-8$~i', $lc_parts['LC_CTYPE']);
}
return $this->isUtf8;
}
public function clear()
{
return "\n";
}
public function underline($text)
{
return $text;
}
public function colorize($text, $fgColor = null, $bgColor = null)
{
return $text;
}
public static function instance() public static function instance()
{ {
if (self::$instance === null) { if (self::$instance === null) {
if (function_exists('posix_isatty') && posix_isatty(STDOUT)) {
self::$instance = new AnsiScreen(); self::$instance = new AnsiScreen();
} else {
self::$instance = new Screen();
}
} }
return self::$instance; return self::$instance;
} }

View File

@ -29,14 +29,13 @@
namespace Icinga\Config; namespace Icinga\Config;
use \Zend_Config; use Zend_Config;
use \Zend_Config_Ini; use Zend_Config_Ini;
use \Zend_Config_Writer_FileAbstract; use Zend_Config_Writer_FileAbstract;
use \Icinga\Config\IniEditor; use Icinga\Config\IniEditor;
/** /**
* A ini file adapter that respects the file structure and the comments of already * A ini file adapter that respects the file structure and the comments of already existing ini files
* existing ini files
*/ */
class PreservingIniWriter extends Zend_Config_Writer_FileAbstract class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
{ {
@ -45,7 +44,7 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
* *
* @var array * @var array
*/ */
private $options; protected $options;
/** /**
* Create a new PreservingIniWriter * Create a new PreservingIniWriter
@ -91,7 +90,7 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
* @param IniEditor $editor The editor that should be used to edit the old config file * @param IniEditor $editor The editor that should be used to edit the old config file
* @param array $parents The parent keys that should be respected when editing the config * @param array $parents The parent keys that should be respected when editing the config
*/ */
private function diffConfigs( protected function diffConfigs(
Zend_Config $oldconfig, Zend_Config $oldconfig,
Zend_Config $newconfig, Zend_Config $newconfig,
IniEditor $editor, IniEditor $editor,
@ -102,13 +101,10 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
} }
/** /**
* Update the order of the sections in the ini file to match * Update the order of the sections in the ini file to match the order of the new config
* the order of the new config
*/ */
private function updateSectionOrder( protected function updateSectionOrder(Zend_Config $newconfig, IniEditor $editor)
Zend_Config $newconfig, {
IniEditor $editor
) {
$order = array(); $order = array();
foreach ($newconfig as $key => $value) { foreach ($newconfig as $key => $value) {
if ($value instanceof Zend_Config) { if ($value instanceof Zend_Config) {
@ -126,48 +122,33 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
* @param IniEditor $editor The editor that should be used to edit the old config file * @param IniEditor $editor The editor that should be used to edit the old config file
* @param array $parents The parent keys that should be respected when editing the config * @param array $parents The parent keys that should be respected when editing the config
*/ */
private function diffPropertyUpdates( protected function diffPropertyUpdates(
Zend_Config $oldconfig, Zend_Config $oldconfig,
Zend_Config $newconfig, Zend_Config $newconfig,
IniEditor $editor, IniEditor $editor,
array $parents = array() array $parents = array()
) { ) {
/* // The current section. This value is null when processing the section-less root element
* The current section. This value is null when processing
* the section-less root element
*/
$section = empty($parents) ? null : $parents[0]; $section = empty($parents) ? null : $parents[0];
// Iterate over all properties in the new configuration file and search for changes
/*
* Iterate over all properties in the new configuration file and search for changes
*/
foreach ($newconfig as $key => $value) { foreach ($newconfig as $key => $value) {
$oldvalue = $oldconfig->get($key); $oldvalue = $oldconfig->get($key);
$nextParents = array_merge($parents, array($key)); $nextParents = array_merge($parents, array($key));
$keyIdentifier = empty($parents) ? $keyIdentifier = empty($parents) ? array($key) : array_slice($nextParents, 1, null, true);
array($key) : array_slice($nextParents, 1, null, true);
if ($value instanceof Zend_Config) { if ($value instanceof Zend_Config) {
/* // The value is a nested Zend_Config, handle it recursively
* The value is a nested Zend_Config, handle it recursively if ($section === null) {
*/ // Update the section declaration
if (!isset($section)) {
/*
* Update the section declaration
*/
$extends = $newconfig->getExtends(); $extends = $newconfig->getExtends();
$extend = array_key_exists($key, $extends) ? $extend = array_key_exists($key, $extends) ? $extends[$key] : null;
$extends[$key] : null;
$editor->setSection($key, $extend); $editor->setSection($key, $extend);
} }
if (!isset($oldvalue)) { if ($oldvalue === null) {
$oldvalue = new Zend_Config(array()); $oldvalue = new Zend_Config(array());
} }
$this->diffConfigs($oldvalue, $value, $editor, $nextParents); $this->diffConfigs($oldvalue, $value, $editor, $nextParents);
} else { } else {
/* // The value is a plain value, use the editor to set it
* The value is a plain value, use the editor to set it
*/
if (is_numeric($key)) { if (is_numeric($key)) {
$editor->setArrayElement($keyIdentifier, $value, $section); $editor->setArrayElement($keyIdentifier, $value, $section);
} else { } else {
@ -185,43 +166,35 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
* @param IniEditor $editor The editor that should be used to edit the old config file * @param IniEditor $editor The editor that should be used to edit the old config file
* @param array $parents The parent keys that should be respected when editing the config * @param array $parents The parent keys that should be respected when editing the config
*/ */
private function diffPropertyDeletions( protected function diffPropertyDeletions(
Zend_Config $oldconfig, Zend_Config $oldconfig,
Zend_Config $newconfig, Zend_Config $newconfig,
IniEditor $editor, IniEditor $editor,
array $parents = array() array $parents = array()
) { ) {
/* // The current section. This value is null when processing the section-less root element
* The current section. This value is null when processing
* the section-less root element
*/
$section = empty($parents) ? null : $parents[0]; $section = empty($parents) ? null : $parents[0];
/* // Iterate over all properties in the old configuration file and search for deleted properties
* Iterate over all properties in the old configuration file and search for
* deleted properties
*/
foreach ($oldconfig as $key => $value) { foreach ($oldconfig as $key => $value) {
$nextParents = array_merge($parents, array($key)); $nextParents = array_merge($parents, array($key));
$newvalue = $newconfig->get($key); $newvalue = $newconfig->get($key);
$keyIdentifier = empty($parents) ? $keyIdentifier = empty($parents) ? array($key) : array_slice($nextParents, 1, null, true);
array($key) : array_slice($nextParents, 1, null, true);
if (!isset($newvalue)) { if ($newvalue === null) {
if ($value instanceof Zend_Config) { if ($value instanceof Zend_Config) {
/* // The deleted value is a nested Zend_Config, handle it recursively
* The deleted value is a nested Zend_Config, handle it recursively
*/
$this->diffConfigs($value, new Zend_Config(array()), $editor, $nextParents); $this->diffConfigs($value, new Zend_Config(array()), $editor, $nextParents);
if (!isset($section)) { if ($section === null) {
$editor->removeSection($key); $editor->removeSection($key);
} }
} else { } else {
/* // The deleted value is a plain value, use the editor to delete it
* The deleted value is a plain value, use the editor to delete it
*/
if (is_numeric($key)) { if (is_numeric($key)) {
$editor->resetArrayElement($keyIdentifier, $section); $editor->resetArrayElement($keyIdentifier, $section);
} elseif (!empty($parents)) {
// Drop nested properties, fixes #5958
$editor->resetArrayElement($nextParents, $section);
} else { } else {
$editor->reset($keyIdentifier, $section); $editor->reset($keyIdentifier, $section);
} }

View File

@ -143,8 +143,18 @@ class ResourceFactory implements ConfigAwareFactory
return $resource; return $resource;
} }
public static function getBackendType($resource) public static function ldapAvailable()
{ {
return extension_loaded('ldap');
}
public static function pgsqlAvailable()
{
return extension_loaded('pgsql');
}
public static function mysqlAvailable()
{
return extension_loaded('mysql');
} }
} }

View File

@ -1,4 +1,6 @@
<?php <?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\File; namespace Icinga\File;
@ -10,6 +12,7 @@ class Csv
protected function __construct() protected function __construct()
{ {
} }
public static function fromQuery(BaseQuery $query) public static function fromQuery(BaseQuery $query)
@ -40,6 +43,7 @@ class Csv
} }
$csv .= implode(',', $out) . "\r\n"; $csv .= implode(',', $out) . "\r\n";
} }
return $csv; return $csv;
} }
} }

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
namespace Icinga\File; namespace Icinga\File;
@ -215,3 +216,4 @@ class Pdf extends DOMPDF
// } // }
} }
// @codeCoverageIgnoreEnd

View File

@ -4,7 +4,7 @@
namespace Icinga\Logger; namespace Icinga\Logger;
use \Zend_Config; use Zend_Config;
/** /**
* Abstract class for writers that write messages to a log * Abstract class for writers that write messages to a log

View File

@ -4,8 +4,8 @@
namespace Icinga\Logger; namespace Icinga\Logger;
use \Exception; use Exception;
use \Zend_Config; use Zend_Config;
use Icinga\Exception\ConfigurationError; use Icinga\Exception\ConfigurationError;
/** /**

View File

@ -4,30 +4,31 @@
namespace Icinga\Logger\Writer; namespace Icinga\Logger\Writer;
use \Zend_Config; use Exception;
use Zend_Config;
use Icinga\Logger\Logger; use Icinga\Logger\Logger;
use Icinga\Logger\LogWriter; use Icinga\Logger\LogWriter;
use Icinga\Application\Config; use Icinga\Application\Config;
use Icinga\Exception\ConfigurationError; use Icinga\Exception\ConfigurationError;
/** /**
* Class to write log messages to a stream * Class to write log messages to a file
*/ */
class StreamWriter extends LogWriter class FileWriter extends LogWriter
{ {
/** /**
* The path to the stream * The path to the file
* *
* @var string * @var string
*/ */
protected $stream; protected $path;
/** /**
* Create a new log writer initialized with the given configuration * Create a new log writer initialized with the given configuration
*/ */
public function __construct(Zend_Config $config) public function __construct(Zend_Config $config)
{ {
$this->stream = Config::resolvePath($config->target); $this->path = Config::resolvePath($config->target);
$this->setup(); $this->setup();
} }
@ -43,17 +44,17 @@ class StreamWriter extends LogWriter
} }
/** /**
* Create the stream if it does not already exist * Create the file if it does not already exist
*/ */
protected function setup() protected function setup()
{ {
if (substr($this->stream, 0, 6) !== 'php://') { if (substr($this->path, 0, 6) !== 'php://') {
if (!file_exists($this->stream) && (!@touch($this->stream) || !@chmod($this->stream, 0664))) { if (!file_exists($this->path) && (!@touch($this->path) || !@chmod($this->path, 0664))) {
throw new ConfigurationError('Cannot create log file "' . $this->stream . '"'); throw new ConfigurationError('Cannot create log file "' . $this->path . '"');
} }
if (!@is_writable($this->stream)) { if (!@is_writable($this->path)) {
throw new ConfigurationError('Cannot write to log file "' . $this->stream . '"'); throw new ConfigurationError('Cannot write to log file "' . $this->path . '"');
} }
} }
} }
@ -84,14 +85,20 @@ class StreamWriter extends LogWriter
} }
/** /**
* Write a message to the stream * Write a message to the path
* *
* @param string $text The message to write * @param string $text The message to write
*
* @throws Exception In case write acess to the path failed
*/ */
protected function write($text) protected function write($text)
{ {
$fd = fopen($this->stream, 'a'); $fd = fopen($this->path, 'a');
fwrite($fd, $text . PHP_EOL);
if ($fd === false || fwrite($fd, $text . PHP_EOL) === false) {
throw new Exception('Failed to write to log file "' . $this->path . '"');
}
fclose($fd); fclose($fd);
} }
} }

View File

@ -1,11 +1,12 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Logger\Writer; namespace Icinga\Logger\Writer;
use \Exception; use Exception;
use \Zend_Config; use Zend_Config;
use Icinga\Logger\Logger; use Icinga\Logger\Logger;
use Icinga\Logger\LogWriter; use Icinga\Logger\LogWriter;
use Icinga\Exception\ConfigurationError; use Icinga\Exception\ConfigurationError;
@ -106,3 +107,4 @@ class SyslogWriter extends LogWriter
closelog(); closelog();
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -30,6 +30,7 @@
namespace Icinga\Protocol\Commandpipe\Transport; namespace Icinga\Protocol\Commandpipe\Transport;
use Icinga\Logger\Logger; use Icinga\Logger\Logger;
use Icinga\Exception\ConfigurationError;
/** /**
* CommandPipe Transport class that writes to a file accessible by the filesystem * CommandPipe Transport class that writes to a file accessible by the filesystem
@ -66,7 +67,7 @@ class LocalPipe implements Transport
Logger::debug('Attempting to send external icinga command %s to local command file ', $message, $this->path); Logger::debug('Attempting to send external icinga command %s to local command file ', $message, $this->path);
$file = @fopen($this->path, $this->openMode); $file = @fopen($this->path, $this->openMode);
if (!$file) { if (!$file) {
throw new \RuntimeException('Could not open icinga pipe at $file : ' . print_r(error_get_last(), true)); throw new ConfigurationError(sprintf('Could not open icinga command pipe at "%s"', $this->path));
} }
fwrite($file, '[' . time() . '] ' . $message . PHP_EOL); fwrite($file, '[' . time() . '] ' . $message . PHP_EOL);
Logger::debug('Writing [' . time() . '] ' . $message . PHP_EOL); Logger::debug('Writing [' . time() . '] ' . $message . PHP_EOL);

View File

@ -184,13 +184,16 @@ class Reader implements DatasourceInterface
$PHP_EOL_len = strlen(PHP_EOL); $PHP_EOL_len = strlen(PHP_EOL);
$lines = array(); $lines = array();
$s = ''; $s = '';
$f = fopen($this->filename, 'rb'); $f = @fopen($this->filename, 'rb');
if ($f !== false) {
$buffer = '';
fseek($f, 0, SEEK_END); fseek($f, 0, SEEK_END);
$pos = ftell($f); if (ftell($f) === 0) {
return array();
}
while ($read_lines === null || count($lines) < $read_lines) { while ($read_lines === null || count($lines) < $read_lines) {
fseek($f, --$pos); $c = $this->fgetc($f, $buffer);
$c = fgetc($f); if ($c === false) {
if ($c === false || $pos < 0) {
$l = $this->validateLine($s, $query); $l = $this->validateLine($s, $query);
if (!($l === false || $skip_lines)) { if (!($l === false || $skip_lines)) {
$lines[] = $l; $lines[] = $l;
@ -210,9 +213,38 @@ class Reader implements DatasourceInterface
$s = ''; $s = '';
} }
} }
}
return $lines; return $lines;
} }
/**
* Backend for $this->readFromEnd
*/
public function fgetc($file, &$buffer)
{
$strlen = strlen($buffer);
if ($strlen === 0) {
$pos = ftell($file);
if ($pos === 0) {
return false;
}
if ($pos < 4096) {
fseek($file, 0);
$buffer = fread($file, $pos);
fseek($file, 0);
} else {
fseek($file, -4096, SEEK_CUR);
$buffer = fread($file, 4096);
fseek($file, -4096, SEEK_CUR);
}
return $this->fgetc($file, $buffer);
} else {
$char = substr($buffer, -1);
$buffer = substr($buffer, 0, $strlen - 1);
return $char;
}
}
/** /**
* Backend for $this->read * Backend for $this->read
* Direction: FIFO * Direction: FIFO
@ -222,17 +254,22 @@ class Reader implements DatasourceInterface
$PHP_EOL_len = strlen(PHP_EOL); $PHP_EOL_len = strlen(PHP_EOL);
$lines = array(); $lines = array();
$s = ''; $s = '';
$f = fopen($this->filename, 'rb'); $f = @fopen($this->filename, 'rb');
if ($f !== false) {
$buffer = '';
while ($read_lines === null || count($lines) < $read_lines) { while ($read_lines === null || count($lines) < $read_lines) {
$c = fgetc($f); if (strlen($buffer) === 0) {
if ($c === false) { $buffer = fread($f, 4096);
if (strlen($buffer) === 0) {
$l = $this->validateLine($s, $query); $l = $this->validateLine($s, $query);
if (!($l === false || $skip_lines)) { if (!($l === false || $skip_lines)) {
$lines[] = $l; $lines[] = $l;
} }
break; break;
} }
$s .= $c; }
$s .= substr($buffer, 0, 1);
$buffer = substr($buffer, 1);
if (strpos($s, PHP_EOL) !== false) { if (strpos($s, PHP_EOL) !== false) {
$l = $this->validateLine((string)substr($s, 0, strlen($s) - $PHP_EOL_len), $query); $l = $this->validateLine((string)substr($s, 0, strlen($s) - $PHP_EOL_len), $query);
if ($l !== false) { if ($l !== false) {
@ -245,6 +282,7 @@ class Reader implements DatasourceInterface
$s = ''; $s = '';
} }
} }
}
return $lines; return $lines;
} }
@ -259,26 +297,29 @@ class Reader implements DatasourceInterface
$PHP_EOL_len = strlen(PHP_EOL); $PHP_EOL_len = strlen(PHP_EOL);
$lines = 0; $lines = 0;
$s = ''; $s = '';
$f = fopen($this->filename, 'rb'); $f = @fopen($this->filename, 'rb');
fseek($f, 0, SEEK_END); if ($f !== false) {
$pos = ftell($f); $buffer = '';
while (true) { while (true) {
fseek($f, --$pos); if (strlen($buffer) === 0) {
$c = fgetc($f); $buffer = fread($f, 4096);
if ($c === false || $pos < 0) { if (strlen($buffer) === 0) {
if ($this->validateLine($s, $query) !== false) { if ($this->validateLine($s, $query) !== false) {
$lines++; $lines++;
} }
break; break;
} }
$s = $c . $s; }
if (strpos($s, PHP_EOL) === 0) { $s .= substr($buffer, 0, 1);
if ($this->validateLine((string)substr($s, $PHP_EOL_len), $query) !== false) { $buffer = substr($buffer, 1);
if (strpos($s, PHP_EOL) !== false) {
if ($this->validateLine((string)substr($s, 0, strlen($s) - $PHP_EOL_len), $query) !== false) {
$lines++; $lines++;
} }
$s = ''; $s = '';
} }
} }
}
return $lines; return $lines;
} }
} }

View File

@ -273,6 +273,15 @@ class Connection
} }
} }
public function connect()
{
if (!$this->connection) {
$this->getConnection();
}
return $this;
}
public function disconnect() public function disconnect()
{ {
if ($this->connection) { if ($this->connection) {

View File

@ -1,30 +1,5 @@
<?php <?php
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2013 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 2013 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>
*
*/
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
namespace { namespace {
@ -46,28 +21,24 @@ namespace {
namespace Icinga\Test { namespace Icinga\Test {
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php'; use Exception;
require_once 'Zend/Db/Adapter/Pdo/Abstract.php'; use RuntimeException;
require_once 'DbTest.php'; use Mockery;
require_once 'FormTest.php';
// @codingStandardsIgnoreStart
use \Exception;
use \RuntimeException;
use Zend_Test_PHPUnit_ControllerTestCase;
use Zend_Config; use Zend_Config;
use Zend_Db_Adapter_Pdo_Abstract; use Zend_Controller_Request_Abstract;
use Zend_Db_Adapter_Pdo_Mysql; use Zend_Controller_Request_HttpTestCase;
use Zend_Db_Adapter_Pdo_Pgsql; use PHPUnit_Framework_TestCase;
use Zend_Db_Adapter_Pdo_Oci; use Icinga\Application\Icinga;
use Icinga\Util\DateTimeFactory;
use Icinga\Data\ResourceFactory; use Icinga\Data\ResourceFactory;
use Icinga\Data\Db\Connection;
use Icinga\User\Preferences; use Icinga\User\Preferences;
use Icinga\Web\Form; use Icinga\Web\Form;
// @codingStandardsIgnoreEnd
/** /**
* Class BaseTestCase * Class BaseTestCase
*/ */
class BaseTestCase extends Zend_Test_PHPUnit_ControllerTestCase implements DbTest, FormTest class BaseTestCase extends PHPUnit_Framework_TestCase implements DbTest, FormTest
{ {
/** /**
* Path to application/ * Path to application/
@ -111,12 +82,19 @@ namespace Icinga\Test {
*/ */
public static $moduleDir; public static $moduleDir;
/**
* Store request for form tests
*
* @var Zend_Controller_Request_HttpTestCase
*/
private $request;
/** /**
* Resource configuration for different database types * Resource configuration for different database types
* *
* @var array * @var array
*/ */
private static $dbConfiguration = array( protected static $dbConfiguration = array(
'mysql' => array( 'mysql' => array(
'type' => 'db', 'type' => 'db',
'db' => 'mysql', 'db' => 'mysql',
@ -138,17 +116,12 @@ namespace Icinga\Test {
); );
/** /**
* Constructs a test case with the given name. * Setup the default timezone and pass it to DateTimeFactory::setConfig
*
* @param string $name
* @param array $data
* @param string $dataName
* @see PHPUnit_Framework_TestCase::__construct
*/ */
public function __construct($name = null, array $data = array(), $dataName = '') public static function setupTimezone()
{ {
parent::__construct($name, $data, $dataName);
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
DateTimeFactory::setConfig(array('timezone' => 'UTC'));
} }
/** /**
@ -158,12 +131,6 @@ namespace Icinga\Test {
*/ */
public static function setupDirectories() public static function setupDirectories()
{ {
static $initialized = false;
if ($initialized === true) {
return;
}
$baseDir = realpath(__DIR__ . '/../../../'); $baseDir = realpath(__DIR__ . '/../../../');
if ($baseDir === false) { if ($baseDir === false) {
@ -176,8 +143,36 @@ namespace Icinga\Test {
self::$testDir = $baseDir . '/test/php'; self::$testDir = $baseDir . '/test/php';
self::$shareDir = $baseDir . '/share/icinga2-web'; self::$shareDir = $baseDir . '/share/icinga2-web';
self::$moduleDir = $baseDir . '/modules'; self::$moduleDir = $baseDir . '/modules';
}
$initialized = true; /**
* Setup MVC bootstrapping and ensure that the Icinga-Mock gets reinitialized
*/
public function setUp()
{
parent::setUp();
$requestMock = Mockery::mock('Icinga\Web\Request');
$requestMock->shouldReceive('getPathInfo')->andReturn('')
->shouldReceive('getBaseUrl')->andReturn('/')
->shouldReceive('getQuery')->andReturn(array());
$this->setupIcingaMock($requestMock);
}
/**
* Setup mock object for the application's bootstrap
*
* @param Zend_Controller_Request_Abstract $request The request to be returned by
* Icinga::app()->getFrontController()->getRequest()
*/
protected function setupIcingaMock(Zend_Controller_Request_Abstract $request)
{
$bootstrapMock = Mockery::mock('Icinga\Application\ApplicationBootstrap')->shouldDeferMissing();
$bootstrapMock->shouldReceive('getFrontController->getRequest')->andReturnUsing(
function () use ($request) { return $request; }
)->shouldReceive('getApplicationDir')->andReturn(self::$appDir);
Icinga::setApp($bootstrapMock, true);
} }
/** /**
@ -188,7 +183,7 @@ namespace Icinga\Test {
* @return Zend_Config * @return Zend_Config
* @throws RuntimeException * @throws RuntimeException
*/ */
private function createDbConfigFor($name) protected function createDbConfigFor($name)
{ {
if (array_key_exists($name, self::$dbConfiguration)) { if (array_key_exists($name, self::$dbConfiguration)) {
return new Zend_Config(self::$dbConfiguration[$name]); return new Zend_Config(self::$dbConfiguration[$name]);
@ -198,67 +193,64 @@ namespace Icinga\Test {
} }
/** /**
* Creates an array of Zend Database Adapter * Creates an array of Icinga\Data\Db\Connection
* *
* @param string $name * @param string $name
* *
* @return array * @return array
*/ */
private function createDbAdapterFor($name) protected function createDbConnectionFor($name)
{ {
$this->requireDbLibraries();
try { try {
$adapter = ResourceFactory::createResource($this->createDbConfigFor($name))->getConnection(); $conn = ResourceFactory::createResource($this->createDbConfigFor($name));
} catch (Exception $e) { } catch (Exception $e) {
$adapter = $e->getMessage(); $conn = $e->getMessage();
} }
return array( return array(
array($adapter) array($conn)
); );
} }
/** /**
* PHPUnit provider for mysql * PHPUnit provider for mysql
* *
* @return Zend_Db_Adapter_Pdo_Mysql * @return Connection
*/ */
public function mysqlDb() public function mysqlDb()
{ {
return $this->createDbAdapterFor('mysql'); return $this->createDbConnectionFor('mysql');
} }
/** /**
* PHPUnit provider for pgsql * PHPUnit provider for pgsql
* *
* @return Zend_Db_Adapter_Pdo_Pgsql * @return Connection
*/ */
public function pgsqlDb() public function pgsqlDb()
{ {
return $this->createDbAdapterFor('pgsql'); return $this->createDbConnectionFor('pgsql');
} }
/** /**
* PHPUnit provider for oracle * PHPUnit provider for oracle
* *
* @return Zend_Db_Adapter_Pdo_Oci * @return Connection
*/ */
public function oracleDb() public function oracleDb()
{ {
return $this->createDbAdapterFor('oracle'); return $this->createDbConnectionFor('oracle');
} }
/** /**
* Executes sql file on PDO object * Executes sql file by using the database connection
* *
* @param Zend_Db_Adapter_Pdo_Abstract $resource * @param Connection $resource
* @param string $filename * @param string $filename
* *
* @return boolean Operational success flag
* @throws RuntimeException * @throws RuntimeException
*/ */
public function loadSql(Zend_Db_Adapter_Pdo_Abstract $resource, $filename) public function loadSql(Connection $resource, $filename)
{ {
if (!is_file($filename)) { if (!is_file($filename)) {
throw new RuntimeException( throw new RuntimeException(
@ -274,17 +266,17 @@ namespace Icinga\Test {
); );
} }
$resource->exec($sqlData); $resource->getConnection()->exec($sqlData);
} }
/** /**
* Setup provider for testcase * Setup provider for testcase
* *
* @param string|Zend_Db_Adapter_PDO_Abstract|null $resource * @param string|Connection|null $resource
*/ */
public function setupDbProvider($resource) public function setupDbProvider($resource)
{ {
if (!$resource instanceof Zend_Db_Adapter_Pdo_Abstract) { if (!$resource instanceof Connection) {
if (is_string($resource)) { if (is_string($resource)) {
$this->markTestSkipped('Could not initialize provider: ' . $resource); $this->markTestSkipped('Could not initialize provider: ' . $resource);
} else { } else {
@ -293,15 +285,17 @@ namespace Icinga\Test {
return; return;
} }
$adapter = $resource->getConnection();
try { try {
$resource->getConnection(); $adapter->getConnection();
} catch (Exception $e) { } catch (Exception $e) {
$this->markTestSkipped('Could not connect to provider: '. $e->getMessage()); $this->markTestSkipped('Could not connect to provider: '. $e->getMessage());
} }
$tables = $resource->listTables(); $tables = $adapter->listTables();
foreach ($tables as $table) { foreach ($tables as $table) {
$resource->exec('DROP TABLE ' . $table . ';'); $adapter->exec('DROP TABLE ' . $table . ';');
} }
} }
@ -341,57 +335,22 @@ namespace Icinga\Test {
} }
/** /**
* Require all libraries to instantiate forms * Retrieve test case request object
*
* This is a mock methods borrowed from Zend Controller Test Case to handle form tests properly (#6106)
*
* @return Zend_Controller_Request_HttpTestCase
*/ */
public static function requireFormLibraries() public function getRequest()
{ {
require_once 'Zend/Form/Decorator/Abstract.php'; if (null === $this->request) {
require_once 'Zend/Validate/Abstract.php'; require_once 'Zend/Controller/Request/HttpTestCase.php';
require_once 'Zend/Form/Element/Xhtml.php'; $this->request = new Zend_Controller_Request_HttpTestCase;
require_once 'Zend/Form/Element/Text.php';
require_once 'Zend/Form/Element/Submit.php';
require_once 'Zend/Form/Element/Checkbox.php';
require_once 'Zend/Form.php';
require_once 'Zend/View.php';
require_once self::$libDir . '/Web/Form/InvalidCSRFTokenException.php';
require_once self::$libDir . '/Web/Form/Element/DateTimePicker.php';
require_once self::$libDir . '/Web/Form/Element/Note.php';
require_once self::$libDir . '/Web/Form/Element/Number.php';
require_once self::$libDir . '/Web/Form/Decorator/ConditionalHidden.php';
require_once self::$libDir . '/Web/Form/Decorator/HelpText.php';
require_once self::$libDir . '/Web/Form/Decorator/BootstrapForm.php';
require_once self::$libDir . '/Web/Form/Validator/DateFormatValidator.php';
require_once self::$libDir . '/Web/Form/Validator/TimeFormatValidator.php';
require_once self::$libDir . '/Web/Form/Validator/WritablePathValidator.php';
require_once self::$libDir . '/Web/Form.php';
require_once self::$libDir . '/User/Preferences.php';
} }
return $this->request;
/**
* Require all classes for database adapter creation
*/
public static function requireDbLibraries()
{
require_once 'Zend/Config.php';
require_once 'Zend/Db.php';
require_once 'Zend/Log.php';
require_once self::$libDir . '/Exception/ConfigurationError.php';
require_once self::$libDir . '/Util/ConfigAwareFactory.php';
require_once self::$libDir . '/Data/DatasourceInterface.php';
require_once self::$libDir . '/Data/ResourceFactory.php';
require_once self::$libDir . '/Data/Db/Connection.php';
require_once self::$libDir . '/Application/Logger.php';
} }
} }
BaseTestCase::setupTimezone();
BaseTestCase::setupDirectories(); BaseTestCase::setupDirectories();
BaseTestCase::requireFormLibraries();
BaseTestcase::requireDbLibraries();
} }

View File

@ -29,48 +29,45 @@
namespace Icinga\Test; namespace Icinga\Test;
use \Zend_Db_Adapter_Pdo_Abstract; use Icinga\Data\Db\Connection;
use \Zend_Db_Adapter_Pdo_Mysql;
use \Zend_Db_Adapter_Pdo_Pgsql;
use \Zend_Db_Adapter_Pdo_Oci;
interface DbTest interface DbTest
{ {
/** /**
* PHPUnit provider for mysql * PHPUnit provider for mysql
* *
* @return Zend_Db_Adapter_Pdo_Mysql * @return Connection
*/ */
public function mysqlDb(); public function mysqlDb();
/** /**
* PHPUnit provider for pgsql * PHPUnit provider for pgsql
* *
* @return Zend_Db_Adapter_Pdo_Pgsql * @return Connection
*/ */
public function pgsqlDb(); public function pgsqlDb();
/** /**
* PHPUnit provider for oracle * PHPUnit provider for oracle
* *
* @return Zend_Db_Adapter_Pdo_Oci * @return Connection
*/ */
public function oracleDb(); public function oracleDb();
/** /**
* Executes sql file on PDO object * Executes sql file on PDO object
* *
* @param Zend_Db_Adapter_PDO_Abstract $resource * @param Connection $resource
* @param string $filename * @param string $filename
* *
* @return boolean Operational success flag * @return boolean Operational success flag
*/ */
public function loadSql(Zend_Db_Adapter_PDO_Abstract $resource, $filename); public function loadSql(Connection $resource, $filename);
/** /**
* Setup provider for testcase * Setup provider for testcase
* *
* @param string|Zend_Db_Adapter_PDO_Abstract|null $resource * @param string|Connection|null $resource
*/ */
public function setupDbProvider($resource); public function setupDbProvider($resource);
} }

View File

@ -29,18 +29,15 @@
namespace Icinga; namespace Icinga;
use \DateTimeZone; use DateTimeZone;
use \Exception; use InvalidArgumentException;
use \InvalidArgumentException;
use Icinga\User\Preferences; use Icinga\User\Preferences;
use Icinga\User\Message; use Icinga\User\Message;
use Icinga\Application\Config;
/** /**
* This class represents an authorized user * This class represents an authorized user
* *
* You can retrieve authorization information (@TODO: Not implemented yet) or * You can retrieve authorization information (@TODO: Not implemented yet) or user information
* to retrieve user information
*/ */
class User class User
{ {
@ -49,77 +46,77 @@ class User
* *
* @var string * @var string
*/ */
private $username; protected $username;
/** /**
* Firstname * Firstname
* *
* @var string * @var string
*/ */
private $firstname; protected $firstname;
/** /**
* Lastname * Lastname
* *
* @var string * @var string
*/ */
private $lastname; protected $lastname;
/** /**
* Users email address * Users email address
* *
* @var string * @var string
*/ */
private $email; protected $email;
/** /**
* Domain * Domain
* *
* @var string * @var string
*/ */
private $domain; protected $domain;
/** /**
* More information about user * More information about this user
* *
* @var array * @var array
*/ */
private $additionalInformation = array(); protected $additionalInformation = array();
/** /**
* Set of permissions * Set of permissions
* *
* @var array * @var array
*/ */
private $permissions = array(); protected $permissions = array();
/** /**
* Set of restrictions * Set of restrictions
* *
* @var array * @var array
*/ */
private $restrictions = array(); protected $restrictions = array();
/** /**
* Groups for this user * Groups for this user
* *
* @var array * @var array
*/ */
private $groups = array(); protected $groups = array();
/** /**
* Preferences object * Preferences object
* *
* @var Preferences * @var Preferences
*/ */
private $preferences; protected $preferences;
/** /**
* Queued notifications for this user. * Queued notifications for this user.
* *
* @var array() * @var array()
*/ */
private $messages; protected $messages;
/** /**
* Creates a user object given the provided information * Creates a user object given the provided information
@ -166,6 +163,7 @@ class User
if ($this->preferences === null) { if ($this->preferences === null) {
$this->preferences = new Preferences(); $this->preferences = new Preferences();
} }
return $this->preferences; return $this->preferences;
} }
@ -181,6 +179,8 @@ class User
/** /**
* Set the groups this user belongs to * Set the groups this user belongs to
*
* @param array $groups
*/ */
public function setGroups(array $groups) public function setGroups(array $groups)
{ {
@ -191,6 +191,7 @@ class User
* Return true if the user is a member of this group * Return true if the user is a member of this group
* *
* @param string $group * @param string $group
*
* @return boolean * @return boolean
*/ */
public function isMemberOf($group) public function isMemberOf($group)
@ -201,7 +202,7 @@ class User
/** /**
* Return permission information for this user * Return permission information for this user
* *
* @return Array * @return array
*/ */
public function getPermissions() public function getPermissions()
{ {
@ -222,6 +223,7 @@ class User
* Return restriction information for this user * Return restriction information for this user
* *
* @param string $name * @param string $name
*
* @return array * @return array
*/ */
public function getRestrictions($name) public function getRestrictions($name)
@ -229,6 +231,7 @@ class User
if (array_key_exists($name, $this->restrictions)) { if (array_key_exists($name, $this->restrictions)) {
return $this->restrictions[$name]; return $this->restrictions[$name];
} }
return array(); return array();
} }
@ -316,6 +319,7 @@ class User
* Setter for mail * Setter for mail
* *
* @param string $mail * @param string $mail
*
* @throws InvalidArgumentException When an invalid mail is provided * @throws InvalidArgumentException When an invalid mail is provided
*/ */
public function setEmail($mail) public function setEmail($mail)
@ -370,6 +374,7 @@ class User
if (isset($this->additionalInformation[$key])) { if (isset($this->additionalInformation[$key])) {
return $this->additionalInformation[$key]; return $this->additionalInformation[$key];
} }
return null; return null;
} }
@ -386,6 +391,7 @@ class User
if ($tz === null) { if ($tz === null) {
$tz = date_default_timezone_get(); $tz = date_default_timezone_get();
} }
return new DateTimeZone($tz); return new DateTimeZone($tz);
} }
@ -404,7 +410,7 @@ class User
/** /**
* Get all currently pending messages * Get all currently pending messages
* *
* @return array the messages * @return array The messages
*/ */
public function getMessages() public function getMessages()
{ {

View File

@ -1,8 +1,9 @@
<?php <?php
// @codeCoverageIgnoreStart
namespace Icinga\User; namespace Icinga\User;
use \Zend_Log; use Zend_Log;
/** /**
* Class Message * Class Message
@ -55,3 +56,4 @@ class Message
return $this->level; return $this->level;
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -44,8 +44,6 @@ use Countable;
* *
* $preferences = new Preferences(array('aPreference' => 'value')); // Start with initial preferences * $preferences = new Preferences(array('aPreference' => 'value')); // Start with initial preferences
* *
* $prefrences = $user->getPreferences(); // Retrieve preferences from a \Icinga\User instance
*
* $preferences->aNewPreference = 'value'; // Set a preference * $preferences->aNewPreference = 'value'; // Set a preference
* *
* unset($preferences->aPreference); // Unset a preference * unset($preferences->aPreference); // Unset a preference
@ -60,7 +58,7 @@ class Preferences implements Countable
* *
* @var array * @var array
*/ */
private $preferences = array(); protected $preferences = array();
/** /**
* Constructor * Constructor
@ -118,6 +116,7 @@ class Preferences implements Countable
if (array_key_exists($name, $this->preferences)) { if (array_key_exists($name, $this->preferences)) {
return $this->preferences[$name]; return $this->preferences[$name];
} }
return $default; return $default;
} }
@ -147,6 +146,7 @@ class Preferences implements Countable
* Determine if a preference is set and is not NULL * Determine if a preference is set and is not NULL
* *
* @param string $name Preference name * @param string $name Preference name
*
* @return bool * @return bool
*/ */
public function __isset($name) public function __isset($name)

View File

@ -4,8 +4,8 @@
namespace Icinga\User\Preferences\Store; namespace Icinga\User\Preferences\Store;
use \Exception; use Exception;
use \Zend_Db_Select; use Zend_Db_Select;
use Icinga\Exception\NotReadableError; use Icinga\Exception\NotReadableError;
use Icinga\Exception\NotWritableError; use Icinga\Exception\NotWritableError;
use Icinga\User\Preferences; use Icinga\User\Preferences;

View File

@ -4,7 +4,7 @@
namespace Icinga\User\Preferences\Store; namespace Icinga\User\Preferences\Store;
use \Zend_Config; use Zend_Config;
use Icinga\Util\File; use Icinga\Util\File;
use Icinga\Config\PreservingIniWriter; use Icinga\Config\PreservingIniWriter;
use Icinga\Exception\NotReadableError; use Icinga\Exception\NotReadableError;

View File

@ -29,8 +29,9 @@
namespace Icinga\Util; namespace Icinga\Util;
use \DateTime; use Exception;
use \DateTimeZone; use DateTime;
use DateTimeZone;
use Icinga\Util\ConfigAwareFactory; use Icinga\Util\ConfigAwareFactory;
use Icinga\Exception\ConfigurationError; use Icinga\Exception\ConfigurationError;
@ -41,35 +42,42 @@ class DateTimeFactory implements ConfigAwareFactory
{ {
/** /**
* Time zone used throughout DateTime object creation * Time zone used throughout DateTime object creation
*
* @var DateTimeZone * @var DateTimeZone
*/ */
private static $timeZone; protected static $timeZone;
/** /**
* Set the factory's config * Set the factory's config
* *
* Set the factory's time zone via key timezone in the given config array * Set the factory's time zone via key timezone in the given config array
* *
* @param array $config * @param array $config An array with key 'timezone'
* @throws \Icinga\Exception\ConfigurationError if the given config is not valid *
* @throws ConfigurationError if the given array misses the key 'timezone'
*/ */
public static function setConfig($config) public static function setConfig($config)
{ {
if (!array_key_exists('timezone', $config)) { try {
throw new ConfigurationError(t('"DateTimeFactory" expects a valid time zone to be set via "setConfig"')); $tz = new DateTimeZone(isset($config['timezone']) ? $config['timezone'] : '');
} catch (Exception $e) {
throw new ConfigurationError('"DateTimeFactory" expects a valid time zone be set via "setConfig"');
} }
self::$timeZone = $config['timezone'];
self::$timeZone = $tz;
} }
/** /**
* Return new DateTime object using the given format, time and set time zone * Return new DateTime object using the given format, time and set timezone
* *
* Wraps DateTime::createFromFormat() * Wraps DateTime::createFromFormat()
* *
* @param string $format * @param string $format
* @param string $time * @param string $time
* @param DateTimeZone $timeZone * @param DateTimeZone $timeZone
*
* @return DateTime * @return DateTime
*
* @see DateTime::createFromFormat() * @see DateTime::createFromFormat()
*/ */
public static function parse($time, $format, DateTimeZone $timeZone = null) public static function parse($time, $format, DateTimeZone $timeZone = null)
@ -84,46 +92,13 @@ class DateTimeFactory implements ConfigAwareFactory
* *
* @param string $time * @param string $time
* @param DateTimeZone $timeZone * @param DateTimeZone $timeZone
*
* @return DateTime * @return DateTime
*
* @see DateTime::__construct() * @see DateTime::__construct()
*/ */
public static function create($time = 'now', DateTimeZone $timeZone = null) public static function create($time = 'now', DateTimeZone $timeZone = null)
{ {
return new DateTime($time, $timeZone !== null ? $timeZone : self::$timeZone); return new DateTime($time, $timeZone !== null ? $timeZone : self::$timeZone);
} }
/**
* Return the amount of seconds based on the given month
*
* @param DateTime $dateTime The date and time to use
*
* @return int
*/
public static function getSecondsByMonth(DateTime $dateTime)
{
return (int) $dateTime->format('t') * 24 * 3600;
}
/**
* Return the amount of seconds based on the given year
*
* @param DateTime $dateTime The date and time to use
*
* @return int
*/
public static function getSecondsByYear(DateTime $dateTime)
{
return (self::isLeapYear($dateTime) ? 366 : 365) * 24 * 3600;
}
/**
* Return whether the given year is a leap year
*
* @param DateTime $dateTime The date and time to check
* @return bool
*/
public static function isLeapYear(DateTime $dateTime)
{
return $dateTime->format('L') == 1;
}
} }

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
@ -12,3 +13,4 @@ class File
chmod($filename, $mode); chmod($filename, $mode);
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -29,6 +29,7 @@
namespace Icinga\Util; namespace Icinga\Util;
use DateTime;
use Icinga\Exception\ProgrammingError; use Icinga\Exception\ProgrammingError;
class Format class Format
@ -49,6 +50,9 @@ class Format
); );
protected static $byteBase = array(1024, 1000); protected static $byteBase = array(1024, 1000);
protected static $secondPrefix = array('s', 'ms', 'µs', 'ns', 'ps', 'fs', 'as');
protected static $secondBase = 1000;
public static function getInstance() public static function getInstance()
{ {
if (self::$instance === null) { if (self::$instance === null) {
@ -75,6 +79,20 @@ class Format
); );
} }
public static function seconds($value)
{
if ($value < 60) {
return self::formatForUnits($value, self::$secondPrefix, self::$secondBase);
} elseif ($value < 3600) {
return sprintf('0.2f m', $value / 60);
} elseif ($value < 86400) {
return sprintf('0.2f h', $value / 3600);
}
// TODO: Do we need weeks, months and years?
return sprintf('0.2f d', $value / 86400);
}
public static function duration($duration) public static function duration($duration)
{ {
if ($duration === null || $duration === false) { if ($duration === null || $duration === false) {
@ -135,19 +153,70 @@ class Format
$value = abs($value); $value = abs($value);
$sign = '-'; $sign = '-';
} }
if ($value == 0) {
$pow = $result = 0;
} else {
$pow = floor(log($value, $base)); $pow = floor(log($value, $base));
$result = $value / pow($base, $pow); $result = $value / pow($base, $pow);
}
// 1034.23 looks better than 1.03, but 2.03 is fine: // 1034.23 looks better than 1.03, but 2.03 is fine:
if ($pow > 0 && $result < 2) { if ($pow > 0 && $result < 2) {
$pow--; $result = $value / pow($base, --$pow);
$result = $value / pow($base, $pow);
} }
return sprintf( return sprintf(
'%s%0.2f %s', '%s%0.2f %s',
$sign, $sign,
$result, $result,
$units[$pow] $units[abs($pow)]
); );
} }
/**
* Return the amount of seconds based on the given month
*
* @param DateTime|int $dateTimeOrTimestamp The date and time to use
*
* @return int
*/
public static function secondsByMonth($dateTimeOrTimestamp)
{
if (!($dt = $dateTimeOrTimestamp) instanceof DateTime) {
$dt = new DateTime();
$dt->setTimestamp($dateTimeOrTimestamp);
}
return (int) $dt->format('t') * 24 * 3600;
}
/**
* Return the amount of seconds based on the given year
*
* @param DateTime|int $dateTimeOrTimestamp The date and time to use
*
* @return int
*/
public static function secondsByYear($dateTimeOrTimestamp)
{
return (self::isLeapYear($dateTimeOrTimestamp) ? 366 : 365) * 24 * 3600;
}
/**
* Return whether the given year is a leap year
*
* @param DateTime|int $dateTimeOrTimestamp The date and time to use
*
* @return bool
*/
public static function isLeapYear($dateTimeOrTimestamp)
{
if (!($dt = $dateTimeOrTimestamp) instanceof DateTime) {
$dt = new DateTime();
$dt->setTimestamp($dateTimeOrTimestamp);
}
return $dt->format('L') == 1;
}
} }

View File

@ -29,7 +29,7 @@
namespace Icinga\Util; namespace Icinga\Util;
use \Exception; use Exception;
/** /**
* Helper class to ease internationalization when using gettext * Helper class to ease internationalization when using gettext

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -372,7 +373,7 @@ class ActionController extends Zend_Controller_Action
exit; exit;
} }
if ($isXhr || $this->getParam('view') === 'compact') { if ($isXhr) {
$layout->setLayout('inline'); $layout->setLayout('inline');
} }
@ -464,3 +465,4 @@ class ActionController extends Zend_Controller_Action
return parent::__call($name, $params); return parent::__call($name, $params);
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -29,7 +30,7 @@
namespace Icinga\Web\Controller; namespace Icinga\Web\Controller;
use \Zend_Log; use Zend_Log;
use Icinga\Web\Session; use Icinga\Web\Session;
use Icinga\User\Message; use Icinga\User\Message;
use Icinga\Authentication\Manager as AuthenticationManager; use Icinga\Authentication\Manager as AuthenticationManager;
@ -95,3 +96,4 @@ class BaseConfigController extends ActionController
$this->view->tabs = ControllerTabCollector::collectControllerTabs('ConfigController'); $this->view->tabs = ControllerTabCollector::collectControllerTabs('ConfigController');
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -91,3 +92,4 @@ class BasePreferenceController extends ActionController
$store->save($currentPreferences); $store->save($currentPreferences);
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -29,18 +30,16 @@
namespace Icinga\Web\Controller; namespace Icinga\Web\Controller;
use \Icinga\Application\Modules\Module; use Icinga\Application\Modules\Module;
use \Icinga\Application\Icinga; use Icinga\Application\Icinga;
use \Icinga\Web\Widget\Tabs; use Icinga\Web\Widget\Tabs;
/** /**
* Static helper class that collects tabs provided by the 'createProvidedTabs' method * Static helper class that collects tabs provided by the 'createProvidedTabs' method
* of controllers. * of controllers.
*
*/ */
class ControllerTabCollector class ControllerTabCollector
{ {
/** /**
* Scan all controllers with the provided name * Scan all controllers with the provided name
* in the application and (loaded) module folders and collects their provided tabs * in the application and (loaded) module folders and collects their provided tabs
@ -124,3 +123,4 @@ class ControllerTabCollector
return array(); return array();
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -29,18 +29,18 @@
namespace Icinga\Web; namespace Icinga\Web;
use \Zend_Controller_Request_Abstract; use Zend_Controller_Request_Abstract;
use \Zend_Form; use Zend_Form;
use \Zend_Config; use Zend_Config;
use \Zend_Form_Element_Submit; use Zend_Form_Element_Submit;
use \Zend_Form_Element_Reset; use Zend_Form_Element_Reset;
use \Zend_View_Interface; use Zend_View_Interface;
use \Icinga\Web\Form\Element\Note; use Icinga\Web\Form\Element\Note;
use \Icinga\Exception\ProgrammingError; use Icinga\Exception\ProgrammingError;
use \Icinga\Web\Form\Decorator\HelpText; use Icinga\Web\Form\Decorator\HelpText;
use \Icinga\Web\Form\Decorator\BootstrapForm; use Icinga\Web\Form\Decorator\BootstrapForm;
use \Icinga\Web\Form\InvalidCSRFTokenException; use Icinga\Web\Form\InvalidCSRFTokenException;
use \Icinga\Application\Config as IcingaConfig; use Icinga\Application\Config as IcingaConfig;
/** /**
* Base class for forms providing CSRF protection, confirmation logic and auto submission * Base class for forms providing CSRF protection, confirmation logic and auto submission
@ -52,7 +52,7 @@ class Form extends Zend_Form
* *
* @var Zend_Controller_Request_Abstract * @var Zend_Controller_Request_Abstract
*/ */
private $request; protected $request;
/** /**
* Main configuration * Main configuration
@ -61,14 +61,14 @@ class Form extends Zend_Form
* *
* @var IcingaConfig * @var IcingaConfig
*/ */
private $config; protected $config;
/** /**
* The preference object to use instead of the one from the user (used for testing) * The preference object to use instead of the one from the user (used for testing)
* *
* @var Zend_Config * @var Zend_Config
*/ */
private $preferences; protected $preferences;
/** /**
* Whether this form should NOT add random generated "challenge" tokens that are associated with the user's current * Whether this form should NOT add random generated "challenge" tokens that are associated with the user's current
@ -84,21 +84,21 @@ class Form extends Zend_Form
* *
* @var string * @var string
*/ */
private $tokenElementName = 'CSRFToken'; protected $tokenElementName = 'CSRFToken';
/** /**
* Flag to indicate that form is already build * Flag to indicate that form is already build
* *
* @var bool * @var bool
*/ */
private $created = false; protected $created = false;
/** /**
* Session id used for CSRF token generation * Session id used for CSRF token generation
* *
* @var string * @var string
*/ */
private $sessionId; protected $sessionId;
/** /**
* Label for submit button * Label for submit button
@ -107,7 +107,7 @@ class Form extends Zend_Form
* *
* @var string * @var string
*/ */
private $submitLabel; protected $submitLabel;
/** /**
* Label for cancel button * Label for cancel button
@ -116,7 +116,7 @@ class Form extends Zend_Form
* *
* @var string * @var string
*/ */
private $cancelLabel; protected $cancelLabel;
/** /**
* Last used note-id * Last used note-id
@ -125,21 +125,7 @@ class Form extends Zend_Form
* *
* @var int * @var int
*/ */
private $last_note_id = 0; protected $last_note_id = 0;
/**
* Decorator that replaces the DtDd Zend-Form default
*
* @var Form\Decorator\BootstrapFormDecorator
*/
private $formDecorator;
/**
* Whether to ignore users leaving the form with unsaved changes
*
* @var bool
*/
private $ignoreChangeDiscarding = false;
/** /**
* Getter for the session ID * Getter for the session ID
@ -147,26 +133,14 @@ class Form extends Zend_Form
* If the ID has never been set, the ID from session_id() is returned * If the ID has never been set, the ID from session_id() is returned
* *
* @return string * @return string
*
* @see session_id()
* @see setSessionId()
*/ */
public function getSessionId() public function getSessionId()
{ {
if (!$this->sessionId) { if (!$this->sessionId) {
$this->sessionId = session_id(); $this->sessionId = session_id();
} }
return $this->sessionId;
}
/** return $this->sessionId;
* Set whether to inform a user when he is about to discard changes (false, default) or not
*
* @param boolean $bool False to not inform users when they leave modified forms, otherwise true
*/
public function setIgnoreChangeDiscarding($bool)
{
$this->ignoreChangeDiscarding = (boolean) $bool;
} }
/** /**
@ -210,6 +184,7 @@ class Form extends Zend_Form
*/ */
protected function create() protected function create()
{ {
} }
/** /**
@ -217,6 +192,7 @@ class Form extends Zend_Form
*/ */
protected function preValidation(array $data) protected function preValidation(array $data)
{ {
} }
/** /**
@ -264,6 +240,7 @@ class Form extends Zend_Form
if ($this->config === null) { if ($this->config === null) {
$this->config = new Zend_Config(array(), true); $this->config = new Zend_Config(array(), true);
} }
return $this->config; return $this->config;
} }
@ -287,6 +264,7 @@ class Form extends Zend_Form
if ($this->preferences) { if ($this->preferences) {
return $this->preferences; return $this->preferences;
} }
return $this->getRequest()->getUser()->getPreferences(); return $this->getRequest()->getUser()->getPreferences();
} }
@ -297,7 +275,6 @@ class Form extends Zend_Form
*/ */
public function buildForm() public function buildForm()
{ {
if ($this->created === false) { if ($this->created === false) {
$this->initCsrfToken(); $this->initCsrfToken();
$this->create(); $this->create();
@ -314,11 +291,8 @@ class Form extends Zend_Form
if (!$this->getAction() && $this->getRequest()) { if (!$this->getAction() && $this->getRequest()) {
$this->setAction($this->getRequest()->getRequestUri()); $this->setAction($this->getRequest()->getRequestUri());
} }
$this->addElementDecorators();
$this->created = true; $this->created = true;
if (!$this->ignoreChangeDiscarding) {
//$this->setAttrib('data-icinga-component', 'app/form');
}
} }
} }
@ -335,16 +309,17 @@ class Form extends Zend_Form
/** /**
* Add cancel button to form * Add cancel button to form
*/ */
private function addCancelButton() protected function addCancelButton()
{ {
$cancelLabel = new Zend_Form_Element_Reset( $this->addElement(
new Zend_Form_Element_Reset(
array( array(
'name' => 'btn_reset', 'name' => 'btn_reset',
'label' => $this->cancelLabel, 'label' => $this->cancelLabel,
'class' => 'btn pull-right' 'class' => 'btn pull-right'
) )
)
); );
$this->addElement($cancelLabel);
} }
/** /**
@ -360,15 +335,16 @@ class Form extends Zend_Form
/** /**
* Add submit button to form * Add submit button to form
*/ */
private function addSubmitButton() protected function addSubmitButton()
{ {
$submitButton = new Zend_Form_Element_Submit( $this->addElement(
new Zend_Form_Element_Submit(
array( array(
'name' => 'btn_submit', 'name' => 'btn_submit',
'label' => $this->submitLabel, 'label' => $this->submitLabel
)
) )
); );
$this->addElement($submitButton);
} }
/** /**
@ -403,13 +379,12 @@ class Form extends Zend_Form
* *
* @throws ProgrammingError When an element is found which does not yet exist * @throws ProgrammingError When an element is found which does not yet exist
*/ */
final public function enableAutoSubmit($triggerElements) public function enableAutoSubmit($triggerElements)
{ {
foreach ($triggerElements as $elementName) { foreach ($triggerElements as $elementName) {
$element = $this->getElement($elementName); $element = $this->getElement($elementName);
if ($element !== null) { if ($element !== null) {
$element->setAttrib('onchange', '$(this.form).submit();'); $element->setAttrib('onchange', '$(this.form).submit();');
$element->setAttrib('data-icinga-form-autosubmit', true);
} else { } else {
throw new ProgrammingError( throw new ProgrammingError(
'You need to add the element "' . $elementName . '" to' . 'You need to add the element "' . $elementName . '" to' .
@ -426,8 +401,6 @@ class Form extends Zend_Form
* in the request is valid and gets repopulated in case its invalid. * in the request is valid and gets repopulated in case its invalid.
* *
* @return bool True when the form is submitted and valid, otherwise false * @return bool True when the form is submitted and valid, otherwise false
* @see Form::isValid()
* @see Form::isSubmitted()
*/ */
public function isSubmittedAndValid() public function isSubmittedAndValid()
{ {
@ -466,6 +439,7 @@ class Form extends Zend_Form
$checkData = $this->getRequest()->getParams(); $checkData = $this->getRequest()->getParams();
$submitted = isset($checkData['btn_submit']); $submitted = isset($checkData['btn_submit']);
} }
return $submitted; return $submitted;
} }
@ -474,13 +448,13 @@ class Form extends Zend_Form
* *
* This method should be used for testing purposes only * This method should be used for testing purposes only
* *
* @param bool $disabled Set true in order to disable CSRF tokens in this form (default: true), otherwise false * @param bool $disabled Set true in order to disable CSRF tokens in
* * this form (default: true), otherwise false
* @see tokenDisabled
*/ */
final public function setTokenDisabled($disabled = true) public function setTokenDisabled($disabled = true)
{ {
$this->tokenDisabled = (boolean) $disabled; $this->tokenDisabled = (boolean) $disabled;
if ($disabled === true) { if ($disabled === true) {
$this->removeElement($this->tokenElementName); $this->removeElement($this->tokenElementName);
} }
@ -489,20 +463,18 @@ class Form extends Zend_Form
/** /**
* Add CSRF counter measure field to form * Add CSRF counter measure field to form
*/ */
final public function initCsrfToken() public function initCsrfToken()
{ {
if ($this->tokenDisabled || $this->getElement($this->tokenElementName)) { if (!$this->tokenDisabled && $this->getElement($this->tokenElementName) === null) {
return;
}
$this->addElement( $this->addElement(
'hidden', 'hidden',
$this->tokenElementName, $this->tokenElementName,
array( array(
'value' => $this->generateCsrfTokenAsString(), 'value' => $this->generateCsrfTokenAsString()
'decorators' => array('ViewHelper')
) )
); );
} }
}
/** /**
* Test the submitted data for a correct CSRF token * Test the submitted data for a correct CSRF token
@ -511,18 +483,16 @@ class Form extends Zend_Form
* *
* @throws InvalidCSRFTokenException When CSRF Validation fails * @throws InvalidCSRFTokenException When CSRF Validation fails
*/ */
final public function assertValidCsrfToken(array $checkData) public function assertValidCsrfToken(array $checkData)
{ {
if ($this->tokenDisabled) { if (!$this->tokenDisabled) {
return;
}
if (!isset($checkData[$this->tokenElementName]) if (!isset($checkData[$this->tokenElementName])
|| !$this->hasValidCsrfToken($checkData[$this->tokenElementName]) || !$this->hasValidCsrfToken($checkData[$this->tokenElementName])
) { ) {
throw new InvalidCSRFTokenException(); throw new InvalidCSRFTokenException();
} }
} }
}
/** /**
* Check whether the form's CSRF token-field has a valid value * Check whether the form's CSRF token-field has a valid value
@ -531,12 +501,9 @@ class Form extends Zend_Form
* *
* @return bool * @return bool
*/ */
private function hasValidCsrfToken($elementValue) protected function hasValidCsrfToken($elementValue)
{ {
if ($this->getElement($this->tokenElementName) === null) { if ($this->getElement($this->tokenElementName) === null || strpos($elementValue, '|') === false) {
return false;
}
if (strpos($elementValue, '|') === false) {
return false; return false;
} }
@ -549,26 +516,12 @@ class Form extends Zend_Form
return $token === hash('sha256', $this->getSessionId() . $seed); return $token === hash('sha256', $this->getSessionId() . $seed);
} }
/**
* Add element decorators which apply to all elements
*
* Adds `HelpText` decorator
*
* @see HelpText
*/
private function addElementDecorators()
{
foreach ($this->getElements() as $element) {
$element->addDecorator(new HelpText());
}
}
/** /**
* Generate a new (seed, token) pair * Generate a new (seed, token) pair
* *
* @return array * @return array
*/ */
final public function generateCsrfToken() public function generateCsrfToken()
{ {
$seed = mt_rand(); $seed = mt_rand();
$hash = hash('sha256', $this->getSessionId() . $seed); $hash = hash('sha256', $this->getSessionId() . $seed);
@ -581,7 +534,7 @@ class Form extends Zend_Form
* *
* @return string * @return string
*/ */
final public function generateCsrfTokenAsString() public function generateCsrfTokenAsString()
{ {
list ($seed, $token) = $this->generateCsrfToken($this->getSessionId()); list ($seed, $token) = $this->generateCsrfToken($this->getSessionId());
return sprintf('%s|%s', $seed, $token); return sprintf('%s|%s', $seed, $token);
@ -593,31 +546,29 @@ class Form extends Zend_Form
* Additionally, all DtDd tags will be removed and the Bootstrap compatible * Additionally, all DtDd tags will be removed and the Bootstrap compatible
* BootstrapForm decorator will be added to the elements * BootstrapForm decorator will be added to the elements
* *
*
* @param string|Zend_Form_Element $element String element type, or an object of type Zend_Form_Element * @param string|Zend_Form_Element $element String element type, or an object of type Zend_Form_Element
* @param string $name The name of the element to add if $element is a string * @param string $name The name of the element to add if $element is a string
* @param array $options The settings for the element if $element is a string * @param array $options The settings for the element if $element is a string
* *
* @return Form * @return self
* @see Zend_Form::addElement() * @see Zend_Form::addElement()
*/ */
public function addElement($element, $name = null, $options = null) public function addElement($element, $name = null, $options = null)
{ {
parent::addElement($element, $name, $options); parent::addElement($element, $name, $options);
$el = $name ? $this->getElement($name) : $element; $el = $name !== null ? $this->getElement($name) : $element;
// Do not add structural elements to invisible elements
// which produces ugly views
if (strpos(strtolower(get_class($el)), 'hidden') !== false) {
$el->setDecorators(array('ViewHelper'));
return $this;
}
if ($el) { if ($el) {
if (strpos(strtolower(get_class($el)), 'hidden') !== false) {
// Do not add structural elements to invisible elements which produces ugly views
$el->setDecorators(array('ViewHelper'));
} else {
$el->removeDecorator('HtmlTag'); $el->removeDecorator('HtmlTag');
$el->removeDecorator('Label'); $el->removeDecorator('Label');
$el->removeDecorator('DtDdWrapper'); $el->removeDecorator('DtDdWrapper');
$el->addDecorator(new BootstrapForm()); $el->addDecorator(new BootstrapForm());
$el->addDecorator(new HelpText());
}
} }
return $this; return $this;
@ -626,7 +577,9 @@ class Form extends Zend_Form
/** /**
* Load the default decorators * Load the default decorators
* *
* @return Zend_Form * Overwrites Zend_Form::loadDefaultDecorators to avoid having the HtmlTag-Decorator added
*
* @return self
*/ */
public function loadDefaultDecorators() public function loadDefaultDecorators()
{ {
@ -637,8 +590,10 @@ class Form extends Zend_Form
$decorators = $this->getDecorators(); $decorators = $this->getDecorators();
if (empty($decorators)) { if (empty($decorators)) {
$this->addDecorator('FormElements') $this->addDecorator('FormElements')
//->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
->addDecorator('Form'); ->addDecorator('Form');
} }
return $this; return $this;
} }
} }

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -103,3 +104,4 @@ class BootstrapForm extends Zend_Form_Decorator_Abstract
. '</div>'; . '</div>';
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php <?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/** /**
* This file is part of Icinga Web 2. * This file is part of Icinga Web 2.
@ -59,3 +60,4 @@ class ConditionalHidden extends Zend_Form_Decorator_Abstract
return $content; return $content;
} }
} }
// @codeCoverageIgnoreEnd

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