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
test/frontend/static/public
test/php/library/Icinga/Protocol/Statusdat/.cache
# Generated API documentation
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':
replace => 'no',
source => 'puppet:////vagrant/config/authentication.ini',
source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/authentication.ini',
owner => 'apache',
group => 'apache',
require => File['/etc/icingaweb']
}
file { '/etc/icingaweb/config.ini':
replace => 'no',
source => 'puppet:////vagrant/config/config.ini',
ensure => file,
owner => 'apache',
group => 'apache',
require => File['/etc/icingaweb']
}
file { '/etc/icingaweb/menu.ini':
replace => 'no',
source => 'puppet:////vagrant/config/menu.ini',
source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/menu.ini',
owner => 'apache',
group => 'apache',
# replace => false,
}
file { '/etc/icingaweb/resources.ini':
replace => 'no',
source => 'puppet:////vagrant/config/resources.ini',
source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/resources.ini',
owner => 'apache',
group => 'apache',
replace => false
}
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',
}
file { '/etc/icingaweb/enabledModules/monitoring':
ensure => 'link',
target => '/vagrant/modules/monitoring',
owner => 'apache',
group => 'apache',
}
file { '/etc/icingaweb/modules/monitoring/backends.ini':
replace => 'no',
source => 'puppet:////vagrant/config/modules/monitoring/backends.ini',
source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/modules/monitoring/backends.ini',
owner => 'apache',
group => 'apache',
}
file { '/etc/icingaweb/modules/monitoring/instances.ini':
replace => 'no',
source => 'puppet:////vagrant/config/modules/monitoring/instances.ini',
source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/modules/monitoring/instances.ini',
owner => 'apache',
group => 'apache',
}
file { '/etc/icingaweb/modules/monitoring/menu.ini':
replace => 'no',
source => 'puppet:////vagrant/config/modules/monitoring/menu.ini',
source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/modules/monitoring/menu.ini',
owner => 'apache',
group => 'apache',
}
@ -707,8 +694,11 @@ file { '/etc/icingaweb/dashboard':
}
file { '/etc/icingaweb/dashboard/dashboard.ini':
replace => 'no',
source => 'puppet:////vagrant/config/dashboard/dashboard.ini',
source => 'puppet:////vagrant/.vagrant-puppet/files/etc/icingaweb/dashboard/dashboard.ini',
owner => 'apache',
group => 'apache',
}
pear::package { 'deepend/Mockery':
channel => 'pear.survivethedeepend.com'
}

View File

@ -28,14 +28,23 @@ define pear::package(
$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}":
command => "pear install --alldeps ${channel}",
creates => "/usr/bin/${name}",
command => "pear install --alldeps ${name}",
unless => "pear list ${name}",
require => $require_
}
exec { "pear upgrade ${name}":
command => "pear upgrade ${channel}",
command => "pear upgrade ${name}",
require => Exec["pear install ${name}"]
}
}

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
<?php
// @codeCoverageIgnoreStart
namespace Icinga\Clicommands;
@ -44,7 +45,7 @@ class WebCommand extends Command
readlink('/proc/self/exe'),
$socket,
$basedir,
$basedir . '/index.php'
ICINGA_LIBDIR . '/Icinga/Application/webrouter.php'
);
// 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
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
@ -138,3 +139,4 @@ class AuthenticationController extends ActionController
}
}
}
// @codeCoverageIgnoreEnd

View File

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

View File

@ -1,5 +1,5 @@
<?php
// @codingStandardsIgnoreStart
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
@ -28,14 +28,16 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Web\Controller\ActionController;
use \Zend_Config;
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\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
@ -88,13 +90,19 @@ class DashboardController extends ActionController
*/
public function addurlAction()
{
$this->getTabs()->add('addurl', array(
'title' => 'Add Dashboard URL',
'url' => Url::fromRequest()
))->activate('addurl');
$this->getTabs()->add(
'addurl',
array(
'title' => 'Add Dashboard URL',
'url' => Url::fromRequest()
)
)->activate('addurl');
$form = new AddUrlForm();
$form->setRequest($this->_request);
$form->setRequest($this->getRequest());
$form->setAction(Url::fromRequest()->setParams(array())->getAbsoluteUrl());
$this->view->form = $form;
if ($form->isSubmittedAndValid()) {
$dashboard = $this->getDashboard();
$dashboard->setComponentUrl(
@ -102,15 +110,12 @@ class DashboardController extends ActionController
$form->getValue('component'),
ltrim($form->getValue('url'), '/')
);
try {
$dashboard->store();
$this->redirectNow(
Url::fromPath('dashboard', array('pane' => $form->getValue('pane')))
);
} catch (ConfigurationError $exc) {
$this->_helper->viewRenderer('show_configuration');
$this->view->exceptionMessage = $exc->getMessage();
$this->view->iniConfigurationString = $dashboard->toIni();
$configFile = IcingaConfig::app('dashboard/dashboard')->getConfigFile();
if ($this->writeConfiguration(new Zend_Config($dashboard->toArray()), $configFile)) {
$this->redirectNow(Url::fromPath('dashboard', array('pane' => $form->getValue('pane'))));
} else {
$this->render('show-configuration');
}
}
}
@ -141,5 +146,30 @@ class DashboardController extends ActionController
*/
$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
// @codingStandardsIgnoreStart
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
@ -67,7 +67,7 @@ class ErrorController extends ActionController
break;
default:
$this->getResponse()->setHttpResponseCode(500);
$this->view->title = 'Server error';
$this->view->title = 'Server error: ' . $exception->getMessage();
$this->view->message = $exception->getMessage();
if ($this->getInvokeArg('displayExceptions') == true) {
$this->view->stackTrace = $exception->getTraceAsString();
@ -77,4 +77,4 @@ class ErrorController extends ActionController
$this->view->request = $error->request;
}
}
// @codingStandardsIgnoreEnd
// @codeCoverageIgnoreEnd

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
<?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}}
/**
* 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;
use \Zend_Config;
use \Icinga\Web\Form\Decorator\HelpText;
use \Icinga\Data\ResourceFactory;
use \Icinga\Web\Form;
use \Zend_Form_Element_Checkbox;
use Icinga\Web\Form;
use Icinga\Data\ResourceFactory;
use Icinga\Web\Form\Decorator\HelpText;
/**
* Base form for authentication backend forms
@ -46,26 +47,26 @@ abstract class BaseBackendForm extends Form
*
* @var string
*/
private $backendName = '';
protected $backendName = '';
/**
* The backend configuration as a Zend_Config object
*
* @var Zend_Config
*/
private $backend;
protected $backend;
/**
* The resources to use instead of the factory provided ones (use for testing)
*
* @var Zend_Config
*/
private $resources;
protected $resources;
/**
* Set the name of the currently displayed backend
*
* @param string $name The name to be stored as the section when persisting
* @param string $name The name to be stored as the section when persisting
*/
public function setBackendName($name)
{
@ -75,7 +76,7 @@ abstract class BaseBackendForm extends Form
/**
* Return the backend name of this form
*
* @return string
* @return string
*/
public function getBackendName()
{
@ -85,7 +86,7 @@ abstract class BaseBackendForm extends Form
/**
* Return the backend configuration or a empty Zend_Config object if none is given
*
* @return Zend_Config
* @return Zend_Config
*/
public function getBackend()
{
@ -95,7 +96,7 @@ abstract class BaseBackendForm extends Form
/**
* Set the backend configuration for initial population
*
* @param Zend_Config $backend The backend to display in this form
* @param Zend_Config $backend The backend to display in this form
*/
public function setBackend(Zend_Config $backend)
{
@ -104,9 +105,8 @@ abstract class BaseBackendForm extends Form
/**
* 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
*/
public function setResources(array $resources)
{
@ -114,9 +114,9 @@ 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
*/
public function getResources()
{
@ -130,13 +130,13 @@ abstract class BaseBackendForm extends Form
/**
* 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(
'name' => 'backend_force_creation',
'label' => 'Force Changes',
'helptext' => 'Check this box to enforce changes without connectivity validation',
'label' => t('Force Changes'),
'helptext' => t('Check this box to enforce changes without connectivity validation'),
'order' => 0
)
);
@ -150,16 +150,16 @@ abstract class BaseBackendForm extends Form
* If logic 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
* @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)
{
if (!parent::isValid($data)) {
return false;
}
if ($this->getRequest()->getPost('backend_force_creation')) {
if (isset($data['backend_force_creation']) && $data['backend_force_creation']) {
return true;
}
if (!$this->isValidAuthenticationBackend()) {
@ -173,7 +173,7 @@ abstract class BaseBackendForm extends Form
* Return an array containing all sections defined by this form as the key and all settings
* as an key-value sub-array
*
* @return array
* @return array
*/
abstract public function getConfig();
@ -183,7 +183,7 @@ abstract class BaseBackendForm extends Form
* 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.
*
* @return bool True when validation succeeded, otherwise false
* @return bool Whether validation succeeded or not
*/
abstract public function isValidAuthenticationBackend();
}

View File

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

View File

@ -30,11 +30,10 @@
namespace Icinga\Form\Config\Authentication;
use \Exception;
use Icinga\Data\ResourceFactory;
use \Zend_Config;
use \Icinga\Web\Form;
use \Icinga\Authentication\Backend\LdapUserBackend;
use \Icinga\Protocol\Ldap\Connection as LdapConnection;
use Icinga\Web\Form;
use Icinga\Data\ResourceFactory;
use Icinga\Authentication\Backend\LdapUserBackend;
/**
* Form for adding or modifying LDAP authentication backends
@ -42,14 +41,31 @@ use \Icinga\Protocol\Ldap\Connection as LdapConnection;
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:
* 'resources' => All available resources.
* @return array
*/
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()
*/
public function create($options = array())
public function create()
{
$this->setName('form_modify_backend');
$name = $this->filterName($this->getBackendName());
@ -57,12 +73,12 @@ class LdapBackendForm extends BaseBackendForm
$this->addElement(
'text',
'backend_'.$name.'_name',
'backend_' . $name . '_name',
array(
'required' => true,
'allowEmpty' => false,
'label' => 'Backend Name',
'helptext' => 'The name of this authentication backend',
'allowEmpty' => false,
'label' => t('Backend Name'),
'helptext' => t('The name of this authentication backend'),
'value' => $this->getBackendName()
)
);
@ -71,13 +87,12 @@ class LdapBackendForm extends BaseBackendForm
'select',
'backend_' . $name . '_resource',
array(
'label' => 'Database Connection',
'required' => true,
'allowEmpty' => false,
'helptext' => 'The database connection to use for authenticating with this provider',
'value' => $this->getBackend()->get('resource'),
'multiOptions' => array_key_exists('resources', $options) ?
$options['resources'] : $this->getLdapResources()
'required' => true,
'allowEmpty' => false,
'label' => t('LDAP Resource'),
'helptext' => t('The resource to use for authenticating with this provider'),
'value' => $this->getBackend()->get('resource'),
'multiOptions' => $this->getResources()
)
);
@ -85,10 +100,10 @@ class LdapBackendForm extends BaseBackendForm
'text',
'backend_' . $name . '_user_class',
array(
'label' => 'LDAP User Object Class',
'value' => $backend->get('user_class', 'inetOrgPerson'),
'helptext' => 'The object class used for storing users on the ldap server',
'required' => true
'required' => true,
'label' => t('LDAP User Object Class'),
'helptext' => t('The object class used for storing users on the ldap server'),
'value' => $backend->get('user_class', 'inetOrgPerson')
)
);
@ -96,10 +111,10 @@ class LdapBackendForm extends BaseBackendForm
'text',
'backend_' . $name . '_user_name_attribute',
array(
'label' => 'LDAP User Name Attribute',
'value' => $backend->get('user_name_attribute', 'uid'),
'helptext' => 'The attribute name used for storing the user name on the ldap server',
'required' => true
'required' => true,
'label' => t('LDAP User Name Attribute'),
'helptext' => t('The attribute name used for storing the user name on the ldap server'),
'value' => $backend->get('user_name_attribute', 'uid')
)
);
@ -125,52 +140,55 @@ class LdapBackendForm extends BaseBackendForm
*/
public function getConfig()
{
$name = $this->getBackendName();
$prefix = 'backend_' . $this->filterName($name) . '_';
$prefix = 'backend_' . $this->filterName($this->getBackendName()) . '_';
$section = $this->getValue($prefix . 'name');
$cfg = array(
'target' => 'user',
'resource' => $this->getValue($prefix . 'resource'),
'user_class' => $this->getValue($prefix . 'user_class'),
'user_name_attribute' => $this->getValue($prefix . 'user_name_attribute')
);
return array(
$section => $cfg
'backend' => 'ldap',
'resource' => $this->getValue($prefix . 'resource'),
'user_class' => $this->getValue($prefix . 'user_class'),
'user_name_attribute' => $this->getValue($prefix . 'user_name_attribute')
);
return array($section => $cfg);
}
/**
* 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
*/
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 {
$cfg = $this->getConfig();
$backendName = 'backend_' . $this->filterName($this->getBackendName()) . '_name';
$backendConfig = new Zend_Config($cfg[$this->getValue($backendName)]);
$testConn = new LdapUserBackend($backendConfig);
if ($testConn->getUserCount() === 0) {
$backend = ResourceFactory::createResource(ResourceFactory::getResourceConfig($backendConfig->resource));
$testConn = new LdapUserBackend(
$backend,
$backendConfig->user_class,
$backendConfig->user_name_attribute
);
if ($testConn->count() === 0) {
throw new Exception('No Users Found On Directory Server');
}
} catch (Exception $exc) {
$this->addErrorMessage(
'Connection Validation Failed:' . $exc->getMessage()
t('Connection Validation Failed: ' . $exc->getMessage())
);
return false;
}
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;
use \Zend_Config;
use \Icinga\Web\Form;
use \Icinga\Web\Url;
use Icinga\Web\Form;
/**
* Form for modifying the authentication provider order.
*
* Form for modifying the authentication provider order
*/
class ReorderForm extends Form
{
@ -44,19 +42,20 @@ class ReorderForm extends Form
*
* @var string
*/
private $backend = null;
protected $backend;
/**
* The current ordering of all backends, required to determine possible changes
*
* @var array
*/
private $currentOrder = array();
protected $currentOrder = array();
/**
* 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)
{
@ -66,20 +65,17 @@ class ReorderForm extends Form
/**
* Set the name of the authentication backend for which to create the 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;
}
/**
* 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 filtered name of the backend
* @see Form::filterName()
* @return string The name of the backend
*/
public function getBackendName()
{
@ -87,28 +83,24 @@ class ReorderForm extends Form
}
/**
* Create this form.
*
* Note: The form action will be set here to the authentication overview
* Create this form
*
* @see Form::create
*/
public function create()
{
$this->upForm = new Form();
$this->downForm = new Form();
if ($this->moveElementUp($this->backend, $this->currentOrder) !== $this->currentOrder) {
$upForm = new Form();
$this->upForm->addElement(
$upForm->addElement(
'hidden',
'form_backend_order',
array(
'required' => true,
'value' => join(',', $this->moveElementUp($this->backend, $this->currentOrder))
'value' => join(',', $this->moveElementUp($this->backend, $this->currentOrder))
)
);
$this->upForm->addElement(
$upForm->addElement(
'button',
'btn_' . $this->getBackendName() . '_reorder_up',
array(
@ -116,21 +108,25 @@ class ReorderForm extends Form
'escape' => false,
'value' => '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) {
$this->downForm->addElement(
$downForm = new Form();
$downForm->addElement(
'hidden',
'form_backend_order',
array(
'required' => true,
'value' => join(',', $this->moveElementDown($this->backend, $this->currentOrder))
'value' => join(',', $this->moveElementDown($this->backend, $this->currentOrder))
)
);
$this->downForm->addElement(
$downForm->addElement(
'button',
'btn_' . $this->getBackendName() . '_reorder_down',
array(
@ -138,72 +134,68 @@ class ReorderForm extends Form
'escape' => false,
'value' => '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
* @return array The currently set values
*
* @param bool $supressArrayNotation passed to getValues
*
* @return array The currently set values
* @see Form::getValues()
*/
public function getFlattenedValues($supressArrayNotation = false)
protected function getFlattenedValues()
{
$values = parent::getValues($supressArrayNotation);
$result = array();
foreach ($values as $key => &$value) {
foreach (parent::getValues() as $key => $value) {
if (is_array($value)) {
$result += $value;
} else {
$result[$key] = $value;
}
}
return $result;
}
/**
* 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()
{
$checkData = $this->getRequest()->getParams();
return isset ($checkData['btn_' . $this->getBackendName() . '_reorder_up']) ||
isset ($checkData['btn_' . $this->getBackendName() . '_reorder_down']);
return isset($checkData['btn_' . $this->getBackendName() . '_reorder_up']) ||
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
*
* @return array An array containing the reordered configuration
* @return array An array containing the reordered configuration
*/
public function getReorderedConfig(Zend_Config $config)
{
$originalConfig = $config->toArray();
$reordered = array();
$newOrder = $this->getFlattenedValues();
$order = explode(',', $newOrder['form_backend_order']);
$reordered = array();
foreach ($order as $key) {
if (!isset($originalConfig[$key])) {
continue;
if (isset($originalConfig[$key])) {
$reordered[$key] = $originalConfig[$key];
}
$reordered[$key] = $originalConfig[$key];
}
return $reordered;
}
/**
@ -216,28 +208,27 @@ class ReorderForm extends Form
* moveElementUp('third', $array); // returns ['first', 'third', 'second']
* </pre>
*
* @param string $key The key to bubble up one slot
* @param array $array The array to work with
* @param string $key The key to bubble up one slot
* @param array $array The array to work with
*
* @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++) {
if ($array[$i+1] !== $key) {
continue;
for ($i = 0; $i < count($array) - 1; $i++) {
if ($array[$i + 1] === $key) {
$swap = $array[$i];
$array[$i] = $array[$i + 1];
$array[$i + 1] = $swap;
return $array;
}
$swap = $array[$i];
$array[$i] = $array[$i+1];
$array[$i+1] = $swap;
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:
*
@ -246,23 +237,22 @@ class ReorderForm extends Form
* moveElementDown('first', $array); // returns ['second', 'first', 'third']
* </pre>
*
* @param string $key The key to bubble up one slot
* @param array $array The array to work with
* @param string $key The key to bubble up one slot
* @param array $array The array to work with
*
* @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++) {
if ($array[$i] !== $key) {
continue;
for ($i = 0; $i < count($array) - 1; $i++) {
if ($array[$i] === $key) {
$swap = $array[$i + 1];
$array[$i + 1] = $array[$i];
$array[$i] = $swap;
return $array;
}
$swap = $array[$i+1];
$array[$i+1] = $array[$i];
$array[$i] = $swap;
return $array;
}
return $array;
}
}

View File

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

View File

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

View File

@ -1,4 +1,5 @@
<?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
@ -30,12 +31,9 @@
namespace Icinga\Form\Config;
use Zend_Config;
use Zend_Form_Element_Text;
use Icinga\Application\Config;
use Icinga\Application\Icinga;
use Icinga\Web\Form;
use Icinga\Application\Icinga;
use Icinga\Web\Form\Validator\WritablePathValidator;
use Icinga\Web\Form\Decorator\ConditionalHidden;
/**
* Form class for setting the application wide logging configuration
@ -43,58 +41,13 @@ use Icinga\Web\Form\Decorator\ConditionalHidden;
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
* @return string
*/
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)
protected function getDefaultLogDir()
{
$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
*/
public function getBaseDir()
{
if ($this->baseDir) {
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;
}
return realpath(Icinga::app()->getApplicationDir() . '/../var/log/icingaweb.log');
}
/**
@ -107,108 +60,124 @@ class LoggingForm extends Form
$this->setName('form_config_logging');
$config = $this->getConfiguration();
$logging = $config->logging;
if ($logging === null) {
$logging = new Zend_Config(array());
}
$debug = $logging->debug;
if ($debug === null) {
$debug = new Zend_Config(array());
if (($loggingConfig = $config->logging) === null) {
$loggingConfig = new Zend_Config(array());
}
$txtLogPath = new Zend_Form_Element_Text(
$this->addElement(
'checkbox',
'logging_enable',
array(
'required' => true,
'label' => t('Logging Enabled'),
'helptext' => t('Check this to enable logging.'),
'value' => $loggingConfig->enable ? 1 : 0
)
);
$this->addElement(
'select',
'logging_level',
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')
'label' => t('Logging Level'),
'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')
)
)
);
$txtLogPath->addValidator(new WritablePathValidator());
$this->addElement($txtLogPath);
$this->addElement(
'checkbox',
'logging_app_verbose',
'select',
'logging_type',
array(
'label' => 'Verbose Logging',
'required' => true,
'helptext' => 'Check to write more verbose output to the icinga log file',
'value' => intval($logging->get('verbose', 0)) === 1
'required' => true,
'label' => t('Logging Type'),
'helptext' => t('The type of logging to utilize.'),
'value' => $loggingConfig->get('type', 'file'),
'multiOptions' => array(
'file' => t('File'),
'syslog' => 'Syslog'
)
)
);
$this->enableAutoSubmit(array('logging_type'));
$this->addElement(
'checkbox',
'logging_debug_enable',
array(
'label' => 'Use Debug Log',
'required' => true,
'helptext' => 'Check to write a seperate debug log (Warning: This file can grow very big)',
'value' => $this->shouldDisplayDebugLog($debug)
)
);
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())
)
);
}
$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(
'button',
'btn_submit',
array(
'type' => 'submit',
'escape' => false,
'value' => '1',
'class' => 'btn btn-cta btn-common',
'label' => '<i class="icinga-icon-save"></i> Save Changes'
)
);
$this->setSubmitLabel('{{SAVE_ICON}} Save Changes');
}
/**
* Return a Zend_Config object containing the state defined in this form
* Return a Zend_Config object containing the state defined in this form
*
* @return Zend_Config The config defined in this form
* @return Zend_Config The config defined in this form
*/
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();
$cfg = $config->toArray();
$cfg = $this->getConfiguration()->toArray();
$cfg['logging']['enable'] = 1;
$cfg['logging']['type'] = 'stream';
$cfg['logging']['verbose'] = $values['logging_app_verbose'];
$cfg['logging']['target'] = $values['logging_app_target'];
$cfg['logging']['enable'] = $values['logging_enable'] == 1;
$cfg['logging']['level'] = $values['logging_level'];
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);
}
}
// @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
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
@ -29,7 +30,7 @@
namespace Icinga\Form\Dashboard;
use \Icinga\Application\Config as IcingaConfig;
use Icinga\Application\Config as IcingaConfig;
use Icinga\Web\Form;
use Icinga\Web\Widget\Dashboard;
use Zend_Form_Element_Text;
@ -39,11 +40,9 @@ use Zend_Form_Element_Select;
/**
* Form to add an url a dashboard pane
*
*/
class AddUrlForm extends Form
{
/**
* Add a selection box for different panes to the form
*
@ -51,7 +50,6 @@ class AddUrlForm extends Form
*/
private function addPaneSelectionBox(Dashboard $dashboard)
{
$selectPane = new Zend_Form_Element_Select(
'pane',
array(
@ -84,7 +82,6 @@ class AddUrlForm extends Form
/**
* Add a textfield for creating a new pane to this form
*
*/
private function addNewPaneTextField($showExistingButton = true)
{
@ -130,7 +127,6 @@ class AddUrlForm extends Form
/**
* Add elements to this form (used by extending classes)
*
*/
protected function create()
{
@ -143,7 +139,7 @@ class AddUrlForm extends Form
array(
'label' => 'Url',
'required' => true,
'value' => $this->getRequest()->getParam('url', null)
'value' => htmlspecialchars_decode($this->getRequest()->getParam('url', ''))
)
);
$elems = $dashboard->getPaneKeyTitleArray();
@ -167,6 +163,6 @@ class AddUrlForm extends Form
)
);
$this->setSubmitLabel("Add To Dashboard");
}
}
// @codeCoverageIgnoreEnd

View File

@ -1,4 +1,5 @@
<?php
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}}
/**
* 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
// @codingStandardsIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
@ -29,10 +27,10 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
use \Icinga\Application\Icinga;
use \Icinga\Application\Config;
use \Icinga\Util\DateTimeFactory;
use \Icinga\Web\Form\Validator\DateTimeValidator;
use Icinga\Application\Icinga;
use Icinga\Application\Config;
use Icinga\Util\DateTimeFactory;
use Icinga\Web\Form\Validator\DateTimeValidator;
/**
* 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
*/
private $request;
protected $request;
/**
* Constructor
@ -79,6 +77,7 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
*
* @param int $timestamp
* @param string $format
*
* @return string
*/
public function format($timestamp, $format)
@ -89,6 +88,7 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
} else {
return $timestamp;
}
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
*
* @param int $timestamp A unix timestamp
*
* @return string The formatted date string
*/
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
*
* @param int $timestamp A unix timestamp
*
* @return string The formatted time string
*/
public function formatTime($timestamp)
@ -133,7 +135,8 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
public function getDateFormat()
{
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()
{
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();
}
}
// @codingStandardsIgnoreStop

View File

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

View File

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

View File

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

View File

@ -3,4 +3,4 @@
use Icinga\Application\Cli;
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"
[logging]
;enable = false
enable = true
; Writing to a Stream
type = "stream"
; Write data to the following file

View File

@ -49,7 +49,7 @@ bind_dn = "@ldap_binddn@"
bind_pw = @ldap_bindpass@
[logfile]
type = file
filename = "/vagrant/var/log/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>.*)$/"
type = file
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]+) - (?<message>.*)$/"
; 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
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
@ -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.
<?php
// The namespace is the same namespace as the file to test has, but with 'Test' prepended
namespace Test\Modules\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';
// The namespace is the same namespace as the file to test has, but with 'Tests' prepended
namespace Tests\Module\MyModule\Helper;
class MyClassTest extends \PHPUnit_Framework_TestCase
{
@ -30,28 +25,33 @@ modules/mymodule/library/MyModule/Helper/MyClass.php.
## 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)
annotation to their [DockBlock](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
should **document** that the test interacts with static attributes:
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 test execution respectively. Use the setUp()
and tearDown() routines instead to accomplish this task.
<?php
namespace My\Test;
use \PHPUnit_Framework_TestCase;
use Icinga\Test\BaseTestCase;
use My\CheesecakeFactory;
class SingletonTest extends PHPUnit_Framework_TestCase
class SingletonTest extends BaseTestCase
{
/**
* Interact with static attributes
*
* Utilizes singleton CheesecakeFactory
*
* @backupStaticAttributes enabled
*/
protected function setUp()
{
parent::setUp();
$this->openingHours = CheesecakeFactory::getOpeningHours();
}
protected function tearDown()
{
parent::tearDown();
CheesecakeFactory::setOpeningHours($this->openingHours);
}
public function testThatInteractsWithStaticAttributes()
{
CheesecakeFactory::setOpeningHours(24);
@ -59,79 +59,7 @@ should **document** that the test interacts with static attributes:
}
}
## 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.
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
some tests are using the mock framework [`Mockery`](https://github.com/padraic/mockery) which is
using static class properties to implement its caching mechanics.

View File

@ -6,11 +6,10 @@ Tests for the application can be found underneath the test folder:
test/
php/ PHPUnit tests for backend code
js/ mocha tests for JavaScript frontend code unittests
frontend/ Integration tests for the frontend using casperjs
regression/ PHPUnit regression tests
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

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**
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.
- When writing unit-tests (like function level tests), try to keep your dependencies as low as possible (best indicator herefor
is the number of require calls in your test). Mock external components and inject them into the class you want to test. If
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
- Mock external components and inject them into the class you want to test. If 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)
## 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):
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
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 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
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
AuthManager (lets dumb it down to just providing an array of users):
require_once "../../library/Icinga/MyLibrary/UserManager.php";
use Icinga/MyLibrary/UserManager
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:
- 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
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
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
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:
/**
* @dataProvider mysqlDb
* @param Zend_Db_Adapter_PDO_Abstract $mysqlDb
* @param Icinga\Data\Db\Connection $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
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
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
@ -124,7 +125,7 @@ abstract class ApplicationBootstrap
/**
* Constructor
*/
protected function __construct($configDir)
protected function __construct($configDir = null)
{
$this->libDir = realpath(__DIR__ . '/../..');
@ -139,13 +140,23 @@ abstract class ApplicationBootstrap
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->setupZendAutoloader();
Benchmark::measure('Bootstrap, autoloader registered');
Icinga::setApp($this);
$this->configDir = realpath($configDir);
require_once dirname(__FILE__) . '/functions.php';
}
@ -269,7 +280,7 @@ abstract class ApplicationBootstrap
*
* @return ApplicationBootstrap
*/
public static function start($configDir)
public static function start($configDir = null)
{
$application = new static($configDir);
$application->bootstrap();
@ -364,7 +375,7 @@ abstract class ApplicationBootstrap
'level' => Logger::$ERROR,
'type' => 'syslog',
'facility' => 'LOG_USER',
'application' => 'Icinga Web'
'application' => 'icingaweb'
)
)
);
@ -446,13 +457,8 @@ abstract class ApplicationBootstrap
protected function setupTimezone()
{
$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);
DateTimeFactory::setConfig(array('timezone' => $tz));
DateTimeFactory::setConfig(array('timezone' => $timeZoneString));
return $this;
}
@ -482,3 +488,4 @@ abstract class ApplicationBootstrap
return $this;
}
}
// @codeCoverageIgnoreEnd

View File

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

View File

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

View File

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

View File

@ -59,12 +59,14 @@ class Icinga
/**
* Setter for an application environment
*
* @param ApplicationBootstrap $app
* @param ApplicationBootstrap $app
* @param bool $overwrite
*
* @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');
}

View File

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

View File

@ -1,30 +1,5 @@
<?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\Application;
@ -40,6 +15,7 @@ class Loader
/**
* List of namespaces
*
* @var array
*/
private $namespaces = array();
@ -54,14 +30,16 @@ class Loader
/**
* Register new namespace for directory
* @param string $namespace
* @param string $directory
* @throws \Icinga\Exception\ProgrammingError
*
* @param string $namespace
* @param string $directory
*
* @throws ProgrammingError
*/
public function registerNamespace($namespace, $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;
@ -69,8 +47,10 @@ class Loader
/**
* Test if a namespace exists
* @param string $namespace
* @return bool
*
* @param string $namespace
*
* @return bool
*/
public function hasNamespace($namespace)
{
@ -80,19 +60,19 @@ class Loader
/**
* Class loader
*
* Ignores all but classes in the Icinga namespace.
* Ignores all but classes in registered namespaces.
*
* @param string $class
* @return boolean
* @param string $class
*
* @return boolean
*/
public function loadClass($class)
{
$namespace = $this->getNamespaceForClass($class);
if ($namespace) {
$file = $this->namespaces[$namespace]. preg_replace('/^'. preg_quote($namespace). '/', '', $class);
$file = str_replace(self::NAMESPACE_SEPARATOR, '/', $file). '.php';
$file = $this->namespaces[$namespace] . preg_replace('/^' . preg_quote($namespace) . '/', '', $class);
$file = str_replace(self::NAMESPACE_SEPARATOR, '/', $file) . '.php';
if (@file_exists($file)) {
require_once $file;
@ -108,16 +88,19 @@ class Loader
*
* Return is the longest match in the array found
*
* @param string $className
* @return bool|string
* @param string $className
*
* @return bool|string
*/
private function getNamespaceForClass($className)
{
$testNamespace = '';
$testLength = 0;
foreach ($this->namespaces as $namespace => $directory) {
$stub = preg_replace('/^'. preg_quote($namespace). '/', '', $className);
foreach (array_keys($this->namespaces) as $namespace) {
$stub = preg_replace(
'/^' . preg_quote($namespace) . '(' . preg_quote(self::NAMESPACE_SEPARATOR) . '|$)/', '', $className
);
$length = strlen($className) - strlen($stub);
if ($length > $testLength) {
$testLength = $length;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
<?php
namespace Icinga\Cli\Screen;
namespace Icinga\Cli;
use Icinga\Cli\Screen;
@ -8,8 +8,6 @@ use Icinga\Cli\Screen;
class AnsiScreen extends Screen
{
protected $isUtf8;
protected $fgColors = array(
'black' => '30',
'darkgray' => '1;30',
@ -40,36 +38,6 @@ class AnsiScreen extends Screen
'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)
{
return strlen($this->stripAnsiCodes($string));
@ -80,40 +48,6 @@ class AnsiScreen extends Screen
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()
{
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?)
}
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)
{
if (! array_key_exists($color, $this->fgColors)) {
@ -163,18 +111,4 @@ class AnsiScreen extends Screen
}
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;
use Icinga\Cli\Screen\AnsiScreen;
use Icinga\Cli\AnsiScreen;
class Screen
{
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()
{
if (self::$instance === null) {
self::$instance = new AnsiScreen();
if (function_exists('posix_isatty') && posix_isatty(STDOUT)) {
self::$instance = new AnsiScreen();
} else {
self::$instance = new Screen();
}
}
return self::$instance;
}

View File

@ -29,14 +29,13 @@
namespace Icinga\Config;
use \Zend_Config;
use \Zend_Config_Ini;
use \Zend_Config_Writer_FileAbstract;
use \Icinga\Config\IniEditor;
use Zend_Config;
use Zend_Config_Ini;
use Zend_Config_Writer_FileAbstract;
use Icinga\Config\IniEditor;
/**
* A ini file adapter that respects the file structure and the comments of already
* existing ini files
* A ini file adapter that respects the file structure and the comments of already existing ini files
*/
class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
{
@ -45,7 +44,7 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
*
* @var array
*/
private $options;
protected $options;
/**
* Create a new PreservingIniWriter
@ -67,7 +66,7 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
/**
* Render the Zend_Config into a config file string
*
* @return string
* @return string
*/
public function render()
{
@ -86,12 +85,12 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
/**
* Create a property diff and apply the changes to the editor
*
* @param Zend_Config $oldconfig The config representing the state before the change
* @param Zend_Config $newconfig The config representing the state after the change
* @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 Zend_Config $oldconfig The config representing the state before the change
* @param Zend_Config $newconfig The config representing the state after the change
* @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
*/
private function diffConfigs(
protected function diffConfigs(
Zend_Config $oldconfig,
Zend_Config $newconfig,
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
* the order of the new config
* Update the order of the sections in the ini file to match the order of the new config
*/
private function updateSectionOrder(
Zend_Config $newconfig,
IniEditor $editor
) {
protected function updateSectionOrder(Zend_Config $newconfig, IniEditor $editor)
{
$order = array();
foreach ($newconfig as $key => $value) {
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 array $parents The parent keys that should be respected when editing the config
*/
private function diffPropertyUpdates(
protected function diffPropertyUpdates(
Zend_Config $oldconfig,
Zend_Config $newconfig,
IniEditor $editor,
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];
/*
* 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) {
$oldvalue = $oldconfig->get($key);
$nextParents = array_merge($parents, array($key));
$keyIdentifier = empty($parents) ?
array($key) : array_slice($nextParents, 1, null, true);
$keyIdentifier = empty($parents) ? array($key) : array_slice($nextParents, 1, null, true);
if ($value instanceof Zend_Config) {
/*
* The value is a nested Zend_Config, handle it recursively
*/
if (!isset($section)) {
/*
* Update the section declaration
*/
// The value is a nested Zend_Config, handle it recursively
if ($section === null) {
// Update the section declaration
$extends = $newconfig->getExtends();
$extend = array_key_exists($key, $extends) ?
$extends[$key] : null;
$extend = array_key_exists($key, $extends) ? $extends[$key] : null;
$editor->setSection($key, $extend);
}
if (!isset($oldvalue)) {
if ($oldvalue === null) {
$oldvalue = new Zend_Config(array());
}
$this->diffConfigs($oldvalue, $value, $editor, $nextParents);
} 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)) {
$editor->setArrayElement($keyIdentifier, $value, $section);
} 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 array $parents The parent keys that should be respected when editing the config
*/
private function diffPropertyDeletions(
protected function diffPropertyDeletions(
Zend_Config $oldconfig,
Zend_Config $newconfig,
IniEditor $editor,
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];
/*
* 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) {
$nextParents = array_merge($parents, array($key));
$newvalue = $newconfig->get($key);
$keyIdentifier = empty($parents) ?
array($key) : array_slice($nextParents, 1, null, true);
$keyIdentifier = empty($parents) ? array($key) : array_slice($nextParents, 1, null, true);
if (!isset($newvalue)) {
if ($newvalue === null) {
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);
if (!isset($section)) {
if ($section === null) {
$editor->removeSection($key);
}
} 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)) {
$editor->resetArrayElement($keyIdentifier, $section);
} elseif (!empty($parents)) {
// Drop nested properties, fixes #5958
$editor->resetArrayElement($nextParents, $section);
} else {
$editor->reset($keyIdentifier, $section);
}

View File

@ -143,8 +143,18 @@ class ResourceFactory implements ConfigAwareFactory
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
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\File;
@ -10,6 +12,7 @@ class Csv
protected function __construct()
{
}
public static function fromQuery(BaseQuery $query)
@ -40,6 +43,7 @@ class Csv
}
$csv .= implode(',', $out) . "\r\n";
}
return $csv;
}
}

View File

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

View File

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

View File

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

View File

@ -4,30 +4,31 @@
namespace Icinga\Logger\Writer;
use \Zend_Config;
use Exception;
use Zend_Config;
use Icinga\Logger\Logger;
use Icinga\Logger\LogWriter;
use Icinga\Application\Config;
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
*/
protected $stream;
protected $path;
/**
* Create a new log writer initialized with the given configuration
*/
public function __construct(Zend_Config $config)
{
$this->stream = Config::resolvePath($config->target);
$this->path = Config::resolvePath($config->target);
$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()
{
if (substr($this->stream, 0, 6) !== 'php://') {
if (!file_exists($this->stream) && (!@touch($this->stream) || !@chmod($this->stream, 0664))) {
throw new ConfigurationError('Cannot create log file "' . $this->stream . '"');
if (substr($this->path, 0, 6) !== 'php://') {
if (!file_exists($this->path) && (!@touch($this->path) || !@chmod($this->path, 0664))) {
throw new ConfigurationError('Cannot create log file "' . $this->path . '"');
}
if (!@is_writable($this->stream)) {
throw new ConfigurationError('Cannot write to log file "' . $this->stream . '"');
if (!@is_writable($this->path)) {
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
*
* @throws Exception In case write acess to the path failed
*/
protected function write($text)
{
$fd = fopen($this->stream, 'a');
fwrite($fd, $text . PHP_EOL);
$fd = fopen($this->path, 'a');
if ($fd === false || fwrite($fd, $text . PHP_EOL) === false) {
throw new Exception('Failed to write to log file "' . $this->path . '"');
}
fclose($fd);
}
}

View File

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

View File

@ -30,6 +30,7 @@
namespace Icinga\Protocol\Commandpipe\Transport;
use Icinga\Logger\Logger;
use Icinga\Exception\ConfigurationError;
/**
* 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);
$file = @fopen($this->path, $this->openMode);
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);
Logger::debug('Writing [' . time() . '] ' . $message . PHP_EOL);

View File

@ -184,35 +184,67 @@ class Reader implements DatasourceInterface
$PHP_EOL_len = strlen(PHP_EOL);
$lines = array();
$s = '';
$f = fopen($this->filename, 'rb');
fseek($f, 0, SEEK_END);
$pos = ftell($f);
while ($read_lines === null || count($lines) < $read_lines) {
fseek($f, --$pos);
$c = fgetc($f);
if ($c === false || $pos < 0) {
$l = $this->validateLine($s, $query);
if (!($l === false || $skip_lines)) {
$lines[] = $l;
}
break;
$f = @fopen($this->filename, 'rb');
if ($f !== false) {
$buffer = '';
fseek($f, 0, SEEK_END);
if (ftell($f) === 0) {
return array();
}
$s = $c . $s;
if (strpos($s, PHP_EOL) === 0) {
$l = $this->validateLine((string)substr($s, $PHP_EOL_len), $query);
if ($l !== false) {
if ($skip_lines) {
$skip_lines--;
} else {
while ($read_lines === null || count($lines) < $read_lines) {
$c = $this->fgetc($f, $buffer);
if ($c === false) {
$l = $this->validateLine($s, $query);
if (!($l === false || $skip_lines)) {
$lines[] = $l;
}
break;
}
$s = $c . $s;
if (strpos($s, PHP_EOL) === 0) {
$l = $this->validateLine((string)substr($s, $PHP_EOL_len), $query);
if ($l !== false) {
if ($skip_lines) {
$skip_lines--;
} else {
$lines[] = $l;
}
}
$s = '';
}
$s = '';
}
}
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
* Direction: FIFO
@ -222,27 +254,33 @@ class Reader implements DatasourceInterface
$PHP_EOL_len = strlen(PHP_EOL);
$lines = array();
$s = '';
$f = fopen($this->filename, 'rb');
while ($read_lines === null || count($lines) < $read_lines) {
$c = fgetc($f);
if ($c === false) {
$l = $this->validateLine($s, $query);
if (!($l === false || $skip_lines)) {
$lines[] = $l;
}
break;
}
$s .= $c;
if (strpos($s, PHP_EOL) !== false) {
$l = $this->validateLine((string)substr($s, 0, strlen($s) - $PHP_EOL_len), $query);
if ($l !== false) {
if ($skip_lines) {
$skip_lines--;
} else {
$lines[] = $l;
$f = @fopen($this->filename, 'rb');
if ($f !== false) {
$buffer = '';
while ($read_lines === null || count($lines) < $read_lines) {
if (strlen($buffer) === 0) {
$buffer = fread($f, 4096);
if (strlen($buffer) === 0) {
$l = $this->validateLine($s, $query);
if (!($l === false || $skip_lines)) {
$lines[] = $l;
}
break;
}
}
$s = '';
$s .= substr($buffer, 0, 1);
$buffer = substr($buffer, 1);
if (strpos($s, PHP_EOL) !== false) {
$l = $this->validateLine((string)substr($s, 0, strlen($s) - $PHP_EOL_len), $query);
if ($l !== false) {
if ($skip_lines) {
$skip_lines--;
} else {
$lines[] = $l;
}
}
$s = '';
}
}
}
return $lines;
@ -259,24 +297,27 @@ class Reader implements DatasourceInterface
$PHP_EOL_len = strlen(PHP_EOL);
$lines = 0;
$s = '';
$f = fopen($this->filename, 'rb');
fseek($f, 0, SEEK_END);
$pos = ftell($f);
while (true) {
fseek($f, --$pos);
$c = fgetc($f);
if ($c === false || $pos < 0) {
if ($this->validateLine($s, $query) !== false) {
$lines++;
$f = @fopen($this->filename, 'rb');
if ($f !== false) {
$buffer = '';
while (true) {
if (strlen($buffer) === 0) {
$buffer = fread($f, 4096);
if (strlen($buffer) === 0) {
if ($this->validateLine($s, $query) !== false) {
$lines++;
}
break;
}
}
break;
}
$s = $c . $s;
if (strpos($s, PHP_EOL) === 0) {
if ($this->validateLine((string)substr($s, $PHP_EOL_len), $query) !== false) {
$lines++;
$s .= substr($buffer, 0, 1);
$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++;
}
$s = '';
}
$s = '';
}
}
return $lines;

View File

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

View File

@ -1,30 +1,5 @@
<?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 {
@ -46,28 +21,24 @@ namespace {
namespace Icinga\Test {
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';
require_once 'Zend/Db/Adapter/Pdo/Abstract.php';
require_once 'DbTest.php';
require_once 'FormTest.php';
// @codingStandardsIgnoreStart
use \Exception;
use \RuntimeException;
use Zend_Test_PHPUnit_ControllerTestCase;
use Exception;
use RuntimeException;
use Mockery;
use Zend_Config;
use Zend_Db_Adapter_Pdo_Abstract;
use Zend_Db_Adapter_Pdo_Mysql;
use Zend_Db_Adapter_Pdo_Pgsql;
use Zend_Db_Adapter_Pdo_Oci;
use Zend_Controller_Request_Abstract;
use Zend_Controller_Request_HttpTestCase;
use PHPUnit_Framework_TestCase;
use Icinga\Application\Icinga;
use Icinga\Util\DateTimeFactory;
use Icinga\Data\ResourceFactory;
use Icinga\Data\Db\Connection;
use Icinga\User\Preferences;
use Icinga\Web\Form;
// @codingStandardsIgnoreEnd
/**
* Class BaseTestCase
*/
class BaseTestCase extends Zend_Test_PHPUnit_ControllerTestCase implements DbTest, FormTest
class BaseTestCase extends PHPUnit_Framework_TestCase implements DbTest, FormTest
{
/**
* Path to application/
@ -111,12 +82,19 @@ namespace Icinga\Test {
*/
public static $moduleDir;
/**
* Store request for form tests
*
* @var Zend_Controller_Request_HttpTestCase
*/
private $request;
/**
* Resource configuration for different database types
*
* @var array
*/
private static $dbConfiguration = array(
protected static $dbConfiguration = array(
'mysql' => array(
'type' => 'db',
'db' => 'mysql',
@ -138,17 +116,12 @@ namespace Icinga\Test {
);
/**
* Constructs a test case with the given name.
*
* @param string $name
* @param array $data
* @param string $dataName
* @see PHPUnit_Framework_TestCase::__construct
* Setup the default timezone and pass it to DateTimeFactory::setConfig
*/
public function __construct($name = null, array $data = array(), $dataName = '')
public static function setupTimezone()
{
parent::__construct($name, $data, $dataName);
date_default_timezone_set('UTC');
DateTimeFactory::setConfig(array('timezone' => 'UTC'));
}
/**
@ -158,12 +131,6 @@ namespace Icinga\Test {
*/
public static function setupDirectories()
{
static $initialized = false;
if ($initialized === true) {
return;
}
$baseDir = realpath(__DIR__ . '/../../../');
if ($baseDir === false) {
@ -176,8 +143,36 @@ namespace Icinga\Test {
self::$testDir = $baseDir . '/test/php';
self::$shareDir = $baseDir . '/share/icinga2-web';
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
* @throws RuntimeException
*/
private function createDbConfigFor($name)
protected function createDbConfigFor($name)
{
if (array_key_exists($name, self::$dbConfiguration)) {
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
*
* @return array
*/
private function createDbAdapterFor($name)
protected function createDbConnectionFor($name)
{
$this->requireDbLibraries();
try {
$adapter = ResourceFactory::createResource($this->createDbConfigFor($name))->getConnection();
$conn = ResourceFactory::createResource($this->createDbConfigFor($name));
} catch (Exception $e) {
$adapter = $e->getMessage();
$conn = $e->getMessage();
}
return array(
array($adapter)
array($conn)
);
}
/**
* PHPUnit provider for mysql
*
* @return Zend_Db_Adapter_Pdo_Mysql
* @return Connection
*/
public function mysqlDb()
{
return $this->createDbAdapterFor('mysql');
return $this->createDbConnectionFor('mysql');
}
/**
* PHPUnit provider for pgsql
*
* @return Zend_Db_Adapter_Pdo_Pgsql
* @return Connection
*/
public function pgsqlDb()
{
return $this->createDbAdapterFor('pgsql');
return $this->createDbConnectionFor('pgsql');
}
/**
* PHPUnit provider for oracle
*
* @return Zend_Db_Adapter_Pdo_Oci
* @return Connection
*/
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 string $filename
* @param Connection $resource
* @param string $filename
*
* @return boolean Operational success flag
* @throws RuntimeException
*/
public function loadSql(Zend_Db_Adapter_Pdo_Abstract $resource, $filename)
public function loadSql(Connection $resource, $filename)
{
if (!is_file($filename)) {
throw new RuntimeException(
@ -274,17 +266,17 @@ namespace Icinga\Test {
);
}
$resource->exec($sqlData);
$resource->getConnection()->exec($sqlData);
}
/**
* Setup provider for testcase
*
* @param string|Zend_Db_Adapter_PDO_Abstract|null $resource
* @param string|Connection|null $resource
*/
public function setupDbProvider($resource)
{
if (!$resource instanceof Zend_Db_Adapter_Pdo_Abstract) {
if (!$resource instanceof Connection) {
if (is_string($resource)) {
$this->markTestSkipped('Could not initialize provider: ' . $resource);
} else {
@ -293,15 +285,17 @@ namespace Icinga\Test {
return;
}
$adapter = $resource->getConnection();
try {
$resource->getConnection();
$adapter->getConnection();
} catch (Exception $e) {
$this->markTestSkipped('Could not connect to provider: '. $e->getMessage());
}
$tables = $resource->listTables();
$tables = $adapter->listTables();
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';
require_once 'Zend/Validate/Abstract.php';
require_once 'Zend/Form/Element/Xhtml.php';
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';
}
/**
* 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';
if (null === $this->request) {
require_once 'Zend/Controller/Request/HttpTestCase.php';
$this->request = new Zend_Controller_Request_HttpTestCase;
}
return $this->request;
}
}
BaseTestCase::setupTimezone();
BaseTestCase::setupDirectories();
BaseTestCase::requireFormLibraries();
BaseTestcase::requireDbLibraries();
}

View File

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

View File

@ -29,18 +29,15 @@
namespace Icinga;
use \DateTimeZone;
use \Exception;
use \InvalidArgumentException;
use DateTimeZone;
use InvalidArgumentException;
use Icinga\User\Preferences;
use Icinga\User\Message;
use Icinga\Application\Config;
/**
* This class represents an authorized user
*
* You can retrieve authorization information (@TODO: Not implemented yet) or
* to retrieve user information
* You can retrieve authorization information (@TODO: Not implemented yet) or user information
*/
class User
{
@ -49,85 +46,85 @@ class User
*
* @var string
*/
private $username;
protected $username;
/**
* Firstname
*
* @var string
*/
private $firstname;
protected $firstname;
/**
* Lastname
*
* @var string
*/
private $lastname;
protected $lastname;
/**
* Users email address
*
* @var string
*/
private $email;
protected $email;
/**
* Domain
*
* @var string
*/
private $domain;
protected $domain;
/**
* More information about user
* More information about this user
*
* @var array
*/
private $additionalInformation = array();
protected $additionalInformation = array();
/**
* Set of permissions
*
* @var array
*/
private $permissions = array();
protected $permissions = array();
/**
* Set of restrictions
*
* @var array
*/
private $restrictions = array();
protected $restrictions = array();
/**
* Groups for this user
*
* @var array
*/
private $groups = array();
protected $groups = array();
/**
* Preferences object
*
* @var Preferences
*/
private $preferences;
protected $preferences;
/**
* Queued notifications for this user.
*
* @var array()
*/
private $messages;
protected $messages;
/**
* Creates a user object given the provided information
*
* @param string $username
* @param string $firstname
* @param string $lastname
* @param string $email
* @param string $username
* @param string $firstname
* @param string $lastname
* @param string $email
*/
public function __construct($username, $firstname = null, $lastname = null, $email = null)
{
@ -149,7 +146,7 @@ class User
/**
* Setter for preferences
*
* @param Preferences $preferences
* @param Preferences $preferences
*/
public function setPreferences(Preferences $preferences)
{
@ -159,20 +156,21 @@ class User
/**
* Getter for preferences
*
* @return Preferences
* @return Preferences
*/
public function getPreferences()
{
if ($this->preferences === null) {
$this->preferences = new Preferences();
}
return $this->preferences;
}
/**
* Return all groups this user belongs to
*
* @return array
* @return array
*/
public function getGroups()
{
@ -181,6 +179,8 @@ class User
/**
* Set the groups this user belongs to
*
* @param array $groups
*/
public function setGroups(array $groups)
{
@ -190,8 +190,9 @@ class User
/**
* Return true if the user is a member of this group
*
* @param string $group
* @return boolean
* @param string $group
*
* @return boolean
*/
public function isMemberOf($group)
{
@ -201,7 +202,7 @@ class User
/**
* Return permission information for this user
*
* @return Array
* @return array
*/
public function getPermissions()
{
@ -211,7 +212,7 @@ class User
/**
* Setter for permissions
*
* @param array $permissions
* @param array $permissions
*/
public function setPermissions(array $permissions)
{
@ -222,6 +223,7 @@ class User
* Return restriction information for this user
*
* @param string $name
*
* @return array
*/
public function getRestrictions($name)
@ -229,13 +231,14 @@ class User
if (array_key_exists($name, $this->restrictions)) {
return $this->restrictions[$name];
}
return array();
}
/**
* Settter for restrictions
*
* @param array $restrictions
* @param array $restrictions
*/
public function setRestrictions(array $restrictions)
{
@ -245,7 +248,7 @@ class User
/**
* Getter for username
*
* @return string
* @return string
*/
public function getUsername()
{
@ -255,7 +258,7 @@ class User
/**
* Setter for username
*
* @param string $name
* @param string $name
*/
public function setUsername($name)
{
@ -265,7 +268,7 @@ class User
/**
* Getter for firstname
*
* @return string
* @return string
*/
public function getFirstname()
{
@ -275,7 +278,7 @@ class User
/**
* Setter for firstname
*
* @param string $name
* @param string $name
*/
public function setFirstname($name)
{
@ -285,7 +288,7 @@ class User
/**
* Getter for lastname
*
* @return string
* @return string
*/
public function getLastname()
{
@ -295,7 +298,7 @@ class User
/**
* Setter for lastname
*
* @param string $name
* @param string $name
*/
public function setLastname($name)
{
@ -305,7 +308,7 @@ class User
/**
* Getter for email
*
* @return string
* @return string
*/
public function getEmail()
{
@ -315,8 +318,9 @@ class User
/**
* Setter for mail
*
* @param string $mail
* @throws InvalidArgumentException When an invalid mail is provided
* @param string $mail
*
* @throws InvalidArgumentException When an invalid mail is provided
*/
public function setEmail($mail)
{
@ -330,7 +334,7 @@ class User
/**
* Setter for domain
*
* @param string $domain
* @param string $domain
*/
public function setDomain($domain)
{
@ -340,7 +344,7 @@ class User
/**
* Getter for domain
*
* @return string
* @return string
*/
public function getDomain()
{
@ -351,8 +355,8 @@ class User
/**
* Set additional information about user
*
* @param string $key
* @param string $value
* @param string $key
* @param string $value
*/
public function setAdditional($key, $value)
{
@ -362,14 +366,15 @@ class User
/**
* Getter for additional information
*
* @param string $key
* @return mixed|null
* @param string $key
* @return mixed|null
*/
public function getAdditional($key)
{
if (isset($this->additionalInformation[$key])) {
return $this->additionalInformation[$key];
}
return null;
}
@ -386,6 +391,7 @@ class User
if ($tz === null) {
$tz = date_default_timezone_get();
}
return new DateTimeZone($tz);
}
@ -394,7 +400,7 @@ class User
*
* This function does NOT automatically write to the session, messages will not be persisted until you do.
*
* @param Message $msg The message
* @param Message $msg The message
*/
public function addMessage(Message $msg)
{
@ -404,7 +410,7 @@ class User
/**
* Get all currently pending messages
*
* @return array the messages
* @return array The messages
*/
public function getMessages()
{

View File

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

View File

@ -44,8 +44,6 @@ use Countable;
*
* $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
*
* unset($preferences->aPreference); // Unset a preference
@ -60,12 +58,12 @@ class Preferences implements Countable
*
* @var array
*/
private $preferences = array();
protected $preferences = array();
/**
* Constructor
*
* @param array $preferences Preferences key-value array
* @param array $preferences Preferences key-value array
*/
public function __construct(array $preferences = array())
{
@ -75,7 +73,7 @@ class Preferences implements Countable
/**
* Count all preferences
*
* @return int The number of preferences
* @return int The number of preferences
*/
public function count()
{
@ -85,7 +83,7 @@ class Preferences implements Countable
/**
* Determine whether a preference exists
*
* @param string $name
* @param string $name
*
* @return bool
*/
@ -97,8 +95,8 @@ class Preferences implements Countable
/**
* Write data to a preference
*
* @param string $name
* @param mixed $value
* @param string $name
* @param mixed $value
*/
public function __set($name, $value)
{
@ -108,8 +106,8 @@ class Preferences implements Countable
/**
* Retrieve a preference and return $default if the preference is not set
*
* @param string $name
* @param mixed $default
* @param string $name
* @param mixed $default
*
* @return mixed
*/
@ -118,13 +116,14 @@ class Preferences implements Countable
if (array_key_exists($name, $this->preferences)) {
return $this->preferences[$name];
}
return $default;
}
/**
* Magic method so that $obj->value will work.
*
* @param string $name
* @param string $name
*
* @return mixed
*/
@ -136,7 +135,7 @@ class Preferences implements Countable
/**
* Remove a given preference
*
* @param string $name Preference name
* @param string $name Preference name
*/
public function remove($name)
{
@ -146,7 +145,8 @@ class Preferences implements Countable
/**
* Determine if a preference is set and is not NULL
*
* @param string $name Preference name
* @param string $name Preference name
*
* @return bool
*/
public function __isset($name)
@ -157,7 +157,7 @@ class Preferences implements Countable
/**
* Unset a given preference
*
* @param string $name Preference name
* @param string $name Preference name
*/
public function __unset($name)
{
@ -167,7 +167,7 @@ class Preferences implements Countable
/**
* Get preferences as array
*
* @return array
* @return array
*/
public function toArray()
{

View File

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

View File

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

View File

@ -29,8 +29,9 @@
namespace Icinga\Util;
use \DateTime;
use \DateTimeZone;
use Exception;
use DateTime;
use DateTimeZone;
use Icinga\Util\ConfigAwareFactory;
use Icinga\Exception\ConfigurationError;
@ -41,35 +42,42 @@ class DateTimeFactory implements ConfigAwareFactory
{
/**
* Time zone used throughout DateTime object creation
*
* @var DateTimeZone
*/
private static $timeZone;
protected static $timeZone;
/**
* Set the factory's config
*
* Set the factory's time zone via key timezone in the given config array
*
* @param array $config
* @throws \Icinga\Exception\ConfigurationError if the given config is not valid
* @param array $config An array with key 'timezone'
*
* @throws ConfigurationError if the given array misses the key 'timezone'
*/
public static function setConfig($config)
{
if (!array_key_exists('timezone', $config)) {
throw new ConfigurationError(t('"DateTimeFactory" expects a valid time zone to be set via "setConfig"'));
try {
$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()
*
* @param string $format
* @param string $time
* @param DateTimeZone $timeZone
*
* @return DateTime
*
* @see DateTime::createFromFormat()
*/
public static function parse($time, $format, DateTimeZone $timeZone = null)
@ -84,46 +92,13 @@ class DateTimeFactory implements ConfigAwareFactory
*
* @param string $time
* @param DateTimeZone $timeZone
*
* @return DateTime
*
* @see DateTime::__construct()
*/
public static function create($time = 'now', DateTimeZone $timeZone = null)
{
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
// @codeCoverageIgnoreStart
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
@ -12,3 +13,4 @@ class File
chmod($filename, $mode);
}
}
// @codeCoverageIgnoreEnd

View File

@ -29,6 +29,7 @@
namespace Icinga\Util;
use DateTime;
use Icinga\Exception\ProgrammingError;
class Format
@ -49,6 +50,9 @@ class Format
);
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()
{
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)
{
if ($duration === null || $duration === false) {
@ -135,19 +153,70 @@ class Format
$value = abs($value);
$sign = '-';
}
$pow = floor(log($value, $base));
$result = $value / pow($base, $pow);
if ($value == 0) {
$pow = $result = 0;
} else {
$pow = floor(log($value, $base));
$result = $value / pow($base, $pow);
}
// 1034.23 looks better than 1.03, but 2.03 is fine:
if ($pow > 0 && $result < 2) {
$pow--;
$result = $value / pow($base, $pow);
$result = $value / pow($base, --$pow);
}
return sprintf(
'%s%0.2f %s',
$sign,
$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;
use \Exception;
use Exception;
/**
* Helper class to ease internationalization when using gettext

View File

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

View File

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

View File

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

View File

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

View File

@ -29,18 +29,18 @@
namespace Icinga\Web;
use \Zend_Controller_Request_Abstract;
use \Zend_Form;
use \Zend_Config;
use \Zend_Form_Element_Submit;
use \Zend_Form_Element_Reset;
use \Zend_View_Interface;
use \Icinga\Web\Form\Element\Note;
use \Icinga\Exception\ProgrammingError;
use \Icinga\Web\Form\Decorator\HelpText;
use \Icinga\Web\Form\Decorator\BootstrapForm;
use \Icinga\Web\Form\InvalidCSRFTokenException;
use \Icinga\Application\Config as IcingaConfig;
use Zend_Controller_Request_Abstract;
use Zend_Form;
use Zend_Config;
use Zend_Form_Element_Submit;
use Zend_Form_Element_Reset;
use Zend_View_Interface;
use Icinga\Web\Form\Element\Note;
use Icinga\Exception\ProgrammingError;
use Icinga\Web\Form\Decorator\HelpText;
use Icinga\Web\Form\Decorator\BootstrapForm;
use Icinga\Web\Form\InvalidCSRFTokenException;
use Icinga\Application\Config as IcingaConfig;
/**
* 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
*/
private $request;
protected $request;
/**
* Main configuration
@ -61,14 +61,14 @@ class Form extends Zend_Form
*
* @var IcingaConfig
*/
private $config;
protected $config;
/**
* The preference object to use instead of the one from the user (used for testing)
*
* @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
@ -84,21 +84,21 @@ class Form extends Zend_Form
*
* @var string
*/
private $tokenElementName = 'CSRFToken';
protected $tokenElementName = 'CSRFToken';
/**
* Flag to indicate that form is already build
*
* @var bool
*/
private $created = false;
protected $created = false;
/**
* Session id used for CSRF token generation
*
* @var string
*/
private $sessionId;
protected $sessionId;
/**
* Label for submit button
@ -107,7 +107,7 @@ class Form extends Zend_Form
*
* @var string
*/
private $submitLabel;
protected $submitLabel;
/**
* Label for cancel button
@ -116,7 +116,7 @@ class Form extends Zend_Form
*
* @var string
*/
private $cancelLabel;
protected $cancelLabel;
/**
* Last used note-id
@ -125,21 +125,7 @@ class Form extends Zend_Form
*
* @var int
*/
private $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;
protected $last_note_id = 0;
/**
* 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
*
* @return string
*
* @see session_id()
* @see setSessionId()
*/
public function getSessionId()
{
if (!$this->sessionId) {
$this->sessionId = session_id();
}
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;
return $this->sessionId;
}
/**
@ -174,7 +148,7 @@ class Form extends Zend_Form
*
* This method should be used for testing purposes only
*
* @param string $sessionId
* @param string $sessionId
*/
public function setSessionId($sessionId)
{
@ -184,7 +158,7 @@ class Form extends Zend_Form
/**
* Return the HTML element name of the CSRF token field
*
* @return string
* @return string
*/
public function getTokenElementName()
{
@ -194,7 +168,7 @@ class Form extends Zend_Form
/**
* Render the form to HTML
*
* @param Zend_View_Interface $view
* @param Zend_View_Interface $view
*
* @return string
*/
@ -210,6 +184,7 @@ class Form extends Zend_Form
*/
protected function create()
{
}
/**
@ -217,12 +192,13 @@ class Form extends Zend_Form
*/
protected function preValidation(array $data)
{
}
/**
* Setter for the request
*
* @param Zend_Controller_Request_Abstract $request
* @param Zend_Controller_Request_Abstract $request
*/
public function setRequest(Zend_Controller_Request_Abstract $request)
{
@ -232,7 +208,7 @@ class Form extends Zend_Form
/**
* Getter for the request
*
* @return Zend_Controller_Request_Abstract
* @return Zend_Controller_Request_Abstract
*/
public function getRequest()
{
@ -242,7 +218,7 @@ class Form extends Zend_Form
/**
* Set the configuration to be used for this form when no preferences are set yet
*
* @param IcingaConfig $cfg
* @param IcingaConfig $cfg
*
* @return self
*/
@ -257,20 +233,21 @@ class Form extends Zend_Form
*
* Returns the set configuration or an empty default one.
*
* @return Zend_Config
* @return Zend_Config
*/
public function getConfiguration()
{
if ($this->config === null) {
$this->config = new Zend_Config(array(), true);
}
return $this->config;
}
/**
* Set preferences to be used instead of the one from the user object (used for testing)
*
* @param Zend_Config $prefs
* @param Zend_Config $prefs
*/
public function setUserPreferences($prefs)
{
@ -280,13 +257,14 @@ class Form extends Zend_Form
/**
* Return the preferences of the user or the overwritten ones
*
* @return Zend_Config
* @return Zend_Config
*/
public function getUserPreferences()
{
if ($this->preferences) {
return $this->preferences;
}
return $this->getRequest()->getUser()->getPreferences();
}
@ -297,7 +275,6 @@ class Form extends Zend_Form
*/
public function buildForm()
{
if ($this->created === false) {
$this->initCsrfToken();
$this->create();
@ -314,18 +291,15 @@ class Form extends Zend_Form
if (!$this->getAction() && $this->getRequest()) {
$this->setAction($this->getRequest()->getRequestUri());
}
$this->addElementDecorators();
$this->created = true;
if (!$this->ignoreChangeDiscarding) {
//$this->setAttrib('data-icinga-component', 'app/form');
}
}
}
/**
* Setter for the cancel label
*
* @param string $cancelLabel
* @param string $cancelLabel
*/
public function setCancelLabel($cancelLabel)
{
@ -335,22 +309,23 @@ class Form extends Zend_Form
/**
* Add cancel button to form
*/
private function addCancelButton()
protected function addCancelButton()
{
$cancelLabel = new Zend_Form_Element_Reset(
array(
'name' => 'btn_reset',
'label' => $this->cancelLabel,
'class' => 'btn pull-right'
$this->addElement(
new Zend_Form_Element_Reset(
array(
'name' => 'btn_reset',
'label' => $this->cancelLabel,
'class' => 'btn pull-right'
)
)
);
$this->addElement($cancelLabel);
}
/**
* Setter for the submit label
*
* @param string $submitLabel
* @param string $submitLabel
*/
public function setSubmitLabel($submitLabel)
{
@ -360,22 +335,23 @@ class Form extends Zend_Form
/**
* Add submit button to form
*/
private function addSubmitButton()
protected function addSubmitButton()
{
$submitButton = new Zend_Form_Element_Submit(
array(
'name' => 'btn_submit',
'label' => $this->submitLabel,
$this->addElement(
new Zend_Form_Element_Submit(
array(
'name' => 'btn_submit',
'label' => $this->submitLabel
)
)
);
$this->addElement($submitButton);
}
/**
* Add message to form
*
* @param string $message The message to be displayed
* @param int $headingType Whether it should be displayed as heading (1-6) or not (null)
* @param string $message The message to be displayed
* @param int $headingType Whether it should be displayed as heading (1-6) or not (null)
*/
public function addNote($message, $headingType = null)
{
@ -399,17 +375,16 @@ class Form extends Zend_Form
*
* Enables automatic submission of this form once the user edits specific elements
*
* @param array $triggerElements The element names which should auto-submit the form
* @param array $triggerElements The element names which should auto-submit the 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) {
$element = $this->getElement($elementName);
if ($element !== null) {
$element->setAttrib('onchange', '$(this.form).submit();');
$element->setAttrib('data-icinga-form-autosubmit', true);
} else {
throw new ProgrammingError(
'You need to add the element "' . $elementName . '" to' .
@ -425,9 +400,7 @@ class Form extends Zend_Form
* Ensures that the current request method is POST, that the form was manually submitted and that the data provided
* in the request is valid and gets repopulated in case its invalid.
*
* @return bool True when the form is submitted and valid, otherwise false
* @see Form::isValid()
* @see Form::isSubmitted()
* @return bool True when the form is submitted and valid, otherwise false
*/
public function isSubmittedAndValid()
{
@ -457,7 +430,7 @@ class Form extends Zend_Form
* Per default, this checks whether the button set with the 'setSubmitLabel' method
* is being submitted. For custom submission logic, this method must be overwritten
*
* @return bool True when the form is marked as submitted, otherwise false
* @return bool True when the form is marked as submitted, otherwise false
*/
public function isSubmitted()
{
@ -466,6 +439,7 @@ class Form extends Zend_Form
$checkData = $this->getRequest()->getParams();
$submitted = isset($checkData['btn_submit']);
}
return $submitted;
}
@ -474,13 +448,13 @@ class Form extends Zend_Form
*
* 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
*
* @see tokenDisabled
* @param bool $disabled Set true in order to disable CSRF tokens in
* this form (default: true), otherwise false
*/
final public function setTokenDisabled($disabled = true)
public function setTokenDisabled($disabled = true)
{
$this->tokenDisabled = (boolean) $disabled;
if ($disabled === true) {
$this->removeElement($this->tokenElementName);
}
@ -489,54 +463,47 @@ class Form extends Zend_Form
/**
* Add CSRF counter measure field to form
*/
final public function initCsrfToken()
public function initCsrfToken()
{
if ($this->tokenDisabled || $this->getElement($this->tokenElementName)) {
return;
if (!$this->tokenDisabled && $this->getElement($this->tokenElementName) === null) {
$this->addElement(
'hidden',
$this->tokenElementName,
array(
'value' => $this->generateCsrfTokenAsString()
)
);
}
$this->addElement(
'hidden',
$this->tokenElementName,
array(
'value' => $this->generateCsrfTokenAsString(),
'decorators' => array('ViewHelper')
)
);
}
/**
* Test the submitted data for a correct CSRF token
*
* @param array $checkData The POST data send by the user
* @param array $checkData The POST data send by the user
*
* @throws InvalidCSRFTokenException When CSRF Validation fails
*/
final public function assertValidCsrfToken(array $checkData)
public function assertValidCsrfToken(array $checkData)
{
if ($this->tokenDisabled) {
return;
}
if (!isset($checkData[$this->tokenElementName])
|| !$this->hasValidCsrfToken($checkData[$this->tokenElementName])
) {
throw new InvalidCSRFTokenException();
if (!$this->tokenDisabled) {
if (!isset($checkData[$this->tokenElementName])
|| !$this->hasValidCsrfToken($checkData[$this->tokenElementName])
) {
throw new InvalidCSRFTokenException();
}
}
}
/**
* Check whether the form's CSRF token-field has a valid value
*
* @param string $elementValue Value from the form element
* @param string $elementValue Value from the form element
*
* @return bool
*/
private function hasValidCsrfToken($elementValue)
protected function hasValidCsrfToken($elementValue)
{
if ($this->getElement($this->tokenElementName) === null) {
return false;
}
if (strpos($elementValue, '|') === false) {
if ($this->getElement($this->tokenElementName) === null || strpos($elementValue, '|') === false) {
return false;
}
@ -549,26 +516,12 @@ class Form extends Zend_Form
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
*
* @return array
* @return array
*/
final public function generateCsrfToken()
public function generateCsrfToken()
{
$seed = mt_rand();
$hash = hash('sha256', $this->getSessionId() . $seed);
@ -579,9 +532,9 @@ class Form extends Zend_Form
/**
* Return the string representation of the CSRF seed/token pair
*
* @return string
* @return string
*/
final public function generateCsrfTokenAsString()
public function generateCsrfTokenAsString()
{
list ($seed, $token) = $this->generateCsrfToken($this->getSessionId());
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
* 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 $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
*
* @return Form
* @return self
* @see Zend_Form::addElement()
*/
public function addElement($element, $name = null, $options = null)
{
parent::addElement($element, $name, $options);
$el = $name ? $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;
}
$el = $name !== null ? $this->getElement($name) : $element;
if ($el) {
$el->removeDecorator('HtmlTag');
$el->removeDecorator('Label');
$el->removeDecorator('DtDdWrapper');
$el->addDecorator(new BootstrapForm());
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('Label');
$el->removeDecorator('DtDdWrapper');
$el->addDecorator(new BootstrapForm());
$el->addDecorator(new HelpText());
}
}
return $this;
@ -626,7 +577,9 @@ class Form extends Zend_Form
/**
* Load the default decorators
*
* @return Zend_Form
* Overwrites Zend_Form::loadDefaultDecorators to avoid having the HtmlTag-Decorator added
*
* @return self
*/
public function loadDefaultDecorators()
{
@ -637,8 +590,10 @@ class Form extends Zend_Form
$decorators = $this->getDecorators();
if (empty($decorators)) {
$this->addDecorator('FormElements')
->addDecorator('Form');
//->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
->addDecorator('Form');
}
return $this;
}
}

View File

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

View File

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

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