diff --git a/.gitattributes b/.gitattributes index e4504cf21..35002d0cb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,5 @@ +# Exclude files related to git when generating an archive .git* export-ignore + +# Normalize puppet manifests' line endings to LF on checkin and prevent conversion to CRLF when the files are checked out +.vagrant-puppet/* eol=lf diff --git a/.gitignore b/.gitignore index 55580cae9..3cc377b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,46 +1,14 @@ # Exclude all hidden files .* -# But not .gitignore, .gitattributes, .vagrant-puppet, .htaccess and .gitkeep -!.gitignore -!.gitattributes -!.vagrant-puppet -!public/.htaccess -!packages/rhel/usr/share/icingaweb/public/.htaccess -!public/.htaccess.in -!.gitkeep -build/ +# Except those related to git and vagrant +!.git* +!.vagrant-puppet/* -development/ +# Exclude application log files +var/log/* -# ./configure output -config.log -autom4te.cache -autoscan* -config.status -Makefile - -# cmd tester -modules/test/bin/extcmd_test - -# misc test output -test/php/library/Icinga/Protocol/Statusdat/.cache - -# Generated API documentation -doc/api - -# Enabled modules -config/enabledModules/ - -# User preferences -config/preferences/*.ini - -# Application logfiles -var/log/*.log - -# Packaging +# Exclude symlink you need for packaging /debian -*.tar.gz -*.komodoproject - +build/* diff --git a/.vagrant-puppet/.gitattributes b/.vagrant-puppet/.gitattributes deleted file mode 100644 index af67531d8..000000000 --- a/.vagrant-puppet/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* -crlf diff --git a/.vagrant-puppet/profiles/icinga2_dev/files/conf.d/test-config.conf b/.vagrant-puppet/profiles/icinga2_dev/files/conf.d/test-config.conf index f25df325b..560fc6a1c 100644 --- a/.vagrant-puppet/profiles/icinga2_dev/files/conf.d/test-config.conf +++ b/.vagrant-puppet/profiles/icinga2_dev/files/conf.d/test-config.conf @@ -76,7 +76,7 @@ __function createService(service_type, num) { enable_active_checks = (service_type != "pending") vars.check_type = service_type - assign where match("*" + service_type + "*", host.vars.check_config) + assign where service_type in host.vars.check_config } } @@ -102,12 +102,12 @@ __function createHost(checkType, checkConfig, num, checkEnabled) { } __for (num in range(10)) { - createHost("ok", "ok", num, true) - createHost("random", "random,flapping", num, true) - createHost("down", "warning,critical", num, true) - createHost("unreachable", "unknown", num, true) - createHost("pending", "pending", num, false) - createHost("flap", "flapping", num, true) + createHost("ok", [ "ok" ], num, true) + createHost("random", [ "random", "flapping" ], num, true) + createHost("down", [ "warning", "critical" ], num, true) + createHost("unreachable", [ "unknown" ], num, true) + createHost("pending", [ "pending" ], num, false) + createHost("flap", [ "flapping" ], num, true) } // EOF diff --git a/Makefile.in b/Makefile.in deleted file mode 100644 index d97040cc3..000000000 --- a/Makefile.in +++ /dev/null @@ -1,158 +0,0 @@ -SHELL=/bin/sh - -PACKAGE_TARNAME=@PACKAGE_TARNAME@ -PACKAGE_NAME=@PACKAGE_NAME@ -PACKAGE_VERSION=@PACKAGE_VERSION@ - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -bindir=@bindir@ - -HTTPD_CONFIG_PATH=@httpd_config_path@ -ICINGAWEB_CONFIG_PATH=@icingaweb_config_path@ -ICINGAWEB_LOG_PATH=@icingaweb_log_path@ - -INSTALL=@INSTALL@ -INSTALL_OPTS=@INSTALL_OPTS@ -INSTALL_OPTS_WEB=@INSTALL_OPTS_WEB@ - -default: - @echo "IcingaWeb make targets: " - @printf "%b" " -install:\t\t\tInstall the application and overwrite configs\n" - @printf "%b" " -update:\t\t\tInstall the application without touching the configs\n" - @printf "%b" " -install-apache-config:\tInstall the apache configuration\n" - -# -# Installs the whole application w\o httpd configurations -# -install: install-config install-basic ensure-writable-folders install-cli - -# -# Install icingacli bin -# - -install-cli: - $(INSTALL) -m 755 -d $(INSTALL_OPTS) $(bindir) - $(INSTALL) -m 755 $(INSTALL_OPTS) "./bin/icingacli" $(bindir)/icingacli; - -# -# Installs the whole application w\o configuration -# -install-basic: install-static-files install-runtime-dirs ensure-writable-folders - -# -# Updates only the application -# -update: install-application - -# -# Removes files created by ./configure -# -clean: - if [ -f ./Makefile ];then \ - rm ./Makefile; \ - fi; \ - if [ -f ./etc/apache/icingaweb.conf ];then \ - rm ./etc/apache/icingaweb.conf; \ - fi; - -# -# Installs/copies all static files (executables, scripts, html, etc) -# -install-static-files: install-application copy-web-files-public copy-web-files-modules - -# -# Installs all configuration files -# -install-config: - $(INSTALL) -m 755 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(ICINGAWEB_CONFIG_PATH) - - @dirs=`cd ./config ; find . -mindepth 1 -type d `;\ - for dir in $$dirs; do \ - $(INSTALL) -m 755 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(ICINGAWEB_CONFIG_PATH)/"$$dir"; \ - done; - - @files=`cd ./config ; find . -mindepth 1 -type f \ - -and ! -name ".*" -and ! -name "*.in"`; \ - for file in $$files; do \ - $(INSTALL) -m 644 $(INSTALL_OPTS_WEB) "./config/$$file" $(DESTDIR)$(ICINGAWEB_CONFIG_PATH)/"$$file"; \ - done - - -# -# Installs runtime directories like the application cache -# -install-runtime-dirs: - $(INSTALL) -m 755 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(prefix)/application/cache - -# -# Copies the tests into the installation directory -# -install-tests: copy-folder-tests - -# -# Install configurations for apache2 -# -install-apache-config: - $(INSTALL) -m 755 -d $(INSTALL_OPTS) $(DESTDIR)$(HTTPD_CONFIG_PATH) - $(INSTALL) -m 644 $(INSTALL_OPTS) "./etc/apache/icingaweb.conf" $(DESTDIR)$(HTTPD_CONFIG_PATH)/icingaweb.conf; - -# -# Installs the php files to the prefix -# -install-application: copy-web-files-application copy-web-files-library install-cli - -# -# Rule for copying folders and containing files (arbitary types), hidden files are excluded -# -copy-folder-%: - $(INSTALL) -m 755 $(INSTALL_OPTS) -d $(DESTDIR)$(prefix)/$* - - @dirs=`find ./$* -mindepth 1 -type d `;\ - for dir in $$dirs; do \ - $(INSTALL) -m 755 $(INSTALL_OPTS) -d $(DESTDIR)$(prefix)/"$$dir"; \ - done; - - @files=`find ./$* -mindepth 1 -type f \ - -and ! -name ".*"`; \ - for file in $$files; do \ - $(INSTALL) -m 644 $(INSTALL_OPTS) "$$file" $(DESTDIR)$(prefix)/"$$file"; \ - done - - -ensure-writable-folders: - $(INSTALL) -m 775 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(prefix)/var/ - $(INSTALL) -m 775 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(ICINGAWEB_LOG_PATH) - chmod -R 775 $(DESTDIR)$(ICINGAWEB_CONFIG_PATH) - - -# -# Rule for copying only php, *html, js and ini files. Hidden files are ignored -# -copy-web-files-%: - $(INSTALL) -m 755 $(INSTALL_OPTS) -d $(DESTDIR)$(prefix)/$* - - @dirs=`find ./$* -mindepth 1 -type d `;\ - for dir in $$dirs; do \ - $(INSTALL) -m 755 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(prefix)/"$$dir"; \ - done; - - @files=`find ./$* -mindepth 1 -type f \ - -name "*.php" -or -name "*.ini" -or -name "*.*html" \ - -or -name "*.js" -or -name "*.css" -or -name "*.less" \ - -or -name "*.otf" -or -name "*.ttf" -or -name "*.otf" \ - -or -name "*.svg" -or -name "*.woff" -or -name "*.png" \ - -and ! -name ".*"`; \ - for file in $$files; do \ - $(INSTALL) -m 644 $(INSTALL_OPTS_WEB) "$$file" $(DESTDIR)$(prefix)/"$$file"; \ - done - -# -# Create release or snapshot tarball -# -# TODO: Use git-archive -# create-tarball: -# @./bin/make-tarball --prefix $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)/ -# -# create-tarball-nightly: -# ./bin/make-tarball --prefix $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-`date +%Y%m%d`-`git rev-parse --short HEAD`/ diff --git a/VERSION b/VERSION new file mode 100644 index 000000000..71282c063 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +v2.0.0-beta1 diff --git a/Vagrantfile b/Vagrantfile index 34c9e97f1..6db946f47 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -54,7 +54,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # the path on the host to the actual folder. The second argument is # the path on the guest to mount the folder. And the optional third # argument is a set of non-required options. - config.vm.synced_folder "./config", "/vagrant/config" config.vm.synced_folder "./var/log", "/vagrant/var/log" # Provider-specific configuration so you can fine-tune various diff --git a/aclocal.m4 b/aclocal.m4 deleted file mode 100644 index ed4703fd0..000000000 --- a/aclocal.m4 +++ /dev/null @@ -1,84 +0,0 @@ -AC_DEFUN([AC_USER_GUESS],[ - $2=$3 - for x in $1; do - AC_MSG_CHECKING([if user $x exists]) - AS_IF([ $GREP -q "^$x:" /etc/passwd ], - [ AC_MSG_RESULT([found]); $2=$x ; break], - [ AC_MSG_RESULT([not found]) ]) - done - ]) - -AC_DEFUN([AC_CHECK_PHP_MODULE],[ - for x in $1;do - AC_MSG_CHECKING([if php has $x module]) - AS_IF([ php -m | $GREP -iq "^$x$" ], - [ AC_MSG_RESULT([found]) ], - [ AC_MSG_ERROR([not found])]) - done -]) - -AC_DEFUN([AC_CHECK_PHP_VERSION],[ - AC_MSG_CHECKING([if php has at least version $1.$2.$3]) - AS_IF([ test $1 -le `php -r 'echo PHP_MAJOR_VERSION;'` && \ - test $2 -le `php -r 'echo PHP_MINOR_VERSION;'` && \ - test $3 -le `php -r 'echo PHP_RELEASE_VERSION;'`], - [ AC_MSG_RESULT([PHP version is correct])], - [ AC_MSG_ERROR([You need at least PHP version $1.$2.$3])]) -]) - -AC_DEFUN([AC_CHECK_PHP_INCLUDE],[ - AC_MSG_CHECKING([if PHP runtime dependency '$2' is available]) - AS_IF([ php -r 'require "$1";' ], - [ AC_MSG_RESULT([PHP runtime dependency fulfilled])], - [ AC_MSG_ERROR([PHP runtime dependency '$2' is missing])]) -]) - -AC_DEFUN([AC_GROUP_GUESS],[ - $2=$3 - for x in $1; do - AC_MSG_CHECKING([if group $x exists]) - AS_IF([ $GREP -q "^$x:" /etc/group ], - [ AC_MSG_RESULT([found]); $2=$x ; break], - [ AC_MSG_RESULT([not found]) ]) - done -]) - -AC_DEFUN([AC_CHECK_BIN], [ - AC_PATH_PROG([$1],[$2],[not found]) - - AS_IF([ test "XX${$1}" == "XXnot found" ], - [ AC_MSG_WARN([binary $2 not found in PATH]) ]) - - test "XX${$1}" == "XXnot found" && $1="" -]) - -AC_DEFUN([AC_PATH_GUESS], [ - $2=$3 - for x in $1; do - AC_MSG_CHECKING([if path $x exists]) - AS_IF([test -d $x], - [AC_MSG_RESULT([found]); $2=$x; break], - [AC_MSG_RESULT([not found])] - ) - done -]) - -# ICINGA_CHECK_DBTYPE(DBTYPE, ARGUMENT_NAME) -# ------------------------------------------ -AC_DEFUN([ICINGA_CHECK_DBTYPE], [ - AC_MSG_CHECKING([Testing database type for $2]) - AS_IF(echo "$1" | $GREP -q "^\(my\|pg\)sql$", - AC_MSG_RESULT([OK ($1)]), - AC_MSG_ERROR([$1]) - ) -]) - -# ICINGA_CHECK_BACKENDTYPE(BACKENDTYPE, ARGUMENT_NAME) -# ------------------------------------------ -AC_DEFUN([ICINGA_CHECK_BACKENDTYPE], [ - AC_MSG_CHECKING([Testing backend type for $2]) - AS_IF(echo "$1" | $GREP -q "^\(ido\|statusdat\|livestatus\)$", - AC_MSG_RESULT([OK ($1)]), - AC_MSG_ERROR([$1]) - ) -]) diff --git a/application/clicommands/WebCommand.php b/application/clicommands/WebCommand.php index 11e7f002a..12ed9e1a4 100644 --- a/application/clicommands/WebCommand.php +++ b/application/clicommands/WebCommand.php @@ -4,6 +4,7 @@ namespace Icinga\Clicommands; +use Icinga\Application\Icinga; use Icinga\Cli\Command; use Icinga\Exception\IcingaException; @@ -30,7 +31,7 @@ class WebCommand extends Command // throw new IcingaException('Socket is required'); } if ($basedir === null) { - $basedir = dirname(ICINGAWEB_APPDIR) . '/public'; + $basedir = Icinga::app()->getBaseDir('public'); if (! file_exists($basedir) || ! is_dir($basedir)) { throw new IcingaException('Basedir is required'); } @@ -46,7 +47,7 @@ class WebCommand extends Command readlink('/proc/self/exe'), $socket, $basedir, - ICINGA_LIBDIR . '/Icinga/Application/webrouter.php' + Icinga::app()->getLibraryDir('/Icinga/Application/webrouter.php') ); // TODO: Store webserver log, switch uid, log index.php includes, pid file diff --git a/application/controllers/AuthenticationController.php b/application/controllers/AuthenticationController.php index 8b2bb3715..00dae1c6d 100644 --- a/application/controllers/AuthenticationController.php +++ b/application/controllers/AuthenticationController.php @@ -6,10 +6,10 @@ use Icinga\Authentication\Backend\AutoLoginBackend; use Icinga\Web\Controller\ActionController; -use Icinga\Form\Authentication\LoginForm; +use Icinga\Forms\Authentication\LoginForm; use Icinga\Authentication\AuthChain; use Icinga\Application\Config; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\Exception\AuthenticationException; use Icinga\Exception\NotReadableError; use Icinga\Exception\ConfigurationError; @@ -33,6 +33,10 @@ class AuthenticationController extends ActionController */ public function loginAction() { + if (@file_exists(Config::resolvePath('setup.token')) && !@file_exists(Config::resolvePath('config.ini'))) { + $this->redirectNow(Url::fromPath('setup')); + } + $auth = $this->Auth(); $this->view->form = $form = new LoginForm(); $this->view->title = $this->translate('Icingaweb Login'); @@ -53,7 +57,7 @@ class AuthenticationController extends ActionController $config = Config::app('authentication'); } catch (NotReadableError $e) { throw new ConfigurationError( - $this->translate('Could not read your authentiction.ini, no authentication methods are available.'), + $this->translate('Could not read your authentication.ini, no authentication methods are available.'), 0, $e ); @@ -93,30 +97,30 @@ class AuthenticationController extends ActionController } } if ($backendsTried === 0) { - throw new ConfigurationError( + $this->view->form->addError( $this->translate( 'No authentication methods available. Did you create' - . ' authentication.ini when installing Icinga Web 2?' + . ' authentication.ini when setting up Icinga Web 2?' ) ); - } - if ($backendsTried === $backendsWithError) { - throw new ConfigurationError( + } else if ($backendsTried === $backendsWithError) { + $this->view->form->addError( $this->translate( 'All configured authentication methods failed.' . ' Please check the system log or Icinga Web 2 log for more information.' ) ); - } - if ($backendsWithError) { - $this->view->form->getElement('username')->addError( + } elseif ($backendsWithError) { + $this->view->form->addError( $this->translate( 'Please note that not all authentication methods were available.' . ' Check the system log or Icinga Web 2 log for more information.' ) ); } - $this->view->form->getElement('password')->addError($this->translate('Incorrect username or password')); + if ($backendsTried > 0 && $backendsTried !== $backendsWithError) { + $this->view->form->getElement('password')->addError($this->translate('Incorrect username or password')); + } } elseif ($request->isGet()) { $user = new User(''); foreach ($chain as $backend) { @@ -134,6 +138,8 @@ class AuthenticationController extends ActionController } catch (Exception $e) { $this->view->errorInfo = $e->getMessage(); } + + $this->view->configMissing = is_dir(Config::$configDir) === false; } /** diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php index c12860e72..0c89ebba8 100644 --- a/application/controllers/ConfigController.php +++ b/application/controllers/ConfigController.php @@ -7,12 +7,12 @@ use Icinga\Web\Notification; use Icinga\Application\Modules\Module; use Icinga\Web\Widget; use Icinga\Application\Icinga; -use Icinga\Application\Config as IcingaConfig; -use Icinga\Form\Config\GeneralConfigForm; -use Icinga\Form\Config\AuthenticationBackendReorderForm; -use Icinga\Form\Config\AuthenticationBackendConfigForm; -use Icinga\Form\Config\ResourceConfigForm; -use Icinga\Form\ConfirmRemovalForm; +use Icinga\Application\Config; +use Icinga\Forms\Config\GeneralConfigForm; +use Icinga\Forms\Config\AuthenticationBackendReorderForm; +use Icinga\Forms\Config\AuthenticationBackendConfigForm; +use Icinga\Forms\Config\ResourceConfigForm; +use Icinga\Forms\ConfirmRemovalForm; use Icinga\Data\ResourceFactory; @@ -24,13 +24,13 @@ class ConfigController extends ActionController public function init() { $this->view->tabs = Widget::create('tabs')->add('index', array( - 'title' => 'Application', + 'title' => $this->translate('Application'), 'url' => 'config' ))->add('authentication', array( - 'title' => 'Authentication', + 'title' => $this->translate('Authentication'), 'url' => 'config/authentication' ))->add('resources', array( - 'title' => 'Resources', + 'title' => $this->translate('Resources'), 'url' => 'config/resource' )); } @@ -46,7 +46,7 @@ class ConfigController extends ActionController public function indexAction() { $form = new GeneralConfigForm(); - $form->setIniConfig(IcingaConfig::app()); + $form->setIniConfig(Config::app()); $form->handleRequest(); $this->view->form = $form; @@ -99,7 +99,7 @@ class ConfigController extends ActionController Notification::success(sprintf($this->translate('Module "%s" enabled'), $module)); $this->rerenderLayout()->reloadCss()->redirectNow('config/modules'); } catch (Exception $e) { - $this->view->exceptionMesssage = $e->getMessage(); + $this->view->exceptionMessage = $e->getMessage(); $this->view->moduleName = $module; $this->view->action = 'enable'; $this->render('module-configuration-error'); @@ -131,7 +131,7 @@ class ConfigController extends ActionController public function authenticationAction() { $form = new AuthenticationBackendReorderForm(); - $form->setIniConfig(IcingaConfig::app('authentication')); + $form->setIniConfig(Config::app('authentication')); $form->handleRequest(); $this->view->form = $form; @@ -145,7 +145,7 @@ class ConfigController extends ActionController public function createauthenticationbackendAction() { $form = new AuthenticationBackendConfigForm(); - $form->setIniConfig(IcingaConfig::app('authentication')); + $form->setIniConfig(Config::app('authentication')); $form->setResourceConfig(ResourceFactory::getResourceConfigs()); $form->setRedirectUrl('config/authentication'); $form->handleRequest(); @@ -161,7 +161,7 @@ class ConfigController extends ActionController public function editauthenticationbackendAction() { $form = new AuthenticationBackendConfigForm(); - $form->setIniConfig(IcingaConfig::app('authentication')); + $form->setIniConfig(Config::app('authentication')); $form->setResourceConfig(ResourceFactory::getResourceConfigs()); $form->setRedirectUrl('config/authentication'); $form->handleRequest(); @@ -177,10 +177,10 @@ class ConfigController extends ActionController public function removeauthenticationbackendAction() { $form = new ConfirmRemovalForm(array( - 'onSuccess' => function ($request) { + 'onSuccess' => function ($form) { $configForm = new AuthenticationBackendConfigForm(); - $configForm->setIniConfig(IcingaConfig::app('authentication')); - $authBackend = $request->getQuery('auth_backend'); + $configForm->setIniConfig(Config::app('authentication')); + $authBackend = $form->getRequest()->getQuery('auth_backend'); try { $configForm->remove($authBackend); @@ -212,7 +212,7 @@ class ConfigController extends ActionController */ public function resourceAction() { - $this->view->resources = IcingaConfig::app('resources', true)->toArray(); + $this->view->resources = Config::app('resources', true)->keys(); $this->view->tabs->activate('resources'); } @@ -222,7 +222,7 @@ class ConfigController extends ActionController public function createresourceAction() { $form = new ResourceConfigForm(); - $form->setIniConfig(IcingaConfig::app('resources')); + $form->setIniConfig(Config::app('resources')); $form->setRedirectUrl('config/resource'); $form->handleRequest(); @@ -236,7 +236,7 @@ class ConfigController extends ActionController public function editresourceAction() { $form = new ResourceConfigForm(); - $form->setIniConfig(IcingaConfig::app('resources')); + $form->setIniConfig(Config::app('resources')); $form->setRedirectUrl('config/resource'); $form->handleRequest(); @@ -250,10 +250,10 @@ class ConfigController extends ActionController public function removeresourceAction() { $form = new ConfirmRemovalForm(array( - 'onSuccess' => function ($request) { + 'onSuccess' => function ($form) { $configForm = new ResourceConfigForm(); - $configForm->setIniConfig(IcingaConfig::app('resources')); - $resource = $request->getQuery('resource'); + $configForm->setIniConfig(Config::app('resources')); + $resource = $form->getRequest()->getQuery('resource'); try { $configForm->remove($resource); @@ -274,9 +274,9 @@ class ConfigController extends ActionController // Check if selected resource is currently used for authentication $resource = $this->getRequest()->getQuery('resource'); - $authConfig = IcingaConfig::app('authentication')->toArray(); + $authConfig = Config::app('authentication'); foreach ($authConfig as $backendName => $config) { - if (array_key_exists('resource', $config) && $config['resource'] === $resource) { + if ($config->get('resource') === $resource) { $form->addError(sprintf( $this->translate( 'The resource "%s" is currently in use by the authentication backend "%s". ' . diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index 4942f5cdb..ba2125e12 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -2,111 +2,223 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -use Icinga\Web\Url; -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\Application\Logger; +use Icinga\Exception\ProgrammingError; +use Icinga\Forms\ConfirmRemovalForm; +use Icinga\Forms\Dashboard\DashletForm; +use Icinga\Web\Form; +use Icinga\Web\Notification; use Icinga\Web\Controller\ActionController; -use Icinga\Exception\IcingaException; +use Icinga\Web\Request; +use Icinga\Web\Url; +use Icinga\Web\Widget\Dashboard; +use Icinga\Web\Widget\Tabextension\DashboardSettings; /** - * Handle creation, removal and displaying of dashboards, panes and components + * Handle creation, removal and displaying of dashboards, panes and dashlets * * @see Icinga\Web\Widget\Dashboard for more information about dashboards */ class DashboardController extends ActionController { /** - * Default configuration + * @var Dashboard; */ - const DEFAULT_CONFIG = 'dashboard/dashboard'; - - /** - * Retrieve a dashboard from the provided config - * - * @param string $config The config to read the dashboard from, or 'dashboard/dashboard' if none is given - * - * @return \Icinga\Web\Widget\Dashboard - */ - private function getDashboard($config = self::DEFAULT_CONFIG) + private $dashboard; + + public function init() { - $dashboard = new Dashboard(); - try { - $dashboardConfig = IcingaConfig::app($config); - if (count($dashboardConfig) === 0) { - return null; - } - $dashboard->readConfig($dashboardConfig); - } catch (NotReadableError $e) { - Logger::error(new IcingaException('Cannot load dashboard configuration. An exception was thrown:', $e)); - return null; - } - return $dashboard; + $this->dashboard = new Dashboard(); + $this->dashboard->setUser($this->getRequest()->getUser()); + $this->dashboard->load(); } - /** - * Remove a component from the pane identified by the 'pane' parameter - */ - public function removecomponentAction() + public function newDashletAction() { - $pane = $this->_getParam('pane'); - $dashboard = $this->getDashboard(); - try { - $dashboard->removeComponent( - $pane, - $this->_getParam('component') - )->store(); - $this->redirectNow(Url::fromPath('dashboard', array('pane' => $pane))); - } catch (ConfigurationError $exc ) { - $this->_helper->viewRenderer('show_configuration'); - $this->view->exceptionMessage = $exc->getMessage(); - $this->view->iniConfigurationString = $dashboard->toIni(); + $form = new DashletForm(); + $this->createTabs(); + $dashboard = $this->dashboard; + $form->setDashboard($dashboard); + if ($this->_request->getParam('url')) { + $params = $this->_request->getParams(); + $params['url'] = rawurldecode($this->_request->getParam('url')); + $form->populate($params); } + $action = $this; + $form->setOnSuccess(function (Form $form) use ($dashboard, $action) { + try { + $pane = $dashboard->getPane($form->getValue('pane')); + } catch (ProgrammingError $e) { + $pane = new Dashboard\Pane($form->getValue('pane')); + $pane->setUserWidget(); + $dashboard->addPane($pane); + } + $dashlet = new Dashboard\Dashlet($form->getValue('dashlet'), $form->getValue('url'), $pane); + $dashlet->setUserWidget(); + $pane->addDashlet($dashlet); + try { + $dashboard->write(); + } catch (\Zend_Config_Exception $e) { + $action->view->error = $e; + $action->view->config = $dashboard->createWriter(); + $action->render('error'); + return false; + } + Notification::success(t('Dashlet created')); + return true; + }); + $form->setRedirectUrl('dashboard'); + $form->handleRequest(); + $this->view->form = $form; } - /** - * Display the form for adding new components or add the new component if submitted - */ - public function addurlAction() + public function updateDashletAction() { - $this->getTabs()->add( - 'addurl', - array( - 'title' => 'Add Dashboard URL', - 'url' => Url::fromRequest() - ) - )->activate('addurl'); - - $form = new AddUrlForm(); - $request = $this->getRequest(); - if ($request->isPost()) { - if ($form->isValid($request->getPost()) && $form->isSubmitted()) { - $dashboard = $this->getDashboard(); - $dashboard->setComponentUrl( - $form->getValue('pane'), - $form->getValue('component'), - ltrim($form->getValue('url'), '/') - ); - - $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('showConfiguration'); - return; - } - } - } else { - $form->create()->setDefault('url', htmlspecialchars_decode($request->getParam('url', ''))); + $this->createTabs(); + $dashboard = $this->dashboard; + $form = new DashletForm(); + $form->setDashboard($dashboard); + $form->setSubmitLabel(t('Update Dashlet')); + if (! $this->_request->getParam('pane')) { + throw new Zend_Controller_Action_Exception( + 'Missing parameter "pane"', + 400 + ); } + if (! $this->_request->getParam('dashlet')) { + throw new Zend_Controller_Action_Exception( + 'Missing parameter "dashlet"', + 400 + ); + } + $action = $this; + $form->setOnSuccess(function (Form $form) use ($dashboard, $action) { + try { + $pane = $dashboard->getPane($form->getValue('pane')); + } catch (ProgrammingError $e) { + $pane = new Dashboard\Pane($form->getValue('pane')); + $pane->setUserWidget(); + $dashboard->addPane($pane); + } + try { + $dashlet = $pane->getDashlet($form->getValue('dashlet')); + $dashlet->setUrl($form->getValue('url')); + } catch (ProgrammingError $e) { + $dashlet = new Dashboard\Dashlet($form->getValue('dashlet'), $form->getValue('url'), $pane); + $pane->addDashlet($dashlet); + } + $dashlet->setUserWidget(); + // Rename dashlet + if ($form->getValue('org_dashlet') && $form->getValue('org_dashlet') !== $dashlet->getTitle()) { + $pane->removeDashlet($form->getValue('org_dashlet')); + } + // Move + if ($form->getValue('org_pane') && $form->getValue('org_pane') !== $pane->getTitle()) { + $oldPane = $dashboard->getPane($form->getValue('org_pane')); + $oldPane->removeDashlet($dashlet->getTitle()); + } + try { + $dashboard->write(); + } catch (\Zend_Config_Exception $e) { + $action->view->error = $e; + $action->view->config = $dashboard->createWriter(); + $action->render('error'); + return false; + } + Notification::success(t('Dashlet updated')); + return true; + }); + $form->setRedirectUrl('dashboard/settings'); + $form->handleRequest(); + $pane = $dashboard->getPane($this->getParam('pane')); + $dashlet = $pane->getDashlet($this->getParam('dashlet')); + $form->load($dashlet); $this->view->form = $form; } + public function removeDashletAction() + { + $form = new ConfirmRemovalForm(); + $this->createTabs(); + $dashboard = $this->dashboard; + if (! $this->_request->getParam('pane')) { + throw new Zend_Controller_Action_Exception( + 'Missing parameter "pane"', + 400 + ); + } + if (! $this->_request->getParam('dashlet')) { + throw new Zend_Controller_Action_Exception( + 'Missing parameter "dashlet"', + 400 + ); + } + $pane = $this->_request->getParam('pane'); + $dashlet = $this->_request->getParam('dashlet'); + $action = $this; + $form->setOnSuccess(function (Form $form) use ($dashboard, $dashlet, $pane, $action) { + try { + $pane = $dashboard->getPane($pane); + $pane->removeDashlet($dashlet); + $dashboard->write(); + Notification::success(t('Dashlet has been removed from') . ' ' . $pane->getTitle()); + return true; + } catch (\Zend_Config_Exception $e) { + $action->view->error = $e; + $action->view->config = $dashboard->createWriter(); + $action->render('error'); + return false; + } catch (ProgrammingError $e) { + Notification::error($e->getMessage()); + return false; + } + return false; + }); + $form->setRedirectUrl('dashboard/settings'); + $form->handleRequest(); + $this->view->pane = $pane; + $this->view->dashlet = $dashlet; + $this->view->form = $form; + } + + public function removePaneAction() + { + $form = new ConfirmRemovalForm(); + $this->createTabs(); + $dashboard = $this->dashboard; + if (! $this->_request->getParam('pane')) { + throw new Zend_Controller_Action_Exception( + 'Missing parameter "pane"', + 400 + ); + } + $pane = $this->_request->getParam('pane'); + $action = $this; + $form->setOnSuccess(function (Form $form) use ($dashboard, $pane, $action) { + try { + $pane = $dashboard->getPane($pane); + $dashboard->removePane($pane->getTitle()); + $dashboard->write(); + Notification::success(t('Dashboard has been removed') . ': ' . $pane->getTitle()); + return true; + } catch (\Zend_Config_Exception $e) { + $action->view->error = $e; + $action->view->config = $dashboard->createWriter(); + $action->render('error'); + return false; + } catch (ProgrammingError $e) { + Notification::error($e->getMessage()); + return false; + } + return false; + }); + $form->setRedirectUrl('dashboard/settings'); + $form->handleRequest(); + $this->view->pane = $pane; + $this->view->form = $form; + } + /** * Display the dashboard with the pane set in the 'pane' request parameter * @@ -115,61 +227,49 @@ class DashboardController extends ActionController */ public function indexAction() { - $dashboard = Dashboard::load(); - - if (! $dashboard->hasPanes()) { + $this->createTabs(); + if (! $this->dashboard->hasPanes()) { $this->view->title = 'Dashboard'; } else { if ($this->_getParam('pane')) { $pane = $this->_getParam('pane'); - $dashboard->activate($pane); + $this->dashboard->activate($pane); } - - $this->view->configPath = IcingaConfig::resolvePath(self::DEFAULT_CONFIG); - - if ($dashboard === null) { + if ($this->dashboard === null) { $this->view->title = 'Dashboard'; } else { - $this->view->title = $dashboard->getActivePane()->getTitle() . ' :: Dashboard'; - $this->view->tabs = $dashboard->getTabs(); - - /* Temporarily removed + $this->view->title = $this->dashboard->getActivePane()->getTitle() . ' :: Dashboard'; + if ($this->hasParam('remove')) { + $this->dashboard->getActivePane()->removeDashlet($this->getParam('remove')); + $this->dashboard->write(); + $this->redirectNow(URL::fromRequest()->remove('remove')); + } $this->view->tabs->add( 'Add', array( 'title' => '+', - 'url' => Url::fromPath('dashboard/addurl') + 'url' => Url::fromPath('dashboard/new-dashlet') ) ); - */ - - $this->view->dashboard = $dashboard; + $this->view->dashboard = $this->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 + * Setting dialog */ - protected function writeConfiguration(Zend_Config $config, $target) + public function settingsAction() { - $writer = new PreservingIniWriter(array('config' => $config, 'filename' => $target)); + $this->createTabs(); + $this->view->dashboard = $this->dashboard; + } - try { - $writer->write(); - } catch (Exception $e) { - Logger::error(new ConfiguationError("Cannot write dashboard to $target", 0, $e)); - $this->view->configString = $writer->render(); - $this->view->errorMessage = $e->getMessage(); - $this->view->filePath = $target; - return false; - } - - return true; + /** + * Create tab aggregation + */ + private function createTabs() + { + $this->view->tabs = $this->dashboard->getTabs()->extend(new DashboardSettings()); } } diff --git a/application/controllers/ErrorController.php b/application/controllers/ErrorController.php index 074e2fdc2..23051bd9a 100644 --- a/application/controllers/ErrorController.php +++ b/application/controllers/ErrorController.php @@ -4,7 +4,7 @@ // namespace Icinga\Application\Controllers; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\Web\Controller\ActionController; use Icinga\Application\Icinga; diff --git a/application/controllers/FilterController.php b/application/controllers/FilterController.php index 2ffa869db..09e8f0368 100644 --- a/application/controllers/FilterController.php +++ b/application/controllers/FilterController.php @@ -4,7 +4,7 @@ use Icinga\Web\Controller\ActionController; use Icinga\Filter\Filter; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; /** * Application wide interface for filtering diff --git a/application/controllers/ListController.php b/application/controllers/ListController.php index 004c52148..f8b0ed1d6 100644 --- a/application/controllers/ListController.php +++ b/application/controllers/ListController.php @@ -3,11 +3,9 @@ // {{{ICINGA_LICENSE_HEADER}}} use Icinga\Module\Monitoring\Controller; -use Icinga\Web\Hook; use Icinga\Web\Url; -use Icinga\Data\ResourceFactory; -use Icinga\Logger\Logger; -use Icinga\Logger\Writer\FileWriter; +use Icinga\Application\Logger; +use Icinga\Data\ConfigObject; use Icinga\Protocol\File\FileReader; use \Zend_Controller_Action_Exception as ActionError; @@ -50,7 +48,7 @@ class ListController extends Controller . ' - (?.*)$/'; // message $loggerWriter = Logger::getInstance()->getWriter(); - $resource = new FileReader(new Zend_Config(array( + $resource = new FileReader(new ConfigObject(array( 'filename' => $loggerWriter->getPath(), 'fields' => $pattern ))); diff --git a/application/controllers/PreferenceController.php b/application/controllers/PreferenceController.php index bd76b2466..7acab7c25 100644 --- a/application/controllers/PreferenceController.php +++ b/application/controllers/PreferenceController.php @@ -6,7 +6,7 @@ use Icinga\Web\Controller\BasePreferenceController; use Icinga\Web\Url; use Icinga\Web\Widget\Tab; use Icinga\Application\Config; -use Icinga\Form\PreferenceForm; +use Icinga\Forms\PreferenceForm; use Icinga\Exception\ConfigurationError; use Icinga\User\Preferences\PreferencesStore; @@ -25,9 +25,9 @@ class PreferenceController extends BasePreferenceController public static function createProvidedTabs() { return array( - 'general' => new Tab( + 'preferences' => new Tab( array( - 'title' => 'General settings', + 'title' => t('Preferences'), 'url' => Url::fromPath('/preference') ) ) @@ -39,8 +39,8 @@ class PreferenceController extends BasePreferenceController */ public function indexAction() { - $storeConfig = Config::app()->preferences; - if ($storeConfig === null) { + $storeConfig = Config::app()->getSection('preferences'); + if ($storeConfig->isEmpty()) { throw new ConfigurationError(t('You need to configure how to store preferences first.')); } @@ -51,6 +51,6 @@ class PreferenceController extends BasePreferenceController $form->handleRequest(); $this->view->form = $form; - $this->getTabs()->activate('general'); + $this->getTabs()->activate('preferences'); } } diff --git a/application/controllers/StaticController.php b/application/controllers/StaticController.php index c8b1d9b73..fc5f1354f 100644 --- a/application/controllers/StaticController.php +++ b/application/controllers/StaticController.php @@ -4,7 +4,7 @@ use Icinga\Web\Controller\ActionController; use Icinga\Application\Icinga; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\Web\FileCache; use Zend_Controller_Action_Exception as ActionException; diff --git a/application/fonts/fontello-ifont/LICENSE.txt b/application/fonts/fontello-ifont/LICENSE.txt new file mode 100644 index 000000000..29b99c574 --- /dev/null +++ b/application/fonts/fontello-ifont/LICENSE.txt @@ -0,0 +1,39 @@ +Font license info + + +## Font Awesome + + Copyright (C) 2012 by Dave Gandy + + Author: Dave Gandy + License: SIL () + Homepage: http://fortawesome.github.com/Font-Awesome/ + + +## Iconic + + Copyright (C) 2012 by P.J. Onori + + Author: P.J. Onori + License: SIL (http://scripts.sil.org/OFL) + Homepage: http://somerandomdude.com/work/iconic/ + + +## MFG Labs + + Copyright (C) 2012 by Daniel Bruce + + Author: MFG Labs + License: SIL (http://scripts.sil.org/OFL) + Homepage: http://www.mfglabs.com/ + + +## Entypo + + Copyright (C) 2012 by Daniel Bruce + + Author: Daniel Bruce + License: SIL (http://scripts.sil.org/OFL) + Homepage: http://www.entypo.com + + diff --git a/application/fonts/fontello-ifont/README.txt b/application/fonts/fontello-ifont/README.txt new file mode 100644 index 000000000..43e23f283 --- /dev/null +++ b/application/fonts/fontello-ifont/README.txt @@ -0,0 +1,75 @@ +This webfont is generated by http://fontello.com open source project. + + +================================================================================ +Please, note, that you should obey original font licences, used to make this +webfont pack. Details available in LICENSE.txt file. + +- Usually, it's enough to publish content of LICENSE.txt file somewhere on your + site in "About" section. + +- If your project is open-source, usually, it will be ok to make LICENSE.txt + file publically available in your repository. + +- Fonts, used in Fontello, don't require to make clickable links on your site. + But any kind of additional authors crediting is welcome. +================================================================================ + + +Comments on archive content +--------------------------- + +- /font/* - fonts in different formats + +- /css/* - different kinds of css, for all situations. Should be ok with + twitter bootstrap. Also, you can skip style and assign icon classes + directly to text elements, if you don't mind about IE7. + +- demo.html - demo file, to show your webfont content + +- LICENSE.txt - license info about source fonts, used to build your one. + +- config.json - keeps your settings. You can import it back to fontello anytime, + to continue your work + + +Why so many CSS files ? +----------------------- + +Because we like to fit all your needs :) + +- basic file, .css - is usually enougth, in contains @font-face + and character codes definition + +- *-ie7.css - if you need IE7 support, but still don't wish to put char codes + directly into html + +- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face + rules, but still wish to benefit of css generation. That can be very + convenient for automated assets build systems. When you need to update font - + no needs to manually edit files, just override old version with archive + content. See fontello source codes for example. + +- *-embedded.css - basic css file, but with embedded WOFF font, to avoid + CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain. + We strongly recommend to resolve this issue by `Access-Control-Allow-Origin` + server headers. But if you ok with dirty hack - this file is for you. Note, + that data url moved to separate @font-face to avoid problems with + + + + + + + + +
+

+ ifont + font demo +

+ +
+
+
+
icon-dashboard0xe800
+
icon-user0xe801
+
icon-users0xe802
+
icon-ok0xe803
+
+
+
icon-cancel0xe804
+
icon-plus0xe805
+
icon-minus0xe806
+
icon-folder-empty0xe807
+
+
+
icon-download0xe808
+
icon-upload0xe809
+
icon-git0xe80a
+
icon-cubes0xe80b
+
+
+
icon-database0xe80c
+
icon-gauge0xe80d
+
icon-sitemap0xe80e
+
icon-sort-name-up0xe80f
+
+
+
icon-sort-name-down0xe810
+
icon-megaphone0xe811
+
icon-bug0xe812
+
icon-tasks0xe813
+
+
+
icon-filter0xe814
+
icon-off0xe815
+
icon-book0xe816
+
icon-paste0xe817
+
+
+
icon-scissors0xe818
+
icon-globe0xe819
+
icon-cloud0xe81a
+
icon-flash0xe81b
+
+
+
icon-barchart0xe81c
+
icon-down-dir0xe81d
+
icon-up-dir0xe81e
+
icon-left-dir0xe81f
+
+
+
icon-right-dir0xe820
+
icon-down-open0xe821
+
icon-right-open0xe822
+
icon-up-open0xe823
+
+
+
icon-left-open0xe824
+
icon-up-big0xe825
+
icon-right-big0xe826
+
icon-left-big0xe827
+
+
+
icon-down-big0xe828
+
icon-resize-full-alt0xe829
+
icon-resize-full0xe82a
+
icon-resize-small0xe82b
+
+
+
icon-move0xe82c
+
icon-resize-horizontal0xe82d
+
icon-resize-vertical0xe82e
+
icon-zoom-in0xe82f
+
+
+
icon-block0xe830
+
icon-zoom-out0xe831
+
icon-lightbulb0xe832
+
icon-clock0xe833
+
+
+
icon-volume-up0xe834
+
icon-volume-down0xe835
+
icon-volume-off0xe836
+
icon-mute0xe837
+
+
+
icon-mic0xe838
+
icon-endtime0xe839
+
icon-starttime0xe83a
+
icon-calendar-empty0xe83b
+
+
+
icon-calendar0xe83c
+
icon-wrench0xe83d
+
icon-sliders0xe83e
+
icon-services0xe83f
+
+
+
icon-service0xe840
+
icon-phone0xe841
+
icon-file-pdf0xe842
+
icon-file-word0xe843
+
+
+
icon-file-excel0xe844
+
icon-doc-text0xe845
+
icon-trash0xe846
+
icon-comment-empty0xe847
+
+
+
icon-comment0xe848
+
icon-chat0xe849
+
icon-chat-empty0xe84a
+
icon-bell0xe84b
+
+
+
icon-bell-alt0xe84c
+
icon-attention-alt0xe84d
+
icon-print0xe84e
+
icon-edit0xe84f
+
+
+
icon-forward0xe850
+
icon-reply0xe851
+
icon-reply-all0xe852
+
icon-eye0xe853
+
+
+
icon-tag0xe854
+
icon-tags0xe855
+
icon-lock-open-alt0xe856
+
icon-lock-open0xe857
+
+
+
icon-lock0xe858
+
icon-home0xe859
+
icon-info0xe85a
+
icon-help0xe85b
+
+
+
icon-search0xe85c
+
icon-flapping0xe85d
+
icon-rewind0xe85e
+
icon-chart-line0xe85f
+
+
+
icon-bell-off0xe860
+
icon-bell-off-empty0xe861
+
icon-plug0xe862
+
icon-eye-off0xe863
+
+
+
icon-reschedule0xe864
+
icon-cw0xe865
+
icon-host0xe866
+
icon-thumbs-up0xe867
+
+
+
icon-thumbs-down0xe868
+
icon-spinner0xe869
+
icon-attach0xe86a
+
icon-keyboard0xe86b
+
+
+
icon-menu0xe86c
+
icon-wifi0xe86d
+
icon-moon0xe86e
+
icon-chart-pie0xe86f
+
+
+
icon-chart-area0xe870
+
icon-chart-bar0xe871
+
icon-beaker0xe872
+
icon-magic0xe873
+
+
+ + + \ No newline at end of file diff --git a/application/fonts/fontello-ifont/font/ifont.eot b/application/fonts/fontello-ifont/font/ifont.eot new file mode 100644 index 000000000..22e4b3011 Binary files /dev/null and b/application/fonts/fontello-ifont/font/ifont.eot differ diff --git a/application/fonts/fontello-ifont/font/ifont.svg b/application/fonts/fontello-ifont/font/ifont.svg new file mode 100644 index 000000000..ae7e08c46 --- /dev/null +++ b/application/fonts/fontello-ifont/font/ifont.svg @@ -0,0 +1,127 @@ + + + +Copyright (C) 2014 by original authors @ fontello.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/application/fonts/fontello-ifont/font/ifont.ttf b/application/fonts/fontello-ifont/font/ifont.ttf new file mode 100644 index 000000000..931b3d157 Binary files /dev/null and b/application/fonts/fontello-ifont/font/ifont.ttf differ diff --git a/application/fonts/fontello-ifont/font/ifont.woff b/application/fonts/fontello-ifont/font/ifont.woff new file mode 100644 index 000000000..36c96a967 Binary files /dev/null and b/application/fonts/fontello-ifont/font/ifont.woff differ diff --git a/application/forms/Authentication/LoginForm.php b/application/forms/Authentication/LoginForm.php index 0afc56749..a6d69d15a 100644 --- a/application/forms/Authentication/LoginForm.php +++ b/application/forms/Authentication/LoginForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Authentication; +namespace Icinga\Forms\Authentication; use Icinga\Web\Form; use Icinga\Web\Url; diff --git a/application/forms/Config/Authentication/AutologinBackendForm.php b/application/forms/Config/Authentication/AutologinBackendForm.php index 4f4df73e3..a21d2c006 100644 --- a/application/forms/Config/Authentication/AutologinBackendForm.php +++ b/application/forms/Config/Authentication/AutologinBackendForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Authentication; +namespace Icinga\Forms\Config\Authentication; use Zend_Validate_Callback; use Icinga\Web\Form; @@ -31,7 +31,9 @@ class AutologinBackendForm extends Form array( 'required' => true, 'label' => t('Backend Name'), - 'description' => t('The name of this authentication backend'), + 'description' => t( + 'The name of this authentication provider that is used to differentiate it from others' + ), 'validators' => array( array( 'Regex', @@ -50,9 +52,8 @@ class AutologinBackendForm extends Form 'text', 'strip_username_regexp', array( - 'required' => true, - 'label' => t('Backend Domain Pattern'), - 'description' => t('The domain pattern of this authentication backend'), + 'label' => t('Filter Pattern'), + 'description' => t('The regular expression to use to strip specific parts off from usernames. Leave empty if you do not want to strip off anything'), 'value' => '/\@[^$]+$/', 'validators' => array( new Zend_Validate_Callback(function ($value) { @@ -65,7 +66,7 @@ class AutologinBackendForm extends Form 'hidden', 'backend', array( - 'required' => true, + 'disabled' => true, 'value' => 'autologin' ) ); @@ -82,7 +83,7 @@ class AutologinBackendForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidAuthenticationBackend(Form $form) + public static function isValidAuthenticationBackend(Form $form) { return true; } diff --git a/application/forms/Config/Authentication/DbBackendForm.php b/application/forms/Config/Authentication/DbBackendForm.php index 23335f8fa..572a09c2e 100644 --- a/application/forms/Config/Authentication/DbBackendForm.php +++ b/application/forms/Config/Authentication/DbBackendForm.php @@ -2,11 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Authentication; +namespace Icinga\Forms\Config\Authentication; use Exception; use Icinga\Web\Form; -use Icinga\Web\Request; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Authentication\Backend\DbUserBackend; @@ -54,7 +54,9 @@ class DbBackendForm extends Form array( 'required' => true, 'label' => t('Backend Name'), - 'description' => t('The name of this authentication provider'), + 'description' => t( + 'The name of this authentication provider that is used to differentiate it from others' + ), ) ); $this->addElement( @@ -73,7 +75,7 @@ class DbBackendForm extends Form 'hidden', 'backend', array( - 'required' => true, + 'disabled' => true, 'value' => 'db' ) ); @@ -86,9 +88,9 @@ class DbBackendForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - if (false === $this->isValidAuthenticationBackend($this)) { + if (false === static::isValidAuthenticationBackend($this)) { return false; } } @@ -100,21 +102,29 @@ class DbBackendForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidAuthenticationBackend(Form $form) + public static function isValidAuthenticationBackend(Form $form) { - $element = $form->getElement('resource'); - try { - $dbUserBackend = new DbUserBackend(ResourceFactory::create($element->getValue())); + $dbUserBackend = new DbUserBackend(ResourceFactory::createResource($form->getResourceConfig())); if ($dbUserBackend->count() < 1) { - $element->addError(t('No users found under the specified database backend')); + $form->addError(t('No users found under the specified database backend')); return false; } } catch (Exception $e) { - $element->addError(sprintf(t('Using the specified backend failed: %s'), $e->getMessage())); + $form->addError(sprintf(t('Using the specified backend failed: %s'), $e->getMessage())); return false; } return true; } + + /** + * Return the configuration for the chosen resource + * + * @return ConfigObject + */ + public function getResourceConfig() + { + return ResourceFactory::getResourceConfig($this->getValue('resource')); + } } diff --git a/application/forms/Config/Authentication/LdapBackendForm.php b/application/forms/Config/Authentication/LdapBackendForm.php index 6056b0911..9b48c3dbc 100644 --- a/application/forms/Config/Authentication/LdapBackendForm.php +++ b/application/forms/Config/Authentication/LdapBackendForm.php @@ -2,12 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Authentication; +namespace Icinga\Forms\Config\Authentication; use Exception; use Icinga\Web\Form; -use Icinga\Web\Request; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; +use Icinga\Exception\AuthenticationException; use Icinga\Authentication\Backend\LdapUserBackend; /** @@ -54,7 +55,9 @@ class LdapBackendForm extends Form array( 'required' => true, 'label' => t('Backend Name'), - 'description' => t('The name of this authentication backend') + 'description' => t( + 'The name of this authentication provider that is used to differentiate it from others' + ) ) ); $this->addElement( @@ -93,11 +96,20 @@ class LdapBackendForm extends Form 'hidden', 'backend', array( - 'required' => true, + 'disabled' => true, 'value' => 'ldap' ) ); - + $this->addElement( + 'text', + 'base_dn', + array( + 'required' => false, + 'label' => t('Base DN'), + 'description' => t('The path where users can be found on the ldap server. ' . + ' Leave empty to select all users available on the specified resource.') + ) + ); return $this; } @@ -106,9 +118,9 @@ class LdapBackendForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - if (false === $this->isValidAuthenticationBackend($this)) { + if (false === static::isValidAuthenticationBackend($this)) { return false; } } @@ -120,22 +132,34 @@ class LdapBackendForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidAuthenticationBackend(Form $form) + public static function isValidAuthenticationBackend(Form $form) { - $element = $form->getElement('resource'); - try { $ldapUserBackend = new LdapUserBackend( - ResourceFactory::create($element->getValue()), + ResourceFactory::createResource($form->getResourceConfig()), $form->getElement('user_class')->getValue(), - $form->getElement('user_name_attribute')->getValue() + $form->getElement('user_name_attribute')->getValue(), + $form->getElement('base_dn')->getValue() ); $ldapUserBackend->assertAuthenticationPossible(); + } catch (AuthenticationException $e) { + $form->addError($e->getMessage()); + return false; } catch (Exception $e) { - $element->addError(sprintf(t('Connection validation failed: %s'), $e->getMessage())); + $form->addError(sprintf(t('Unable to validate authentication: %s'), $e->getMessage())); return false; } return true; } + + /** + * Return the configuration for the chosen resource + * + * @return ConfigObject + */ + public function getResourceConfig() + { + return ResourceFactory::getResourceConfig($this->getValue('resource')); + } } diff --git a/application/forms/Config/AuthenticationBackendConfigForm.php b/application/forms/Config/AuthenticationBackendConfigForm.php index e81382cd4..12f407c69 100644 --- a/application/forms/Config/AuthenticationBackendConfigForm.php +++ b/application/forms/Config/AuthenticationBackendConfigForm.php @@ -2,18 +2,19 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; use InvalidArgumentException; -use Icinga\Web\Request; -use Icinga\Form\ConfigForm; +use Icinga\Forms\ConfigForm; use Icinga\Web\Notification; use Icinga\Application\Config; use Icinga\Application\Platform; +use Icinga\Data\ConfigObject; +use Icinga\Data\ResourceFactory; use Icinga\Exception\ConfigurationError; -use Icinga\Form\Config\Authentication\DbBackendForm; -use Icinga\Form\Config\Authentication\LdapBackendForm; -use Icinga\Form\Config\Authentication\AutologinBackendForm; +use Icinga\Forms\Config\Authentication\DbBackendForm; +use Icinga\Forms\Config\Authentication\LdapBackendForm; +use Icinga\Forms\Config\Authentication\AutologinBackendForm; class AuthenticationBackendConfigForm extends ConfigForm { @@ -39,8 +40,6 @@ class AuthenticationBackendConfigForm extends ConfigForm * @param Config $resources The resource configuration * * @return self - * - * @throws ConfigurationError In case no resources are available for authentication */ public function setResourceConfig(Config $resourceConfig) { @@ -49,10 +48,6 @@ class AuthenticationBackendConfigForm extends ConfigForm $resources[strtolower($resource->type)][] = $name; } - if (empty($resources)) { - throw new ConfigurationError(t('Could not find any resources for authentication')); - } - $this->resources = $resources; return $this; } @@ -97,12 +92,12 @@ class AuthenticationBackendConfigForm extends ConfigForm $name = isset($values['name']) ? $values['name'] : ''; if (! $name) { throw new InvalidArgumentException(t('Authentication backend name missing')); - } elseif ($this->config->get($name) !== null) { + } elseif ($this->config->hasSection($name)) { throw new InvalidArgumentException(t('Authentication backend already exists')); } unset($values['name']); - $this->config->{$name} = $values; + $this->config->setSection($name, $values); return $this; } @@ -122,18 +117,19 @@ class AuthenticationBackendConfigForm extends ConfigForm throw new InvalidArgumentException(t('Old authentication backend name missing')); } elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) { throw new InvalidArgumentException(t('New authentication backend name missing')); - } elseif (($backendConfig = $this->config->get($name)) === null) { + } elseif (! $this->config->hasSection($name)) { throw new InvalidArgumentException(t('Unknown authentication backend provided')); } + $backendConfig = $this->config->getSection($name); if ($newName !== $name) { // Only remove the old entry if it has changed as the order gets screwed when editing backend names - unset($this->config->{$name}); + $this->config->removeSection($name); } unset($values['name']); - $this->config->{$newName} = array_merge($backendConfig->toArray(), $values); - return $this->config->{$newName}; + $this->config->setSection($newName, $backendConfig->merge($values)); + return $backendConfig; } /** @@ -149,11 +145,12 @@ class AuthenticationBackendConfigForm extends ConfigForm { if (! $name) { throw new InvalidArgumentException(t('Authentication backend name missing')); - } elseif (($backendConfig = $this->config->get($name)) === null) { + } elseif (! $this->config->hasSection($name)) { throw new InvalidArgumentException(t('Unknown authentication backend provided')); } - unset($this->config->{$name}); + $backendConfig = $this->config->getSection($name); + $this->config->removeSection($name); return $backendConfig; } @@ -171,7 +168,7 @@ class AuthenticationBackendConfigForm extends ConfigForm { if (! $name) { throw new InvalidArgumentException(t('Authentication backend name missing')); - } elseif ($this->config->get($name) === null) { + } elseif (! $this->config->hasSection($name)) { throw new InvalidArgumentException(t('Unknown authentication backend provided')); } @@ -181,10 +178,10 @@ class AuthenticationBackendConfigForm extends ConfigForm $newConfig = array(); foreach ($backendOrder as $backendName) { - $newConfig[$backendName] = $this->config->get($backendName); + $newConfig[$backendName] = $this->config->getSection($backendName); } - $config = new Config($newConfig); + $config = Config::fromArray($newConfig); $this->config = $config->setConfigFile($this->config->getConfigFile()); return $this; } @@ -197,17 +194,17 @@ class AuthenticationBackendConfigForm extends ConfigForm * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) { $backendForm = $this->getBackendForm($this->getElement('type')->getValue()); - if (false === $backendForm->isValidAuthenticationBackend($this)) { + if (false === $backendForm::isValidAuthenticationBackend($this)) { $this->addElement($this->getForceCreationCheckbox()); return false; } } - $authBackend = $request->getQuery('auth_backend'); + $authBackend = $this->request->getQuery('auth_backend'); try { if ($authBackend === null) { // create new backend $this->add($this->getValues()); @@ -235,22 +232,33 @@ class AuthenticationBackendConfigForm extends ConfigForm * * @throws ConfigurationError In case the backend name is missing in the request or is invalid */ - public function onRequest(Request $request) + public function onRequest() { - $authBackend = $request->getQuery('auth_backend'); + $authBackend = $this->request->getQuery('auth_backend'); if ($authBackend !== null) { if ($authBackend === '') { throw new ConfigurationError(t('Authentication backend name missing')); - } elseif (false === isset($this->config->{$authBackend})) { + } elseif (! $this->config->hasSection($authBackend)) { throw new ConfigurationError(t('Unknown authentication backend provided')); - } elseif (false === isset($this->config->{$authBackend}->backend)) { + } elseif ($this->config->getSection($authBackend)->backend === null) { throw new ConfigurationError(sprintf(t('Backend "%s" has no `backend\' setting'), $authBackend)); } - $configValues = $this->config->{$authBackend}->toArray(); + $configValues = $this->config->getSection($authBackend)->toArray(); $configValues['type'] = $configValues['backend']; $configValues['name'] = $authBackend; $this->populate($configValues); + } elseif (empty($this->resources)) { + $autologinBackends = array_filter( + $this->config->toArray(), + function ($authBackendCfg) { + return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'autologin'; + } + ); + + if (false === empty($autologinBackends)) { + throw new ConfigurationError(t('Could not find any resources for authentication')); + } } } @@ -280,7 +288,7 @@ class AuthenticationBackendConfigForm extends ConfigForm public function createElements(array $formData) { $backendTypes = array(); - $backendType = isset($formData['type']) ? $formData['type'] : 'db'; + $backendType = isset($formData['type']) ? $formData['type'] : null; if (isset($this->resources['db'])) { $backendTypes['db'] = t('Database'); @@ -299,6 +307,10 @@ class AuthenticationBackendConfigForm extends ConfigForm $backendTypes['autologin'] = t('Autologin'); } + if ($backendType === null) { + $backendType = key($backendTypes); + } + $this->addElement( 'select', 'type', @@ -307,7 +319,7 @@ class AuthenticationBackendConfigForm extends ConfigForm 'required' => true, 'autosubmit' => true, 'label' => t('Backend Type'), - 'description' => t('The type of the resource to use for this authenticaton backend'), + 'description' => t('The type of the resource to use for this authenticaton provider'), 'multiOptions' => $backendTypes ) ); @@ -319,4 +331,14 @@ class AuthenticationBackendConfigForm extends ConfigForm $this->addElements($this->getBackendForm($backendType)->createElements($formData)->getElements()); } + + /** + * Return the configuration for the chosen resource + * + * @return ConfigObject + */ + public function getResourceConfig() + { + return ResourceFactory::getResourceConfig($this->getValue('resource')); + } } diff --git a/application/forms/Config/AuthenticationBackendReorderForm.php b/application/forms/Config/AuthenticationBackendReorderForm.php index 3b5e70866..07200827a 100644 --- a/application/forms/Config/AuthenticationBackendReorderForm.php +++ b/application/forms/Config/AuthenticationBackendReorderForm.php @@ -2,12 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; use InvalidArgumentException; -use Icinga\Web\Request; use Icinga\Web\Notification; -use Icinga\Form\ConfigForm; +use Icinga\Forms\ConfigForm; class AuthenticationBackendReorderForm extends ConfigForm { @@ -30,17 +29,26 @@ class AuthenticationBackendReorderForm extends ConfigForm return $this->config->keys(); } + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + // This adds just a dummy element to be able to utilize Form::getValue as part of onSuccess() + $this->addElement('hidden', 'backend_newpos'); + } + /** * Update the authentication backend order and save the configuration * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - $formData = $this->getRequestData($request); - if (isset($formData['backend_newpos'])) { + $newPosData = $this->getValue('backend_newpos'); + if ($newPosData) { $configForm = $this->getConfigForm(); - list($backendName, $position) = explode('|', $formData['backend_newpos'], 2); + list($backendName, $position) = explode('|', $newPosData, 2); try { if ($configForm->move($backendName, $position)->save()) { diff --git a/application/forms/Config/General/ApplicationConfigForm.php b/application/forms/Config/General/ApplicationConfigForm.php index fda695886..95ad22071 100644 --- a/application/forms/Config/General/ApplicationConfigForm.php +++ b/application/forms/Config/General/ApplicationConfigForm.php @@ -2,12 +2,14 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\General; +namespace Icinga\Forms\Config\General; use DateTimeZone; -use Icinga\Web\Form; -use Icinga\Util\Translator; +use Icinga\Application\Icinga; use Icinga\Data\ResourceFactory; +use Icinga\Util\Translator; +use Icinga\Web\Form; + /** * Form class to modify the general application configuration @@ -27,56 +29,18 @@ class ApplicationConfigForm extends Form */ public function createElements(array $formData) { - $languages = array(); - foreach (Translator::getAvailableLocaleCodes() as $language) { - $languages[$language] = $language; - } - - $this->addElement( - 'select', - 'global_language', - array( - 'label' => t('Default Language'), - 'required' => true, - 'multiOptions' => $languages, - 'description' => t( - 'Select the language to use by default. Can be overwritten by a user in his preferences.' - ) - ) - ); - - $tzList = array(); - foreach (DateTimeZone::listIdentifiers() as $tz) { - $tzList[$tz] = $tz; - } - - $this->addElement( - 'select', - 'global_timezone', - array( - 'label' => t('Default Application Timezone'), - 'required' => true, - 'multiOptions' => $tzList, - 'description' => t( - 'Select the timezone to be used as the default. User\'s can set their own timezone if' - . ' they like to, but this is the timezone to be used as the default setting .' - ), - 'value' => date_default_timezone_get() - ) - ); - $this->addElement( 'text', - 'global_modulePath', + 'global_module_path', array( 'label' => t('Module Path'), 'required' => true, + 'value' => implode(':', Icinga::app()->getModuleManager()->getModuleDirs()), 'description' => t( 'Contains the directories that will be searched for available modules, separated by ' . 'colons. Modules that don\'t exist in these directories can still be symlinked in ' . 'the module folder, but won\'t show up in the list of disabled modules.' - ), - 'value' => realpath(ICINGAWEB_APPDIR . '/../modules') + ) ) ); diff --git a/application/forms/Config/General/LoggingConfigForm.php b/application/forms/Config/General/LoggingConfigForm.php index 733c306b9..deed06011 100644 --- a/application/forms/Config/General/LoggingConfigForm.php +++ b/application/forms/Config/General/LoggingConfigForm.php @@ -2,10 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\General; +namespace Icinga\Forms\Config\General; use Icinga\Application\Icinga; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\Web\Form; use Icinga\Web\Form\Validator\WritablePathValidator; @@ -30,13 +30,13 @@ class LoggingConfigForm extends Form 'logging_log', array( 'required' => true, - 'class' => 'autosubmit', + 'autosubmit' => true, 'label' => t('Logging Type'), 'description' => t('The type of logging to utilize.'), 'multiOptions' => array( 'syslog' => 'Syslog', - 'file' => t('File'), - 'none' => t('None') + 'file' => t('File', 'app.config.logging.type'), + 'none' => t('None', 'app.config.logging.type') ) ) ); @@ -50,16 +50,16 @@ class LoggingConfigForm extends Form 'label' => t('Logging Level'), 'description' => t('The maximum logging level to emit.'), 'multiOptions' => array( - Logger::$levels[Logger::ERROR] => t('Error'), - Logger::$levels[Logger::WARNING] => t('Warning'), - Logger::$levels[Logger::INFO] => t('Information'), - Logger::$levels[Logger::DEBUG] => t('Debug') + Logger::$levels[Logger::ERROR] => t('Error', 'app.config.logging.level'), + Logger::$levels[Logger::WARNING] => t('Warning', 'app.config.logging.level'), + Logger::$levels[Logger::INFO] => t('Information', 'app.config.logging.level'), + Logger::$levels[Logger::DEBUG] => t('Debug', 'app.config.logging.level') ) ) ); } - if (isset($formData['logging_log']) && $formData['logging_log'] === 'syslog') { + if (false === isset($formData['logging_log']) || $formData['logging_log'] === 'syslog') { $this->addElement( 'text', 'logging_application', diff --git a/application/forms/Config/GeneralConfigForm.php b/application/forms/Config/GeneralConfigForm.php index 0b55704c2..0d81bb96b 100644 --- a/application/forms/Config/GeneralConfigForm.php +++ b/application/forms/Config/GeneralConfigForm.php @@ -2,13 +2,12 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; -use Icinga\Web\Request; use Icinga\Web\Notification; -use Icinga\Form\ConfigForm; -use Icinga\Form\Config\General\LoggingConfigForm; -use Icinga\Form\Config\General\ApplicationConfigForm; +use Icinga\Forms\ConfigForm; +use Icinga\Forms\Config\General\LoggingConfigForm; +use Icinga\Forms\Config\General\ApplicationConfigForm; /** * Form class for application-wide and logging specific settings @@ -38,18 +37,18 @@ class GeneralConfigForm extends ConfigForm /** * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { $sections = array(); foreach ($this->getValues() as $sectionAndPropertyName => $value) { - list($section, $property) = explode('_', $sectionAndPropertyName); + list($section, $property) = explode('_', $sectionAndPropertyName, 2); if (! isset($sections[$section])) { $sections[$section] = array(); } $sections[$section][$property] = $value; } foreach ($sections as $section => $config) { - $this->config->{$section} = $config; + $this->config->setSection($section, $config); } if ($this->save()) { @@ -62,7 +61,7 @@ class GeneralConfigForm extends ConfigForm /** * @see Form::onRequest() */ - public function onRequest(Request $request) + public function onRequest() { $values = array(); foreach ($this->config as $section => $properties) { diff --git a/application/forms/Config/Resource/DbResourceForm.php b/application/forms/Config/Resource/DbResourceForm.php index 4fd7297d9..d5197c94e 100644 --- a/application/forms/Config/Resource/DbResourceForm.php +++ b/application/forms/Config/Resource/DbResourceForm.php @@ -2,14 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Exception; -use Zend_Config; use Icinga\Web\Form; -use Icinga\Web\Request; -use Icinga\Web\Form\Element\Number; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; +use Icinga\Application\Platform; /** * Form class for adding/modifying database resources @@ -29,6 +28,23 @@ class DbResourceForm extends Form */ public function createElements(array $formData) { + $dbChoices = array(); + if (Platform::zendClassExists('Zend_Db_Adapter_Pdo_Mysql')) { + $dbChoices['mysql'] = 'MySQL'; + } + if (Platform::zendClassExists('Zend_Db_Adapter_Pdo_Pgsql')) { + $dbChoices['pgsql'] = 'PostgreSQL'; + } + + $this->addElement( + 'text', + 'name', + array( + 'required' => true, + 'label' => t('Resource Name'), + 'description' => t('The unique name of this resource') + ) + ); $this->addElement( 'select', 'db', @@ -36,11 +52,7 @@ class DbResourceForm extends Form 'required' => true, 'label' => t('Database Type'), 'description' => t('The type of SQL database'), - 'multiOptions' => array( - 'mysql' => 'MySQL', - 'pgsql' => 'PostgreSQL' - //'oracle' => 'Oracle' - ) + 'multiOptions' => $dbChoices ) ); $this->addElement( @@ -54,14 +66,13 @@ class DbResourceForm extends Form ) ); $this->addElement( - new Number( - array( - 'required' => true, - 'name' => 'port', - 'label' => t('Port'), - 'description' => t('The port to use'), - 'value' => 3306 - ) + 'number', + 'port', + array( + 'required' => true, + 'label' => t('Port'), + 'description' => t('The port to use'), + 'value' => 3306 ) ); $this->addElement( @@ -101,9 +112,9 @@ class DbResourceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - if (false === $this->isValidResource($this)) { + if (false === static::isValidResource($this)) { return false; } } @@ -115,10 +126,10 @@ class DbResourceForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidResource(Form $form) + public static function isValidResource(Form $form) { try { - $resource = ResourceFactory::createResource(new Zend_Config($form->getValues())); + $resource = ResourceFactory::createResource(new ConfigObject($form->getValues())); $resource->getConnection()->getConnection(); } catch (Exception $e) { $form->addError(t('Connectivity validation failed, connection to the given resource not possible.')); diff --git a/application/forms/Config/Resource/FileResourceForm.php b/application/forms/Config/Resource/FileResourceForm.php index d1d33a749..8e2920313 100644 --- a/application/forms/Config/Resource/FileResourceForm.php +++ b/application/forms/Config/Resource/FileResourceForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Icinga\Web\Form; use Icinga\Web\Form\Validator\ReadablePathValidator; @@ -25,6 +25,15 @@ class FileResourceForm extends Form */ public function createElements(array $formData) { + $this->addElement( + 'text', + 'name', + array( + 'required' => true, + 'label' => t('Resource Name'), + 'description' => t('The unique name of this resource') + ) + ); $this->addElement( 'text', 'filename', diff --git a/application/forms/Config/Resource/LdapResourceForm.php b/application/forms/Config/Resource/LdapResourceForm.php index 6196f3a17..6641b96bb 100644 --- a/application/forms/Config/Resource/LdapResourceForm.php +++ b/application/forms/Config/Resource/LdapResourceForm.php @@ -2,13 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Exception; -use Zend_Config; use Icinga\Web\Form; -use Icinga\Web\Request; -use Icinga\Web\Form\Element\Number; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; /** @@ -29,6 +27,15 @@ class LdapResourceForm extends Form */ public function createElements(array $formData) { + $this->addElement( + 'text', + 'name', + array( + 'required' => true, + 'label' => t('Resource Name'), + 'description' => t('The unique name of this resource') + ) + ); $this->addElement( 'text', 'hostname', @@ -40,14 +47,13 @@ class LdapResourceForm extends Form ) ); $this->addElement( - new Number( - array( - 'required' => true, - 'name' => 'port', - 'label' => t('Port'), - 'description' => t('The port of the LDAP server to use for authentication'), - 'value' => 389 - ) + 'number', + 'port', + array( + 'required' => true, + 'label' => t('Port'), + 'description' => t('The port of the LDAP server to use for authentication'), + 'value' => 389 ) ); $this->addElement( @@ -56,7 +62,7 @@ class LdapResourceForm extends Form array( 'required' => true, 'label' => t('Root DN'), - 'description' => t('The path where users can be found on the ldap server') + 'description' => t('Only the root and its child nodes will be accessible on this resource.') ) ); $this->addElement( @@ -87,9 +93,9 @@ class LdapResourceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - if (false === $this->isValidResource($this)) { + if (false === static::isValidResource($this)) { return false; } } @@ -101,11 +107,17 @@ class LdapResourceForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidResource(Form $form) + public static function isValidResource(Form $form) { try { - $resource = ResourceFactory::createResource(new Zend_Config($form->getValues())); - $resource->connect(); + $resource = ResourceFactory::createResource(new ConfigObject($form->getValues())); + if (false === $resource->testCredentials( + $form->getElement('bind_dn')->getValue(), + $form->getElement('bind_pw')->getValue() + ) + ) { + throw new Exception(); + } } catch (Exception $e) { $form->addError(t('Connectivity validation failed, connection to the given resource not possible.')); return false; diff --git a/application/forms/Config/Resource/LivestatusResourceForm.php b/application/forms/Config/Resource/LivestatusResourceForm.php index 92534f220..d90600370 100644 --- a/application/forms/Config/Resource/LivestatusResourceForm.php +++ b/application/forms/Config/Resource/LivestatusResourceForm.php @@ -2,13 +2,12 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Exception; -use Zend_Config; use Icinga\Web\Form; -use Icinga\Web\Request; use Icinga\Application\Icinga; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; /** @@ -29,6 +28,15 @@ class LivestatusResourceForm extends Form */ public function createElements(array $formData) { + $this->addElement( + 'text', + 'name', + array( + 'required' => true, + 'label' => t('Resource Name'), + 'description' => t('The unique name of this resource') + ) + ); $this->addElement( 'text', 'socket', @@ -48,9 +56,9 @@ class LivestatusResourceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - if (false === $this->isValidResource($this)) { + if (false === static::isValidResource($this)) { return false; } } @@ -62,10 +70,10 @@ class LivestatusResourceForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidResource(Form $form) + public static function isValidResource(Form $form) { try { - $resource = ResourceFactory::createResource(new Zend_Config($form->getValues())); + $resource = ResourceFactory::createResource(new ConfigObject($form->getValues())); $resource->connect()->disconnect(); } catch (Exception $e) { $form->addError(t('Connectivity validation failed, connection to the given resource not possible.')); diff --git a/application/forms/Config/ResourceConfigForm.php b/application/forms/Config/ResourceConfigForm.php index 1aa7edc96..fe3b9957d 100644 --- a/application/forms/Config/ResourceConfigForm.php +++ b/application/forms/Config/ResourceConfigForm.php @@ -2,16 +2,15 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; use InvalidArgumentException; -use Icinga\Web\Request; use Icinga\Web\Notification; -use Icinga\Form\ConfigForm; -use Icinga\Form\Config\Resource\DbResourceForm; -use Icinga\Form\Config\Resource\FileResourceForm; -use Icinga\Form\Config\Resource\LdapResourceForm; -use Icinga\Form\Config\Resource\LivestatusResourceForm; +use Icinga\Forms\ConfigForm; +use Icinga\Forms\Config\Resource\DbResourceForm; +use Icinga\Forms\Config\Resource\FileResourceForm; +use Icinga\Forms\Config\Resource\LdapResourceForm; +use Icinga\Forms\Config\Resource\LivestatusResourceForm; use Icinga\Application\Platform; use Icinga\Exception\ConfigurationError; @@ -64,12 +63,12 @@ class ResourceConfigForm extends ConfigForm $name = isset($values['name']) ? $values['name'] : ''; if (! $name) { throw new InvalidArgumentException(t('Resource name missing')); - } elseif ($this->config->{$name} !== null) { + } elseif ($this->config->hasSection($name)) { throw new InvalidArgumentException(t('Resource already exists')); } unset($values['name']); - $this->config->{$name} = $values; + $this->config->setSection($name, $values); return $this; } @@ -89,14 +88,15 @@ class ResourceConfigForm extends ConfigForm throw new InvalidArgumentException(t('Old resource name missing')); } elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) { throw new InvalidArgumentException(t('New resource name missing')); - } elseif (($resourceConfig = $this->config->get($name)) === null) { + } elseif (! $this->config->hasSection($name)) { throw new InvalidArgumentException(t('Unknown resource provided')); } + $resourceConfig = $this->config->getSection($name); + $this->config->removeSection($name); unset($values['name']); - unset($this->config->{$name}); - $this->config->{$newName} = array_merge($resourceConfig->toArray(), $values); - return $this->config->{$newName}; + $this->config->setSection($newName, $resourceConfig->merge($values)); + return $resourceConfig; } /** @@ -112,11 +112,12 @@ class ResourceConfigForm extends ConfigForm { if (! $name) { throw new InvalidArgumentException(t('Resource name missing')); - } elseif (($resourceConfig = $this->config->get($name)) === null) { + } elseif (! $this->config->hasSection($name)) { throw new InvalidArgumentException(t('Unknown resource provided')); } - unset($this->config->{$name}); + $resourceConfig = $this->config->getSection($name); + $this->config->removeSection($name); return $resourceConfig; } @@ -128,17 +129,17 @@ class ResourceConfigForm extends ConfigForm * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) { $resourceForm = $this->getResourceForm($this->getElement('type')->getValue()); - if (method_exists($resourceForm, 'isValidResource') && false === $resourceForm->isValidResource($this)) { + if (method_exists($resourceForm, 'isValidResource') && false === $resourceForm::isValidResource($this)) { $this->addElement($this->getForceCreationCheckbox()); return false; } } - $resource = $request->getQuery('resource'); + $resource = $this->request->getQuery('resource'); try { if ($resource === null) { // create new resource $this->add($this->getValues()); @@ -166,17 +167,17 @@ class ResourceConfigForm extends ConfigForm * * @throws ConfigurationError In case the backend name is missing in the request or is invalid */ - public function onRequest(Request $request) + public function onRequest() { - $resource = $request->getQuery('resource'); + $resource = $this->request->getQuery('resource'); if ($resource !== null) { if ($resource === '') { throw new ConfigurationError(t('Resource name missing')); - } elseif (false === isset($this->config->{$resource})) { + } elseif (! $this->config->hasSection($resource)) { throw new ConfigurationError(t('Unknown resource provided')); } - $configValues = $this->config->{$resource}->toArray(); + $configValues = $this->config->getSection($resource)->toArray(); $configValues['name'] = $resource; $this->populate($configValues); } @@ -220,15 +221,6 @@ class ResourceConfigForm extends ConfigForm $resourceTypes['db'] = t('SQL Database'); } - $this->addElement( - 'text', - 'name', - array( - 'required' => true, - 'label' => t('Resource Name'), - 'description' => t('The unique name of this resource') - ) - ); $this->addElement( 'select', 'type', diff --git a/application/forms/ConfigForm.php b/application/forms/ConfigForm.php index 86790d618..28d3111ea 100644 --- a/application/forms/ConfigForm.php +++ b/application/forms/ConfigForm.php @@ -2,12 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form; +namespace Icinga\Forms; use Exception; +use Zend_Form_Decorator_Abstract; use Icinga\Web\Form; use Icinga\Application\Config; -use Icinga\Config\PreservingIniWriter; +use Icinga\File\Ini\IniWriter; /** * Form base-class providing standard functionality for configuration forms @@ -43,7 +44,7 @@ class ConfigForm extends Form */ public function save() { - $writer = new PreservingIniWriter( + $writer = new IniWriter( array( 'config' => $this->config, 'filename' => $this->config->getConfigFile() @@ -58,7 +59,8 @@ class ConfigForm extends Form 'viewScript' => 'showConfiguration.phtml', 'errorMessage' => $e->getMessage(), 'configString' => $writer->render(), - 'filePath' => $this->config->getConfigFile() + 'filePath' => $this->config->getConfigFile(), + 'placement' => Zend_Form_Decorator_Abstract::PREPEND )); return false; } diff --git a/application/forms/ConfirmRemovalForm.php b/application/forms/ConfirmRemovalForm.php index 86a2eb02a..02d7263df 100644 --- a/application/forms/ConfirmRemovalForm.php +++ b/application/forms/ConfirmRemovalForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form; +namespace Icinga\Forms; use Icinga\Web\Form; diff --git a/application/forms/Dashboard/AddUrlForm.php b/application/forms/Dashboard/AddUrlForm.php deleted file mode 100644 index 88195654d..000000000 --- a/application/forms/Dashboard/AddUrlForm.php +++ /dev/null @@ -1,116 +0,0 @@ -setName('form_dashboard_addurl'); - $this->setSubmitLabel(t('Add To Dashboard')); - } - - /** - * @see Form::createElements() - */ - public function createElements(array $formData) - { - $this->addElement( - 'text', - 'url', - array( - 'required' => true, - 'label' => t('Url'), - 'helptext' => t('The url being loaded in the dashlet') - ) - ); - - $paneSelectionValues = $this->getDashboardPaneSelectionValues(); - if (empty($paneSelectionValues) || - ((isset($formData['create_new_pane']) && $formData['create_new_pane'] != false) && - (false === isset($formData['use_existing_dashboard']) || $formData['use_existing_dashboard'] != true)) - ) { - $this->addElement( - 'text', - 'pane', - array( - 'required' => true, - 'label' => t("The New Pane's Title"), - 'style' => 'display: inline-block' - ) - ); - $this->addElement( // Prevent the button from being displayed again on validation errors - 'hidden', - 'create_new_pane', - array( - 'value' => 1 - ) - ); - if (false === empty($paneSelectionValues)) { - $this->addElement( - 'submit', - 'use_existing_dashboard', - array( - 'ignore' => true, - 'label' => t('Use An Existing Pane'), - 'style' => 'display: inline-block' - ) - ); - } - } else { - $this->addElement( - 'select', - 'pane', - array( - 'required' => true, - 'label' => t('Pane'), - 'style' => 'display: inline-block;', - 'multiOptions' => $paneSelectionValues - ) - ); - $this->addElement( - 'submit', - 'create_new_pane', - array( - 'ignore' => true, - 'label' => t('Create A New Pane'), - 'style' => 'display: inline-block' - ) - ); - } - - $this->addElement( - 'text', - 'component', - array( - 'required' => true, - 'label' => t('Title'), - 'helptext' => t('The title for the dashlet') - ) - ); - } - - /** - * Return the names and titles of the available dashboard panes as key-value array - * - * @return array - */ - protected function getDashboardPaneSelectionValues() - { - $dashboard = new Dashboard(); - $dashboard->readConfig(IcingaConfig::app('dashboard/dashboard')); - return $dashboard->getPaneKeyTitleArray(); - } -} diff --git a/application/forms/Dashboard/DashletForm.php b/application/forms/Dashboard/DashletForm.php new file mode 100644 index 000000000..6c38ff97e --- /dev/null +++ b/application/forms/Dashboard/DashletForm.php @@ -0,0 +1,158 @@ +setName('form_dashboard_addurl'); + if (! $this->getSubmitLabel()) { + $this->setSubmitLabel(t('Add To Dashboard')); + } + $this->setAction(URL::fromRequest()); + } + + /** + * Build AddUrl form elements + * + * @see Form::createElements() + */ + public function createElements(array $formData) + { + $groupElements = array(); + $panes = array(); + + if ($this->dashboard) { + $panes = $this->dashboard->getPaneKeyTitleArray(); + } + + $this->addElement( + 'hidden', + 'org_pane', + array( + 'required' => false + ) + ); + + $this->addElement( + 'hidden', + 'org_dashlet', + array( + 'required' => false + ) + ); + + $this->addElement( + 'text', + 'url', + array( + 'required' => true, + 'label' => t('Url'), + 'description' => + t('Enter url being loaded in the dashlet. You can paste the full URL, including filters.') + ) + ); + $this->addElement( + 'text', + 'dashlet', + array( + 'required' => true, + 'label' => t('Dashlet Title'), + 'description' => t('Enter a title for the dashlet.') + ) + ); + $this->addElement( + 'note', + 'note', + array( + 'decorators' => array( + array('HtmlTag', array('tag' => 'hr')) + ) + ) + ); + if (empty($panes) || ((isset($formData['create_new_pane']) && $formData['create_new_pane'] != false))) { + $this->addElement( + 'text', + 'pane', + array( + 'required' => true, + 'label' => t("New Dashboard Title"), + 'description' => + t('Enter a title for the new pane.') + ) + ); + } else { + $this->addElement( + 'select', + 'pane', + array( + 'required' => true, + 'label' => t('Dashboard'), + 'multiOptions' => $panes, + 'description' => + t('Select a pane you want to add the dashlet.') + ) + ); + } + + $this->addElement( + 'checkbox', + 'create_new_pane', + array( + 'required' => false, + 'label' => t('New dashboard'), + 'class' => 'autosubmit', + 'description' => t('Check this box if you want to add the dashlet to a new dashboard') + ) + ); + } + + /** + * @param \Icinga\Web\Widget\Dashboard $dashboard + */ + public function setDashboard(Dashboard $dashboard) + { + $this->dashboard = $dashboard; + } + + /** + * @return \Icinga\Web\Widget\Dashboard + */ + public function getDashboard() + { + return $this->dashboard; + } + + /** + * @param Dashlet $dashlet + */ + public function load(Dashlet $dashlet) + { + $this->populate(array( + 'pane' => $dashlet->getPane()->getName(), + 'org_pane' => $dashlet->getPane()->getName(), + 'dashlet' => $dashlet->getTitle(), + 'org_dashlet' => $dashlet->getTitle(), + 'url' => $dashlet->getUrl() + )); + } +} diff --git a/application/forms/LdapDiscoveryForm.php b/application/forms/LdapDiscoveryForm.php new file mode 100644 index 000000000..0fd0ea0d3 --- /dev/null +++ b/application/forms/LdapDiscoveryForm.php @@ -0,0 +1,75 @@ +setName('form_ldap_discovery'); + } + + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + $this->addElement( + 'text', + 'domain', + array( + 'required' => true, + 'label' => t('Search Domain'), + 'description' => t('Search this domain for records of available servers.'), + ) + ); + + if (false) { + $this->addElement( + 'note', + 'additional_description', + array( + 'value' => t('No Ldap servers found on this domain.' + . ' You can try to specify host and port and try again, or just skip this step and ' + . 'configure the server manually.' + ) + ) + ); + $this->addElement( + 'text', + 'hostname', + array( + 'required' => false, + 'label' => t('Host'), + 'description' => t('IP or host name to search.'), + ) + ); + + $this->addElement( + 'text', + 'port', + array( + 'required' => false, + 'label' => t('Port'), + 'description' => t('Port', 389), + ) + ); + } + return $this; + } + + public function isValid($data) + { + if (false === parent::isValid($data)) { + return false; + } + return true; + } +} diff --git a/application/forms/PreferenceForm.php b/application/forms/PreferenceForm.php index cdb6ff288..e3cfdf319 100644 --- a/application/forms/PreferenceForm.php +++ b/application/forms/PreferenceForm.php @@ -2,18 +2,19 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form; +namespace Icinga\Forms; use Exception; use DateTimeZone; -use Icinga\Web\Form; -use Icinga\Web\Request; -use Icinga\Web\Session; -use Icinga\Web\Notification; -use Icinga\Util\Translator; -use Icinga\Util\TimezoneDetect; +use Icinga\Application\Logger; +use Icinga\Authentication\Manager; use Icinga\User\Preferences; use Icinga\User\Preferences\PreferencesStore; +use Icinga\Util\TimezoneDetect; +use Icinga\Util\Translator; +use Icinga\Web\Form; +use Icinga\Web\Notification; +use Icinga\Web\Session; /** * Form class to adjust user preferences @@ -40,7 +41,6 @@ class PreferenceForm extends Form public function init() { $this->setName('form_config_preferences'); - $this->setSubmitLabel(t('Save Changes')); } /** @@ -75,7 +75,6 @@ class PreferenceForm extends Form */ public function save() { - $this->store->load(); // Necessary for patching existing preferences $this->store->save($this->preferences); return $this; } @@ -85,11 +84,13 @@ class PreferenceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { + $this->preferences = new Preferences($this->store->load()); + $webPreferences = $this->preferences->get('icingaweb', array()); foreach ($this->getValues() as $key => $value) { - if ($value === null) { + if ($value === null || $value === 'autodetect') { if (isset($webPreferences[$key])) { unset($webPreferences[$key]); } @@ -99,15 +100,17 @@ class PreferenceForm extends Form } $this->preferences->icingaweb = $webPreferences; - // TODO: Is this even necessary in case the session is written on response? - $session = Session::getSession(); - $session->user->setPreferences($this->preferences); - $session->write(); + Session::getSession()->user->setPreferences($this->preferences); try { - $this->save(); - Notification::success(t('Preferences successfully saved')); + if ($this->getElement('btn_submit_preferences')->isChecked()) { + $this->save(); + Notification::success(t('Preferences successfully saved')); + } else { + Notification::success(t('Preferences successfully saved for the current session')); + } } catch (Exception $e) { + Logger::error($e); Notification::error($e->getMessage()); } } @@ -117,11 +120,19 @@ class PreferenceForm extends Form * * @see Form::onRequest() */ - public function onRequest(Request $request) + public function onRequest() { - $values = $this->preferences->get('icingaweb', array()); - $values['browser_language'] = false === isset($values['language']); - $values['local_timezone'] = false === isset($values['timezone']); + $auth = Manager::getInstance(); + $values = $auth->getUser()->getPreferences()->get('icingaweb'); + + if (! isset($values['language'])) { + $values['language'] = 'autodetect'; + } + + if (! isset($values['timezone'])) { + $values['timezone'] = 'autodetect'; + } + $this->populate($values); } @@ -131,72 +142,40 @@ class PreferenceForm extends Form public function createElements(array $formData) { $languages = array(); + $languages['autodetect'] = sprintf(t('Browser (%s)', 'preferences.form'), $this->getLocale()); foreach (Translator::getAvailableLocaleCodes() as $language) { $languages[$language] = $language; } $tzList = array(); + $tzList['autodetect'] = sprintf(t('Browser (%s)', 'preferences.form'), $this->getDefaultTimezone()); foreach (DateTimeZone::listIdentifiers() as $tz) { $tzList[$tz] = $tz; } $this->addElement( - 'checkbox', - 'browser_language', - array( - 'ignore' => true, - 'required' => true, - 'autosubmit' => true, - 'value' => true, - 'label' => t('Use your browser\'s language suggestions') - ) - ); - - $useBrowserLanguage = isset($formData['browser_language']) ? $formData['browser_language'] == 1 : true; - $languageSelection = $this->createElement( 'select', 'language', array( - 'required' => false === $useBrowserLanguage, + 'required' => true, 'label' => t('Your Current Language'), 'description' => t('Use the following language to display texts and messages'), 'multiOptions' => $languages, 'value' => substr(setlocale(LC_ALL, 0), 0, 5) ) ); - if ($useBrowserLanguage) { - $languageSelection->setAttrib('disabled', 'disabled'); - } - $this->addElement($languageSelection); $this->addElement( - 'checkbox', - 'local_timezone', - array( - 'ignore' => true, - 'required' => true, - 'autosubmit' => true, - 'value' => true, - 'label' => t('Use your local timezone') - ) - ); - - $useLocalTimezone = isset($formData['local_timezone']) ? $formData['local_timezone'] == 1 : true; - $timezoneSelection = $this->createElement( 'select', 'timezone', array( - 'required' => false === $useLocalTimezone, + 'required' => true, 'label' => t('Your Current Timezone'), 'description' => t('Use the following timezone for dates and times'), 'multiOptions' => $tzList, 'value' => $this->getDefaultTimezone() ) ); - if ($useLocalTimezone) { - $timezoneSelection->setAttrib('disabled', 'disabled'); - } - $this->addElement($timezoneSelection); $this->addElement( 'checkbox', @@ -206,6 +185,43 @@ class PreferenceForm extends Form 'label' => t('Use benchmark') ) ); + + $this->addElement( + 'submit', + 'btn_submit_preferences', + array( + 'ignore' => true, + 'label' => t('Save to the Preferences'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'div')) + ) + ) + ); + + $this->addElement( + 'submit', + 'btn_submit_session', + array( + 'ignore' => true, + 'label' => t('Save for the current Session'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'div')) + ) + ) + ); + + $this->addDisplayGroup( + array('btn_submit_preferences', 'btn_submit_session'), + 'submit_buttons', + array( + 'decorators' => array( + 'FormElements', + array('HtmlTag', array('tag' => 'div', 'class' => 'control-group')) + ) + ) + ); } /** @@ -219,7 +235,18 @@ class PreferenceForm extends Form if ($detect->success()) { return $detect->getTimezoneName(); } else { - return date_default_timezone_get(); + return @date_default_timezone_get(); } } + + /** + * Return the preferred locale based on the given HTTP header and the available translations + * + * @return string + */ + protected function getLocale() + { + $locale = Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']); + return $locale; + } } diff --git a/application/layouts/scripts/parts/navigation.phtml b/application/layouts/scripts/parts/navigation.phtml index da02a02de..bed44ba5f 100644 --- a/application/layouts/scripts/parts/navigation.phtml +++ b/application/layouts/scripts/parts/navigation.phtml @@ -15,7 +15,7 @@ if (! $this->auth()->isAuthenticated()) { id="menu" data-last-update="000" data-base-target="_main" class="container" data-icinga-url="href('layout/menu');?>" data-icinga-refresh="15" > - getPane('search')->hasComponents()): ?> + getPane('search')->hasDashlets()): ?>
diff --git a/application/locale/pt_BR/LC_MESSAGES/icinga.mo b/application/locale/pt_BR/LC_MESSAGES/icinga.mo index 955b4f8f6..a1b90c38b 100644 Binary files a/application/locale/pt_BR/LC_MESSAGES/icinga.mo and b/application/locale/pt_BR/LC_MESSAGES/icinga.mo differ diff --git a/application/locale/pt_BR/LC_MESSAGES/icinga.po b/application/locale/pt_BR/LC_MESSAGES/icinga.po index 54ed95a5d..572f9e6eb 100644 --- a/application/locale/pt_BR/LC_MESSAGES/icinga.po +++ b/application/locale/pt_BR/LC_MESSAGES/icinga.po @@ -1,67 +1,179 @@ -# Icinga Web 2 - Head for multiple monitoring backends. -# Copyright (C) 2014 Icinga Development Team -# This file is distributed under the same license as Icinga Web 2. -# FIRST AUTHOR , YEAR. -# msgid "" msgstr "" "Project-Id-Version: Icinga Web 2 (0.1)\n" "Report-Msgid-Bugs-To: dev@icinga.org\n" "POT-Creation-Date: 2014-06-03 15:23+0200\n" -"PO-Revision-Date: 2014-06-03 12:09-0300\n" +"PO-Revision-Date: 2014-11-18 16:11-0300\n" "Last-Translator: Carlos Cesario \n" "Language-Team: LANGUAGE \n" +"Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: pt_BR\n" "X-Generator: Poedit 1.5.4\n" -#: /usr/local/icingaweb/application/views/scripts/mixedPagination.phtml:15 +#: /usr/local/icingaweb/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php:41 #, php-format -msgid "%d to %d of %d" -msgstr "%d para %d de %d" +msgid "%d unhandled hosts down" +msgstr "%d hosts não tratados down" +#: /usr/local/icingaweb/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php:42 +#, php-format +msgid "%d unhandled services critical" +msgstr "%d serviços não tratados críticos" + +#: /usr/local/icingaweb/library/Icinga/Web/View/DateTimeRenderer.php:186 +msgctxt "timespan" +msgid "%im %ss" +msgstr "%im %ss" + +#: /usr/local/icingaweb/application/views/scripts/joystickPagination.phtml:9 #: /usr/local/icingaweb/application/views/scripts/pivottablePagination.phtml:9 #, php-format msgid "%s: %d to %d of %d" -msgstr "%s: %d para %d de %d" +msgstr "%s: %d até %d de %d" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:117 +#: /usr/local/icingaweb/library/Icinga/Web/Form/Element/Number.php:139 +#, php-format +msgid "'%s' is not a valid number" +msgstr "'%s' não é um número válido" + +#: /usr/local/icingaweb/application/forms/Dashboard/AddUrlForm.php:22 +msgid "Add To Dashboard" +msgstr "Adicionar ao dashboard" + +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterWidget.php:81 +msgid "Add filter..." +msgstr "Adicionar filtro..." + +#: /usr/local/icingaweb/application/controllers/AuthenticationController.php:109 +msgid "" +"All configured authentication methods failed. Please check the system log or " +"Icinga Web 2 log for more information." +msgstr "" +"Todos os métodos de autenticação configurados falharam. Por favor, verifique " +"o log de sistema ou o log do Icinga Web 2 para obter mais informações." + +#: /usr/local/icingaweb/library/Icinga/Web/Menu.php:229 +msgid "Application Log" +msgstr "Log da aplicação" + +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:68 msgid "Application Prefix" msgstr "Prefixo da aplicação" -#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:78 -#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:80 +#: /usr/local/icingaweb/library/Icinga/Web/Form/Decorator/NoScriptApply.php:29 +msgid "Apply" +msgstr "Aplicar" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:214 +#, php-format +msgid "Authentication backend \"%s\" has been successfully changed" +msgstr "Backend de autenticação \"%s\" foi alterado com sucesso" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:211 +#, php-format +msgid "Authentication backend \"%s\" has been successfully created" +msgstr "Backend de autenticação \"%s\" foi criado com sucesso" + +#: /usr/local/icingaweb/application/controllers/ConfigController.php:194 +#, php-format +msgid "Authentication backend \"%s\" has been successfully removed" +msgstr "Backend de autenticação \"%s\" foi removido com sucesso" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:96 +msgid "Authentication backend already exists" +msgstr "Backend de autenticação já existe" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:94 +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:147 +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:170 +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:240 +msgid "Authentication backend name missing" +msgstr "Falta o nome do backend de autenticação" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendReorderForm.php:55 +msgid "Authentication order updated!" +msgstr "Ordem da autenticação atualizada!" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:307 +msgid "Autologin" +msgstr "Login automático" + +#: /usr/local/icingaweb/library/Icinga/Web/Wizard.php:462 +#: /usr/local/icingaweb/library/Icinga/Web/Wizard.php:483 +msgid "Back" +msgstr "Voltar" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:244 +#, php-format +msgid "Backend \"%s\" has no `backend' setting" +msgstr "Backend \"%s\" não tem nenhuma configuração de `backend'" + +#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:56 +#: /usr/local/icingaweb/application/forms/Config/Authentication/AutologinBackendForm.php:33 +#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:57 msgid "Backend Name" msgstr "Nome do backend" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:282 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:282 +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:321 +msgid "Backend Type" +msgstr "Tipo do backend" + +#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:108 +msgid "Base DN" +msgstr "Base DN" + +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:73 msgid "Bind DN" msgstr "Bind DN" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:294 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:294 +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:83 msgid "Bind Password" msgstr "Senha Bind" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:358 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:358 -#: /usr/local/icingaweb/application/forms/Config/Authentication/BaseBackendForm.php:139 +#: /usr/local/icingaweb/application/forms/PreferenceForm.php:145 +#: /usr/local/icingaweb/application/forms/PreferenceForm.php:151 +#, php-format +msgctxt "preferences.form" +msgid "Browser (%s)" +msgstr "Navegador (%s)" + +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterEditor.php:335 +msgid "Cancel this operation" +msgstr "Cancelar esta operação" + +#: /usr/local/icingaweb/library/Icinga/Application/Config.php:296 +#, php-format +msgid "Cannot read config file \"%s\". Permission denied" +msgstr "Não é possível ler arquivo de configuração \"%s\". Permissão negada" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:280 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:201 msgid "Check this box to enforce changes without connectivity validation" -msgstr "Marque esta caixa para aplicar as mudanças sem validação conectividade" +msgstr "" +"Marque esta caixa para forçar as alterações sem validação conectividade" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:73 -msgid "Check this to enable logging." -msgstr "Marque esta opção para ativar o registro log." +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterEditor.php:309 +msgid "Click to add another filter" +msgstr "Clique para adicionar outro filtro" -#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:187 -msgid "Connection Validation Failed: " -msgstr "Validação de conexão falhou:" +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterWidget.php:69 +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterEditor.php:296 +msgid "Click to remove this part of your filter" +msgstr "Clique para remover esta parte do seu filtro" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:477 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:457 +#: /usr/local/icingaweb/library/Icinga/Web/Menu.php:219 +msgid "Configuration" +msgstr "Configuração" + +#: /usr/local/icingaweb/application/forms/ConfirmRemovalForm.php:20 +msgid "Confirm Removal" +msgstr "Confirmar a remoção" + +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:135 +#: /usr/local/icingaweb/application/forms/Config/Resource/LivestatusResourceForm.php:79 +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:122 msgid "" "Connectivity validation failed, connection to the given resource not " "possible." @@ -69,189 +181,317 @@ msgstr "" "A validação de conectividade falhou, a conexão com o recurso selecionado não " "é possível." -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:454 -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:470 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:434 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:450 -msgid "Connectivity validation failed, the provided file does not exist." -msgstr "A validação de conectividade falhou, o arquivo fornecido não existe." +#: /usr/local/icingaweb/application/forms/Config/General/ApplicationConfigForm.php:40 +msgid "" +"Contains the directories that will be searched for available modules, " +"separated by colons. Modules that don't exist in these directories can still " +"be symlinked in the module folder, but won't show up in the list of disabled " +"modules." +msgstr "" +"Contém os diretórios que serão pesquisados para os módulos disponíveis, " +"separados por dois pontos. Módulos que não estão nestes diretórios podem " +"ainda serem linkados simbolicamente para a pasta dos módulos, mas não " +"aparecerão na lista de módulos desabilitados. " -#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:90 +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:260 +msgid "Could not find any resources for authentication" +msgstr "Não foi possível encontrar os recursos para autenticação" + +#: /usr/local/icingaweb/application/controllers/AuthenticationController.php:60 +msgid "" +"Could not read your authentication.ini, no authentication methods are " +"available." +msgstr "" +"Não foi possível ler o arquivo authentication.ini, não há métodos de " +"autenticação disponíveis." + +#: /usr/local/icingaweb/application/views/scripts/config/authentication/reorder.phtml:7 +msgid "Create A New Authentication Backend" +msgstr "Criar um novo backend de autenticação" + +#: /usr/local/icingaweb/application/forms/Dashboard/AddUrlForm.php:88 +msgid "Create A New Pane" +msgstr "Criar um novo painel" + +#: /usr/local/icingaweb/application/views/scripts/config/resource.phtml:7 +#: /usr/local/icingaweb/application/views/scripts/config/resource/create.phtml:4 +msgid "Create A New Resource" +msgstr "Criar um novo recurso" + +#: /usr/local/icingaweb/application/views/scripts/config/authentication/create.phtml:4 +msgid "Create New Authentication Backend" +msgstr "Criar um novo backend de autenticação" + +#: /usr/local/icingaweb/application/views/scripts/config/authentication/create.phtml:7 +msgid "" +"Create a new backend for authenticating your users. This backend will be " +"added at the end of your authentication order." +msgstr "" +"Criar um novo backend para autenticar os usuários. Este backend será " +"adicionado por último." + +#: /usr/local/icingaweb/application/views/scripts/dashboard/index.phtml:12 +#, php-format +msgid "" +"Currently there is no dashlet available. This might change once you enabled " +"some of the available %s." +msgstr "" +"Atualmente não há nenhum dashlet disponível. Isso pode mudar, uma vez que " +"você habilite algum dos disponíveis %s." + +#: /usr/local/icingaweb/application/layouts/scripts/body.phtml:31 +#: /usr/local/icingaweb/library/Icinga/Web/Menu.php:209 +msgid "Dashboard" +msgstr "Dashboard" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:294 +#: /usr/local/icingaweb/application/forms/Config/General/ApplicationConfigForm.php:56 +msgid "Database" +msgstr "Banco de dados" + +#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:67 +#: /usr/local/icingaweb/application/forms/Config/General/ApplicationConfigForm.php:75 msgid "Database Connection" msgstr "Conexão com o banco de dados" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:183 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:183 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:83 msgid "Database Name" msgstr "Nome do banco de dados" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:144 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:144 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:53 msgid "Database Type" msgstr "Tipo do banco de dados" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:89 +#: /usr/local/icingaweb/library/Icinga/Web/Form/Validator/DateTimeValidator.php:49 +#, php-format +msgid "Date/time string not in the expected format %s" +msgstr "String Data/Hora não está no formato esperado %s" + +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:56 +msgctxt "app.config.logging.level" msgid "Debug" msgstr "Depurar" -#: /usr/local/icingaweb/application/forms/Config/GeneralForm.php:185 -msgid "Default Language" -msgstr "Idioma padrão" +#: /usr/local/icingaweb/application/views/scripts/showConfiguration.phtml:20 +msgid "" +"Details can be found in the application log. (If you don't have access to " +"this log, call your administrator in this case)" +msgstr "" +"Detalhes podem ser encontrados no log da aplicação. (Se você não tem acesso " +"a este registro, neste caso entre em contato com o seu administrador)" -#: /usr/local/icingaweb/application/controllers/ErrorController.php:62 +#: /usr/local/icingaweb/application/forms/Config/General/ApplicationConfigForm.php:57 +msgid "Don't Store Preferences" +msgstr "Não salvar as preferências" + +#: /usr/local/icingaweb/application/views/scripts/config/authentication/modify.phtml:4 +msgid "Edit Backend" +msgstr "Editar backend" + +#: /usr/local/icingaweb/application/views/scripts/config/resource/modify.phtml:4 +msgid "Edit Existing Resource" +msgstr "Editar o recurso existente" + +#: /usr/local/icingaweb/application/controllers/ErrorController.php:41 #, php-format msgid "Enabling the \"%s\" module might help!" msgstr "Habilitando o módulo \"%s\" pode ajudar!" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:86 +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:53 +msgctxt "app.config.logging.level" msgid "Error" msgstr "Erro" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:139 -msgid "Facility" -msgstr "Facilidade" - -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:102 -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:383 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:383 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:214 msgid "File" msgstr "Arquivo" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:155 -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:220 -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:231 -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:308 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:220 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:231 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:308 +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:38 +msgctxt "app.config.logging.type" +msgid "File" +msgstr "Arquivo" + +#: /usr/local/icingaweb/application/forms/Config/General/ApplicationConfigForm.php:55 +msgid "File System (INI Files)" +msgstr "Sistema de arquivos (Arquivos INI)" + +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:107 +msgid "File path" +msgstr "Caminho do arquivo" + +#: /usr/local/icingaweb/application/forms/Config/Resource/FileResourceForm.php:42 msgid "Filepath" msgstr "Caminho do arquivo" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:357 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:357 -#: /usr/local/icingaweb/application/forms/Config/Authentication/BaseBackendForm.php:138 -msgid "Force Changes" -msgstr "Forçar mudanças" +#: /usr/local/icingaweb/application/forms/Config/Authentication/AutologinBackendForm.php:55 +msgid "Filter Pattern" +msgstr "Padrão do filtro" -#: /usr/local/icingaweb/application/views/scripts/search/hint.phtml:7 +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterWidget.php:90 +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterEditor.php:642 +msgid "Filter this list" +msgstr "Filtrar esta lista" + +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterWidget.php:94 +msgid "Filtered" +msgstr "Filtrado" + +#: /usr/local/icingaweb/library/Icinga/Web/Wizard.php:493 +msgid "Finish" +msgstr "Finalizar" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:279 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:200 +msgid "Force Changes" +msgstr "Forçar as alterações" + +#: /usr/local/icingaweb/application/views/scripts/search/hint.phtml:3 msgid "Hint" msgstr "Sugestão" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:160 -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:260 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:160 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:260 +#: /usr/local/icingaweb/application/forms/LdapDiscoveryForm.php:50 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:63 +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:44 msgid "Host" msgstr "Host" +#: /usr/local/icingaweb/application/views/scripts/joystickPagination.phtml:35 +#: /usr/local/icingaweb/application/views/scripts/joystickPagination.phtml:87 #: /usr/local/icingaweb/application/views/scripts/pivottablePagination.phtml:28 -#: /usr/local/icingaweb/application/controllers/SearchController.php:33 msgid "Hosts" msgstr "Hosts" -#: /usr/local/icingaweb/application/views/scripts/search/hint.phtml:6 +#: /usr/local/icingaweb/application/views/scripts/search/hint.phtml:2 msgid "I'm ready to search, waiting for your input" msgstr "Estou pronto para pesquisar, aguardando sua entrada" -#: /usr/local/icingaweb/application/views/scripts/authentication/login.phtml:8 -#: /usr/local/icingaweb/application/controllers/AuthenticationController.php:63 +#: /usr/local/icingaweb/application/forms/LdapDiscoveryForm.php:51 +msgid "IP or host name to search." +msgstr "IP ou nome do host para pesquisa." + +#: /usr/local/icingaweb/application/controllers/AuthenticationController.php:42 msgid "Icingaweb Login" msgstr "Login no Icingaweb" -#: /usr/local/icingaweb/application/views/scripts/authentication/logout.phtml:17 +#: /usr/local/icingaweb/application/views/scripts/authentication/logout.phtml:14 msgid "" "If this message does not disappear, it might be necessary to quit the " "current session manually by clearing the cache, or by closing the current " "browser session." msgstr "" "Se esta mensagem não desaparecer, pode ser necessário sair da sessão atual " -"manualmente, limpando o cache ou fechando a sessão atual do navegador. " +"manualmente limpando o cache ou fechando a sessão atual do navegador. " -#: /usr/local/icingaweb/application/controllers/AuthenticationController.php:118 +#: /usr/local/icingaweb/application/views/scripts/showConfiguration.phtml:22 +msgid "" +"In case you can access the file by yourself, you can open it and insert the " +"config manually:" +msgstr "" +"Caso você mesmo possa acessar o arquivo, você pode abri-lo e inserir a " +"configuração manualmente:" + +#: /usr/local/icingaweb/application/controllers/AuthenticationController.php:122 msgid "Incorrect username or password" -msgstr "Usuário ou senha inválido" +msgstr "Usuário ou senha inválida" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:88 +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:55 +msgctxt "app.config.logging.level" msgid "Information" msgstr "Informação" -#: /usr/local/icingaweb/library/Icinga/Web/Wizard/Wizard.php:337 -#: /usr/local/icingaweb/library/Icinga/Web/Wizard/Wizard.php:380 -msgid "Install" -msgstr "Instalar" +#: /usr/local/icingaweb/application/views/scripts/config/modules.phtml:3 +msgid "Installed Modules" +msgstr "Módulos instalados" -#: /usr/local/icingaweb/application/views/scripts/install/index.phtml:29 -msgid "Installation" -msgstr "Instalação" +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:73 +#, php-format +msgid "Invalid backend type \"%s\" provided" +msgstr "Tipo \"%s\" inválido de backend fornecido" -#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:92 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:46 +#, php-format +msgid "Invalid resource type \"%s\" provided" +msgstr "Tipo \"%s\" inválido de recurso fornecido" + +#: /usr/local/icingaweb/library/Icinga/Web/Form/Validator/DateTimeValidator.php:42 +msgid "Invalid type given. Instance of DateTime or date/time string expected" +msgstr "" +"Tipo fornecido inválido. Esperado uma string do tipo DataHora ou data/hora" + +#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:68 msgid "LDAP Resource" msgstr "Recurso LDAP" -#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:115 +#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:90 msgid "LDAP User Name Attribute" msgstr "Atributo LDAP Nome de usuário" -#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:104 +#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:80 msgid "LDAP User Object Class" msgstr "Classe LDAP Objeto de usuário" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:232 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:232 -msgid "Location of your icinga objects.cache file" -msgstr "Localização do arquivo objects.cache do seu icinga" - -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:221 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:221 -msgid "Location of your icinga status.dat file" -msgstr "Localização do arquivo status.dat do seu icinga" - -#: /usr/local/icingaweb/application/controllers/InstallController.php:69 -msgid "Logging" -msgstr "Registro de log" - -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:72 -msgid "Logging Enabled" -msgstr "Registro de log habilitado" - -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:82 +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:50 msgid "Logging Level" msgstr "Nível do registro de log" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:98 +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:34 msgid "Logging Type" msgstr "Tipo do registro de log" -#: /usr/local/icingaweb/application/views/scripts/authentication/logout.phtml:15 +#: /usr/local/icingaweb/application/views/scripts/authentication/logout.phtml:12 msgid "Logging out..." msgstr "Saída do registro de log..." -#: /usr/local/icingaweb/application/views/scripts/authentication/logout.phtml:28 +#: /usr/local/icingaweb/application/views/scripts/authentication/logout.phtml:21 +#: /usr/local/icingaweb/application/forms/Authentication/LoginForm.php:21 msgid "Login" msgstr "Login" -#: /usr/local/icingaweb/application/layouts/scripts/body.phtml:39 #: /usr/local/icingaweb/application/layouts/scripts/parts/topbar.phtml:35 +#: /usr/local/icingaweb/library/Icinga/Web/Menu.php:244 msgid "Logout" -msgstr "Sair" +msgstr "Logout" -#: /usr/local/icingaweb/application/views/scripts/authentication/logout.phtml:64 -msgid "" -"Logout not possible, it may be necessary to quit the session manually by " -"clearing the cache, or closing the current browser session. Error: " -msgstr "" -"Não foi possível, é necessário sair da sessão manualmente, limpando o cache " -"ou fechando a sessão atual do navegador. Erro:" - -#: /usr/local/icingaweb/application/views/scripts/authentication/logout.phtml:69 +#: /usr/local/icingaweb/application/views/scripts/authentication/logout.phtml:43 msgid "Logout successful!" -msgstr "Sucesso na saída!" +msgstr "Sucesso ao realizar o logout!" -#: /usr/local/icingaweb/application/forms/Config/Authentication/ReorderForm.php:137 +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterWidget.php:95 +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterEditor.php:644 +msgid "Modify this filter" +msgstr "Modificar este filtro" + +#: /usr/local/icingaweb/application/controllers/ConfigController.php:118 +#, php-format +msgid "Module \"%s\" disabled" +msgstr "Módulo \"%s\" desabilitado" + +#: /usr/local/icingaweb/application/controllers/ConfigController.php:99 +#, php-format +msgid "Module \"%s\" enabled" +msgstr "Módulo \"%s\" habilitado" + +#: /usr/local/icingaweb/application/forms/Config/General/ApplicationConfigForm.php:36 +msgid "Module Path" +msgstr "Caminho dos módulos" + +#: /usr/local/icingaweb/application/views/scripts/config/modules.phtml:16 +msgid "Module is disabled" +msgstr "Módulo está desabilitado" + +#: /usr/local/icingaweb/application/views/scripts/config/modules.phtml:14 +msgid "Module is enabled" +msgstr "Módulo está habilitado" + +#: /usr/local/icingaweb/library/Icinga/Web/Menu.php:223 +msgid "Modules" +msgstr "Módulos" + +#: /usr/local/icingaweb/application/views/scripts/form/reorder-authbackend.phtml:30 msgid "Move down in authentication order" msgstr "Mover para baixo na ordem de autenticação" -#: /usr/local/icingaweb/application/forms/Config/Authentication/ReorderForm.php:111 +#: /usr/local/icingaweb/application/views/scripts/form/reorder-authbackend.phtml:25 msgid "Move up in authentication order" msgstr "Mover para cima na ordem de autenticação" @@ -259,301 +499,604 @@ msgstr "Mover para cima na ordem de autenticação" msgid "Navigation" msgstr "Navegação" -#: /usr/local/icingaweb/application/views/scripts/mixedPagination.phtml:83 +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:119 +msgid "New authentication backend name missing" +msgstr "Falta o nome do novo backend de autenticação" + +#: /usr/local/icingaweb/application/forms/Config/GeneralConfigForm.php:55 +msgid "New configuration has successfully been stored" +msgstr "A nova configuração foi salva com sucesso" + +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:90 +msgid "New resource name missing" +msgstr "Falta o nome do novo rescurso" + #: /usr/local/icingaweb/application/views/scripts/mixedPagination.phtml:86 -#: /usr/local/icingaweb/library/Icinga/Web/Wizard/Wizard.php:337 -#: /usr/local/icingaweb/library/Icinga/Web/Wizard/Wizard.php:380 +#: /usr/local/icingaweb/application/views/scripts/mixedPagination.phtml:89 +#: /usr/local/icingaweb/library/Icinga/Web/Wizard.php:451 +#: /usr/local/icingaweb/library/Icinga/Web/Wizard.php:472 msgid "Next" msgstr "Próximo" -#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:144 +#: /usr/local/icingaweb/application/forms/LdapDiscoveryForm.php:39 +msgid "" +"No Ldap servers found on this domain. You can try to specify host and port " +"and try again, or just skip this step and configure the server manually." +msgstr "" +"Nenhum servidor LDAP encontrado neste domínio. Você pode tentar especificar " +"host e porta e tentar novamente, ou simplesmente pular esta etapa e " +"configurar o servidor manualmente." + +#: /usr/local/icingaweb/application/controllers/AuthenticationController.php:102 +msgid "" +"No authentication methods available. Did you create authentication.ini when " +"setting up Icinga Web 2?" +msgstr "" +"Não há métodos de autenticação disponíveis. Você criou o arquivo " +"authentication.ini ao configurar Icinga Web 2?" + +#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:110 msgid "No users found under the specified database backend" msgstr "Nenhum usuário encontrado no backend do banco de dados especificado" -#: /usr/local/icingaweb/application/controllers/ErrorController.php:59 +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:39 +msgctxt "app.config.logging.type" +msgid "None" +msgstr "Nenhum" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:117 +msgid "Old authentication backend name missing" +msgstr "Falta o nome antigo do backend de autenticação" + +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:88 +msgid "Old resource name missing" +msgstr "Falta o nome do recurso antigo" + +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:65 +msgid "Only the root and its child nodes will be accessible on this resource." +msgstr "Somente a raiz e seus nós filhos estarão acessíveis neste recurso." + +#: /usr/local/icingaweb/application/views/scripts/form/reorder-authbackend.phtml:6 +msgid "Order" +msgstr "Ordenar" + +#: /usr/local/icingaweb/application/views/scripts/mixedPagination.phtml:33 +msgid "Page" +msgstr "Página" + +#: /usr/local/icingaweb/application/controllers/ErrorController.php:38 msgid "Page not found." msgstr "Página não encontrada." -#: /usr/local/icingaweb/application/forms/Authentication/LoginForm.php:65 -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:206 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:206 +#: /usr/local/icingaweb/application/views/scripts/mixedPagination.phtml:12 +msgid "Pagination" +msgstr "Paginação" + +#: /usr/local/icingaweb/application/forms/Dashboard/AddUrlForm.php:78 +msgid "Pane" +msgstr "Painel" + +#: /usr/local/icingaweb/application/forms/Authentication/LoginForm.php:44 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:102 msgid "Password" msgstr "Senha" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:319 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:319 +#: /usr/local/icingaweb/library/Icinga/Web/Form/Validator/ReadablePathValidator.php:33 +msgid "Path does not exist" +msgstr "Caminho não existe" + +#: /usr/local/icingaweb/library/Icinga/Web/Form/Validator/ReadablePathValidator.php:32 +msgid "Path is not readable" +msgstr "Caminho não tem permissão de leitura" + +#: /usr/local/icingaweb/application/forms/Config/Resource/FileResourceForm.php:52 msgid "Pattern" msgstr "Padrão" -#: /usr/local/icingaweb/library/Icinga/Web/Form/Element/Number.php:61 -msgid "Please enter a number." -msgstr "Por favor entre com um número." +#: /usr/local/icingaweb/application/views/scripts/dashboard/addurl.phtml:9 +msgid "" +"Please have a little patience, we are hard working on it, take a look at " +"icingaweb2 issues." +msgstr "" +"Por favor, tenha um pouco de paciência, estamos trabalhando duro nisso, dê " +"uma olhada nos problemas do icingaweb2." -#: /usr/local/icingaweb/application/views/scripts/search/hint.phtml:8 +#: /usr/local/icingaweb/application/controllers/AuthenticationController.php:116 +msgid "" +"Please note that not all authentication methods were available. Check the " +"system log or Icinga Web 2 log for more information." +msgstr "" +"Por favor, note que nem todos os métodos de autenticação estavam " +"disponíveis. Verifique o log do sistema ou o log do Icinga Web 2 para obter " +"mais informações." + +#: /usr/local/icingaweb/application/views/scripts/search/hint.phtml:4 msgid "" "Please use the asterisk (*) as a placeholder for wildcard searches. For " -"convenience I'll always add a wildcard after the last character you typed." +"convenience I'll always add a wildcard in front and after your search string." msgstr "" "Por favor utilize o asterisco (*) como caractere curinga nas pesquisas. Para " -"maior comodidade vou sempre adicionar um curinga após o último caractere " +"maior comodidade será sempre adicionado um curinga após o último caractere " "digitado." -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:171 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:171 +#: /usr/local/icingaweb/application/forms/LdapDiscoveryForm.php:60 +#: /usr/local/icingaweb/application/forms/LdapDiscoveryForm.php:61 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:73 +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:54 msgid "Port" msgstr "Porta" -#: /usr/local/icingaweb/application/layouts/scripts/body.phtml:38 #: /usr/local/icingaweb/application/layouts/scripts/parts/topbar.phtml:32 +#: /usr/local/icingaweb/application/controllers/PreferenceController.php:30 +#: /usr/local/icingaweb/library/Icinga/Web/Menu.php:239 msgid "Preferences" msgstr "Preferências" -#: /usr/local/icingaweb/application/views/scripts/mixedPagination.phtml:45 +#: /usr/local/icingaweb/application/forms/PreferenceForm.php:108 +msgid "Preferences successfully saved" +msgstr "Preferências salvas com sucesso" + +#: /usr/local/icingaweb/application/forms/PreferenceForm.php:110 +msgid "Preferences successfully saved for the current session" +msgstr "Preferências salvas com sucesso para a sessão atual" + #: /usr/local/icingaweb/application/views/scripts/mixedPagination.phtml:48 +#: /usr/local/icingaweb/application/views/scripts/mixedPagination.phtml:51 msgid "Prev" msgstr "Ant" -#: /usr/local/icingaweb/library/Icinga/Web/Wizard/Wizard.php:326 -#: /usr/local/icingaweb/library/Icinga/Web/Wizard/Wizard.php:367 -msgid "Previous" -msgstr "Anterior" +#: /usr/local/icingaweb/application/views/scripts/config/resource.phtml:13 +#: /usr/local/icingaweb/application/views/scripts/form/reorder-authbackend.phtml:5 +#: /usr/local/icingaweb/application/views/scripts/form/reorder-authbackend.phtml:19 +msgid "Remove" +msgstr "Remover" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:333 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:333 +#: /usr/local/icingaweb/application/views/scripts/config/authentication/remove.phtml:4 +msgid "Remove Backend" +msgstr "Remover backend" + +#: /usr/local/icingaweb/application/views/scripts/config/resource/remove.phtml:4 +msgid "Remove Existing Resource" +msgstr "Remover recurso existente" + +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterWidget.php:99 +msgid "Remove this filter" +msgstr "Remover este filtro" + +#: /usr/local/icingaweb/application/views/scripts/config/resource.phtml:12 +msgid "Resource" +msgstr "Recurso" + +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:149 +#, php-format +msgid "Resource \"%s\" has been successfully changed" +msgstr "Recurso \"%s\" foi alterado com sucesso" + +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:146 +#, php-format +msgid "Resource \"%s\" has been successfully created" +msgstr "Recurso \"%s\" foi criado com sucesso" + +#: /usr/local/icingaweb/application/controllers/ConfigController.php:266 +#, php-format +msgid "Resource \"%s\" has been successfully removed" +msgstr "Recurso \"%s\" foi removido com sucesso" + +#: /usr/local/icingaweb/application/forms/Config/Resource/FileResourceForm.php:33 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:44 +#: /usr/local/icingaweb/application/forms/Config/Resource/LivestatusResourceForm.php:36 +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:35 msgid "Resource Name" msgstr "Nome do recurso" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:375 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:375 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:230 msgid "Resource Type" msgstr "Tipo do recurso" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:271 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:271 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:67 +msgid "Resource already exists" +msgstr "Recurso já existe" + +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:65 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:114 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:175 +msgid "Resource name missing" +msgstr "Falta o nome do recurso" + +#: /usr/local/icingaweb/application/views/scripts/config/resource/create.phtml:5 +msgid "Resources are entities that provide data to Icinga Web 2." +msgstr "Os recursos são entidades que fornecem dados para Icinga Web 2." + +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:64 msgid "Root DN" msgstr "DN Root" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:379 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:379 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:221 msgid "SQL Database" msgstr "Banco de dados SQL" -#: /usr/local/icingaweb/application/controllers/SearchController.php:22 -#: /usr/local/icingaweb/application/controllers/SearchController.php:29 -#: /usr/local/icingaweb/application/controllers/SearchController.php:30 -#: /usr/local/icingaweb/application/controllers/SearchController.php:56 +#: /usr/local/icingaweb/application/forms/Config/GeneralConfigForm.php:23 +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:34 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:25 +msgid "Save Changes" +msgstr "Salvar alterações" + +#: /usr/local/icingaweb/application/forms/PreferenceForm.php:207 +msgid "Save for the current Session" +msgstr "Salvar para a sessão atual" + +#: /usr/local/icingaweb/application/forms/PreferenceForm.php:194 +msgid "Save to the Preferences" +msgstr "Salvar as preferências" + +#: /usr/local/icingaweb/application/views/scripts/showConfiguration.phtml:2 +msgid "Saving Configuration Failed" +msgstr "Falha ao salvar a configuração" + +#: /usr/local/icingaweb/library/Icinga/Web/Widget/SearchDashboard.php:64 msgid "Search" msgstr "Pesquisar" -#: /usr/local/icingaweb/application/layouts/scripts/parts/navigation.phtml:17 +#: /usr/local/icingaweb/application/forms/LdapDiscoveryForm.php:29 +msgid "Search Domain" +msgstr "Pesquisar domínio" + +#: /usr/local/icingaweb/application/forms/LdapDiscoveryForm.php:30 +msgid "Search this domain for records of available servers." +msgstr "Pesquisar este domínio para os registros de servidores disponíveis." + +#: /usr/local/icingaweb/application/views/scripts/layout/menu.phtml:8 +#: /usr/local/icingaweb/application/layouts/scripts/parts/navigation.phtml:20 +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterEditor.php:638 msgid "Search..." msgstr "Pesquisar..." -#: /usr/local/icingaweb/application/forms/Config/GeneralForm.php:189 -msgid "" -"Select the language to use by default. Can be overwritten by a user in his " -"preferences." -msgstr "" -"Selecione o idioma padrão a ser utilizado. Pode ser substituído por um " -"usuário em suas preferências." - +#: /usr/local/icingaweb/application/views/scripts/joystickPagination.phtml:53 +#: /usr/local/icingaweb/application/views/scripts/joystickPagination.phtml:69 #: /usr/local/icingaweb/application/views/scripts/pivottablePagination.phtml:34 -#: /usr/local/icingaweb/application/controllers/SearchController.php:41 msgid "Services" msgstr "Serviços" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:245 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:245 +#: /usr/local/icingaweb/library/Icinga/Web/Widget/Limiter.php:84 +#, php-format +msgid "Show %s rows on one page" +msgstr "Mostrar %s linhas em uma página" + +#: /usr/local/icingaweb/application/views/scripts/mixedPagination.phtml:16 +#, php-format +msgid "Show rows %d to %d of %d" +msgstr "Mostrar linhas %d até %d de %d" + +#: /usr/local/icingaweb/application/forms/Config/Resource/LivestatusResourceForm.php:45 msgid "Socket" msgstr "Soquete" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:140 -msgid "The Syslog facility to utilize." -msgstr "A facilidade do SysLog a ser utilizada" +#: /usr/local/icingaweb/application/views/scripts/showConfiguration.phtml:15 +msgid "Something went wrong while writing the file" +msgstr "Algo deu errado ao gravar o arquivo" -#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:116 +#: /usr/local/icingaweb/application/views/scripts/config/module.phtml:22 +msgid "State" +msgstr "Estado" + +#: /usr/local/icingaweb/library/Icinga/Web/Widget/FilterEditor.php:322 +msgid "Strip this filter" +msgstr "Retirar esse filtro" + +#: /usr/local/icingaweb/library/Icinga/Web/Menu.php:215 +msgid "System" +msgstr "Sistema" + +#: /usr/local/icingaweb/application/views/scripts/authentication/login.phtml:4 +msgid "The Icinga logo" +msgstr "O logotipo Icinga" + +#: /usr/local/icingaweb/application/forms/Dashboard/AddUrlForm.php:50 +msgid "The New Pane's Title" +msgstr "O título do novo painel" + +#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:91 msgid "The attribute name used for storing the user name on the ldap server" msgstr "" "O nome do atributo utilizado para armazenar o nome do usuário no servidor " "ldap" -#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:91 +#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:68 msgid "The database connection to use for authenticating with this provider" msgstr "" -"A conexão com o banco a ser utilizada para autenticar com este provedor" +"A conexão com o banco de dados a ser utilizada para autenticar com este " +"provedor" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:309 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:309 +#: /usr/local/icingaweb/application/views/scripts/showConfiguration.phtml:6 +#, php-format +msgid "The file %s couldn't be stored. (Error: \"%s\")" +msgstr "O arquivo %s não pode ser gravado. (Erro: \"%s\")" + +#: /usr/local/icingaweb/application/forms/Config/Resource/FileResourceForm.php:43 msgid "The filename to fetch information from" msgstr "O nome do arquivo a ser consultado" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:161 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:161 -msgid "The hostname of the database." -msgstr "O nome do host do banco de dados." +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:108 +msgid "The full path to the log file to write messages to." +msgstr "O caminho completo do arquivo de log para gravar as mensagens." -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:261 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:261 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:64 +msgid "The hostname of the database" +msgstr "O nome do host do banco de dados" + +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:45 msgid "The hostname or address of the LDAP server to use for authentication" msgstr "" "O nome do host ou endereço do servidor LDAP a ser utilizado para a " "autenticação" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:156 -msgid "The logfile to write messages to." -msgstr "O arquivo de log para salvar as mensagens." - -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:83 -msgid "The maximum loglevel to emit." +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:51 +msgid "The maximum logging level to emit." msgstr "O nível máximo de log a ser emitido." -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:118 +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:69 msgid "The name of the application by which to prefix syslog messages." msgstr "" -"O nome da aplicação que será adicionado como prefixo nas mensagens do syslog." +"O nome da aplicação que será adicionada como prefixo nas mensagens do syslog." -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:184 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:184 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:84 msgid "The name of the database to use" msgstr "O nome do banco de dados a ser utilizado" +#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:58 +#: /usr/local/icingaweb/application/forms/Config/Authentication/AutologinBackendForm.php:35 +#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:59 +msgid "" +"The name of this authentication provider that is used to differentiate it " +"from others" +msgstr "" +"O nome deste provedor de autenticação que será utilizado para diferenciá-lo " +"de outros" + #: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:81 -msgid "The name of this authentication backend" -msgstr "O nome deste backend de autenticação" - -#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:79 -msgid "The name of this authentication provider" -msgstr "O nome deste provedor de autenticação" - -#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:105 msgid "The object class used for storing users on the ldap server" msgstr "" "A classe de objeto a ser utilizada para armazenar os usuários no servidor " "ldap" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:207 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:207 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:103 msgid "The password to use for authentication" msgstr "A senha a ser utilizada para a autenticação" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:295 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:295 +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:84 msgid "The password to use for querying the ldap server" msgstr "A senha a ser utilizada para consultar o servidor ldap" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:246 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:246 +#: /usr/local/icingaweb/application/forms/Config/Resource/LivestatusResourceForm.php:46 msgid "The path to your livestatus socket used for querying monitoring data" msgstr "" -"O caminho para o socket do livestatus utilizado para consultar os dados de " +"O caminho para o soquete livestatus utilizado para consultar os dados de " "monitoramento" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:272 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:272 -msgid "The path where users can be found on the ldap server" -msgstr "O caminho onde os usuários possam ser encontrados no servidor ldap" +#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:109 +msgid "" +"The path where users can be found on the ldap server. Leave empty to select " +"all users available on the specified resource." +msgstr "" +"O caminho onde os usuários serão encontrados no servidor LDAP. Deixe em " +"branco para selecionar todos os usuários disponíveis no recurso especificado." -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:172 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:172 -msgid "The port to use." -msgstr "A porta utilizada." +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:55 +msgid "The port of the LDAP server to use for authentication" +msgstr "A porta do servidor LDAP utilizado para autenticação" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:320 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:320 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:74 +msgid "The port to use" +msgstr "Porta utilizada" + +#: /usr/local/icingaweb/application/forms/Config/Resource/FileResourceForm.php:53 msgid "The regular expression by which to identify columns" msgstr "A expressão regular para identificar as colunas" -#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:93 +#: /usr/local/icingaweb/application/forms/Config/Authentication/AutologinBackendForm.php:56 +msgid "" +"The regular expression to use to strip specific parts off from usernames. " +"Leave empty if you do not want to strip off anything" +msgstr "" +"A expressão regular usada para retirar partes específicas dos nomes de " +"usuário. Deixe em branco se você não quiser retirar nada" + +#: /usr/local/icingaweb/application/controllers/ConfigController.php:282 +#, php-format +msgid "" +"The resource \"%s\" is currently in use by the authentication backend \"%s" +"\". Removing the resource can result in noone being able to log in any " +"longer." +msgstr "" +"O recurso \"%s\" está atualmente em uso pelo backend de autenticação \"%s\". " +"Removendo o recurso poderá tornar o login indisponível por mais tempo." + +#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:69 msgid "The resource to use for authenticating with this provider" msgstr "O recurso a ser utilizado para autenticação com este provedor" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:145 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:145 -msgid "The type of SQL database you want to create." -msgstr "O tipo do banco de dados SQL que você quer criar." +#: /usr/local/icingaweb/application/forms/Dashboard/AddUrlForm.php:100 +msgid "The title for the dashlet" +msgstr "O título para o dashlet" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:99 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:54 +msgid "The type of SQL database" +msgstr "Tipo do banco de dados SQL" + +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:35 msgid "The type of logging to utilize." msgstr "O tipo do registro de log a ser utilizado." -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:376 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:376 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:231 msgid "The type of resource" msgstr "O tipo do recurso" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:334 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:334 +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:322 +msgid "The type of the resource to use for this authenticaton provider" +msgstr "Tipo do recurso a ser utilizado para este provedor de autenticação" + +#: /usr/local/icingaweb/application/forms/Config/Resource/FileResourceForm.php:34 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:45 +#: /usr/local/icingaweb/application/forms/Config/Resource/LivestatusResourceForm.php:37 +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:36 msgid "The unique name of this resource" msgstr "O nome único deste recurso" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:283 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:283 +#: /usr/local/icingaweb/application/forms/Dashboard/AddUrlForm.php:36 +msgid "The url being loaded in the dashlet" +msgstr "A url que a ser carregada no dashlet" + +#: /usr/local/icingaweb/application/forms/Config/Resource/LdapResourceForm.php:74 msgid "The user dn to use for querying the ldap server" msgstr "O usuário DN a ser utilizado para consultar o servidor ldap." -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:195 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:195 -msgid "The user name to use for authentication." -msgstr "O nome do usuário a ser utilizado para a autenticação." +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:93 +msgid "The user name to use for authentication" +msgstr "O nome do usuário a ser utilizado para a autenticação" -#: /usr/local/icingaweb/application/views/scripts/config/module.phtml:6 +#: /usr/local/icingaweb/application/views/scripts/config/module.phtml:7 msgid "There is no such module installed." msgstr "Não existe nenhum módulo instalado." -#: /usr/local/icingaweb/application/views/scripts/config/module.phtml:32 +#: /usr/local/icingaweb/application/views/scripts/showConfiguration.phtml:16 +msgid "" +"There's an application error preventing you from persisting the configuration" +msgstr "Há um erro na aplicação impedindo você de salvar a configuração" + +#: /usr/local/icingaweb/application/views/scripts/showConfiguration.phtml:11 +msgid "This could have one or more of the following reasons:" +msgstr "Isto pode ter uma ou mais das seguintes razões:" + +#: /usr/local/icingaweb/application/views/scripts/dashboard/addurl.phtml:6 +msgid "This feature is deactivated at the moment." +msgstr "Esta funcionalidade está desabilitada no momento." + +#: /usr/local/icingaweb/application/views/scripts/config/module.phtml:46 msgid "This module has no dependencies" msgstr "Este módulo não tem dependências" -#: /usr/local/icingaweb/library/Icinga/Application/Modules/Module.php:383 +#: /usr/local/icingaweb/library/Icinga/Application/Modules/Module.php:501 msgid "This module has no description" msgstr "Este módulo não tem descrição" -#: /usr/local/icingaweb/application/forms/Preference/GeneralForm.php:100 -msgid "Use Default Language" -msgstr "Utilizar idioma padrão" +#: /usr/local/icingaweb/application/forms/Dashboard/AddUrlForm.php:99 +msgid "Title" +msgstr "Título" -#: /usr/local/icingaweb/application/forms/Preference/GeneralForm.php:109 +#: /usr/local/icingaweb/application/views/scripts/config/devtools.phtml:5 +msgid "UI Debug" +msgstr "Interface de depuração" + +#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:149 +#, php-format +msgid "Unable to validate authentication: %s" +msgstr "Não é possível validar a autenticação: %s" + +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:121 +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:149 +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:172 +#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:242 +msgid "Unknown authentication backend provided" +msgstr "Backend de autenticação fornecido desconhecido" + +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:92 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:116 +#: /usr/local/icingaweb/application/forms/Config/ResourceConfigForm.php:177 +msgid "Unknown resource provided" +msgstr "Recurso fornecido desconhecido" + +#: /usr/local/icingaweb/application/forms/Dashboard/AddUrlForm.php:35 +msgid "Url" +msgstr "Url" + +#: /usr/local/icingaweb/application/forms/Dashboard/AddUrlForm.php:67 +msgid "Use An Existing Pane" +msgstr "Usar um painel existente" + +#: /usr/local/icingaweb/application/forms/PreferenceForm.php:185 +msgid "Use benchmark" +msgstr "Utilizar benchmark" + +#: /usr/local/icingaweb/application/forms/PreferenceForm.php:162 msgid "Use the following language to display texts and messages" msgstr "Utilizar o seguinte idioma para exibir textos e mensagens" -#: /usr/local/icingaweb/application/forms/Authentication/LoginForm.php:57 -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:194 -#: /usr/local/icingaweb/application/forms/Config/Resource/ResourceForm.php:194 +#: /usr/local/icingaweb/application/forms/PreferenceForm.php:174 +msgid "Use the following timezone for dates and times" +msgstr "Utilizar o seguinte fuso horário para as datas e horários" + +#: /usr/local/icingaweb/application/forms/Config/General/ApplicationConfigForm.php:53 +msgid "User Preference Storage Type" +msgstr "Tipo de armazenamento para as preferências do usuário" + +#: /usr/local/icingaweb/application/forms/Authentication/LoginForm.php:34 +#: /usr/local/icingaweb/application/forms/Config/Resource/DbResourceForm.php:92 msgid "Username" msgstr "Nome do usuário" -#: /usr/local/icingaweb/application/forms/Config/Authentication/LdapBackendForm.php:169 -msgid "" -"Using ldap is not possible, the php extension \"ldap\" is not installed." -msgstr "" -"A utilização do ldap não é possível, a extensão php \"ldap\" não está " -"instalada." - -#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:148 +#: /usr/local/icingaweb/application/forms/Config/Authentication/DbBackendForm.php:114 #, php-format msgid "Using the specified backend failed: %s" msgstr "A utilização do backend especificado falhou: %s" -#: /usr/local/icingaweb/application/forms/Config/LoggingForm.php:87 +#: /usr/local/icingaweb/application/forms/Config/General/LoggingConfigForm.php:54 +msgctxt "app.config.logging.level" msgid "Warning" msgstr "Atenção" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:435 -msgid "" -"You need to install the php extension \"mysql\" and the Zend_Pdo_Mysql " -"classes to use MySQL database resources." -msgstr "" -"Você precisa instalar a extensão php \"mysql\" e as classes Zend_Pdo_Mysql " -"para usar o recurso de banco de dados MySQL." +#: /usr/local/icingaweb/application/views/scripts/dashboard/index.phtml:10 +msgid "Welcome to Icinga Web!" +msgstr "Bem vindo ao Icinga Web" -#: /usr/local/icingaweb/application/forms/Config/ResourceForm.php:442 -msgid "" -"You need to install the php extension \"pgsql\" and the Zend_Pdo_Pgsql " -"classes to use PostgreSQL database resources." -msgstr "" -"Você precisa instalar a extensão php \"pgsql\" e as classes Zend_Pdo_Pgsql " -"para usar o recurso de banco de dados PostgreSQL." +#: /usr/local/icingaweb/application/views/scripts/showConfiguration.phtml:14 +msgid "You don't have file-system permissions to write to the file" +msgstr "Você não tem permissão no sistema de arquivos para gravar o arquivo" -#: /usr/local/icingaweb/application/forms/Preference/GeneralForm.php:106 +#: /usr/local/icingaweb/application/controllers/PreferenceController.php:44 +msgid "You need to configure how to store preferences first." +msgstr "" +"Você precisa em primeiro lugar configurar as preferências de armazenamento." + +#: /usr/local/icingaweb/application/views/scripts/authentication/login.phtml:20 +#, php-format +msgid "" +"You seem not to have Icinga Web 2 configured yet so it's not possible to log " +"in without any defined authentication method. Please define a authentication " +"method by following the instructions in the %1$sdocumentation%3$s or by " +"using our %2$sweb-based setup-wizard%3$s." +msgstr "" +"Você parece não ter configurado o Icinga Web 2. Deste modo não é possível " +"efetuar o login sem nenhum método de autenticação definido. Por favor, " +"defina um método de autenticação seguindo as instruções na %1$sdocumentação" +"%3$s ou usando nosso %2$sassistente de configuração web%3$s." + +#: /usr/local/icingaweb/application/forms/PreferenceForm.php:161 msgid "Your Current Language" msgstr "Seu idioma atual" + +#: /usr/local/icingaweb/application/forms/PreferenceForm.php:173 +msgid "Your Current Timezone" +msgstr "Seu fuso horário atual" + +#: /usr/local/icingaweb/library/Icinga/Web/Widget/Limiter.php:58 +msgid "all" +msgstr "todas" + +#: /usr/local/icingaweb/library/Icinga/Util/Format.php:83 +#: /usr/local/icingaweb/library/Icinga/Util/Format.php:89 +msgid "for" +msgstr "até" + +#: /usr/local/icingaweb/application/views/scripts/dashboard/index.phtml:13 +msgid "modules" +msgstr "módulos" + +#: /usr/local/icingaweb/library/Icinga/Util/Format.php:87 +#: /usr/local/icingaweb/library/Icinga/Util/Format.php:109 +#: /usr/local/icingaweb/library/Icinga/Util/Format.php:111 +msgid "since" +msgstr "desde" + +#: /usr/local/icingaweb/application/views/scripts/config/devtools.phtml:5 +msgid "toggle" +msgstr "alternar" diff --git a/application/views/scripts/authentication/login.phtml b/application/views/scripts/authentication/login.phtml index fe3ab5e3b..584d8ad16 100644 --- a/application/views/scripts/authentication/login.phtml +++ b/application/views/scripts/authentication/login.phtml @@ -1,11 +1,11 @@
-

translate('Icingaweb Login') ?>

+

Welcome to Icinga Web 2

errorInfo)): ?> @@ -14,6 +14,18 @@
form ?> - + + +
', // TODO: Documentation link + '', + '' + ); ?>
+
diff --git a/application/views/scripts/config/authentication/reorder.phtml b/application/views/scripts/config/authentication/reorder.phtml index 0ae7850eb..688d99f88 100644 --- a/application/views/scripts/config/authentication/reorder.phtml +++ b/application/views/scripts/config/authentication/reorder.phtml @@ -4,8 +4,8 @@ \ No newline at end of file + diff --git a/application/views/scripts/config/module.phtml b/application/views/scripts/config/module.phtml index c74cac80d..b7f6bf346 100644 --- a/application/views/scripts/config/module.phtml +++ b/application/views/scripts/config/module.phtml @@ -1,5 +1,6 @@
tabs ?> +

escape($module->getTitle()) ?>

@@ -12,7 +13,6 @@ $permissions = $module->getProvidedPermissions(); $state = $moduleData->enabled ? ($moduleData->loaded ? 'enabled' : 'failed') : 'disabled' ?> -

escape($module->getTitle()) ?>

diff --git a/application/views/scripts/config/modules.phtml b/application/views/scripts/config/modules.phtml index c0951d415..95c9fa731 100644 --- a/application/views/scripts/config/modules.phtml +++ b/application/views/scripts/config/modules.phtml @@ -11,9 +11,9 @@ @@ -37,4 +37,4 @@
escape('Name') ?>
enabled): ?> - icon('success.png', $this->translate('Module is enabled')) ?> + icon('thumbs-up', $this->translate('Module is enabled')) ?> - icon('remove.png', $this->translate('Module is disabled')) ?> + icon('thumbs-down', $this->translate('Module is disabled')) ?>

- icon('create.png'); ?> translate('Create A New Resource'); ?> + icon('plus'); ?> translate('Create A New Resource'); ?>

@@ -13,20 +13,20 @@ -resources as $name => $resource): ?> +resources as $name): ?>
translate('Remove'); ?>
- icon('edit.png'); ?> escape($name); ?> + icon('edit'); ?> escape($name); ?> - icon('remove.png'); ?> + icon('cancel'); ?>
- \ No newline at end of file + diff --git a/application/views/scripts/dashboard/addurl.phtml b/application/views/scripts/dashboard/addurl.phtml deleted file mode 100644 index c2d3f7e6c..000000000 --- a/application/views/scripts/dashboard/addurl.phtml +++ /dev/null @@ -1,12 +0,0 @@ -
-tabs ?> -
- -
-

escape($this->translate('This feature is deactivated at the moment.')); ?>

-

- escape($this->translate('Please have a little patience, we are hard working on it, take a look at icingaweb2 issues.')); - ?> -

-
\ No newline at end of file diff --git a/application/views/scripts/dashboard/error.phtml b/application/views/scripts/dashboard/error.phtml new file mode 100644 index 000000000..e5a0f3939 --- /dev/null +++ b/application/views/scripts/dashboard/error.phtml @@ -0,0 +1,13 @@ +
+

+

+ + config->getFilename(); ?>;. +
+ +

+
config->render(); ?>
+
+

+

error->getMessage(); ?>

+
diff --git a/application/views/scripts/dashboard/index.phtml b/application/views/scripts/dashboard/index.phtml index 4adad7b66..7c3724dc6 100644 --- a/application/views/scripts/dashboard/index.phtml +++ b/application/views/scripts/dashboard/index.phtml @@ -8,9 +8,11 @@

escape($this->translate('Welcome to Icinga Web!')) ?>

-

escape($this->translate('Currently there is no dashlet available. This might change once you enabled some of the available %s.')), - $this->qlink($this->translate('modules'), 'config/modules') - ) ?>

+

+ escape($this->translate('Currently there is no dashlet available. This might change once you enabled some of the available %s.')), + $this->qlink($this->translate('modules'), 'config/modules') + ) ?> +

\ No newline at end of file diff --git a/application/views/scripts/dashboard/new-dashlet.phtml b/application/views/scripts/dashboard/new-dashlet.phtml new file mode 100644 index 000000000..98b055414 --- /dev/null +++ b/application/views/scripts/dashboard/new-dashlet.phtml @@ -0,0 +1,7 @@ +
+ tabs ?> +
+
+

+ form; ?> +
\ No newline at end of file diff --git a/application/views/scripts/dashboard/remove-dashlet.phtml b/application/views/scripts/dashboard/remove-dashlet.phtml new file mode 100644 index 000000000..4c842cf29 --- /dev/null +++ b/application/views/scripts/dashboard/remove-dashlet.phtml @@ -0,0 +1,14 @@ +
+ tabs ?> +
+ +
+

+ +

+ translate('Please confirm the removal'); ?>: + pane; ?>/dashlet; ?> +

+ + form; ?> +
\ No newline at end of file diff --git a/application/views/scripts/dashboard/remove-pane.phtml b/application/views/scripts/dashboard/remove-pane.phtml new file mode 100644 index 000000000..45455d37d --- /dev/null +++ b/application/views/scripts/dashboard/remove-pane.phtml @@ -0,0 +1,14 @@ +
+ tabs ?> +
+ +
+

+ +

+ translate('Please confirm the removal of'); ?>: + pane; ?> +

+ + form; ?> +
\ No newline at end of file diff --git a/application/views/scripts/dashboard/settings.phtml b/application/views/scripts/dashboard/settings.phtml new file mode 100644 index 000000000..19a846ace --- /dev/null +++ b/application/views/scripts/dashboard/settings.phtml @@ -0,0 +1,63 @@ + +
+ tabs ?> +
+
+

+ + + + + + + + + + + dashboard->getPanes() as $pane): ?> + + + + + getDashlets(); ?> + + + + + + + getDisabled() === true) continue; ?> + + + + + + + + + +
+ + + +  
+ getName(); ?> + + + icon('cancel'); ?> + +
+ translate('No dashlets added to dashboard') ?>. +
+ + getTitle(); ?> + + + getUrl(); ?> + + + icon('cancel'); ?> + +
+
\ No newline at end of file diff --git a/application/views/scripts/dashboard/show-configuration.phtml b/application/views/scripts/dashboard/show-configuration.phtml deleted file mode 100644 index 7cdce496c..000000000 --- a/application/views/scripts/dashboard/show-configuration.phtml +++ /dev/null @@ -1,28 +0,0 @@ -
-
-

{{WARNING_ICON}}Saving Dashboard Failed

-
-

- Your dashboard couldn't be stored (error: "exceptionMessage; ?>"). This could have one or more - of the following reasons: -

-
    -
  • You don't have permissions to write to the dashboard file
  • -
  • Something went wrong while writing the file
  • -
  • There's an application error preventing you from persisting the configuration
  • -
-
- -

- Details can be seen in your application log (if you don't have access to this file, call your administrator in this case). -
- In case you can access the configuration file (config/dashboard/dashboard.ini) by yourself, you can open it and - insert the config manually: -

-

-

-        
-escape($this->iniConfigurationString); ?>
-        
-    
-

\ No newline at end of file diff --git a/application/views/scripts/dashboard/update-dashlet.phtml b/application/views/scripts/dashboard/update-dashlet.phtml new file mode 100644 index 000000000..e83c8b6c3 --- /dev/null +++ b/application/views/scripts/dashboard/update-dashlet.phtml @@ -0,0 +1,8 @@ +
+ tabs ?> +
+ +
+

+ form; ?> +
\ No newline at end of file diff --git a/application/views/scripts/form/reorder-authbackend.phtml b/application/views/scripts/form/reorder-authbackend.phtml index 8153e17d2..90319e0ad 100644 --- a/application/views/scripts/form/reorder-authbackend.phtml +++ b/application/views/scripts/form/reorder-authbackend.phtml @@ -11,23 +11,23 @@
- icon('edit.png'); ?> escape($backendNames[$i]); ?> + icon('edit'); ?> escape($backendNames[$i]); ?> - icon('remove.png', $this->translate('Remove')); ?> + icon('cancel', $this->translate('Remove')); ?> 0): ?>
getElement($form->getTokenElementName()); ?> getElement($form->getUidElementName()); ?> - \ No newline at end of file + diff --git a/application/views/scripts/joystickPagination.phtml b/application/views/scripts/joystickPagination.phtml new file mode 100644 index 000000000..27cafa309 --- /dev/null +++ b/application/views/scripts/joystickPagination.phtml @@ -0,0 +1,99 @@ +count() <= 1 && $yAxisPaginator->count() <= 1) { + return; // Display this pagination only if there are multiple pages +} + +$fromTo = t('%s: %d to %d of %d'); +$xAxisPages = $xAxisPaginator->getPages('all'); +$yAxisPages = $yAxisPaginator->getPages('all'); + +$totalYAxisPages = $yAxisPaginator->count(); +$currentYAxisPage = $yAxisPaginator->getCurrentPageNumber(); +$prevYAxisPage = $currentYAxisPage > 1 ? $currentYAxisPage - 1 : null; +$nextYAxisPage = $currentYAxisPage < $totalYAxisPages ? $currentYAxisPage + 1 : null; + +$totalXAxisPages = $xAxisPaginator->count(); +$currentXAxisPage = $xAxisPaginator->getCurrentPageNumber(); +$prevXAxisPage = $currentXAxisPage > 1 ? $currentXAxisPage - 1 : null; +$nextXAxisPage = $currentXAxisPage < $totalXAxisPages ? $currentXAxisPage + 1 : null; + +?> + + + + + + + + + + + + + + + + + + + +
  + + icon('up-open'); ?> + + icon('up-open'); ?> + +  
+ + icon('left-open'); ?> + + icon('left-open'); ?> + +   + + icon('right-open'); ?> + + icon('right-open'); ?> + +
  + + icon('down-open'); ?> + + icon('down-open'); ?> + +  
diff --git a/application/views/scripts/layout/menu.phtml b/application/views/scripts/layout/menu.phtml index 08373b2e9..83196d362 100644 --- a/application/views/scripts/layout/menu.phtml +++ b/application/views/scripts/layout/menu.phtml @@ -2,7 +2,7 @@ use Icinga\Web\Widget\SearchDashboard; ?> -getPane('search')->hasComponents()): ?> +getPane('search')->hasDashlets()): ?>

translate('Saving Configuration Failed'); ?>

-

translate('The file %s couldn\'t be stored. (Error: "%s")'), @@ -25,4 +24,4 @@

     escape($configString); ?>
   
-

\ No newline at end of file +

diff --git a/bin/icingacli b/bin/icingacli index 1a0781222..69aa35421 100755 --- a/bin/icingacli +++ b/bin/icingacli @@ -1,6 +1,8 @@ -#!/usr/bin/php +#!/usr/bin/env php dispatch(); + +Icinga\Application\Cli::start()->dispatch(); diff --git a/bin/license_writer.py b/bin/license_writer.py index 532839e2e..6612758ce 100755 --- a/bin/license_writer.py +++ b/bin/license_writer.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # {{{ICINGA_LICENSE_HEADER}}} # {{{ICINGA_LICENSE_HEADER}}} diff --git a/config/.gitignore b/config/.gitignore deleted file mode 100644 index 0a2f13d0d..000000000 --- a/config/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -authentication.ini -config.ini -modules/monitoring/backends.ini -modules/monitoring/instances.ini -resources.ini - diff --git a/config/authentication.ini.in b/config/authentication.ini.in deleted file mode 100644 index 2a2d2a969..000000000 --- a/config/authentication.ini.in +++ /dev/null @@ -1,29 +0,0 @@ -; authentication.ini -; -; Each section listed in this configuration represents a backend used to authenticate users. The backend configurations -; must define a resource referring to a configured database or LDAP connection in the INI file resources.ini. -; -; The backends will be processed from top to bottom using the first backend for authentication which reports that -; the user trying to log in is available. - -[autologin] -backend = autologin -; -; If you want to strip the domain -; strip_username_regexp = /\@[^$]+$/ - -[internal_ldap_authentication] -@ldap_auth_disabled@ -backend = ldap -resource = internal_ldap -user_class = @ldap_user_objectclass@ -user_name_attribute = @ldap_attribute_username@ -group_base_dn = @ldap_group_base_dn@ -group_attribute = @ldap_group_attribute@ -group_member_attribute = @ldap_group_member_attribute@ -group_class = @ldap_group_class@ - -[internal_db_authentication] -@internal_auth_disabled@ -backend = db -resource = internal_db diff --git a/config/config.ini.in b/config/config.ini.in deleted file mode 100644 index 560acf527..000000000 --- a/config/config.ini.in +++ /dev/null @@ -1,41 +0,0 @@ -[global] -timezone = "Europe/Berlin" - -; Contains the directories that will be searched for available modules. Modules that -; don't exist in these directories can still be symlinked in the module folder, but -; won't show up in the list of disabled modules -; modulePath = "/vagrant/modules:/usr/share/icingaweb/modules" - -[logging] -enable = true -; Writing to a Stream -type = "file" -; Write data to the following file -target = "@icingaweb_log_path@/icingaweb.log" -; Write data to a PHP stream -;target = "php://output" - -; Writing to the System Log -;type = "syslog" -; Prefix all syslog messages generated with the string "icingaweb" -;application = "icingaweb" -;facility = "LOG_USER" - -level = 1 -; The default level is WARNING, which means that only events of this level and -; above will be tracked. Level numbers descend in order of importance where -; ERROR (0) is the most important level and DEBUG (3) is the least important -; level: -; -; ERROR = 0 - Error: error conditions -; WARNING = 1 - Warning: warning conditions -; INFO = 2 - Informational: informational messages -; DEBUG = 3 - Debug: debug messages - -[preferences] -; Use INI file storage to save preferences to a local disk -type = "ini" - -; Use database storage to save preferences in either a MySQL or PostgreSQL database -;type = db -;resource = icingaweb-mysql diff --git a/config/enabledModules/README b/config/enabledModules/README deleted file mode 100644 index 7a55ea091..000000000 --- a/config/enabledModules/README +++ /dev/null @@ -1 +0,0 @@ -Enabled modules shall be symlinked here. diff --git a/config/ldap/ldap_ca.conf.in b/config/ldap/ldap_ca.conf.in deleted file mode 100644 index 2682820b8..000000000 --- a/config/ldap/ldap_ca.conf.in +++ /dev/null @@ -1,4 +0,0 @@ -# Use given CA file -TLS_REQCERT demand -TLS_CACERT @prefix@/config/ssl/cacerts/trusted.crt - diff --git a/config/ldap/ldap_nocert.conf b/config/ldap/ldap_nocert.conf deleted file mode 100644 index 768691479..000000000 --- a/config/ldap/ldap_nocert.conf +++ /dev/null @@ -1,4 +0,0 @@ -# This config file will allow TLS-based LDAP connections ignoring -# unknown certificates -TLS_REQCERT never - diff --git a/config/memberships.ini b/config/memberships.ini deleted file mode 100644 index c92fae47c..000000000 --- a/config/memberships.ini +++ /dev/null @@ -1,9 +0,0 @@ -[membership-set1] -backend = groupX -users = icingaadmin,tgelf -groups = admin,users - -[membership-set2] -backend = groupY -users = icingaadmin -groups = support1,support2 diff --git a/config/modules/monitoring/backends.ini.in b/config/modules/monitoring/backends.ini.in deleted file mode 100644 index 910f17f81..000000000 --- a/config/modules/monitoring/backends.ini.in +++ /dev/null @@ -1,19 +0,0 @@ -[localdb] -@ido_enabled@ -type = ido -resource = "ido" - -[locallive] -@livestatus_enabled@ -type = livestatus -resource = livestatus - -[localfile] -@statusdat_enabled@ -type = statusdat -resource = statusdat - -;[localfailsafe] -;enabled=false -;type = combo -;backends = localdb, locallive, localfile diff --git a/config/modules/monitoring/config.ini b/config/modules/monitoring/config.ini deleted file mode 100644 index 9b69fe86f..000000000 --- a/config/modules/monitoring/config.ini +++ /dev/null @@ -1,2 +0,0 @@ -[security] -protected_customvars = "*pw*,*pass*,community" diff --git a/config/modules/monitoring/instances.ini.in b/config/modules/monitoring/instances.ini.in deleted file mode 100644 index f129553d0..000000000 --- a/config/modules/monitoring/instances.ini.in +++ /dev/null @@ -1,2 +0,0 @@ -[icinga] -path = "@icinga_commandpipe@" diff --git a/config/permissions.ini b/config/permissions.ini deleted file mode 100644 index 3fec92f1c..000000000 --- a/config/permissions.ini +++ /dev/null @@ -1,11 +0,0 @@ -[test1] -users = icingaadmin,root,tgelf -groups = support2,support2 -permission_1 = monitoring, monitoring/log -permission_2 = monitoring/command/all - -[test2] -users = root -groups = admin -permission_2 = test/permission/1, test/permission/2 -permission_3 = test/permission/15, test/permission/7 \ No newline at end of file diff --git a/config/preferences/.gitkeep b/config/preferences/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/resources.ini.in b/config/resources.ini.in deleted file mode 100644 index d4c617c51..000000000 --- a/config/resources.ini.in +++ /dev/null @@ -1,55 +0,0 @@ -; resources.ini -; -; The configuration file *resources.ini* contains data sources that -; can be referenced in other configurations. This allows you to manage -; all connections to SQL databases in one single place, avoiding the need -; to edit several different configuration files, when the connection -; information of a resource change. -; -; Each section represents a resource, with the section name being the -; identifier used to reference this certain section. Depending on the -; resource type, each section contains different properties. The property -; *type* defines the resource type and thus how the properties are going to -; be interpreted. Currently only the resource type *db* is available. - - -[internal_db] -type = db -db = @internal_db_type@ -host = @internal_db_host@ -port = @internal_db_port@ -password = @internal_db_password@ -username = @internal_db_user@ -dbname = @internal_db_name@ - -[ido] -type = db -db = @ido_db_type@ -host = @ido_host@ -port = @ido_port@ -password = @ido_password@ -username = @ido_user@ -dbname = @ido_db_name@ - -[statusdat] -type = statusdat -status_file = @statusdat_file@ -object_file = @objects_cache_file@ - -[livestatus] -type = livestatus -socket = @livestatus_socket@ - -[internal_ldap] -type = ldap -hostname = @ldap_host@ -port = @ldap_port@ -root_dn = "@ldap_rootdn@" -bind_dn = "@ldap_binddn@" -bind_pw = @ldap_bindpass@ - -[logfile] -type = file -filename = "@icingaweb_log_path@/icingaweb.log" -fields = "/^(?[0-9]{4}(-[0-9]{2}){2}T[0-9]{2}(:[0-9]{2}){2}(\\+[0-9]{2}:[0-9]{2})?) - (?[A-Za-z]+) - (?.*)$/" -; format: PCRE diff --git a/config/restrictions.ini b/config/restrictions.ini deleted file mode 100644 index d14a8a60f..000000000 --- a/config/restrictions.ini +++ /dev/null @@ -1,16 +0,0 @@ -[test1] -users = "user1" -groups = "no-such-group" -name = "monitoring/filter" -restriction = "hostgroup=lalala&service_description=*ping*" - -[test2] -users = "user2" -name = "monitoring/filter" -restriction = "hostgroup=kunden*&service_description=*ping*" - -[test3] -users = "user3" -name = "monitoring/filter" -restriction = "hostgroup=kunden*&service_description=*ping-ping*" - diff --git a/config/ssl/cacerts/trusted.crt.in b/config/ssl/cacerts/trusted.crt.in deleted file mode 100644 index e69de29bb..000000000 diff --git a/configure b/configure deleted file mode 100755 index a48f71506..000000000 --- a/configure +++ /dev/null @@ -1,4125 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for IcingaWeb2 1.0.0. -# -# Report bugs to . -# -# -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : - -else - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : - as_have_required=yes -else - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : - -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : - CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : - break 2 -fi -fi - done;; - esac - as_found=false -done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } -IFS=$as_save_IFS - - - if test "x$CONFIG_SHELL" != x; then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." - else - $as_echo "$0: Please tell bug-autoconf@gnu.org and info@icinga.org -$0: about your system, including any error possibly output -$0: before this message. Then install a modern shell, or -$0: manually run the script under such a shell if you do -$0: have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='IcingaWeb2' -PACKAGE_TARNAME='icingaweb2' -PACKAGE_VERSION='1.0.0' -PACKAGE_STRING='IcingaWeb2 1.0.0' -PACKAGE_BUGREPORT='info@icinga.org' -PACKAGE_URL='' - -ac_default_prefix=/usr/local/icingaweb -ac_subst_vars='LTLIBOBJS -LIBOBJS -INSTALL_OPTS_WEB -INSTALL_OPTS -internal_auth_disabled -ldap_auth_disabled -icinga_commandpipe -livestatus_enabled -livestatus_socket -objects_cache_file -statusdat_file -statusdat_enabled -ido_password -ido_user -ido_db_name -ido_port -ido_host -ido_db_type -ido_enabled -icinga_backend -ldap_attribute_username -ldap_attribute_basedn -ldap_user_objectclass -ldap_bindpass -ldap_binddn -ldap_rootdn -ldap_port -ldap_host -internal_db_password -internal_db_user -internal_db_port -internal_db_host -internal_db_name -internal_db_type -icingaweb_log_path -icingaweb_config_path -bin_group -bin_user -httpd_config_path -web_path -web_group -web_user -app_name -PHP -SED -GREP -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -with_icingaweb_config_path -with_icingaweb_log_path -with_web_user -with_web_group -with_web_path -with_httpd_config_path -with_bin_user -with_bin_group -with_internal_db_type -with_internal_db_name -with_internal_db_host -with_internal_db_port -with_internal_db_password -with_internal_db_user -with_internal_authentication -with_ldap_authentication -with_ldap_host -with_ldap_port -with_ldap_binddn -with_ldap_bindpass -with_ldap_rootdn -with_ldap_user_objectclass -with_ldap_attribute_username -with_icinga_backend -with_ido_db_type -with_ido_host -with_ido_port -with_ido_db_name -with_ido_user -with_ido_password -with_statusdat_file -with_objects_cache_file -with_livestatus_socket -with_icinga_commandpipe -' - ac_precious_vars='build_alias -host_alias -target_alias -PHP' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures IcingaWeb2 1.0.0 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/icingaweb2] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of IcingaWeb2 1.0.0:";; - esac - cat <<\_ACEOF - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-icingaweb-config-path=PATH - Configuration path for icinga web (default - $prefix/config) - --with-icingaweb-log-path=PATH - Log path for icinga web (default $prefix/var/log) - --with-web-user=USER username for web writable files (default www-data) - --with-web-group=GROUP group for web writable files (default www-data) - --with-web-path=PATH web sub path (default /icingaweb) - --with-httpd-config-path=PATH - Include folder apache2 (default /etc/apache2/conf.d) - --with-bin-user=USER user for all other files (default root) - --with-bin-group=GROUP group for all other files (default bin) - --with-internal-db-type=TYPE - database type to use for internal database (default - mysql, supported: pgsql, mysql) - --with-internal-db-name=NAME - database name to use for internal database (default - icingaweb) - --with-internal-db-host=HOST - database host to use for internal database (default - localhost) - --with-internal-db-port=PORT - database port to use for internal database (default: - 3306 for mysql, 5432 for pgsql) - --with-internal-db-password=PASS - database pass to use for internal database (default - icingaweb) - --with-internal-db-user=USER - database user to use for internal database (default - icingaweb) - --with-internal-authentication - use the internal database for authentication - (default: yes) - --with-ldap-authentication - use a ldap server for authentication (default: no) - --with-ldap-host=HOST host to use for authentication via ldap (default - localhost) - --with-ldap-port=PORT port to use for authentication via ldap (default - 389) - --with-ldap-binddn=DN dn to use for retrieving user information via ldap - (default cn=admin, cn=config) - --with-ldap-bindpass=PASS - password to use for retrieving user information via - ldap (default admin) - --with-ldap-rootdn=LDAP_ATTRIBUTE - root dn to use for user lookup (default ou=people, - dc=icinga, dc=org) - --with-ldap-user-objectclass=LDAP_OBJECT_CLASS - ldap object class to use for user authentication - (default: inetOrgPerson) - --with-ldap-attribute-username=LDAP_ATTRIBUTE - user attribute to use for the username (default: - uid) - --with-icinga-backend=(ido, statusdat, livestatus) - backend to use for rb (default: statusdat) - --with-ido-db-type=(mysql, pgsql) - database engine to use for retrieving data from the - ido db (default: mysql) - --with-ido-host=HOST host to use for retrieving data from the ido db - (default: localhost) - --with-ido-port=PORT backend to use for retrieving data from the ido db - (default: 3306 for mysql. 5432 for pgsql) - --with-ido-db-name=DATABASE - database name to use for retrieving data from the - ido db (default: icinga) - --with-ido-user=USER user to use for retrieving data from the ido db - (default: icinga) - --with-ido-password=PASSWORD - password to use for retrieving data from the ido db - (default: icinga) - --with-statusdat-file=FILE - location of the status.dat file when retrieving data - from status.dat (default: - /usr/local/icinga/var/status.dat) - --with-objects-cache-file=FILE - location of the objects.cache file when retrieving - data from status.dat (default: - /usr/local/icinga/var/objects.cache) - --with-livestatus-socket=FILE - location of the livestatus socket (default: - /usr/local/icinga/var/rw/live) - --with-icinga-commandpipe=FILE - location of the command pipe used for sending - commands (default: - /usr/local/icinga/var/rw/icinga.cmd) - --with-objects-file=FILE - location of the objects.cache file when retrieving - data from status.dat (default: - /usr/local/icinga/var/objects.cache) - -Some influential environment variables: - PHP php cli binary - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -IcingaWeb2 configure 1.0.0 -generated by GNU Autoconf 2.69 - -Copyright (C) 2012 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by IcingaWeb2 $as_me 1.0.0, which was -generated by GNU Autoconf 2.69. Invocation command line was - - $ $0 $@ - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Save into config.log some information that might help in debugging. - { - echo - - $as_echo "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - $as_echo "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - $as_echo "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -$as_echo "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE -if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac -elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site -else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site -fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" -do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - -if test "x$prefix" = "xNONE" ; then - installDir="/usr/local/icingaweb" - prefix=$installDir -else - installDir=$prefix -fi - -# Checks for programs. -ac_aux_dir= -for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 -fi - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -$as_echo_n "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : - $as_echo_n "(cached) " >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in #(( - ./ | .// | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - -fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -$as_echo_n "checking for a sed that does not truncate output... " >&6; } -if ${ac_cv_path_SED+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -$as_echo "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - - -# Check for php - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PHP runtime dependency 'Zend Framework' is available" >&5 -$as_echo_n "checking if PHP runtime dependency 'Zend Framework' is available... " >&6; } - if php -r 'require "Zend/Application.php";' ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP runtime dependency fulfilled" >&5 -$as_echo "PHP runtime dependency fulfilled" >&6; } -else - as_fn_error $? "PHP runtime dependency 'Zend Framework' is missing" "$LINENO" 5 -fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has at least version 5.3.0" >&5 -$as_echo_n "checking if php has at least version 5.3.0... " >&6; } - if test 5 -le `php -r 'echo PHP_MAJOR_VERSION;'` && \ - test 3 -le `php -r 'echo PHP_MINOR_VERSION;'` && \ - test 0 -le `php -r 'echo PHP_RELEASE_VERSION;'`; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP version is correct" >&5 -$as_echo "PHP version is correct" >&6; } -else - as_fn_error $? "You need at least PHP version 5.3.0" "$LINENO" 5 -fi - - - # Extract the first word of "php", so it can be a program name with args. -set dummy php; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_PHP+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $PHP in - [\\/]* | ?:[\\/]*) - ac_cv_path_PHP="$PHP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_PHP="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_PHP" && ac_cv_path_PHP="not found" - ;; -esac -fi -PHP=$ac_cv_path_PHP -if test -n "$PHP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PHP" >&5 -$as_echo "$PHP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - - if test "XX${PHP}" == "XXnot found" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: binary php not found in PATH" >&5 -$as_echo "$as_me: WARNING: binary php not found in PATH" >&2;} -fi - - test "XX${PHP}" == "XXnot found" && PHP="" - - -# Checks for libraries. - - for x in sockets json;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - -# -# Configuration files -# - -# Check whether --with-icingaweb_config_path was given. -if test "${with_icingaweb_config_path+set}" = set; then : - withval=$with_icingaweb_config_path; icingaweb_config_path=$withval -else - icingaweb_config_path=$prefix/config - -fi - - -# -# Log files -# - -# Check whether --with-icingaweb_log_path was given. -if test "${with_icingaweb_log_path+set}" = set; then : - withval=$with_icingaweb_log_path; icingaweb_log_path=$withval -else - icingaweb_log_path=$prefix/var/log - -fi - - -# -# Users for webfiles -# - - -# Check whether --with-web_user was given. -if test "${with_web_user+set}" = set; then : - withval=$with_web_user; web_user=$withval -else - - web_user=www-data - for x in www wwwrun www-data apache httpd nobody; do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if user $x exists" >&5 -$as_echo_n "checking if user $x exists... " >&6; } - if $GREP -q "^$x:" /etc/passwd ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; }; web_user=$x ; break -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } -fi - done - - -fi - - - -# Check whether --with-web_group was given. -if test "${with_web_group+set}" = set; then : - withval=$with_web_group; web_group=$withval -else - - web_group=www-data - for x in www www-data apache httpd nogroup nobody; do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if group $x exists" >&5 -$as_echo_n "checking if group $x exists... " >&6; } - if $GREP -q "^$x:" /etc/group ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; }; web_group=$x ; break -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } -fi - done - - -fi - - - -# Check whether --with-web_path was given. -if test "${with_web_path+set}" = set; then : - withval=$with_web_path; web_path=$withval -else - web_path=/icingaweb - -fi - - - -# Check whether --with-httpd_config_path was given. -if test "${with_httpd_config_path+set}" = set; then : - withval=$with_httpd_config_path; httpd_config_path=$withval -else - httpd_config_path= - httpd_config_path=/etc/apache2/conf.d - for x in /etc/httpd/conf.d /etc/apache2/conf-available /etc/apache2/conf.d /etc/apache/conf.d; do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if path $x exists" >&5 -$as_echo_n "checking if path $x exists... " >&6; } - if test -d $x; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; }; httpd_config_path=$x; break -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - -fi - done - - -fi - - -# -# Users and groups for installation -# - - -# Check whether --with-bin_user was given. -if test "${with_bin_user+set}" = set; then : - withval=$with_bin_user; bin_user=$withval -else - bin_user=root - -fi - - - -# Check whether --with-bin_group was given. -if test "${with_bin_group+set}" = set; then : - withval=$with_bin_group; bin_group=$withval -else - bin_group=bin - -fi - - -# -# Internal database setup -# - - -# Check whether --with-internal_db_type was given. -if test "${with_internal_db_type+set}" = set; then : - withval=$with_internal_db_type; internal_db_type=$withval -else - internal_db_type=mysql - -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking Testing database type for --with-internal-db-type" >&5 -$as_echo_n "checking Testing database type for --with-internal-db-type... " >&6; } - if echo "$internal_db_type" | $GREP -q "^\(my\|pg\)sql$"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK ($internal_db_type)" >&5 -$as_echo "OK ($internal_db_type)" >&6; } -else - as_fn_error $? "$internal_db_type" "$LINENO" 5 - -fi - - - -# Check whether --with-internal_db_name was given. -if test "${with_internal_db_name+set}" = set; then : - withval=$with_internal_db_name; internal_db_name=$withval -else - internal_db_name=icingaweb - -fi - - - -# Check whether --with-internal_db_host was given. -if test "${with_internal_db_host+set}" = set; then : - withval=$with_internal_db_host; internal_db_host=$withval -else - internal_db_host=localhost - -fi - - - -# Check whether --with-internal_db_port was given. -if test "${with_internal_db_port+set}" = set; then : - withval=$with_internal_db_port; internal_db_port=$withval -else - internal_db_port=db_default_port - -fi - - - -# Check whether --with-internal_db_password was given. -if test "${with_internal_db_password+set}" = set; then : - withval=$with_internal_db_password; internal_db_password=$withval -else - internal_db_password=icingaweb - -fi - - - -# Check whether --with-internal_db_user was given. -if test "${with_internal_db_user+set}" = set; then : - withval=$with_internal_db_user; internal_db_user=$withval -else - internal_db_user=icingaweb - -fi - - -# -# Authorization method -# - - -# Check whether --with-internal_authentication was given. -if test "${with_internal_authentication+set}" = set; then : - withval=$with_internal_authentication; internal_authentication=$withval -else - internal_authentication=yes - -fi - - - -# Check whether --with-ldap_authentication was given. -if test "${with_ldap_authentication+set}" = set; then : - withval=$with_ldap_authentication; ldap_authentication=$withval -else - ldap_authentication=no - -fi - - -# -# LDAP Authorization -# - - -# Check whether --with-ldap_host was given. -if test "${with_ldap_host+set}" = set; then : - withval=$with_ldap_host; ldap_host=$withval -else - ldap_host=localhost - -fi - - - -# Check whether --with-ldap_port was given. -if test "${with_ldap_port+set}" = set; then : - withval=$with_ldap_port; ldap_port=$withval -else - ldap_port=389 - -fi - - - -# Check whether --with-ldap_binddn was given. -if test "${with_ldap_binddn+set}" = set; then : - withval=$with_ldap_binddn; ldap_binddn=$withval -else - ldap_binddn="cn=admin,cn=config" - -fi - - - -# Check whether --with-ldap_bindpass was given. -if test "${with_ldap_bindpass+set}" = set; then : - withval=$with_ldap_bindpass; ldap_bindpass=$withval -else - ldap_bindpass="admin" - -fi - - - -# Check whether --with-ldap_rootdn was given. -if test "${with_ldap_rootdn+set}" = set; then : - withval=$with_ldap_rootdn; ldap_rootdn=$withval -else - ldap_rootdn="ou=people, dc=icinga, dc=org" - -fi - - - -# Check whether --with-ldap_user_objectclass was given. -if test "${with_ldap_user_objectclass+set}" = set; then : - withval=$with_ldap_user_objectclass; ldap_user_objectclass=$withval -else - ldap_user_objectclass="inetOrgPerson" - -fi - - - -# Check whether --with-ldap_attribute_username was given. -if test "${with_ldap_attribute_username+set}" = set; then : - withval=$with_ldap_attribute_username; ldap_attribute_username=$withval -else - ldap_attribute_username="uid" - -fi - - -# -# Icinga backend selection -# - - -# Check whether --with-icinga_backend was given. -if test "${with_icinga_backend+set}" = set; then : - withval=$with_icinga_backend; icinga_backend=$withval -else - icinga_backend="statusdat" - -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking Testing backend type for --with-icinga-backend" >&5 -$as_echo_n "checking Testing backend type for --with-icinga-backend... " >&6; } - if echo "$icinga_backend" | $GREP -q "^\(ido\|statusdat\|livestatus\)$"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK ($icinga_backend)" >&5 -$as_echo "OK ($icinga_backend)" >&6; } -else - as_fn_error $? "$icinga_backend" "$LINENO" 5 - -fi - - -# -# Ido settings -# - - -# Check whether --with-ido_db_type was given. -if test "${with_ido_db_type+set}" = set; then : - withval=$with_ido_db_type; ido_db_type=$withval -else - ido_db_type="mysql" - -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking Testing database type for --with-ido-db-type" >&5 -$as_echo_n "checking Testing database type for --with-ido-db-type... " >&6; } - if echo "$ido_db_type" | $GREP -q "^\(my\|pg\)sql$"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK ($ido_db_type)" >&5 -$as_echo "OK ($ido_db_type)" >&6; } -else - as_fn_error $? "$ido_db_type" "$LINENO" 5 - -fi - - - -# Check whether --with-ido_host was given. -if test "${with_ido_host+set}" = set; then : - withval=$with_ido_host; ido_host=$withval -else - ido_host="localhost" - -fi - - - -# Check whether --with-ido_port was given. -if test "${with_ido_port+set}" = set; then : - withval=$with_ido_port; ido_port=$withval -else - ido_port=db_default_port - -fi - - - -# Check whether --with-ido_db_name was given. -if test "${with_ido_db_name+set}" = set; then : - withval=$with_ido_db_name; ido_db_name=$withval -else - ido_db_name="icinga" - -fi - - - -# Check whether --with-ido_user was given. -if test "${with_ido_user+set}" = set; then : - withval=$with_ido_user; ido_user=$withval -else - ido_user="icinga" - -fi - - - -# Check whether --with-ido_password was given. -if test "${with_ido_password+set}" = set; then : - withval=$with_ido_password; ido_password=$withval -else - ido_password="icinga" - -fi - - -# -# Statusdat file location -# - - -# Check whether --with-statusdat_file was given. -if test "${with_statusdat_file+set}" = set; then : - withval=$with_statusdat_file; statusdat_file=$withval -else - statusdat_file="/usr/local/icinga/var/status.dat" - -fi - - - -# Check whether --with-objects_cache_file was given. -if test "${with_objects_cache_file+set}" = set; then : - withval=$with_objects_cache_file; objects_cache_file=$withval -else - objects_cache_file="/usr/local/icinga/var/objects.cache" - -fi - - -# -# Livestatus connection -# - - -# Check whether --with-livestatus_socket was given. -if test "${with_livestatus_socket+set}" = set; then : - withval=$with_livestatus_socket; livestatus_socket=$withval -else - livestatus_socket="/usr/local/icinga/var/rw/live" - -fi - - -# -# Icinga commandpipe -# - - -# Check whether --with-icinga_commandpipe was given. -if test "${with_icinga_commandpipe+set}" = set; then : - withval=$with_icinga_commandpipe; icinga_commandpipe=$withval -else - icinga_commandpipe="/usr/local/icinga/var/rw/icinga.cmd" - -fi - - - -# Check whether --with-objects_cache_file was given. -if test "${with_objects_cache_file+set}" = set; then : - withval=$with_objects_cache_file; objects_cache_file=$withval -else - objects_cache_file="/usr/local/icinga/var/objects.cache" - -fi - - -# -# Livestatus connection -# - - -# Check whether --with-livestatus_socket was given. -if test "${with_livestatus_socket+set}" = set; then : - withval=$with_livestatus_socket; livestatus_socket=$withval -else - livestatus_socket="/usr/local/icinga/var/rw/live" - -fi - - -# -# Icinga commandpipe -# - - -# Check whether --with-icinga_commandpipe was given. -if test "${with_icinga_commandpipe+set}" = set; then : - withval=$with_icinga_commandpipe; icinga_commandpipe=$withval -else - icinga_commandpipe="/usr/local/icinga/var/rw/icinga.cmd" - -fi - - -# Installation options -INSTALL_OPTS="-o $bin_user -g $bin_group" -INSTALL_OPTS_WEB="-o $web_user -g $web_group" - -if test "x$internal_db_type" = xmysql; then : - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is available" >&5 -$as_echo_n "checking if PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is available... " >&6; } - if php -r 'require "Zend/Db/Adapter/Pdo/Mysql.php";' ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP runtime dependency fulfilled" >&5 -$as_echo "PHP runtime dependency fulfilled" >&6; } -else - as_fn_error $? "PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is missing" "$LINENO" 5 -fi - - - for x in mysql;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - if test "x$internal_db_port" == xdb_default_port; then : - internal_db_port=3306 -fi - -fi - -if test "x$ido_db_type" = xmysql; then : - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is available" >&5 -$as_echo_n "checking if PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is available... " >&6; } - if php -r 'require "Zend/Db/Adapter/Pdo/Mysql.php";' ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP runtime dependency fulfilled" >&5 -$as_echo "PHP runtime dependency fulfilled" >&6; } -else - as_fn_error $? "PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is missing" "$LINENO" 5 -fi - - - for x in mysql;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - if test "x$ido_port" = xdb_default_port; then : - ido_port=3306 -fi - -fi - -if test "x$internal_db_type" = xpgsql; then : - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is available" >&5 -$as_echo_n "checking if PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is available... " >&6; } - if php -r 'require "Zend/Db/Adapter/Pdo/Pgsql.php";' ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP runtime dependency fulfilled" >&5 -$as_echo "PHP runtime dependency fulfilled" >&6; } -else - as_fn_error $? "PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is missing" "$LINENO" 5 -fi - - - for x in pgsql;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - if test "x$internal_db_port" = xdb_default_port; then : - internal_db_port=5432 -fi - -fi - -if test "x$ido_db_type" = xpgsql; then : - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is available" >&5 -$as_echo_n "checking if PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is available... " >&6; } - if php -r 'require "Zend/Db/Adapter/Pdo/Pgsql.php";' ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP runtime dependency fulfilled" >&5 -$as_echo "PHP runtime dependency fulfilled" >&6; } -else - as_fn_error $? "PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is missing" "$LINENO" 5 -fi - - - for x in pgsql;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - if test "x$ido_port" = xdb_default_port; then : - ido_port=5432 -fi - -fi - -# -# Disable authentication backends -# - -ido_enabled="disabled = \"1\"" -statusdat_enabled="disabled = \"1\"" -livestatus_enabled="disabled = \"1\"" - -case $icinga_backend in #( - "ido") : - ido_enabled="" ;; #( - "statusdat") : - statusdat_enabled="" ;; #( - "livestatus") : - livestatus_enabled="" ;; #( - *) : - statusdat_enabled="" ;; -esac - -ldap_auth_disabled="disabled = \"1\"" -if test "x$ldap_authentication" != xno; then : - - for x in ldap;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - ldap_auth_disabled="" - -fi - -internal_auth_disabled="disabled = \"1\"" -if test "x$internal_authentication" != xno; then : - - for x in ldap;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - internal_auth_disabled="" - -fi - -# -# Substitution variables -# - -# Installation directives - - - - - - - - - - -# Internal db setup - - - - - - - -# ldap setup - - - - - - - - - -# backend setup - - -# ido backend variables - - - - - - - - -# status.dat backend - - - - -# livestatus backend - - - -# command pipe - - -# Comment placeholders for toggling backends - - - - -# Application and installation - - - - -# -# Create config files -# -ac_config_files="$ac_config_files Makefile config/authentication.ini config/config.ini config/resources.ini config/modules/monitoring/backends.ini config/modules/monitoring/instances.ini etc/apache/icingaweb.conf" - - -# -# Commit and write -# -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -# Transform confdefs.h into DEFS. -# Protect against shell expansion while executing Makefile rules. -# Protect against Makefile macro expansion. -# -# If the first sed substitution is executed (which looks for macros that -# take arguments), then branch to the quote section. Otherwise, -# look for a macro that doesn't take arguments. -ac_script=' -:mline -/\\$/{ - N - s,\\\n,, - b mline -} -t clear -:clear -s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g -t quote -s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g -t quote -b any -:quote -s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g -s/\[/\\&/g -s/\]/\\&/g -s/\$/$$/g -H -:any -${ - g - s/^\n// - s/\n/ /g - p -} -' -DEFS=`sed -n "$ac_script" confdefs.h` - - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by IcingaWeb2 $as_me 1.0.0, which was -generated by GNU Autoconf 2.69. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - -Configuration files: -$config_files - -Report bugs to ." - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" -ac_cs_version="\\ -IcingaWeb2 config.status 1.0.0 -configured by $0, generated by GNU Autoconf 2.69, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2012 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h | --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - $as_echo "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "config/authentication.ini") CONFIG_FILES="$CONFIG_FILES config/authentication.ini" ;; - "config/config.ini") CONFIG_FILES="$CONFIG_FILES config/config.ini" ;; - "config/resources.ini") CONFIG_FILES="$CONFIG_FILES config/resources.ini" ;; - "config/modules/monitoring/backends.ini") CONFIG_FILES="$CONFIG_FILES config/modules/monitoring/backends.ini" ;; - "config/modules/monitoring/instances.ini") CONFIG_FILES="$CONFIG_FILES config/modules/monitoring/instances.ini" ;; - "etc/apache/icingaweb.conf") CONFIG_FILES="$CONFIG_FILES etc/apache/icingaweb.conf" ;; - - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >$CONFIG_STATUS || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - - -eval set X " :F $CONFIG_FILES " -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - - - - esac - -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 065c81a8f..000000000 --- a/configure.ac +++ /dev/null @@ -1,448 +0,0 @@ -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. - -AC_PREREQ([2.61]) -AC_INIT([IcingaWeb2], [1.0.0], [info@icinga.org]) -AC_PREFIX_DEFAULT(/usr/local/icingaweb) - -if test "x$prefix" = "xNONE" ; then - installDir="/usr/local/icingaweb" - prefix=$installDir -else - installDir=$prefix -fi - -# Checks for programs. -AC_PROG_INSTALL -AC_PROG_GREP -AC_PROG_SED - -# Check for php -AC_ARG_VAR([PHP],[php cli binary]) -AC_CHECK_PHP_INCLUDE([Zend/Application.php],[Zend Framework]) -AC_CHECK_PHP_VERSION([5],[3],[0]) -AC_CHECK_BIN([PHP], [php]) - -# Checks for libraries. -AC_CHECK_PHP_MODULE([sockets json]) - -# -# Configuration files -# -AC_ARG_WITH([icingaweb_config_path], - AS_HELP_STRING([--with-icingaweb-config-path=PATH], [Configuration path for icinga web (default $prefix/config)]), - icingaweb_config_path=$withval, - icingaweb_config_path=$prefix/config -) - -# -# Log files -# -AC_ARG_WITH([icingaweb_log_path], - AS_HELP_STRING([--with-icingaweb-log-path=PATH], [Log path for icinga web (default $prefix/var/log)]), - icingaweb_log_path=$withval, - icingaweb_log_path=$prefix/var/log -) - -# -# Users for webfiles -# - -AC_ARG_WITH([web_user], - AS_HELP_STRING([--with-web-user=USER], [username for web writable files (default www-data)]), - web_user=$withval, - AC_USER_GUESS([www wwwrun www-data apache httpd nobody],[web_user],[www-data]) -) - -AC_ARG_WITH([web_group], - AS_HELP_STRING([--with-web-group=GROUP], [group for web writable files (default www-data)]), - web_group=$withval, - AC_GROUP_GUESS([www www-data apache httpd nogroup nobody],[web_group], [www-data]) -) - -AC_ARG_WITH([web_path], - AS_HELP_STRING([--with-web-path=PATH], [web sub path (default /icingaweb)]), - web_path=$withval, - web_path=/icingaweb -) - -AC_ARG_WITH([httpd_config_path], - AS_HELP_STRING([--with-httpd-config-path=PATH], [Include folder apache2 (default /etc/apache2/conf.d)]), - httpd_config_path=$withval, - httpd_config_path=AC_PATH_GUESS([/etc/httpd/conf.d /etc/apache2/conf-available /etc/apache2/conf.d /etc/apache/conf.d], [httpd_config_path], [/etc/apache2/conf.d]) -) - -# -# Users and groups for installation -# - -AC_ARG_WITH([bin_user], - AS_HELP_STRING([--with-bin-user=USER], [user for all other files (default root)]), - bin_user=$withval, - bin_user=root -) - -AC_ARG_WITH([bin_group], - AS_HELP_STRING([--with-bin-group=GROUP], [group for all other files (default bin)]), - bin_group=$withval, - bin_group=bin -) - -# -# Internal database setup -# - -AC_ARG_WITH([internal_db_type], - AS_HELP_STRING([--with-internal-db-type=TYPE], [database type to use for internal database (default mysql, supported: pgsql, mysql)]), - internal_db_type=$withval, - internal_db_type=mysql -) - -ICINGA_CHECK_DBTYPE($internal_db_type, [--with-internal-db-type]) - -AC_ARG_WITH([internal_db_name], - AS_HELP_STRING([--with-internal-db-name=NAME], [database name to use for internal database (default icingaweb)]), - internal_db_name=$withval, - internal_db_name=icingaweb -) - -AC_ARG_WITH([internal_db_host], - AS_HELP_STRING([--with-internal-db-host=HOST], [database host to use for internal database (default localhost)]), - internal_db_host=$withval, - internal_db_host=localhost -) - -AC_ARG_WITH([internal_db_port], - AS_HELP_STRING([--with-internal-db-port=PORT], [database port to use for internal database (default: 3306 for mysql, 5432 for pgsql)]), - internal_db_port=$withval, - internal_db_port=db_default_port -) - -AC_ARG_WITH([internal_db_password], - AS_HELP_STRING([--with-internal-db-password=PASS], [database pass to use for internal database (default icingaweb)]), - internal_db_password=$withval, - internal_db_password=icingaweb -) - -AC_ARG_WITH([internal_db_user], - AS_HELP_STRING([--with-internal-db-user=USER], [database user to use for internal database (default icingaweb)]), - internal_db_user=$withval, - internal_db_user=icingaweb -) - -# -# Authorization method -# - -AC_ARG_WITH([internal_authentication], - AC_HELP_STRING([--with-internal-authentication], [use the internal database for authentication (default: yes)]), - internal_authentication=$withval, - internal_authentication=yes -) - -AC_ARG_WITH([ldap_authentication], - AC_HELP_STRING([--with-ldap-authentication], [use a ldap server for authentication (default: no)]), - ldap_authentication=$withval, - ldap_authentication=no -) - -# -# LDAP Authorization -# - -AC_ARG_WITH([ldap_host], - AS_HELP_STRING([--with-ldap-host=HOST], [host to use for authentication via ldap (default localhost)]), - ldap_host=$withval, - ldap_host=localhost -) - -AC_ARG_WITH([ldap_port], - AS_HELP_STRING([--with-ldap-port=PORT], [port to use for authentication via ldap (default 389)]), - ldap_port=$withval, - ldap_port=389 -) - -AC_ARG_WITH([ldap_binddn], - AS_HELP_STRING([--with-ldap-binddn=DN], [dn to use for retrieving user information via ldap (default cn=admin, cn=config)]), - ldap_binddn=$withval, - ldap_binddn=["cn=admin,cn=config"] -) - -AC_ARG_WITH([ldap_bindpass], - AS_HELP_STRING([--with-ldap-bindpass=PASS], [password to use for retrieving user information via ldap (default admin)]), - ldap_bindpass=$withval, - ldap_bindpass=["admin"] -) - -AC_ARG_WITH([ldap_rootdn], - AS_HELP_STRING([--with-ldap-rootdn=LDAP_ATTRIBUTE], [root dn to use for user lookup (default ou=people, dc=icinga, dc=org)]), - ldap_rootdn=$withval, - ldap_rootdn=["ou=people, dc=icinga, dc=org"] -) - -AC_ARG_WITH([ldap_user_objectclass], - AS_HELP_STRING([--with-ldap-user-objectclass=LDAP_OBJECT_CLASS], [ldap object class to use for user authentication (default: inetOrgPerson)]), - ldap_user_objectclass=$withval, - ldap_user_objectclass="inetOrgPerson" -) - -AC_ARG_WITH([ldap_attribute_username], - AS_HELP_STRING([--with-ldap-attribute-username=LDAP_ATTRIBUTE], [user attribute to use for the username (default: uid)]), - ldap_attribute_username=$withval, - ldap_attribute_username="uid" -) - -# -# Icinga backend selection -# - -AC_ARG_WITH([icinga_backend], - AS_HELP_STRING([--with-icinga-backend=(ido, statusdat, livestatus)], [backend to use for rb (default: statusdat)]), - icinga_backend=$withval, - icinga_backend="statusdat" -) - -ICINGA_CHECK_BACKENDTYPE($icinga_backend, [--with-icinga-backend]) - -# -# Ido settings -# - -AC_ARG_WITH([ido_db_type], - AS_HELP_STRING([--with-ido-db-type=(mysql, pgsql)], [database engine to use for retrieving data from the ido db (default: mysql)]), - ido_db_type=$withval, - ido_db_type="mysql" -) - -ICINGA_CHECK_DBTYPE($ido_db_type, [--with-ido-db-type]) - -AC_ARG_WITH([ido_host], - AS_HELP_STRING([--with-ido-host=HOST], [host to use for retrieving data from the ido db (default: localhost)]), - ido_host=$withval, - ido_host="localhost" -) - -AC_ARG_WITH([ido_port], - AS_HELP_STRING([--with-ido-port=PORT], [backend to use for retrieving data from the ido db (default: 3306 for mysql. 5432 for pgsql)]), - ido_port=$withval, - ido_port=db_default_port -) - -AC_ARG_WITH([ido_db_name], - AS_HELP_STRING([--with-ido-db-name=DATABASE], [database name to use for retrieving data from the ido db (default: icinga)]), - ido_db_name=$withval, - ido_db_name="icinga" -) - -AC_ARG_WITH([ido_user], - AS_HELP_STRING([--with-ido-user=USER], [user to use for retrieving data from the ido db (default: icinga)]), - ido_user=$withval, - ido_user="icinga" -) - -AC_ARG_WITH([ido_password], - AS_HELP_STRING([--with-ido-password=PASSWORD], [password to use for retrieving data from the ido db (default: icinga)]), - ido_password=$withval, - ido_password="icinga" -) - -# -# Statusdat file location -# - -AC_ARG_WITH([statusdat_file], - AS_HELP_STRING([--with-statusdat-file=FILE], [location of the status.dat file when retrieving data from status.dat (default: /usr/local/icinga/var/status.dat)]), - statusdat_file=$withval, - statusdat_file="/usr/local/icinga/var/status.dat" -) - -AC_ARG_WITH([objects_cache_file], - AS_HELP_STRING([--with-objects-cache-file=FILE], [location of the objects.cache file when retrieving data from status.dat (default: /usr/local/icinga/var/objects.cache)]), - objects_cache_file=$withval, - objects_cache_file="/usr/local/icinga/var/objects.cache" -) - -# -# Livestatus connection -# - -AC_ARG_WITH([livestatus_socket], - AS_HELP_STRING([--with-livestatus-socket=FILE], [location of the livestatus socket (default: /usr/local/icinga/var/rw/live)]), - livestatus_socket=$withval, - livestatus_socket="/usr/local/icinga/var/rw/live" -) - -# -# Icinga commandpipe -# - -AC_ARG_WITH([icinga_commandpipe], - AS_HELP_STRING([--with-icinga-commandpipe=FILE], [location of the command pipe used for sending commands (default: /usr/local/icinga/var/rw/icinga.cmd)]), - icinga_commandpipe=$withval, - icinga_commandpipe="/usr/local/icinga/var/rw/icinga.cmd" -) - -AC_ARG_WITH([objects_cache_file], - AS_HELP_STRING([--with-objects-file=FILE], [location of the objects.cache file when retrieving data from status.dat (default: /usr/local/icinga/var/objects.cache)]), - objects_cache_file=$withval, - objects_cache_file="/usr/local/icinga/var/objects.cache" -) - -# -# Livestatus connection -# - -AC_ARG_WITH([livestatus_socket], - AS_HELP_STRING([--with-livestatus-socket=FILE], [location of the livestatus socket (default: /usr/local/icinga/var/rw/live)]), - livestatus_socket=$withval, - livestatus_socket="/usr/local/icinga/var/rw/live" -) - -# -# Icinga commandpipe -# - -AC_ARG_WITH([icinga_commandpipe], - AS_HELP_STRING([--with-icinga-commandpipe=FILE], [location of the command pipe used for sending commands (default: /usr/local/icinga/var/rw/icinga.cmd)]), - icinga_commandpipe=$withval, - icinga_commandpipe="/usr/local/icinga/var/rw/icinga.cmd" -) - -# Installation options -INSTALL_OPTS="-o $bin_user -g $bin_group" -INSTALL_OPTS_WEB="-o $web_user -g $web_group" - -AS_IF([test "x$internal_db_type" = xmysql], [ - AC_CHECK_PHP_INCLUDE([Zend/Db/Adapter/Pdo/Mysql.php],[Zend Framework - MySQL PDO Adapter]) - AC_CHECK_PHP_MODULE([mysql]) - AS_IF([test "x$internal_db_port" == xdb_default_port], [internal_db_port=3306]) -]) - -AS_IF([test "x$ido_db_type" = xmysql], [ - AC_CHECK_PHP_INCLUDE([Zend/Db/Adapter/Pdo/Mysql.php],[Zend Framework - MySQL PDO Adapter]) - AC_CHECK_PHP_MODULE([mysql]) - AS_IF([test "x$ido_port" = xdb_default_port], [ido_port=3306]) -]) - -AS_IF([test "x$internal_db_type" = xpgsql], [ - AC_CHECK_PHP_INCLUDE([Zend/Db/Adapter/Pdo/Pgsql.php],[Zend Framework - PostgreSQL PDO Adapter]) - AC_CHECK_PHP_MODULE([pgsql]) - AS_IF([test "x$internal_db_port" = xdb_default_port], [internal_db_port=5432]) -]) - -AS_IF([test "x$ido_db_type" = xpgsql], [ - AC_CHECK_PHP_INCLUDE([Zend/Db/Adapter/Pdo/Pgsql.php],[Zend Framework - PostgreSQL PDO Adapter]) - AC_CHECK_PHP_MODULE([pgsql]) - AS_IF([test "x$ido_port" = xdb_default_port], [ido_port=5432]) -]) - -# -# Disable authentication backends -# - -ido_enabled="disabled = \"1\"" -statusdat_enabled="disabled = \"1\"" -livestatus_enabled="disabled = \"1\"" - -AS_CASE([$icinga_backend], - ["ido"], [ido_enabled=""], - ["statusdat"], [statusdat_enabled=""], - ["livestatus"], [livestatus_enabled=""], - [statusdat_enabled=""]) - -ldap_auth_disabled="disabled = \"1\"" -AS_IF([test "x$ldap_authentication" != xno], - AC_CHECK_PHP_MODULE([ldap]) - ldap_auth_disabled="" -) - -internal_auth_disabled="disabled = \"1\"" -AS_IF([test "x$internal_authentication" != xno], - AC_CHECK_PHP_MODULE([ldap]) - internal_auth_disabled="" -) - -# -# Substitution variables -# - -# Installation directives -AC_SUBST(app_name) -AC_SUBST(web_user) -AC_SUBST(web_group) -AC_SUBST(web_path) -AC_SUBST(httpd_config_path) -AC_SUBST(bin_user) -AC_SUBST(bin_group) -AC_SUBST(icingaweb_config_path) -AC_SUBST(icingaweb_log_path) - -# Internal db setup -AC_SUBST(internal_db_type) -AC_SUBST(internal_db_name) -AC_SUBST(internal_db_host) -AC_SUBST(internal_db_port) -AC_SUBST(internal_db_user) -AC_SUBST(internal_db_password) - -# ldap setup -AC_SUBST(ldap_host) -AC_SUBST(ldap_port) -AC_SUBST(ldap_rootdn) -AC_SUBST(ldap_binddn) -AC_SUBST(ldap_bindpass) -AC_SUBST(ldap_user_objectclass) -AC_SUBST(ldap_attribute_basedn) -AC_SUBST(ldap_attribute_username) - -# backend setup -AC_SUBST(icinga_backend) - -# ido backend variables -AC_SUBST(ido_enabled) -AC_SUBST(ido_db_type) -AC_SUBST(ido_host) -AC_SUBST(ido_port) -AC_SUBST(ido_db_name) -AC_SUBST(ido_user) -AC_SUBST(ido_password) - -# status.dat backend -AC_SUBST(statusdat_enabled) -AC_SUBST(statusdat_file) -AC_SUBST(objects_cache_file) - -# livestatus backend -AC_SUBST(livestatus_socket) -AC_SUBST(livestatus_enabled) - -# command pipe -AC_SUBST(icinga_commandpipe) - -# Comment placeholders for toggling backends - -AC_SUBST(ldap_auth_disabled) -AC_SUBST(internal_auth_disabled) - -# Application and installation -AC_SUBST(PHP) -AC_SUBST(INSTALL_OPTS) -AC_SUBST(INSTALL_OPTS_WEB) - -# -# Create config files -# -AC_CONFIG_FILES([ - Makefile - config/authentication.ini - config/config.ini - config/resources.ini - config/modules/monitoring/backends.ini - config/modules/monitoring/instances.ini - etc/apache/icingaweb.conf -]) - -# -# Commit and write -# -AC_OUTPUT diff --git a/doc/CONFIG.md b/doc/CONFIG.md deleted file mode 100644 index e19f90bd5..000000000 --- a/doc/CONFIG.md +++ /dev/null @@ -1,35 +0,0 @@ -# Application and Module Configuration - -## Basic usage - -The \Icinga\Application\Config class is a general purpose service to help you find, load and save -configuration data. It is used both by the Icinga Web 2 modules and the framework itself. With -INI files as source it enables you to store configuration in a familiar format. Icinga Web 2 -defines some configuration files for its own purposes. Please note that both modules and framework -keep their main configuration in the INI file called config.ini. Here's some example code: - -```php -global->get('defaultTimezone', 'Europe/Berlin'); - -// If you don't pass a configuration name to IcingaConfig::app it tries to load values from the -// application's config.ini. For using other files you have to pass this parameter though. -// The following example loads a section from the application's authentication.ini: -IcingaConfig::app('authentication')->get('ldap-authentication'); - -// If you don't pass a configuration name to IcingaConfig::module it tries to load values from -// the module's config.ini. For using other files you have to pass this parameter though. -// The following example loads values from the example module's extra.ini: -IcingaConfig::module('example', 'extra')->logging->get('enabled', true); -``` - -## Reload from disk - -If you want to force reading a configuration from disk (i.e. after you modified it), you can use the $fromDisk flag in -the IcingaConfig::app/IcingaConfig::module call: - - IcingaConfig::app('authentication', true)-> ... // read authentication from disk - IcingaConfig::module('example', 'extra', true)->... // read module configuration from disk diff --git a/doc/Icinga-Design/bootstrap.min.css b/doc/Icinga-Design/bootstrap.min.css deleted file mode 100644 index a553c4f5e..000000000 --- a/doc/Icinga-Design/bootstrap.min.css +++ /dev/null @@ -1,9 +0,0 @@ -/*! - * Bootstrap v3.0.0 - * - * Copyright 2013 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world by @mdo and @fat. - *//*! normalize.css v2.1.0 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}button,input,select[multiple],textarea{background-image:none}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16.099999999999998px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-warning{color:#c09853}.text-danger{color:#b94a48}.text-success{color:#468847}.text-info{color:#3a87ad}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h4,h5,h6{margin-top:10px;margin-bottom:10px}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}h1 small,.h1 small{font-size:24px}h2 small,.h2 small{font-size:18px}h3 small,.h3 small,h4 small,.h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:1.428571429}code,pre{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-1{width:8.333333333333332%}.col-xs-2{width:16.666666666666664%}.col-xs-3{width:25%}.col-xs-4{width:33.33333333333333%}.col-xs-5{width:41.66666666666667%}.col-xs-6{width:50%}.col-xs-7{width:58.333333333333336%}.col-xs-8{width:66.66666666666666%}.col-xs-9{width:75%}.col-xs-10{width:83.33333333333334%}.col-xs-11{width:91.66666666666666%}.col-xs-12{width:100%}@media(min-width:768px){.container{max-width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-1{width:8.333333333333332%}.col-sm-2{width:16.666666666666664%}.col-sm-3{width:25%}.col-sm-4{width:33.33333333333333%}.col-sm-5{width:41.66666666666667%}.col-sm-6{width:50%}.col-sm-7{width:58.333333333333336%}.col-sm-8{width:66.66666666666666%}.col-sm-9{width:75%}.col-sm-10{width:83.33333333333334%}.col-sm-11{width:91.66666666666666%}.col-sm-12{width:100%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-3{left:25%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-6{left:50%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-9{left:75%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-11{left:91.66666666666666%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-3{right:25%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-6{right:50%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-9{right:75%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-11{margin-left:91.66666666666666%}}@media(min-width:992px){.container{max-width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-1{width:8.333333333333332%}.col-md-2{width:16.666666666666664%}.col-md-3{width:25%}.col-md-4{width:33.33333333333333%}.col-md-5{width:41.66666666666667%}.col-md-6{width:50%}.col-md-7{width:58.333333333333336%}.col-md-8{width:66.66666666666666%}.col-md-9{width:75%}.col-md-10{width:83.33333333333334%}.col-md-11{width:91.66666666666666%}.col-md-12{width:100%}.col-md-push-0{left:auto}.col-md-push-1{left:8.333333333333332%}.col-md-push-2{left:16.666666666666664%}.col-md-push-3{left:25%}.col-md-push-4{left:33.33333333333333%}.col-md-push-5{left:41.66666666666667%}.col-md-push-6{left:50%}.col-md-push-7{left:58.333333333333336%}.col-md-push-8{left:66.66666666666666%}.col-md-push-9{left:75%}.col-md-push-10{left:83.33333333333334%}.col-md-push-11{left:91.66666666666666%}.col-md-pull-0{right:auto}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-3{right:25%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-6{right:50%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-9{right:75%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-11{right:91.66666666666666%}.col-md-offset-0{margin-left:0}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-3{margin-left:25%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-6{margin-left:50%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-9{margin-left:75%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-11{margin-left:91.66666666666666%}}@media(min-width:1200px){.container{max-width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-1{width:8.333333333333332%}.col-lg-2{width:16.666666666666664%}.col-lg-3{width:25%}.col-lg-4{width:33.33333333333333%}.col-lg-5{width:41.66666666666667%}.col-lg-6{width:50%}.col-lg-7{width:58.333333333333336%}.col-lg-8{width:66.66666666666666%}.col-lg-9{width:75%}.col-lg-10{width:83.33333333333334%}.col-lg-11{width:91.66666666666666%}.col-lg-12{width:100%}.col-lg-push-0{left:auto}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-3{left:25%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-6{left:50%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-9{left:75%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-11{left:91.66666666666666%}.col-lg-pull-0{right:auto}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-3{right:25%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-6{right:50%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-9{right:75%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-offset-0{margin-left:0}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-11{margin-left:91.66666666666666%}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table thead>tr>th,.table tbody>tr>th,.table tfoot>tr>th,.table thead>tr>td,.table tbody>tr>td,.table tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table caption+thead tr:first-child th,.table colgroup+thead tr:first-child th,.table thead:first-child tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed thead>tr>th,.table-condensed tbody>tr>th,.table-condensed tfoot>tr>th,.table-condensed thead>tr>td,.table-condensed tbody>tr>td,.table-condensed tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8;border-color:#d6e9c6}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td{background-color:#d0e9c6;border-color:#c9e2b3}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede;border-color:#eed3d7}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td{background-color:#ebcccc;border-color:#e6c1c7}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3;border-color:#fbeed5}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td{background-color:#faf2cc;border-color:#f8e5be}@media(max-width:768px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0;background-color:#fff}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>thead>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>thead>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{padding-top:7px;margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-print:before{content:"\e045"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-briefcase:before{content:"\1f4bc"}.glyphicon-calendar:before{content:"\1f4c5"}.glyphicon-pushpin:before{content:"\1f4cc"}.glyphicon-paperclip:before{content:"\1f4ce"}.glyphicon-camera:before{content:"\1f4f7"}.glyphicon-lock:before{content:"\1f512"}.glyphicon-bell:before{content:"\1f514"}.glyphicon-bookmark:before{content:"\1f516"}.glyphicon-fire:before{content:"\1f525"}.glyphicon-wrench:before{content:"\1f527"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent;content:""}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#fff;text-decoration:none;background-color:#428bca}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}}.nav-tabs.nav-justified>li>a{margin-right:0;border-bottom:1px solid #ddd}.nav-tabs.nav-justified>.active>a{border-bottom-color:#fff}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:5px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-bottom:1px solid #ddd}.nav-tabs-justified>.active>a{border-bottom-color:#fff}.tabbable:before,.tabbable:after{display:table;content:" "}.tabbable:after{clear:both}.tabbable:before,.tabbable:after{display:table;content:" "}.tabbable:after{clear:both}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;z-index:1000;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;border-width:0 0 1px}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;z-index:1030}.navbar-fixed-bottom{bottom:0;margin-bottom:0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e6e6e6}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%}a.thumbnail:hover,a.thumbnail:focus{border-color:#428bca}.thumbnail>img{margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.alert-warning hr{border-top-color:#f8e5be}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger hr{border-top-color:#e6c1c7}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table{margin-bottom:0}.panel>.panel-body+.table{border-top:1px solid #ddd}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#fbeed5}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#fbeed5}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#fbeed5}.panel-danger{border-color:#eed3d7}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#eed3d7}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#eed3d7}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}body.modal-open,.modal-open .navbar-fixed-top,.modal-open .navbar-fixed-bottom{margin-right:15px}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{right:auto;left:50%;width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;left:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.affix{position:fixed}@-ms-viewport{width:device-width}@media screen and (max-width:400px){@-ms-viewport{width:320px}}.hidden{display:none!important;visibility:hidden!important}.visible-xs{display:none!important}tr.visible-xs{display:none!important}th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm{display:none!important}tr.visible-sm{display:none!important}th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md{display:none!important}tr.visible-md{display:none!important}th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg{display:none!important}tr.visible-lg{display:none!important}th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs{display:none!important}tr.hidden-xs{display:none!important}th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm{display:none!important}tr.hidden-xs.hidden-sm{display:none!important}th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md{display:none!important}tr.hidden-xs.hidden-md{display:none!important}th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg{display:none!important}tr.hidden-xs.hidden-lg{display:none!important}th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs{display:none!important}tr.hidden-sm.hidden-xs{display:none!important}th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}tr.hidden-sm{display:none!important}th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md{display:none!important}tr.hidden-sm.hidden-md{display:none!important}th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg{display:none!important}tr.hidden-sm.hidden-lg{display:none!important}th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs{display:none!important}tr.hidden-md.hidden-xs{display:none!important}th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm{display:none!important}tr.hidden-md.hidden-sm{display:none!important}th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}tr.hidden-md{display:none!important}th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg{display:none!important}tr.hidden-md.hidden-lg{display:none!important}th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs{display:none!important}tr.hidden-lg.hidden-xs{display:none!important}th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm{display:none!important}tr.hidden-lg.hidden-sm{display:none!important}th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md{display:none!important}tr.hidden-lg.hidden-md{display:none!important}th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg{display:none!important}tr.hidden-lg{display:none!important}th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print{display:none!important}tr.visible-print{display:none!important}th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print{display:none!important}tr.hidden-print{display:none!important}th.hidden-print,td.hidden-print{display:none!important}} \ No newline at end of file diff --git a/doc/Icinga-Design/documentation.css b/doc/Icinga-Design/documentation.css deleted file mode 100644 index 30bd9c27f..000000000 --- a/doc/Icinga-Design/documentation.css +++ /dev/null @@ -1,125 +0,0 @@ -/* ========================================================================== - Styles ONLY used for documentation - ========================================================================== */ - -html { - font-family: sans-serif; -} - - -/* Projektname - color customer CI */ - -.docu-project-name { - font-size: 2em; - color: #049BAF; - padding-bottom: 10px; -} - - -.docu-main { - width: 100%; - padding: 20px; - margin: 0 auto; - margin-top: 50px; - display: block; -} - - -.docu-main-headline { - font-size: 2em; - color: #333; - /* customer CI */ - padding-bottom: 10px; - padding-top: 40px; -} - - -.docu-sub-headline { - font-size: 1.5em; - color: #333; - padding-bottom: 3px; - padding-top: 10px; -} - - -.docu-section { - border: 1px solid #dddddd; - overflow: hidden; - display: block; -} - - -.docu-description { - padding-bottom: 10px; -} - - -.docu-example { - background-color: #FFFFFF; - padding: 10px; -} - - -.docu-example:before { - color: #BBBBBB; - content: "Example"; - font-weight: bold; - letter-spacing: 1px; - margin-bottom: 10px; -} - - -.docu-module { - /* width: 320px; */ - /* show your modules in device width */ - padding-top: 10px; -} - - -.docu-codeblock { - background-color: #F7F7F9; - border-top: 1px solid #e1e1e8; - padding: 10px; - overflow: hidden; - height: 100%; -} - - -.docu-codeblock:before { - color: #BBBBBB; - content: "Code"; - font-weight: bold; - letter-spacing: 1px; - margin-bottom: 10px; -} - - -.docu-code { - font-family: "Courier New", Courier, monospace; - font-weight: bold; - color: #777; - padding-top: 10px; - border: none; - background-color: transparent; - display: block; - width: 100%; - height: 150px; -} - - -.docu-footer { - margin-top: 40px; - padding-top: 10px; - border-top: 1px solid #dddddd; - font-size: 0.75em; - color: #ccc; -} - - -.docu-classes { - background-color: #FEFBED; - padding: 3px; - color: #c6b256; - font-family: "Courier New", Courier, monospace, sans-serif; - font-weight: bold; -} diff --git a/doc/Icinga-Design/documentation.html b/doc/Icinga-Design/documentation.html deleted file mode 100644 index e0ae9b066..000000000 --- a/doc/Icinga-Design/documentation.html +++ /dev/null @@ -1,974 +0,0 @@ - - - - - Icinga Documentation - - - - - - - - - - - - - - - - - - - - - - -
- -

Icinga Documentation

- - - -

Basic Elements

- -

Headlines

- - -
-
-
-

Main headline h1

-

Sub headline h2

-
-
- -
- -
-
- - -

Textblocks

-
- Used on simple pages with continuous text e.g. Imprint or Privacy. -
- -
-
-
- -

- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -

- -
-
- -
- -
-
- - - - -

Table

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StatusOutput
- - - - - - - - 12 - - -
- - Up
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok
- - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. - -
- - -
-
-
-
- - - 6 - - -
- Unreachable
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. - -
- - - - - - - 6 - - -
- Down
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok -
- - - - - - - 6 - - -
- Up
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok -
- - - - - - - 6 - - -
- Up
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. - -
- - -
-
-
-
- - - 6 - - -
- Down
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. - -
- - - -
-
- -
- -
-
- - - - -

Pagination

- -
- The pagination is placed on top and bottom of every list. -
- -
-
-
- - - -
-
- -
- -
-
- - - - -

Details

- -

Basic Example

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
- - -
-
- Host Status host_000 ölaierjoe paeurüuaeraeüure - Unreachable since 15:59
-
-
- -
- -
-

host_000 (checked by localhost.localdomain) OK: random hostcheck ok sometimes with multiline and html tags\n

-
- -
- Recheck -
- - -
-
- Last Check -
-
- 1381308168 -
-
- -
-
- Next Check -
-
- 1381309978 -
-
- -
-
- - -
-
- Host Address -
-
- 127.0.0.1 -
-
- -
-
- Alias -
-
- random_000 -
-
- - - -
- - - - - -
-
- Box mit Tabelle
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LoremIpsum xyzblablubb
08.10. 15:51Lorem ipusm_002
08.10. 15:51Ich bin ein toller Text
Hallo halloServer 123 blablaNoch ein Text
Lorem ipsumJuhuhallo_host01128747404
-
- - - - - -
-
- Heading
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Passive Checks
Active Checks
Obsessing
Notifications
Event Handler
Flap Detection
-
- - - -
-
- -
- -
-
- - - - -

Form Elements

- -

Select

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
- - - -
- - -
-
-
-
-
- - - -
-
- -
- -
-
- - -

Main Navigation

- -

Without Subnavigation

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
- - - - -
-
- - -
- - - - -

With Subnavigation

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
- - - - -
-
- - -
- - - - - - - - - - - -

Dashboard

- - -
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Dies ist eine tolle Headline -
09.10. 17:40 - - - - - Service on Hosta
unknown - - Ping on Host_123456
11.10. - - - - random_06 on Host_insertEFFECT
unknown - - Ping on Host_123456
unknown - - Ping on Host_123456
-
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Dies ist eine tolle Headline -
09.10. - - - - Ping on Host_0815
unknown - - Ping on Host_123456
11.10. - - - - random_06 on Host_insertEFFECT
unknown - - Ping on Host_123456
unknown - - Ping on Host_123456
11.10. - - - - random_06 on Host_insertEFFECT
11.10. - - - - random_06 on Host_insertEFFECT
-
- -
-
- - -
- - - - - - - - - -

Main Header

- -

Sub Header

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
-

bla

-

blubb

-
-
- -
- -
-
- - - - - - - - -
- - - - diff --git a/doc/Icinga-Design/icinga-design.css b/doc/Icinga-Design/icinga-design.css deleted file mode 100644 index d8f2bd724..000000000 --- a/doc/Icinga-Design/icinga-design.css +++ /dev/null @@ -1,955 +0,0 @@ -/* ========================================================================== - Icinga Design - ========================================================================== */ - -html { - font-family: sans-serif; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ - overflow-y: scroll; -} - -body { - margin: 0; - color: #262625; - font-family: "Lucida Grande","Lucida Sans Unicode",Verdana,Helvetica,Arial,sans-serif; - font-size: 16px; -} - -p { - line-height: 18px; -} - -.gap { - margin-bottom: 15px; -} - - -/* ========================================================================== - Links - ========================================================================== */ - -a { - color: #049baf; - text-decoration: none; -} - -/** - * Address `outline` inconsistency between Chrome and other browsers. - */ - -a:focus { - outline: thin dotted; -} - -/** - * Improve readability when focused and also mouse hovered in all browsers. - */ - -a:active, -a:hover { - outline: 0; - color: #049baf; - text-decoration: underline; -} - -/* ========================================================================== - Typography - ========================================================================== */ - -/** - * Address variable `h1` font-size and margin within `section` and `article` - * contexts in Firefox 4+, Safari 5, and Chrome. - */ - -h1 { - color: #262625; - font-size: 20px; -} - -h2 { - color: #262625; - font-size: 16px; -} - - -p { - margin-top: 0; -} - - -/* ========================================================================== - Tables - ========================================================================== */ - - -table, th, td { -text-align: left; -vertical-align: top; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -th { - font-weight: bold; - font-size: 18px; - padding: 8px 8px 10px 8px; - border-bottom: 2px solid #ddd; -} - -.table-detail th { - font-size: 16px; - border-top: 0; -} - - -.table-detail thead > tr > th, .table tbody > tr > th, -.table-detail tbody > tr > td, .table tfoot > tr > td { - border-top: 0 !important; -} - - - - -.table-detail > thead { - border-top: 0 !important; -} - - - -td { - padding: 8px 10px 8px 8px !important; - border-bottom: 1px dotted #ddd !important; - border-top: none; - -} - -.pull-right { - float: right !important; - clear: right !important; - - display: block; - clear: right; - overflow: hidden; -} - -.badge-container { - display: block; - overflow: hidden; -} - - -.badge { - background-color: #fff; - border-radius: 2px; - color: #ff3300; - display: inline-block; - font-size: 12px; - font-weight: bold; - line-height: 1; - min-width: 10px; - padding-bottom: 3px; - padding-left: 10px; - padding-right: 10px; - padding-top: 3px; - text-align: center; - vertical-align: baseline; - white-space: nowrap; - border: 1px solid #ff3300; - -} - -.badge a, -.badge a:active, -.badge a:hover, -.badge:hover { - color: #ff3300 !important; - display: inline-block !important; - -} - -.host-name { - display: block; - margin-top: 5px; - font-weight: bold; -} - - -.active { - background-color: #f5f5f5; - -} - -.output-text { - font-size: 12px; - line-height: 14px; - display: inline-block; -} - - - -.panel-disabled { - border-left: 8px solid #FF3300; -} - -.panel-enabled { - border-left: 8px solid #00CC33; -} - - -/* ========================================================================== - Forms - ========================================================================== */ - - -.form-inline .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; -} -.form-group { - margin-bottom: 15px; -} - -label { - display: inline-block; - font-weight: bold; - margin-bottom: 5px; -} - -.input-sm { - border-radius: 3px; - font-size: 16px; - - - padding: 5px; - margin-right: 15px; - -} -.form-control { - background-color: #FFFFFF; - border: 1px solid #CCCCCC; - border-radius: 4px; - padding: 5px; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset; - color: #555555; - display: block; - - - - - vertical-align: middle; - width: 100%; -} - -select.input-sm { - -} - - - -/* ========================================================================== - Pagination - ========================================================================== */ - -.pagination > .active > a, -.pagination > .active > span, -.pagination > .active > a:hover, -.pagination > .active > span:hover, -.pagination > .active > a:focus, -.pagination > .active > span:focus { - - background-color: #049baf !important; - border-color: fuchsia !important; - -} - - -.pagination-sm > li > a, .pagination-sm > li > span { - font-size: 16px !important; -} - - - -/* ========================================================================== - Status colors - ========================================================================== */ - -.status-up { - background-color: #00cc33; /* green */ -} - -.status-warning { - background-color: #00cc33; /* xx */ -} - -.status-critical { - background-color: #ff3300; /* red */ -} - -.status-unknown { - background-color: #00cc33; /* xx */ -} - -.status-pending { - background-color: #00cc33; /* xx */ -} - - - -/** Service status **/ - -.tacheader-status-critical { - background-color: #FF3300; -} - -.tacheader-status-ok { - background-color: #00CC33; -} - -.tacheader-status-warning { - background-color: #FFA500; -} - -.tacheader-status-unknown { - background-color: #E066FF; -} - -/** Host status **/ - -.tacheader-status-unreachable { - background-color: #E066FF; -} - -.tacheader-status-down { - background-color: #FF3300; -} - -.tacheader-status-up { - background-color: #00CC33; -} - - -/* Borders for Detail Headers */ - -.border-status-critical { - border-left: 10px solid #FF3300; -} - -.border-status-ok { - border-left: 10px solid #00CC33; -} - -.border-status-warning { - border-left: 10px solid #FFA500; -} - -.border-status-unknown { - border-left: 10px solid #E066FF; -} - -/** Host status **/ - -.border-status-unreachable { - border-left: 10px solid #E066FF; -} - -.border-status-down { - border-left: 10px solid #FF3300; -} - -.border-status-up { - background-color: #00CC33; -} - - - - - - - -/* ========================================================================== - Icons - ========================================================================== */ - -.icon-table { - width: 16px; - height: 20px; - display: block; - background-position: 50% 0; -} - -.icon-header { - background-position: 0 50%; - padding-left: 25px; - height: 20px; -} - -.icon-btn-small { - background-position: 0 0; - width: 16px; - height: 16px; - display: block; -} - -.icon-table-hint { - width: 16px; - height: 20px; - display: block; - background-position: 50% 50%; -} -.icon-table-hint:after { - content: "edited"; - padding-left: 22px; -} - - -.icon-flapping { - background-image: url('images/flapping.png'); - background-repeat: no-repeat; -} -.icon-comment { - background-image: url('images/comment.png'); - background-repeat: no-repeat; -} -.icon-unhandled { - background-image: url('images/unhandled.png'); - background-repeat: no-repeat; -} -.icon-host { - background-image: url('images/host.png'); - background-repeat: no-repeat; -} -.icon-acknowledgement { - background-image: url('images/acknowledgement.png'); - background-repeat: no-repeat; -} -.icon-remove { - background-image: url('images/remove.png'); - background-repeat: no-repeat; -} -.icon-submit { - background-image: url('images/submit.png'); - background-repeat: no-repeat; -} -.icon-create { - background-image: url('images/create.png'); - background-repeat: no-repeat; -} -.icon-dashboard { - background-image: url('images/dashboard.png'); - background-repeat: no-repeat; -} -.icon-disable { - background-image: url('images/disable.png'); - background-repeat: no-repeat; -} -.icon-edit { - background-image: url('images/edit.png'); - background-repeat: no-repeat; -} -.icon-error { - background-image: url('images/error.png'); - background-repeat: no-repeat; -} -.icon-downtime { - background-image: url('images/in_downtime.png'); - background-repeat: no-repeat; -} -.icon-save { - background-image: url('images/save.png'); - background-repeat: no-repeat; -} -.icon-service { - background-image: url('images/service.png'); - background-repeat: no-repeat; -} -.icon-user { - background-image: url('images/user.png'); - background-repeat: no-repeat; -} -.icon-reschedule { - background-image: url('images/reschedule.png'); - background-repeat: no-repeat; -} -.icon-refresh { - background-image: url('images/refresh.png'); - background-repeat: no-repeat; -} - - -/* ========================================================================== - Details Panel - ========================================================================== */ - - -.panel-heading { - border-bottom: 0; - margin-bottom: 0px !important; - padding-left: 5px; - padding-bottom: 3px; - padding-top: 5px; - overflow: hidden; - border-radius: 0; -} - -.panel-hostname { - font-weight: bold; -} - -.separator { - border-top: 2px solid #ddd; - border-bottom: 0; - margin: 0; - height: 2px; -} - -.panel-header-status { - font-weight: normal; -} - -.panel-row { - display: block; - margin-bottom: 10px; - overflow: hidden; - border-bottom: 1px dotted #ddd; - padding-bottom: 10px; -} - - -.panel-label { - float: left; - padding-right: 10px; - width: 30%; - clear: left; - -} -.panel-content { - float: left; - padding-right: 10px; - display: inline-block; - max-width: 40%; -} - -.panel-button { - float: right; - display: inline-block; - overflow: hidden; -} - -.panel-body { - margin-bottom: 45px; -} - - - -/* ========================================================================== - Buttons - ========================================================================== */ - -.button { - text-align: center; - padding: 3px; - border-width: 1px; - border-style: solid; - border-radius: 3px; -} - -.btn-common { - border-color: #ddd; - color: #262625; - background: rgb(255,255,255); /* Old browsers */ - background: -moz-linear-gradient(top, rgb(255,255,255) 1%, rgb(245,245,245) 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(1%,rgb(255,255,255)), color-stop(100%,rgb(245,245,245))); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* IE10+ */ - background: linear-gradient(to bottom, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* W3C */ -} - -.panel-row > a:hover, -.btn-common:hover { - border-color: #262625 !important; - color: #262625 !important; - text-decoration: none; -} - - -.btn-cta { - border-color: #049BAF; - color: #049BAF; - background: rgb(255,255,255); /* Old browsers */ - background: -moz-linear-gradient(top, rgb(255,255,255) 1%, rgb(245,245,245) 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(1%,rgb(255,255,255)), color-stop(100%,rgb(245,245,245))); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* IE10+ */ - background: linear-gradient(to bottom, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* W3C */ -} - - - -.btn-small { - width: 25px; - height: 25px; - display: inline-block; -} - -.btn-wide { - width: 100%; - display: block; -} - -.btn-half-left { - float: left; - width: 48%; -} -.btn-half-right { - float: right; - width: 48%; -} - - -/* ========================================================================== - Main Navigation - ========================================================================== */ - - -.nav-stacked > li + li { - margin-left: 0; - margin-top: 0; -} - - -.nav-stacked { - background-color: #f8f8f8; -} - -.icinga-subnavigation { - list-style: none; -} - - - -.nav-stacked > li { - padding-top: 7px; - padding-bottom: 7px; - border-bottom: 1px dotted #049baf; - border-right: 1px dotted #049baf; -} -.nav-stacked > li:first-child { - border-top: 1px dotted #049baf; -} - - -.icinga-subnavigation > li { - padding-top: 8px; - padding-bottom: 8px; - border-bottom: 1px dotted #049baf; - border-right: 1px dotted #049baf; -} - -ul.icinga-subnavigation { - - border-bottom: 1px dotted #049baf; - margin-left: 0; - padding-left: 15px; -} - -.icinga-subnavigation > li:last-child { - padding-top: 8px; - padding-bottom: 8px; - border-bottom: 0; - -} - -.nav-stacked > li > a, -.icinga-subnavigation > li > a { - padding-left: 40px; - padding-right: 3px; - border-left: 6px solid #049baf; - display: inline-block; -} - -.nav-stacked > li > a.nav-notification, -.icinga-subnavigation > li > a.nav-notification { - border-left: 6px solid red !important; -} - -.nav-stacked > li > a:hover, -.icinga-subnavigation > li > a:focus { -/* font-weight: bold;*/ - background-color: transparent !important; - display: inline-block; -} - -.nav-stacked > li:hover, -.nav-stacked > li:focus, -.icinga-subnavigation > li:hover, -.icinga-subnavigation > li:focus { -background-color: #fff; - -} - -.nav-stacked > li.active, -.icinga-subnavigation > li.active { - background-color: #fff; - border-right: 0; -} - - - - -.nav-icon-hosts { - background-image: url('images/host_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} - -.nav-icon-services { - background-image: url('images/service_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} -.nav-icon-downtimes { - background-image: url('images/in_downtime_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} -.nav-icon-notifications { - background-image: url('images/notification_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 20px; -} -.nav-icon-comments { - background-image: url('images/comment_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} -.nav-icon-dashboard { - background-image: url('images/dashboard_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} -.nav-icon-configuration { - background-image: url('images/configuration_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} - - -.subnav-icon-configuration { - background-image: url('images/configuration_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} - - - - - -.badge-container-nav { - display: inline-block; - overflow: hidden; - padding-top: 0; - margin-bottom: 5px; - -} -.badge-nav { - background-color: #fff; - border-radius: 2px; - color: #ff3300; - display: inline-block; - font-size: 12px; - font-weight: bold; - line-height: 1; - min-width: 10px; - padding-bottom: 3px; - padding-left: 7px; - padding-right: 7px; - padding-top: 3px; - text-align: center; - vertical-align: baseline; - white-space: nowrap; - border: 1px solid #ff3300; -} - -.badge-container-subnav { - position: absolute; - overflow: hidden; - padding-top: 0; - margin-left: 2px; - margin-top: -8px; -} -.badge-subnav { - background-color: #fff; - border-radius: 2px; - color: #ff3300; - display: inline-block; - font-size: 10px; - font-weight: bold; - line-height: 1; - min-width: 10px; - padding-bottom: 2px; - padding-left: 5px; - padding-right: 5px; - padding-top: 2px; - text-align: center; - vertical-align: baseline; - white-space: nowrap; - border: 1px solid #ff3300; -} - - - -/* ========================================================================== - Dashboard - ========================================================================== */ - -.dashboard-container { - - margin-right: 40px; - margin-bottom: 20px; - - display: inline-block; - vertical-align: top; - -} - -.dashboard-icons { - display: inline-block; - height: 16px; - width: 16px; -} - - - - -/* ========================================================================== - Top Navbar - ========================================================================== */ - - -.icinga-logo { - background-attachment: scroll; - background-clip: border-box; - background-color: rgba(0, 0, 0, 0); - background-image: url("images/logo_icinga.png"); - background-origin: padding-box; - background-position: center center; - background-repeat: no-repeat; - background-size: auto auto; - display: block; - height: 33px; - margin-bottom: 0; - margin-left: 8px; - margin-right: 30px; - margin-top: 8px; - text-indent: -999px; - width: 94px; -} - -.icinga-icon-user { - background-attachment: scroll; - background-clip: border-box; - background-color: rgba(0, 0, 0, 0); - background-image: url("images/user.png"); - background-origin: padding-box; - background-position: center center; - background-repeat: no-repeat; - background-size: auto auto; - display: inline-block; - height: 16px; - width: 16px; -} - -.icinga-navbar { - margin-right: 15px; -} -.icinga-navbar-reload { - margin-top: 13px; - margin-right: 40px; -} - -.icinga-navbar-search { - background-image: url('images/search.png'); - background-repeat: no-repeat; - background-position: 5px 50%; - padding-left: 25px !important; -} - -.icinga-navbar-search-container { - border-left: 1px solid #ddd; - padding-left: 15px; - margin-top: 12px; -} - - - -.icinga-navbar-hosts-container { - background-image: url('images/host.png'); - background-repeat: no-repeat; - background-position: 5px 50%; - padding-left: 30px !important; - margin-top: 15px; -} -.icinga-navbar-services-container { - background-image: url('images/service.png'); - background-repeat: no-repeat; - background-position: 5px 50%; - padding-left: 25px !important; - margin-top: 15px; -} - -.icinga-navbar-pills { - border-style: solid; - border-width: 1px; - padding: 3px 5px 3px 5px; - border-radius: 3px; - font-size: 13px; -} - - - -/** Service status **/ - -.icinga-navbar-pills-critical { - border-color: #FF3300; - color: #FF3300; -} - -.icinga-navbar-pills-ok { - border-color: #00CC33; - color: #00CC33; -} - -.icinga-navbar-pills-warning { - border-color: #FFA500; - color: #FFA500; -} - -.icinga-navbar-pills-unknown { - border-color: #E066FF; - color: #E066FF; -} - -/** Host status **/ - -.icinga-navbar-pills-unreachable { - border-color: #E066FF; - color: #E066FF; -} - -.icinga-navbar-pills-down { - border-color: #FF3300; - color: #FF3300; -} - -.icinga-navbar-pills-up { - border-color: #00CC33; - color: #00CC33; -} - diff --git a/doc/Icinga-Design/images/acknowledgement.png b/doc/Icinga-Design/images/acknowledgement.png deleted file mode 100644 index eb03d2db9..000000000 Binary files a/doc/Icinga-Design/images/acknowledgement.png and /dev/null differ diff --git a/doc/Icinga-Design/images/comment.png b/doc/Icinga-Design/images/comment.png deleted file mode 100644 index b7d88a0ac..000000000 Binary files a/doc/Icinga-Design/images/comment.png and /dev/null differ diff --git a/doc/Icinga-Design/images/comment_petrol.png b/doc/Icinga-Design/images/comment_petrol.png deleted file mode 100644 index 53c1223e9..000000000 Binary files a/doc/Icinga-Design/images/comment_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/configuration_petrol.png b/doc/Icinga-Design/images/configuration_petrol.png deleted file mode 100644 index 8168133ec..000000000 Binary files a/doc/Icinga-Design/images/configuration_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/create.png b/doc/Icinga-Design/images/create.png deleted file mode 100644 index b9bedf82a..000000000 Binary files a/doc/Icinga-Design/images/create.png and /dev/null differ diff --git a/doc/Icinga-Design/images/dashboard.png b/doc/Icinga-Design/images/dashboard.png deleted file mode 100644 index e5f9c09f3..000000000 Binary files a/doc/Icinga-Design/images/dashboard.png and /dev/null differ diff --git a/doc/Icinga-Design/images/dashboard_petrol.png b/doc/Icinga-Design/images/dashboard_petrol.png deleted file mode 100644 index 04936ba85..000000000 Binary files a/doc/Icinga-Design/images/dashboard_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/disabled.png b/doc/Icinga-Design/images/disabled.png deleted file mode 100644 index 54d036410..000000000 Binary files a/doc/Icinga-Design/images/disabled.png and /dev/null differ diff --git a/doc/Icinga-Design/images/edit.png b/doc/Icinga-Design/images/edit.png deleted file mode 100644 index 00d8e291f..000000000 Binary files a/doc/Icinga-Design/images/edit.png and /dev/null differ diff --git a/doc/Icinga-Design/images/error.png b/doc/Icinga-Design/images/error.png deleted file mode 100644 index 62458999f..000000000 Binary files a/doc/Icinga-Design/images/error.png and /dev/null differ diff --git a/doc/Icinga-Design/images/flapping.png b/doc/Icinga-Design/images/flapping.png deleted file mode 100644 index 4b253e09c..000000000 Binary files a/doc/Icinga-Design/images/flapping.png and /dev/null differ diff --git a/doc/Icinga-Design/images/host.png b/doc/Icinga-Design/images/host.png deleted file mode 100644 index 12eb9a6b9..000000000 Binary files a/doc/Icinga-Design/images/host.png and /dev/null differ diff --git a/doc/Icinga-Design/images/host_petrol.png b/doc/Icinga-Design/images/host_petrol.png deleted file mode 100644 index 6568fe6f7..000000000 Binary files a/doc/Icinga-Design/images/host_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/in_downtime.png b/doc/Icinga-Design/images/in_downtime.png deleted file mode 100644 index d609df62e..000000000 Binary files a/doc/Icinga-Design/images/in_downtime.png and /dev/null differ diff --git a/doc/Icinga-Design/images/in_downtime_petrol.png b/doc/Icinga-Design/images/in_downtime_petrol.png deleted file mode 100644 index f6ee49a6b..000000000 Binary files a/doc/Icinga-Design/images/in_downtime_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/logo_icinga.png b/doc/Icinga-Design/images/logo_icinga.png deleted file mode 100644 index 162bfdd69..000000000 Binary files a/doc/Icinga-Design/images/logo_icinga.png and /dev/null differ diff --git a/doc/Icinga-Design/images/notification_petrol.png b/doc/Icinga-Design/images/notification_petrol.png deleted file mode 100644 index cf4e9505a..000000000 Binary files a/doc/Icinga-Design/images/notification_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/refresh.png b/doc/Icinga-Design/images/refresh.png deleted file mode 100644 index b0222a525..000000000 Binary files a/doc/Icinga-Design/images/refresh.png and /dev/null differ diff --git a/doc/Icinga-Design/images/remove.png b/doc/Icinga-Design/images/remove.png deleted file mode 100644 index 98ada7447..000000000 Binary files a/doc/Icinga-Design/images/remove.png and /dev/null differ diff --git a/doc/Icinga-Design/images/reschedule.png b/doc/Icinga-Design/images/reschedule.png deleted file mode 100644 index 5efc20dbc..000000000 Binary files a/doc/Icinga-Design/images/reschedule.png and /dev/null differ diff --git a/doc/Icinga-Design/images/save.png b/doc/Icinga-Design/images/save.png deleted file mode 100644 index 2db271920..000000000 Binary files a/doc/Icinga-Design/images/save.png and /dev/null differ diff --git a/doc/Icinga-Design/images/search.png b/doc/Icinga-Design/images/search.png deleted file mode 100644 index a66c3ca95..000000000 Binary files a/doc/Icinga-Design/images/search.png and /dev/null differ diff --git a/doc/Icinga-Design/images/service.png b/doc/Icinga-Design/images/service.png deleted file mode 100644 index 9df3b4840..000000000 Binary files a/doc/Icinga-Design/images/service.png and /dev/null differ diff --git a/doc/Icinga-Design/images/service_petrol.png b/doc/Icinga-Design/images/service_petrol.png deleted file mode 100644 index ea165a293..000000000 Binary files a/doc/Icinga-Design/images/service_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/submit.png b/doc/Icinga-Design/images/submit.png deleted file mode 100644 index 40e482600..000000000 Binary files a/doc/Icinga-Design/images/submit.png and /dev/null differ diff --git a/doc/Icinga-Design/images/unhandled.png b/doc/Icinga-Design/images/unhandled.png deleted file mode 100644 index 59dab8445..000000000 Binary files a/doc/Icinga-Design/images/unhandled.png and /dev/null differ diff --git a/doc/Icinga-Design/images/user.png b/doc/Icinga-Design/images/user.png deleted file mode 100644 index 694ddfcd6..000000000 Binary files a/doc/Icinga-Design/images/user.png and /dev/null differ diff --git a/doc/api/.gitkeep b/doc/api/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/apidoc_creation.md b/doc/apidoc_creation.md deleted file mode 100644 index 89eb99feb..000000000 --- a/doc/apidoc_creation.md +++ /dev/null @@ -1,27 +0,0 @@ -# Create API documentation - -## Prerequisites - -You need phpDocumentor 2 installed on your system to create the api -documentation. Please visit [phpdoc's website](http://phpdoc.org/) for more -information. Additionally, the graphviz package is required to be installed. - -## Configuration - -phpDocumentator is configured with xml configuration reside in doc/phpdoc.xml. -In there you'll find the target path where the documentation is created as -html. Default location is doc/api/. Just point to index.html in this directory -with a browser. - -If you generated the documentation already, you can follow [this link](apidoc/idnex.html). - -## Generation - -Change to Icinga Web 2 root directory (source tree) and run: - - bin/createapidoc.sh - -## Options for createapidoc.sh - - --build Optional, silent build mode - --help Displays help message diff --git a/doc/authentication.md b/doc/authentication.md index 4590dc230..994d44e48 100644 --- a/doc/authentication.md +++ b/doc/authentication.md @@ -1,62 +1,95 @@ -# Authentication +# Authentication -The authentication manager can use different backend types like LDAP or Databases as data sources. During -the application bootstrap the different available resources are checked for availability and -the resource with the highest priority will be used for authentication. This behaviour is useful for setting -up fallback accounts, that are available when the regular authentication backend is not available. +**Choosing the Authentication Method** + +With Icinga Web 2 you can authenticate against Active Directory, LDAP, a MySQL or PostgreSQL database or delegate +authentication to the web server. Authentication methods can be chained to set up fallback authentication methods +or if users are spread over multiple places. ## Configuration -The internal authentication is configured in *config/authentication.ini*. +Authentication methods are configured in the INI file **config/authentication.ini**. -Each section listed in this configuration represents a single backend -that can be used to authenticate users or groups. +Each section in the authentication configuration represents a single authentication method. -The order of entries in this configuration is used to determine the fallback -priority in case of an error. If the resource referenced in the first entry (the one at the top if the file) -is not reachable, the next lower entry will be used for authentication. -Please be aware that this behaviour is not valid for the authentication itself. -The authentication will only be done against the one available resource with the highest -priority. When an account is only present in a backend with lower priority, it will not -be able to authenticate when a backend with higher priority is active that does not contain -this account. +The order of entries in the authentication configuration determines the order of the authentication methods. +If the current authentication method errors or the current authentication method does not know the account being +authenticated, the next authentication method will be used. -### Backend +## External Authentication -The value of the configuration key *backend* will determine which UserBackend class to -load. To use the internal backend you need to specifiy the value "Db" -which will cause the class "DbUserBackend" to be loaded. +For delegating authentication to the web server simply add `autologin` to your authentication configuration: -Currently these types of backends are allowed: - * ldap - * db +```` +[autologin] +backend = autologin +```` -#### db +If your web server is not configured for authentication though the `autologin` section has no effect. -The authentication source is a SQL database and points to a resource defined in *resources.ini*, which -contains all the connection information. Every entry should therefore contain a property *resource* -with the name of the assigned resource. For a more detailed description about how to set up resources, -please read the chapter *Resources*. +## Active Directory or LDAP Authentication -The authentication currently supports the databases MySQL and PostgreSQL. +If you want to authenticate against Active Directory or LDAP, you have to define a +[LDAP resource](#resources-configuration-ldap) first which will be referenced as data source for the Active Directory +or LDAP configuration method. -#### ldap +### LDAP -The authentication source is an ldap server. The connection information should be directly present -in the *authentication.ini*, like described in the example configuration. +Directive | Description +------------------------|------------ +**backend** | `ldap` +**resource** | The name of the LDAP resource defined in [resources.ini](resources). +**user_class** | LDAP user class. +**user_name_attribute** | LDAP attribute which contains the username. +**Example:** -### target +``` +[auth_ldap] +backend = ldap +resource = my_ldap +user_class = inetOrgPerson +user_name_attribute = uid +``` -The value of the configuration key *target* defines the type of authentication the described backend provides. -The allowed values are *user* for a backend that provides user authentication or *group* for group authentication. +### Active Directory +Directive | Description +------------------------|------------ +**backend** | `ad` +**resource** | The name of the LDAP resource defined in [resources.ini](resources). -## Technical description +**Example:** -If an ldap-backend is used, the standard ldap bind will be executed and all user credentials will be managed -directly by the ldap server. +``` +[auth_ad] +backend = ad +resource = my_ad +``` -In case of an SQL-backend, the backend will store the salted hash of the password in the column "password" and the salt in the column "salt". -When a password is checked, the hash is calculated with the function hash_hmac("sha256",salt,password) and compared -to the stored value. +## Database Authentication + +If you want to authenticate against a MySQL or PostgreSQL database, you have to define a +[database resource](#resources-configuration-database) first which will be referenced as data source for the database +authentication method. + +Directive | Description +------------------------|------------ +**backend** | `db` +**resource** | The name of the database resource defined in [resources.ini](resources). + +**Example:** + +``` +[auth_ad] +backend = ad +resource = my_db +``` + +**Manually Creating Users** + +```` +openssl passwd -1 "password" + +INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, 'hash from openssl'); +```` diff --git a/doc/command.md b/doc/command.md deleted file mode 100644 index f442432a4..000000000 --- a/doc/command.md +++ /dev/null @@ -1,184 +0,0 @@ -# Commands - -## Abstract - -Commands are one important intersection between the monitoring core and the -frontend. This is the writable interface where you can control the core how -checks will be processed. Usually you can interact by buttons in the frontend. - -This document describes the URL interface and what commands can be used. - -## Configuration - -**To be done.** - -## URL Interface - -The interface offers to options how to deal with commands: - -1. Show html forms to enter information about the commands (GET requests) -2. Send commands when providing post data - -### Endpoint - -Endpoint of commands is specified as follow: - -``` -http://localhost:8080/icinga2-web/monitoring/command/ -``` - -### List of commands - -To see which commands are support you can supply the **list** argument: - -``` -http://localhost:8080/icinga2-web/monitoring/command/list -``` - -### Examples of command urls: - -``` -# Schedule downtime for an object -http://localhost:8080/icinga2-web/monitoring/command/scheduledowntime - -# Provide a new commend for an object -http://localhost:8080/icinga2-web/monitoring/command/addcomment -``` - -# Provide a global command for host or service checks - -http://localhost:8080/icinga2-web/monitoring/command/disableactivechecks?global=host -http://localhost:8080/icinga2-web/monitoring/command/disableactivechecks?global=service - -# Provide a object command globally - -http://localhost:8080/icinga2-web/monitoring/command/disablenotifications?global=1 - -## List of commands - -*Please note that the list is not complete yet, more commands will follow* - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CommandDescription
disableactivechecksDisable active checks for an object
enableactivechecksEnable active checks for an object
reschedulenextcheckReschedule next active check
submitpassivecheckresultSubmit a passive result set for this check
stopobsessingStop obsessing over object
startobsessingStart obsessing over object
stopacceptingpassivechecksStop accepting passive results for this object
startacceptingpassivechecksStart accepting passive results for this object
disablenotificationsDisable sending messages for problems
enablenotificationsEnable sending messages for problems
sendcustomnotificationSend a custom notification for this object
scheduledowntimeSchedule a downtime for this object
scheduledowntimeswithchildrenSchedule a downtime for host and all services
removedowntimeswithchildrenRemove all downtimes from this host and its services
disablenotificationswithchildrenDisable all notification from this host and its services
enablenotificationswithchildrenEnable all notification from this host and its services
reschedulenextcheckwithchildrenReschedule next check of host ans its services
disableactivecheckswithchildrenDisable all checks of this host and its services
enableactivecheckswithchildrenDisable all checks of this host and its services
disableeventhandlerDisable event handler for this object
enableeventhandlerDisable event handler for this object
disableflapdetectionDisable flap detection
enableflapdetectionEnable flap detection
addcommentAdd a new comment to this object
resetattributesReset all changed attributes
acknowledgeproblemAcknowledge problem of this object
removeacknowledgementRemove problem acknowledgement
delaynotificationDelay next object notification
removedowntimeRemove a specific downtime
\ No newline at end of file diff --git a/doc/container_component.md b/doc/container_component.md deleted file mode 100644 index ed505f81b..000000000 --- a/doc/container_component.md +++ /dev/null @@ -1,198 +0,0 @@ -# The Container Component (app/container) - -The container component is the most basic building block for icingaweb. Even when displaying an empty controller, -you always have at least two containers in your viewport which are implicitly created: The main and the detail container. - -Container handle the following tasks: - -* Updating the url part responsible for the container -* Handling Url changes like they occur when the browser history is used by synchronizing their content with the - associated Url part -* Informing subcomponents about changes in the container - - -## The Container Api - -You can find the sourcecode for containers along with jsdoc comments at *./public/js/icinga/components/container.js*. -Here we will discuss the most important calls and their synopsis: - -### Accessing Containers: - -The container component returns a 'Container' object which allows you to access responsible containers for dom nodes via -the following methods: - -* using `new Container($myDomNodes)` which returns a stateless container object wrapping the container responsible for - the first node in $myDomNodes -* using `Container.getMainContainer()` or `Container.getDetailContainer()` which remove the main or detail container - (this one is stateful with a few notes, read on) - -**Note:** `new Container($('#icingamain')) != Container.getMainContainer()`, but -`(new Container($('#icingamain'))).containerDom == Container.getMainContainer().containerDom` - -** Example #1 getting the container responsible for a dom node ** - -**HTML** - -
-
- Some kind of node -
-
-
- Some other kind of node -

- Insert your lorem ipsum here -

-
-
-
- -**JS**: - - require(['jquery', 'app/container'], function($, Container) { - var firstContainer = new Container($('.myNode')); // firstContainer wraps '#icingamain' - var mainContainer = Container.getMainContainer(); // also wraps '#icingamain' - var secondContainer = new Container($('.myNode p')); // #somecontainer is wrapped by secondContainer - - firstContainer.someProperty = 'What a nice property!'; - mainContainer.someState = 'I have some state'; - console.log(firstContainer.someProperty); // return 'What a nice property' - console.log(main.someProperty); // return 'undefined' - console.log(Container.getMainContainer().someState) // return 'I have some state' when page hasn't been refreshed - }); - -## Containers And The Browser Url - -As noted before (and indicated by the `getMainContainer()` and `getDetailContainer()` function), the main and detail -container have a special role. Considering the following Url: - - http://my.monitoringhost.org/icingaweb/monitoring/list/host?page=4&detail=%2Fmonitoring%2Fshow%2Fhost%3Fhost%3Dlocalhost - -This URL displays the 4th page of your host list in the main container (monitoring/list/host?page=4) and the host information -for localhost in the detail container (monitoring/show/host?host=localhost). When you split this Url up in logical pieces -it looks like this: - - http://my.monitoringhost.org/icingaweb/monitoring/list/host?page=4&detail=%2Fmonitoring%2Fshow%2Fhost%3Fhost%3Dlocalhost - \___________ _______________________/\_________ ______________/ \_ ____/\________________ _______________________/ - \/ \/ \/ \/ - 1. Base URL 2.Main container URL and Query 3.Detail param 4. Encoded detail URL and params - -1. **Base URL** : I don't think this needs much explanation. -2. **Main container URL and query** : This is the *normal* part of your Url and denotes the controller route that is - being displayed in your main container -3. **Detail parameter**: This parameter will be ignored by the main container and used for rendering the detail container, - if omitted there's simple no detail view to be displayed -4 **Encoded detail URL**: The value of the "detail" parameter is the Url (without the base Url) that returns the content - of the detail area - - -### Updating A Container's Url - -If you want your container to display content from a different Url, you can use the *replaceDomFromUrl()* on your -Container object: - -**Example #2 Updating A Containers URL** - -**HTML:** - -
-
-
-
-
-
- -**JS:** - - // this loads the page with the new main container - require(['jquery', 'app/container'], function($, Container) { - new Container('#mainSub').replaceDomFormUrl('/another/url'); - } - - // this loads the page with the new detail container - require(['jquery', 'app/container'], function($, Container) { - new Container('#detailSub').replaceDomFormUrl('/another/url'); - } - - // this does NOT work: - require(['jquery', 'app/container'], function($, Container) { - Container.getMainContainer().replaceDomFormUrl('/another/url'); - // will never be reached due to a reload - Container.getMainContainer().replaceDomFormUrl('/another/url2'); - } - - // this loads the page with both main and detail changed (this is rarely needed and should be avoided) - require(['icinga', 'jquery', 'app/container'], function('Icinga', $, Container) { - // it's better to use this: - var mainContainer = Container.getMainContainer(); - var detailContainer = Container.getDetailContainer(); - - mainContainer.updateContainerHref('/another/url'); // first update the main container href - detailContainer.updateContainerHref('/another/url2'); // update the detail href - - var url = mainContainer.getContainerHref(detailContainer.getContainerHref()); // fetch the new url - Icinga.replaceBodyFromUrl(url); // and update manual - } - -This results in the URL changing to './another/url?detail=%2Fanother%2Fdetail%2Furl. -The advantage of using a Container instance with the subelements (i.e. '\#mainSub') over calling getMain/DetailContainer -directly is that you don't need to know in what container your view is displayed - when you move 'mainSub' into the -detail container, the detail container would be updated afterwards. - -**NOTE**: You should read the '...' section in order to understand why you shouldn't do it like in this example - -### How container refresh states are handled - -If you refresh containers content (load url or replace dom), the container displaya a loading -mask as default behaviour. To disable this mask and handle it yourself, you can register own events: - -**Example #3 Load indicator events** - - require(['icinga', 'jquery', 'app/container'], function('Icinga', $, Container) { - var mainContainer = Container.getMainContainer(); - - // Detach the default behaviour from container - mainContainer.removeDefaultLoadIndicator(); - - var showFunction = function() { - console.log('container is loading'); - }; - - var hideFunction = function() { - console.log('container content refreshed'); - }; - - // Install new handlers - mainContainer.registerOnShowLoadIndicator(showFunction); - mainContainer.registerOnHideLoadIndicator(hideFunction); - }; - -**Example #4 Use this for your components** - -Please have a look into [components documentation](components.md) for detailed information about components. - - define(['components/app/container', 'jquery', 'logging', 'URIjs/URI', 'URIjs/URITemplate'], - function(Container, $, logger, URI) { - "use strict"; - - /** - * Master/Detail grid component handling history, link behaviour, selection (@TODO 3788) and updates of - * grids - * - * @param {HTMLElement} The outer element to apply the behaviour on - */ - return function(gridDomNode) { - /** - * Constructor method for this component - */ - this.construct = function(target) { - // Container object for the component - this.container = new Container(target); - - // Detach default handlers - this.container.removeDefaultLoadIndicator(); - }; - - this.construct(gridDomNode); - }; - }; \ No newline at end of file diff --git a/doc/dashboard.md b/doc/dashboard.md deleted file mode 100644 index 1b1e7a983..000000000 --- a/doc/dashboard.md +++ /dev/null @@ -1,17 +0,0 @@ -# The dashboard - -The icingaweb dashboard allows you to display different views on one page. You can create customized overviews over -the objects you're interested in and can add and remove elements. - -## Dashboard, Panes and Components - -![Dashboard structure][dashboards1] - -* The building blocks of dashboards are components - those represent a single URL and display it's content (often in - a more condensed layout) -* Different components can be added to a pane and will be shown there. All panes are shown as tabs on top of the dashboard, - whereas the title is used for the text in the tab -* The dashboard itself is just the view containing the panes - - -[dashboards1]: res/Dashboard.png diff --git a/doc/form.md b/doc/form.md deleted file mode 100644 index ccd09694f..000000000 --- a/doc/form.md +++ /dev/null @@ -1,222 +0,0 @@ -# Forms - -## Abstract - -This document describe how to develop forms in Icinga Web 2. This is important -if you want to write modules or extend Icinga Web 2 with your flavour of code. - -## Architecture - -Forms are basically Zend_Form classes with Zend_Form_Element items as controls. -To ensure common functionallity and control dependent fields Icinga Web 2 -provides sub classes to build forms on that. - -### Key design - -#### Build of forms - -Creating elements is done within protected function *create()* of your subclass. -In here you can add elements to your form, add validations and filters of your -choice. The creation method is invoked lazy just before a form is rendered or -*isValid()* is called. - -In order to let icingaweb create a submit button for you (which is required for using the *isSubmittedAndValid* -method) you have to call the *setSubmitLabel($label)* method, which will add a -Zend_Form_Element_Submit element to your form. - -#### Client side behaviour - -A few methods in our Form implementation don't affect the rendering, but the behaviour of a form. - -* **Automatic submission of fields via *\Icinga\Web\Form::enableAutoSubmit(array $forms)*** - All form element ids passed in the $forms array will cause a submission of the form when changed. This normally - doesn't cause validation errors, as the form is not really seen as submitted by the 'isSubmittedAndValid', but allows - you to update your form when necessary. For example, when you have a select box whose selection affects which form elements - should be shown, you can use `$form->enableAutoSubmit(array('myForm'))`. -* **User confirmation when discarding forms.** When a user wants to leave the current page despite having unsaved changes, - a popup will appear and asks the user if he **really** wants to leave. This is implemented by the *app/form* componenent - and enabled by default. If you don't want this, you can call *setIgnoreChangeDiscarding($bool)* on your form. - - -#### Calling is *isSubmittedAndValid()* - -*isSubmittedAndValid()* is used to check whether the form is ready to be processed or not. -It 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. This only works when -the sumbit button has been added with the *setSubmitLabel($label)* function, otherwise a form is always considered to be -submitted when a POST request is received. - -If the form has been updated, but not submitted (for example, because the a button has been pressed that adds or removes -some fields in the form) the form is repopulated but not validated at this time. is SubmittedAndValid() returns false -in this case, but no errors are added to the created form. - -In order to be able to use isSubmittedAndValid, you have to define a submitbutton in the form. -This is done with the *setSubmitLabel(string)* function, with the first parameter being the -label set to the submit button. - -#### Pre validation - -To handle dependend fields you can just override *preValid()* or *postValid()* -to dynamically add or remove validations. This behaviour reduces the overhead -to write own validator classes. - -* *preValidation()* Work just before pre validation - -#### Autoloading of form code - -Because of forms are no library code we need to put them into application code. -The application or the module has an reserved namespace for forms which loads -code from special directories: - -

- - - - - - - - - - - - - - -
Class nameFile path
\Icinga\Form\Test\MyFormapplication/forms/Test/MyForm.php
\MyModule\Form\Testmodules/forms/Test.php
- -If you want to create custom elements or organize library code in form context -use an other namesoace for, e.g. - -``` -\Icinga\Web\Form\Element\MySpecialElement -\MyModule\Web\Form\Element\FancyDatePicker -``` - -## Example implementation - - - namespace MyModule\Form; - - use Icinga\Web\Form; - - class TestForm extends Form - { - /** - * Add elements to this form (used by extending classes) - */ - protected function create() - { - $this->addElement( - 'checkbox', - 'flag', - array( - 'label' => 'Check this box to user feature 1' - ) - ); - - $this->addElement( - 'text', - 'flagValue', - array( - 'label' => 'Enter text' - ) - ); - } - - /** - * Check dependent fields - * @param array $data - */ - protected function preValidation(array $data) - { - if (isset($data['flag']) && $data['flag'] === '1') { - $textField = $this->getElement('flagValue'); - $textField->setRequired(true); - - $textField->addValidator( - 'alnum', - true, - array( - 'allowWhitespace' => true - ) - ); - } - } - } - -The example above adds to elements to the form: A checkbox and a textfield. -The function *preValid()* set the textfield required if checkbox was -checked before. - -### Full overriding example - -The following example shows form with most usefull method utilization of -interface methods: - - namespace MyModule\Form; - - use Icinga\Web\Form; - - class TestForm extends Form - { - /** - * When sub-classing replace the constructor - */ - public function init() - { - // Do some initializing work here if needed - } - - /** - * Add elements to this form (used by extending classes) - */ - protected function create() - { - // Add elements to form - } - - /** - * Pre validation - * @param array $data - */ - protected function preValidation(array $data) - { - // Add depending filters or validation here - } - } - -## Testing forms - -When testing forms it is a good idea to use Zend_Test_PHPUnit_ControllerTestCase -instead of others like PHPUnit_Framework_TestCase as this enables you to use a -request dummy which can be passed to your form. - -### Example: - - require_once 'Zend/Test/PHPUnit/ControllerTestCase.php'; - - class YourTestCase extends Zend_Test_PHPUnit_ControllerTestCase - { - function exampleTest() - { - $request = $this->getRequest(); - $request->setMethod('POST')->setPost(array( - 'key' => 'value' - ) - ); - $form = new SomeForm(); - $form->setRequest($request); - - ... - } - } - -## Additional resources - -* [API documentation](http://build.icinga.org/jenkins/view/icinga2-web/job/icinga2web-development/javadoc/?) -* Live examples: application/forms or modules/monitoring/application/forms -* [Zend API documentation](http://framework.zend.com/apidoc/1.10/_Form.html#Zend_Form) - - -[form1]: res/Form.png diff --git a/doc/form_elements.md b/doc/form_elements.md deleted file mode 100644 index 4f83b00fc..000000000 --- a/doc/form_elements.md +++ /dev/null @@ -1,138 +0,0 @@ -# Form Elements Shipped With Icinga Web 2 - -On top of the elements provided by the Zend Framework, Icinga Web 2 ships its own to offer additional functionality. -The following is a list of these classes, as well as descriptions of the functionality they offer. - -## Elements - -### DateTimePicker - -`Icinga\Web\Form\Element\DateTimePicker` represents a control that allows the user to select date/time and to -display the date and time with a user specified format. Internally the element returns the input as Unix timestamp after -it has been proven valid. That is when the input is valid to `\DateTime::createFromFormat()` according to the user -specified format. Input is always timezone aware because the element utilizes `Icinga\Util\DateTimeFactory` which relies -on the timezone set by the user. - -**Example #1 DateTimePicker expecting date** - - use Icinga\Web\Form\Element\DateTimePicker; - - $element = new DateTimePicker( - array( - 'name' => 'date', - 'label' => t('Date'), - 'patterns' => array('Y-m-d') // Allowed format - ) - ) - -**Example #2 DateTimePicker expecting time** - - use Icinga\Web\Form\Element\DateTimePicker; - - $element = new DateTimePicker( - array( - 'name' => 'time', - 'label' => t('Time'), - 'patterns' => array('H:i:s') // Allowed format - ) - ) - -**Example #3 DateTimePicker expecting date and time** - - use Icinga\Web\Form\Element\DateTimePicker; - - $element = new DateTimePicker( - array( - 'name' => 'datetime', - 'label' => t('Date And Time'), - 'patterns' => array('Y-m-d H:i:s') // Allowed format - ) - ) - -**Example #4 DateTimePicker expecting date/time w/ default value** - - use Icinga\Web\Form\Element\DateTimePicker; - use Icinga\Util\DateTimeFactory; - - $now = DateTimeFactory::create(); - - $element = new DateTimePicker( - array( - 'name' => 'datetime', - 'label' => t('Date/Time'), - 'value' => $now->getTimestamp() + 3600, // now plus 1 hour - 'patterns' => array('Y-m-d H:i:s', 'Y-m-d', 'H:i:s') // Allowed format - ) - ) - -## Validators - -### WritablePathValidator - -This *Icinga\Web\Form\Validator\WritablePathValidator* validator tests a given (string-)input for being a valid writable -path. Normally it just tests for an existing, writable path but when setRequireExistence() is called, the path must -exist on form submission and be writable. - -**Example usage of writablePathValidator - - use \Icinga\Web\Form\Validator\WritablePathValidator; - $txtLogPath = new Zend_Form_Element_Text( - array( - 'name' => 'logging_app_target', - 'label' => 'Application Log Path', - 'helptext' => 'The logfile to write the icingaweb debug logs to.' - . 'The webserver must be able to write at this location', - 'required' => true, - 'value' => $logging->get('target', '/var/log/icingaweb.log') - ) - ); - $txtLogPath->addValidator(new WritablePathValidator()); - - -### DateTimeValidator - -The *Icinga\Web\Form\Validator\DateTimeValidator* validator allows you to validate an input against a set of datetime -patterns. On successful validation, it either gives a valid pattern via getValidPattern, or null if the entered time -is a timestamp. The above DateTimePicker utilizes this validator and should be used instead of directly using the validator. - - -## Decorators - -### ConditionalHidden Decorator - -The `Icinga\Web\Form\Decorator\ConditionalHidden` allows you to hide a form element with the 'conditional' attribute for -users that don't have JavaScript enabled (the form is rendered in a <noscript> tag when conditional is 1). Users with -javascript won't see the elements, users with javascript will see it. This is useful in a lot of cases to allow icingaweb -to be fully functional without JavaScript: Forms can show only sensible forms for most users (and, for example hide the -debug log filepath input when debugging is disabled) and automatically reload the form as soon as the forms should be -shown (e.g. when the debug checkbox is clicked), while users with text-browsers or javascript disabled see all forms, -but can only fill out the ones relative or them. - -**Example use of ConditionalHidden** - - use Icinga\Web\Form\Decorator\ConditionalHidden; - - $textLoggingDebugPath = new Zend_Form_Element_Text(array( - 'name' => 'logging_debug_target', - 'label' => 'Debug Log Path', - 'required' => $this->shouldDisplayDebugLog($debug), - 'condition' => $this->shouldDisplayDebugLog($debug), // 1 if displayed, otherwise 0 - 'value' => getLogPath, - 'helptext' => 'Set the path to the debug log' - )) - $textLoggingDebugPath->addDecorator(new ConditionalHidden()); - $form->addElement($textLoggingDebugPath); - -### HelpText Decorator ### - -The `Icinga\Web\Form\Decorator\HelpText` decorator allows you to use the 'helptext' property and renders this text in -a consistent ways across the application. It is automatically added by our Form implementation, so you can just use -the 'helptext' property in your form elements. - - -### BootstrapForm Decorator - -`Icinga\Web\Form\Decorator\BoostrapForm` is the decorator we use for our forms. -It causes the forms to be rendered in a bootstrap friendly manner instead of the <dd> <dt> encapsulated way Zend normally -renders the forms. You usually don't have to work with this decorator as our Form implementation automatically uses it, -but it's always good to know why forms look how they look. \ No newline at end of file diff --git a/doc/graphs.md b/doc/graphs.md deleted file mode 100644 index 3c898f7a6..000000000 --- a/doc/graphs.md +++ /dev/null @@ -1,393 +0,0 @@ -# Drawing Graphs - -## Feature Set - -Icinga Web comes with an SVG based graphing library that supports the basic graph types required for displaying monitoring -data. These include: - -* **Pie Charts**, which display a set of data in a typical pie diagram. -* **Stacked Pie Charts**, which render one or multiple pies nested in another pie chart -* **Line Charts**, which display a set of datapoints as a line graph -* **Stacked Line Charts**, which display multiple line charts on top of each other, providing a cumulative view over - a set of datapoints -* **Bar Charts**, which display a set of datapoints as bars -* **Stacked Bar Charts**, which, like the Stacked Line Chart, combines several charts and displays them on top of each other - -## Creating Grid Charts (Line and Bar Charts) - -### Base Api Synopsis - -The `Icinga/Chart/GridChart` class provides the calls required for setting up Grid Charts. A GridChart draws three -separate parts: Axis, Legend and the Gridarea. - -To create a new Grid, simply create a `GridChart` object (the constructor takes no parameters): - -**Example #1: Create a grid chart** - - $this->chart = new GridChart(); - -Now you can go on and customize the chart to fit your needs (this will be explained in depth in the next sections). - -**Example #2: Customize the grid chart** - - $this->chart - ->setAxisMin(null, 0) // Set the Y-axis to always start at 0 - ->setAxisMax(null, 100) // Set the Y-Axis to end at 100 - ->setAxisLabel("X axis label", "Y axis label"); // Set labels for X-axis and Y-axis - -And finally you can draw data: - -**Example #3: Drawing graphs** - - $this->chart->drawLines( - array( - 'label' => 'A Graph Line', - 'color' => 'red', - 'width' => '5', - 'data' => array(array(0, 10), array(2, 40), array(3, 55), array(7, 92)) - ) - ); - -This example would produce a graph like this if rendered: - -![Simple Line Graph][graph1] - - - -### Graph Setup Methods - -When creating the above graph without any setup options (like `setAxisMin`), it would use default values when being rendered. -This means: - -* No label for X-Axis and Y-Axis -* The X/Y axis minimal value is the lowest X/Y value from the dataset -* The X/Y axis maximum value is the highest X/Y value from the dataset - -Let's create a minimal example for this: - -**Example #4: The most simple line graph** - - $this->chart = new GridChart(); - $this->chart->drawLines( - array( - 'data' => array(array(0, 10), array(2, 40), array(3, 55), array(7, 92)) - ) - ); - -![The Most Simple Line Graph][graph2] - - -#### Adding Axis Labels - -A graph without axis labels is rather useless. With the `GridChart::setAxisLabel($xAxisLabel, $yAxisLabel)` method you -can define the axis labels for both the X and Y axis: - -**Example #5: Adding axis labels** - - $this->chart = new GridChart(); - $this->chart->setAxisLabel("X axis label", "Y axis label"); - $this->chart->drawLines( - array( - 'data' => array(array(0, 10), array(2, 40), array(3, 55), array(7, 92)) - ) - ); - -![Line Graph With Label][graph3] - -#### Defining Axis Types - -Normally, axis display their values as numeric, linear types. You can overwrite the axis for the X or Y direction with -one that suits your needs more specifically. Supported axis are: - -* Linear Axis: This is the default axis that displays numeric values with an equal distance between each tick - -**Example #6: Defining A Linear Axis With A Custom Number Of Ticks** - - $this->chart = new GridChart(); - $this->chart->setAxisLabel("X axis label", "Y axis label"); - $this->chart->setXAxis(Axis::linearUnit(40)); - $this->chart->setYAxis(Axis::linearUnit(10)); - $this->chart->drawLines( - array( - 'data' => array(array(0, 10), array(2, 40), array(3, 55), array(7, 92)) - ) - ); - -![Line Graph With Custom Tick Count][graph4] - - -* Calendar Axis: The calendar axis is a special axis for using timestamps in the axis. It will display the ticks as -sensible time values - -**Example #7: Defining A Calendar Axis** - - $this->chart = new GridChart(); - $this->chart->setAxisLabel("X axis label", "Y axis label"); - $this->chart->setXAxis(Axis::calendarUnit()); - $this->chart->drawLines( - array( - 'data' => array( - array(time()-7200, 10),array(time()-3620, 30), array(time()-1800, 15), array(time(), 92)) - ) - ); - -![Line Graph With Custom Tick Count][graph5] - -## Line Charts - -We've already seen an example of line charts in the last section, but this was rather minimal. The call for creating -Line Charts in the Chart Api is `GridChart::drawLines(array $lineDefinition1, array $lineDefinition2, ...)`, while '...' -means 'as many definitions as you want'. - -$lineDefinition is an configuration array that describes how your data will be displayed. Possible configuration options -are: - -* **label** The text that will be displayed in the legend of the graph for this line. If none is given simply - 'Dataset %nr%' will be displayed, with %nr% meaning a number starting at 1 and incrementing for every - line without a label -* **stack** If provided, this graph will be shown on top of each other graph in the same stack and causes all - graphs in the same stack to be rendered cumulative -* **discrete** Set to display the line in a discrete manner, i.e. using hard steps between values instead of drawing - a interpolated line between points -* **color** The color to use for the line or fill, either in Hex form or as a string supported in the SVG style tag -* **palette** (Ignored if 'color' is set) The color palette to use for determining the line or fill color -* **fill** True to fill the graph instead of drawing a line. Take care of the graph ordering when using this - option, as previously drawn graphs will be hidden if they overlap this graph. -* **showPoints** Set true to emphasize datapoints with additional dots -* **width** Set the thickness of the line stroke in px (default: 5) -* **data** The dataset as an two dimensional array in the form `array(array($x1, $y2), array($x2, $y2), ...) - -**Example #8: Various Line Graph Options** - - - $this->chart->drawLines( - array( - 'label' => 'Hosts critical', - 'palette' => Palette::PROBLEM, - 'stack' => 'stack1', - 'fill' => true, - 'data' => $data2 - ), - array( - 'label' => 'Hosts warning', - 'stack' => 'stack1', - 'palette' => Palette::WARNING, - 'fill' => true, - 'showPoints' => true, - 'data' => $data - ), - array( - 'label' => 'Hosts ok', - 'discrete' => true, - 'color' => '#00ff00', - 'fill' => false, - 'showPoints' => true, - 'width' => '10', - 'data' => $data3 - ) - ); - -You can see the effects here, notice how the first two lines are stacked: - -![Various Line Graph Options][graph6] - - -## Bar Charts - -Bar Charts almost offer the same functionality as Line Charts, but some configuration options from Line Charts don't make sense -and are therefore omitted. -The call for creating Line Charts in the Chart Api is `GridChart::drawBars(array $lineDefinition1, array $lineDefinition2, ...)`, -while '...' means 'as many definitions as you want'. Possible configuration options are: - -* **label** The text that will be displayed in the legend of the graph for this line. If none is given simply - 'Dataset %nr%' will be displayed, with %nr% meaning a number starting at 1 and incrementing for every - line without a label -* **stack** If provided, this graph will be shown on top of each other graph in the same stack and causes all - graphs in the same stack to be rendered cumulative -* **color** The color to use for filling the bar, either in Hex form or as a string supported in the SVG style tag -* **palette** (Ignored if 'color' is set) The color palette to use for determining the fill color -* **width** Set the thickness of the line stroke in px (default: 1) -* **data** The dataset as an two dimensional array in the form `array(array($x1, $y2), array($x2, $y2), ...) - -The same graph as rendered above would look as follows when using `drawBars` instead of `drawLines`. If you don't want -the labels to show you can use the 'disableLegend()' call on the GridChart object. - -**Example #9: Various Bar Chart Options** - - $this->chart->drawBars( - array( - 'label' => 'Hosts critical', - 'palette' => Palette::PROBLEM, - 'stack' => 'stack1', - 'data' => $data2 - ), - array( - 'label' => 'Hosts warning', - 'stack' => 'stack1', - 'palette' => Palette::WARNING, - 'data' => $data - ), - array( - 'label' => 'Hosts ok', - 'color' => '#00ff00', - 'width' => '10', - 'data' => $data3 - ) - ); - - -![Various Line Graph Options][graph7] - - -### Tooltips - -It is possible to specify custom tooltip format strings when creating bar charts. -Tooltips provide information about the points of each bar chart column, by aggregating -the values of all data sets with the same x-coordinate. - -When no custom format string is given, a sane default format string is used, but its usually -clearer for the user to describe the data of each chart more accurately with a custom one. - - -**Example #9.1: Bar Charts with custom tooltips** - - $this->chart->drawBars( - array( - 'label' => 'Hosts critical', - 'palette' => Palette::PROBLEM, - 'stack' => 'stack1', - 'data' => $data2, - 'tooltip' => '{title}
{value} of {sum} hosts are ok.' - ), - array( - 'label' => 'Hosts warning', - 'stack' => 'stack1', - 'palette' => Palette::WARNING, - 'data' => $data, - 'tooltip' => '{title}
Oh no, {value} of {sum} hosts are down!' - ) - ); - - -As you can see, you can specify a format string for each data set, which allows you to -pass a custom message for all "down" hosts, one custom message for all "Ok" hosts and so on. -In contrast to that, the aggregation of values works on a column basis and will give you the -sum of all y-values with the same x-coordinate and not the aggregation of all values of the data set. - -#### Rich Tooltips - -It is also possible to use HTML in the tooltip strings to create rich tooltip markups, which can -be useful to provide extended output that spans over multiple lines. Please keep in mind that -users without JavaScript will see the tooltip with all of its html-tags stripped. - -![Various Line Graph Options][graph7.1] - -#### Available replacements - -The available replacements depend on the used chart type, since the tooltip data is - instantiated and populated by the chart. All bar graphs have the following replacements available: - -Aggregated values, are calculated from the data points of each column: - - - sum: The amount of all Y-values of the current column - - max: The biggest occurring Y-value of the current column - - min: The smallest occurring Y-value of the current column - - -Column values are also defined by the current column, but are not -the product of any aggregation - - - title: The x-value of the current column - - -Row values are defined by the properties the current data set, and are only useful for rendering the -generic tooltip correctly, since you could also just directly write -those values into your custom tooltip. - - - label: The name of the current data set - - color: The color of this data set - - - -## Pie Charts - -### The PieChart Object - -Additionally to Line and Bar Charts, the Graphing Api also supports drawing Pie charts. In order to work with Pie charts -you have to create an `Icinga\Chart\PieChart` object first: - -**Example #10: Creating a PieChart Object** - - $pie = new PieChart(); - -### Drawing Pies - -Pies are now drawn using the `PieChart::drawPies(array $pieDefinition1, array $pieDefinition2, ...)` method: - -**Example #11: Example PieChart Definition** - - $pie->drawPie(array( - 'data' => array(5,80,1), - 'palette' => array(Palette::PROBLEM, Palette::OK, Palette::WARNING), - 'labels' => array( - 'Hosts down', 'Hosts up', 'Hosts unknown' - ) - )); - -This would produce a Pie Chart similar to this: - -![Example Pie Chart][graph8] - -Notice how every datapoint has it's own label and palette definition. Possible attributes for $pieDefinition are: - -* **labels**: An array containing a label for every definition in the 'data' array -* **colors**: An array of colors to use for every definition in the 'data' array -* **palette**: (ignored when using 'colors') An array containing the palette to user for every definition in the 'data' - array -* **data** An array containing of numeric values that define the relative sizes of the pie slices to the whole pie - -If you don't want the labels to show you can use the 'disableLegend()' call on the PieChart object. - -### Stacked Pies - -When adding multiple pies, they will be per default shown as a stacked pie: - -**Example #12: Stacked Pie Charts** - - $pie = new PieChart(); - $pie->drawPie(array( - 'data' => array(5,80,1), - 'palette' => array(Palette::PROBLEM, Palette::OK, Palette::WARNING), - 'labels' => array( - 'Hosts down', 'Hosts up', 'Hosts unknown' - ) - ), array( - 'data' => array(40,60,90,2), - 'palette' => array(Palette::PROBLEM, Palette::WARNING, Palette::OK, Palette::NEUTRAL), - 'labels' => array('Services down', 'Services Warning', 'Services OK', 'Services pending') - )); - -![Example Pie Chart][graph9] - -## Rendering in templates: - -Rendering is straightforward, assuming $svg is the PieChart/GridChart object, you just call render() to create an SVG: - - myTemplate.phtml - -
- render(); - ?> -
- -[graph1]: res/GraphExample#1.png -[graph2]: res/GraphExample#2.png -[graph3]: res/GraphExample#3.png -[graph4]: res/GraphExample#4.png -[graph5]: res/GraphExample#5.png -[graph6]: res/GraphExample#6.png -[graph7]: res/GraphExample#7.png -[graph7.1]: res/GraphExample#7.1.png -[graph8]: res/GraphExample#8.png -[graph9]: res/GraphExample#9.png diff --git a/doc/installation.md b/doc/installation.md index 9de3f7d5c..88c9c3650 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -1,119 +1,62 @@ +# Installation -# Installation +The preferred way of installing Icinga Web 2 is to use the official package repositories depending on which operating +system and distribution you are running. But it is also possible to install Icinga Web 2 directly from source. -## Requirements +## Installing Requirements -* Apache2 with PHP >= 5.3.0 enabled -* PHP Zend Framework -* PHP with MySQL or PostgreSQL libraries -* MySQL or PostgreSQL server and client software -* Icinga 1.x or Icinga 2 as backend providers +* A web server, e.g. Apache or nginx +* PHP >= 5.3.0 +* MySQL or PostgreSQL PHP libraries when using a database for authentication or storing user preferences into a database +* LDAP PHP library when using Active Directory or LDAP for authentication +* Icinga 1.x w/ Livestatus or IDO, Icinga 2 w/ Livestatus or IDO feature enabled -RHEL/CentOS requires the EPEL repository enabled (which provides the `php-ZendFramework` -package). OpenSUSE requires the [server monitoring](https://build.opensuse.org/project/show/server:monitoring) repository (which provides the `php5-ZendFramework` package) enabled. +## Installing Icinga Web 2 from Package -## configure && make +A guide on how to install Icinga Web 2 from package will follow shortly. -### Basic installation +## Installing Icinga Web 2 from Source -If you like to configurea and install icinga2-web from the command line or -if you want to create packages, configure and make is the best choice for installation. +**Step 1: Getting the Source** - ./configure && make install && make install-apache2-config +First of all, you need to download the sources. Icinga Web 2 is available through a Git repository. You can clone this +repository either via git or http protocol using the following URLs: -will install the application to the default target (/usr/local/icinga2-web). Also -an apache configuration entry is added to your apache server, so you should restart -your web server according to your systems configuration. + * git://git.icinga.org/icingaweb2.git + * http://git.icinga.org/icingaweb2.git -### Installation directory +There is also a browsable version available at +[gi.icinga.org](https://git.icinga.org/?p=icingaweb2.git;a=summary "Icinga Web 2 Git Repository"). +This version also offers snapshots for easy download which you can use if you do not have git present on your system. -If you want to install the application to a different directory, use the --prefix flag in your -configure call: +```` +git clone git://git.icinga.org/icingaweb2.git +```` - ./configure --prefix=/my/target/directory +**Step 2: Install the Source** +Choose a target directory and move Icinga Web 2 there. -### Authentication +```` +mv icingaweb2 /usr/share/icingaweb +```` -By default, icinga2-web will be installed to authenticate againts its internal database, -but you can configure it to use ldap-authentication by adding the `--with-ldap-authentication` -flag. You must provide the authentication details for your ldap server by using the --with-ldap-* flags. -To see a full list of the flags, call `./configure --help` +**Step 3: Configuring the Web Server** -### Icinga backend +Use `icingacli` to generate web server configuration for either Apache or nginx. -The default option for icinga2web is to configure all icinga backends with the default settings (for example -/usr/local/icinga/ as the icinga directory) but only enable statusdat. To use a different backend, -call `--with-icinga-backend=` and provide ido, livestatus or statusdat as an option. To further configure -your backend, take a look at the various options described in `./configure --help` +*Apache* -### Databases +```` +./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb/public +```` -It is required to set up all used Databases correctly, which basically means to create all needed user accounts and to -create all database tables. You will find the installation guides for the different databases in the sections below: +*nginx* -*IMPORTANT*: Select a secure password instead of "icingaweb" and alter the config/authentication.ini accordingly. +```` +./bin/icingacli setup config webserver nginx --document-root /usr/share/icingaweb/public +```` +**Step 4: Web Setup** -#### MySQL - -1. Create the user and the database - - - mysql -u root -p - mysql> CREATE USER `icingaweb`@`localhost` IDENTIFIED BY 'icingaweb'; - mysql> CREATE DATABASE `icingaweb`; - mysql> GRANT ALL PRIVILEGES ON `icingaweb`.* TO `icingaweb`@`localhost`; - mysql> FLUSH PRIVILEGES; - mysql> quit - - -2. Create all tables (You need to be in the icinga2-web folder) - -> **Note** -> -> RPM packages install the schema into /usr/share/doc/icingaweb-<version>/schema - - bash$ mysql -u root -p icingaweb < etc/schema/accounts.mysql.sql - bash$ mysql -u root -p icingaweb < etc/schema/preferences.mysql.sql - - -#### PostgreSQL - -1. Create the user and the database - - - sudo su postgres - psql - postgres=# CREATE USER icingaweb WITH PASSWORD 'icingaweb'; - postgres=# CREATE DATABASE icingaweb; - postgres=# \q - - -2. Enable trust authentication on localhost - -Add the following lines to your pg_hba.conf (etc/postgresql/X.x/main/pg_hba.conf under debian, /var/lib/pgsql/data/pg_hba.conf for Redhat/Fedora) -to enable trust authentication for the icingaweb user when connecting from the localhost. - - local icingaweb icingaweb trust - host icingaweb icingaweb 127.0.0.1/32 trust - host icingaweb icingaweb ::1/128 trust - -And restart your database ('service postgresql restart' or '/etc/init.d/postgresql-X.x reload' while being root) - - -3. Create all tables (You need to be in the icinga2-web folder) - -> **Note** -> -> RPM packages install the schema into /usr/share/doc/icingaweb-<version>/schema - - bash$ psql -U icingaweb -a -f etc/schema/accounts.pgsql.sql - bash$ psql -U icingaweb -a -f etc/schema/preferences.pgsql.sql - - - -Quick and Dirty ----------------- - -tdb. +Visit Icinga Web 2 in your browser and complete installation using the web setup. diff --git a/doc/module/configuration_and_preferences.md b/doc/module/configuration_and_preferences.md deleted file mode 100644 index a259e524a..000000000 --- a/doc/module/configuration_and_preferences.md +++ /dev/null @@ -1,57 +0,0 @@ -# Module Development: Configuration and Preferences Dialogs - -When developing modules, you might want your module's configuration and preferences dialogs to appear in the Icinga Web -Configuration/Preferences interface. This is rather easy to accomplish and should be the preferred way to allow user's -to customize your module. - -## Terminology - -When talking about 'Configuration' and 'Preference', we have a clear distinction between those words: - -- **Configurations** are application/module wide settings that affect every user when being changed. This could be - the data backend of your module or other 'global' settings that affect everyone when being changed -- **Preferences** are settings a user can set for *his* account only, like the page size of pagination, entry points, etc. - - -## Usage - -The two base classes for preferences and configurations are \Icinga\Web\Controller\BasePreferenceController for preferences and - \Icinga\Web\Controller\BaseConfigController for configurations. - -If you want to create a preference or configuration panel you have to create a ConfigController and/or PreferenceController - in your Module's a controller directory and make it a subclass of BaseConfigController or BasePreferenceController. - -Those controllers can be used like normal controllers, with two exceptions: - -- If you want your module to appear as a tab in the applications configuration/preference interface you have to implement - the static createProvidedTabs function that returns an array of tabs to be displayed -- The init() method of the base class must be called in order to make sure tabs are collected and the view's tabs variable - is populated - -## Example - -We'll just provide an example for ConfigControllers here, as PreferenceController are the same with a different name - - use \Icinga\Web\Controller\BaseConfigController; - use \Icinga\Web\Widget\Tab; - use \Icinga\Web\Url; - - class My_ConfigController extends BaseConfigController { - - static public function createProvidedTabs() - { - return array( - "myModuleTab" => new Tab(array( - "name" => "myModuleTab", // the internal name of the tab - "iconCls" => "myicon", // the icon to be displayed - "title" => "The tab title", // The title of the configuration's tab - "url" => Url::fromPath("/myModule/config") // The Url that will ne called (can also be just a path) - )) - ); - } - - public function indexAction() - { - // create the form here - } - } diff --git a/doc/resources.md b/doc/resources.md index cddfb04d1..29a35c30d 100644 --- a/doc/resources.md +++ b/doc/resources.md @@ -1,96 +1,82 @@ -# Resources +# Resources -The configuration file *config/resources.ini* contains data sources that can be referenced -in other configurations. This allows you to manage all connections to databases at one central -place, avoiding the need to edit several different files, when the connection information of a resource change. +The INI configuration file **config/resources.ini** contains information about data sources that can be referenced in other +configuration files. This allows you to manage all data sources at one central place, avoiding the need to edit several +different files, when the information about a data source changes. -## Configuration +## Configuration -Each section represents a resource, with the section name being the identifier used to -reference this certain section. Depending on the resource type, each section contains different properties. -The property *type* defines the resource type and thus how the properties are going to be interpreted. -The available resource types are 'db', 'statusdat', 'livestatus' and 'ldap' and are -described in detail in the following sections: +Each section in **config/resources.ini** represents a data source with the section name being the identifier used to +reference this specific data source. Depending on the data source type, the sections define different directives. +The available data source types are *db*, *ldap* and *livestatus* which will described in detail in the following +paragraphs. -### db +### Database -This resource type describes a SQL database on an SQL server. Databases can contain users and groups -to handle authentication and permissions, or monitoring data using IDO. +A Database resource defines a connection to a SQL databases which can contain users and groups +to handle authentication and authorization, monitoring data or user preferences. -- *db*: defines the used database vendor, which could be a value like *mysql* or *pgsql*. -- *host*: The hostname that is used to connect to the database. -- *port*: The port that is used to connect to the database. -- *username*: The user name that is used to authenticate. -- *password*: The password of the user given in *username*. -- *dbname*: The name of the database that contains the resources data. +Directive | Description +----------------|------------ +**type** | `db` +**db** | Database management system. Either `mysql` or `pgsql`. +**host** | Connect to the database server on the given host. +**port** | Port number to use for the connection. +**username** | The username to use when connecting to the server. +**password** | The password to use when connecting to the server. +**dbname** | The database to use. -### ldap +**Example:** -The resource is a tree in a ldap domain. This resource type is usually used to fetch users and groups -to handle authentication and permissions. +``` +[icingaweb] +type = db +db = mysql +host = localhost +port = 3306 +username = icingaweb +password = icingaweb +dbname = icingaweb +``` -- *hostname*: The hostname that is used to connect to the ldap server. -- *port*: The port that is used to connect to the ldap server. -- *root_dn*: The root object of the tree. This is usually an organizational unit like - "ou=people, dc=icinga, dc=org". -- *bind_dn*: The user on the LDAP server that will be used to access it. Usually something - like "cn=admin, cn=config". -- *bind_pw*: The password of the user given in *bind_dn*. +### LDAP +A LDAP resource represents a tree in a LDAP directory. LDAP is usually used for authentication and authorization. -### livestatus +Directive | Description +----------------|------------ +**type** | `ldap` +**hostname** | Connect to the LDAP server on the given host. +**port** | Port number to use for the connection. +**root_dn** | Root object of the tree, e.g. "ou=people,dc=icinga,dc=org" +**bind_dn** | The user to use when connecting to the server. +**bind_pw** | The password to use when connecting to the server. -A resource that points to a livestatus socket. This resource type contains monitoring data. +**Example:** -- *socket*: The livestatus socket. Can be either be a path to a domain socket (like - "/usr/local/icinga-mysql/var/rw/live") or to a TCP socket like - (tcp://:) +```` +[ad] +type = ldap +hostname = localhost +port = 389 +root_dn = "ou=people,dc=icinga,dc=org" +bind_dn = "cn=admin,ou=people,dc=icinga,dc=org" +bind_pw = admin` +```` -### statusdat +### Livestatus -A resource that points to statusdat files. This resource type contains monitoring data. +A Livestatus resource represents the location of a Livestatus socket which is used for fetching monitoring data. -- *status_file*: The path to the *status.dat* file, like "/usr/local/icinga-mysql/var/status.dat" -- *object_file*: The path to *objects.cache*, like "/usr/local/icinga-mysql/var/objects.cache" +Directive | Description +----------------|------------ +**type** | `livestatus` +**socket** | Location of the Livestatus socket. Either a path to a local Livestatus socket or a path to a remote Livestatus socket in the format `tcp://:`. +**Example:** -## Factory Implementations - -This section contains documentation documentation for the Icinga2-Web developers that want to -use resources defined in the *resources.ini*. Each supported resource type should have an own -factory class, that can be used to comfortably create instances of classes that provide access -to the data of the resources. - - -### ResourceFactory - -The ResourceFactory can be used to retrieve objects to access resources. Lets assume -for the following examples, that we have an *resources.ini* that looks like this: - - [statusdat] - type = statusdat - status_file = /usr/local/icinga-mysql/var/status.dat - object_file = /usr/local/icinga-mysql/var/objects.cache - - [ldap_authentication] - type = "ldap" - hostname = "localhost" - port = "389" - root_dn = "ou=people, dc=icinga, dc=org" - bind_dn = "cn=admin, cn=config" - bind_pw = "admin" - - -Here is an example of how to retrieve the resource 'statusdat' from the factory. - - $resource = ResourceFactory::createResource( - ResourceFactory::getResourceConfig('statusdat') - ); - -If you specify a resource that does not exist or has the wrong type, -the factory will throw an ConfigurationException. - - -You can also retrieve a list of all available resources by calling *getResourceConfigs*. - - $resourceConfigs = ResourceFactory::getResourceConfigs(); +```` +[livestatus] +type = livestatus +socket = /var/run/icinga2/cmd/livestatus +```` diff --git a/doc/test/php_tests.md b/doc/test/php_tests.md deleted file mode 100644 index b0ab668a6..000000000 --- a/doc/test/php_tests.md +++ /dev/null @@ -1,65 +0,0 @@ -# Writing PHPUnit tests - -## Test path and filename - -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 tests are underneath modules/myModule/test/php - -## Example test skeleton - -Let's assume you're testing a class MyClass underneath the MyModule module and the file can be found at -modules/mymodule/library/MyModule/Helper/MyClass.php. - - assertTrue(true, "Asserting that the world didn't end yet"); - } - } - -## Testing Singletons - -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 [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. - - openingHours = CheesecakeFactory::getOpeningHours(); - } - - protected function tearDown() - { - parent::tearDown(); - CheesecakeFactory::setOpeningHours($this->openingHours); - } - - public function testThatInteractsWithStaticAttributes() - { - CheesecakeFactory::setOpeningHours(24); - // ... - } - } - -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. diff --git a/doc/test/running_tests.md b/doc/test/running_tests.md deleted file mode 100644 index 116911057..000000000 --- a/doc/test/running_tests.md +++ /dev/null @@ -1,88 +0,0 @@ -# Test organization - -## Testfolders - -Tests for the application can be found underneath the test folder: - - test/ - php/ PHPUnit tests for backend code - 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 it in 'regression' and name it %DESCRIPTION%%TicketNumber% (myBug1234.php) - -## Running tests - -The tests can be run in the specific folder using the runtests script. - -Running PHP tests example: - - cd test/php - ./runtests - -In this case, all application and all module tests will be executed. The testrunners also support additional flags, which -affect they way the test is executed: - - Options: - -h, --help show this help message and exit - -b, --build Enable reporting. - -v, --verbose Be more verbose. - -i PATTERN, --include=PATTERN - Include only specific files/test cases. - -V, --vagrant Run in vagrant VM - -Some tests also support the --exclude method, it's best to use the --help option to see which flags are supported. - - -## Setting up databases - -Despite running most of the tests should work out of the box, a few specific cases require some setup. -At this moment, only database tests require additional setup and expect an icinga_unittest user with an icinga_unittest -database to exist and have rights in your database. - -### The database test procedure - -When testing PostgreSQL and MySQL databases, the test library (normally) executes the following test procedure for every -test case: - -- Log in to the rdbms as the user icinga_unittest with password icinga_unittest -- Use the icinga_unittest database (which must be existing) -- **Drop all tables** in the icinga_unittest database -- Create a new, clean database schema - -If anything goes wrong during this procedure, the test will be skipped (because maybe you don't have a pgsql database, but -want to test mysql, for example). - -### Setting up a test user and database in MySQL - -In MySQL, it's best to create a user icinga_unittest@localhost, a database icinga_unittest and grant all privileges on -this database: - - mysql -u root -p - mysql> CREATE USER `icinga_unittest`@`localhost` IDENTIFIED BY 'icinga_unittest'; - mysql> CREATE DATABASE `icinga_unittest`; - mysql> GRANT ALL PRIVILEGES ON `icinga_unittest`.* TO `icinga_unittest`@`localhost`; - mysql> FLUSH PRIVILEGES; - mysql> quit - -### Setting up a test user and database in PostgreSQL - -In PostgreSQL, you have to modify the pg_hba database if you don't have password authentication set up (which often is -the case). In this setup the icinga_unittest user is set to trust authentication on localhost, which means that no -password is queried when connecting from the local machine: - - sudo su postgres - psql - postgres=# CREATE USER icinga_unittest WITH PASSWORD 'icinga_unittest'; - postgres=# CREATE DATABASE icinga_unittest; - postgres=# \q - bash$ createlang plpgsql icinga; - - -Add the following lines to your pg_hba.conf (etc/postgresql/X.x/main/pg_hba.conf under debian, /var/lib/pgsql/data/pg_hba.conf for Redhat/Fedora) -to enable trust authentication for the icingaweb user when connecting from the localhost. - - local icinga_unittest icinga_unittest trust - host icinga_unittest icinga_unittest 127.0.0.1/32 trust - host icinga_unittest icinga_unittest ::1/128 trust - diff --git a/doc/test/styleguide.md b/doc/test/styleguide.md deleted file mode 100644 index 4186b3375..000000000 --- a/doc/test/styleguide.md +++ /dev/null @@ -1,359 +0,0 @@ -# General testing guidelines - -## The short summary - -This list summarizes what will be described in the next few chapters: - -- You really should write tests for your code -- Think about your what you want to test and how you can assert the behaviour correctly. -- Isolate your tests and start without any assumptions about your test environment (like a specific user existing). The - only excuse here is to assume a correct login if you need a database for testing (but not the tables/content of the database!) -- Don't just test correct behaviour - test border cases and invalid input or assumptions to make sure the application handles - cases that might not occur in a normal test environment -- Use description strings in your assertions, this makes it easy to detect what's going wrong when they fail and it's easier - to follow what *exactly* you are asserting -- Test methods should be one scenario and the method name should describe this scenario. - *testLogin* is bad for example (do you test if the login fails? Or if it is correct? - *testLoginWithCorrectCredentials*, *testLoginWithWrongPassword* is a far better name here -- 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. -- 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 - -### Writing meaningful tests - -Writing tests doesn't ensure that your code is free of errors, but it can test if, in a specific scenario, the behaviour of -your code is as expected. This means that you have to think about your test scenario before writing a test. This involves -three steps: - -- Determine what you want to test: Which errors can occur, what is the normal input and what are the border cases. -- Define a test scenario: What datasets make sense for the test? -- How do I write my assertions so they are really meaningful about the correctness of the testcase - -Especially the border cases are important, often they lay inside of try/catch blocks or error detection routines. When -looking at your code coverages, these blocks should be covered. - -### Example - -Let's say you have the following function (the examples in this section are to be considered as php-like pseudocode) : - - function isValidName($name) - { - if (hasCorrectFormat($name)) { - return false; - } - - if (nameExistsInDatabase($name)) { - return false; - } - - return true; - } - - -#### Determine what to test: - -At first glance there can be 3 scenarios: - -1. The username is unique and valid -2. The username has the wrong format -3. The username has the correct format, but exists in the database - -But - what happens if the database is down? Should an exception be thrown or should it return false? This case has to be added -to your tests, so you have (at least!) the following scenarios: - -1. The username is unique and valid -2. The username has the wrong format -3. The username has the correct format, but exists in the database -4. The username has the correct format, but access to the database fails. - - -#### Determine meaningful testscenarios - -When it comes to creating your testscenario, we start with the easiest one: Test the wrongly formatted username. This -should be pretty straightforward, as we never reach the code where we need the database: - - function testWrongFormat() - { - assertFalse(isValidName("$$% 1_', "Assert a name with special characters to be considered an invalid name"); - } - -The first and third scenario are more sophisticated (like always, when a database comes into the game). There are two ways -to test this: -- Either you create an empty table on each test, fill them with the users and run the test -- or you Mock the database call with a class that behaves like querying the users and returns true or false in each case - -You **shouldn't** create a static database for all tests and assume this one to be existing - these are decoupled from the -actual test and soon get outdated or difficult to reflect all scenarios. Also it's not considered good practice to create -a precondition your tests have to rely on. In this case the second approach makes sense, as the mock class should be rather simple: - - - function testCorrectUserName() - { - // set no users in the database mock - $db = new UserDatabaseMock(array()); - setupUserDatabaseMock($db); - - assertTrue(isValidName("hans"), "Assert a correctly formatted and unique name to be considered valid"); - } - - function testNonUniqueUserName() - { - // set no users in the database mock - $db = new UserDatabaseMock(array("pete")); - setupUserDatabaseMock($db); - - assertFalse(isValidName("pete"), "Assert a correctly formatted, but existing name to be considered invalid"); - } - -The exception can be tested by providing invalid db credentials when using a real databse or by extending the mock (which -we will do here): - - function testDatabaseError() - { - // set no users in the database mock - $db = new UserDatabaseMock(array()); - $db->setThrowsException(true); - setupUserDatabaseMock($db); - - assertFalse(isValidName("hans"), "Assert a correct, unique user to be considered invalid when the database doesn't work"); - } - -This, of course, depends on how you want the behaviour to be when the db is down: Do you want to log the error and proceed -as usual or do you want the error to bubble up via an exception. - -#### Writing sensible assertions - -It's crucial to write sensible assertions in your test-classes: You can write a perfect test that covers the right scenario, -but don't catch errors because you aren't asking the correct questions. - -- Write assertions that cover your scenario - if you test a correct behaviour don't test what happens if something goes wrong - (this is a seperate scenario) -- While you should try to write redundant assertions it's better to assert more than to have a missing assertion -- A failed assertion means that the implementation is incorrect, other assertions are to be avoided (like testing if a - precondition applies) -- When testing one function, you have to be naive and assume that everything else is bug free, testing whether other parts - worked correctly before testing should be made in a different test. - -## How to test - -Unit tests should only test an isolated, atomic of your code - in theory just one single function - and shouldn't -need much dependency handling. An example for a unittest would be to test the following (hypothetical) class method: - - class UserManager - { - /** - * returns true when a user with this name exists and the - * password for this user is correct - **/ - public function isCorrectPassword($name, $password) - { - // You needn't to know the implementation. - } - } - -### The wrong way - -A unit test for this user could, but should not look like this (we'll explain why): - - use Icinga/MyLibrary/UserManager - - class UserManagerTest extends \PHPUnit_Framework_TestCase - { - /** - * Test whether an user is correctly recognized by the UserManager - * - **/ - public function testUserManager() - { - // Connect to the test database that contains jdoe and jsmith - $mgrConfg = new \Zend_Config(array( - "backend" => "db", - "user" => "dbuser.." - "pass" => - // all the other db credentials - )); - - $mgr = new UserManager($mgrConfig); - - $this->assertTrue($mgr->isCorrectPassword("jdoe", "validpassword")); - $this->assertTrue($mgr->isCorrectPassword("jsmith", "validpassword")); - $this->assertTrue($mgr->isCorrectPassword("jdoe", "nonvalidpassword")); - $this->assertTrue($mgr->isCorrectPassword("jsmith", "nonvalidpassword")); - $this->assertTrue($mgr->isCorrectPassword("hans", "validpasswor")); - } - -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 -- There are a lot of dependencies in this code, almost the complete Authentication code must exists. Our test - will fail if this code changes or contains bugs, even the isCorrectPassword method is correct. - -### Reducing dependencies - -To avoid these issues, you need to code your classes with testing in mind. Maybe now you're screaming *"Tests shouldn't -affect my code, just test if it is correct!"*, but it's not that easy. Testability should be considered as a quality aspect -of your code, just like commenting, keeping functions coherent, etc. Non-testable code should be considered as a bug, or -at least as a design-flaw. - -One big buzzword in development is now Inversion of Control and Dependency Injection. You can google the details, but in -our case it basically means: Instead of your class (in this case UserManager) setting up it's dependencies (creating an Authentication Manager and -then fetching users from it), the dependencies are given to the class. This has the advantage that you can mock the -dependencies in your testclasses which heavily reduces test-complexity. On the downside this can lead to more complicate -Api's, as you have to know the dependencies of your Object when creating it. Therefore we often allow to provide an -dependency from the outside (when testing), but normally create the dependencies when nothing is provided (normal use). - -In our case we could say that we allow our UserManager to use a provided set of Users instead of fetching it from the -Authmanger: - - class UserManager - { - - public function __construct($config, $authMgr = null) - { - if ($authMgr == null) { - // no Authmanager provided, resolve dependency by yourself - $this->authMgr = new AuthManager($config); - } else { - $this->authMgr = $authMgr; - } - } - } - -It would of course be best to create an Interface like UserSource which the AuthManger implements, but in this example -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): - - use Icinga/MyLibrary/UserManager - - class AuthManagerMock - { - public $users; - - /** - * Create a new mock classw with the provided users and their credentials - * - * @param array $userPasswordCombinations The users and password combinations to use - **/ - public function __construct(array $userPasswordCombinations) - { - $this->users = $userPasswordCombinations; - } - - public function getUsers() - { - return $this->users; - } - } - - class UserManagerTest extends \PHPUnit_Framework_TestCase - { - /** - * Test whether an user is correctly recognized by the UserManager - * - **/ - public function testUserManager() - { - $authMock = new AuthManagerMock(array( - "jdoe" => "validpassword", - "jsmith" => "validpassword" - )); - $mgrConfg = new \Zend_Config(array(), $authMock); - $mgr = new UserManager($mgrConfig); - - $this->assertTrue($mgr->isCorrectPassword("jdoe", "validpassword")); - $this->assertTrue($mgr->isCorrectPassword("jsmith", "validpassword")); - $this->assertFalse($mgr->isCorrectPassword("jdoe", "nonvalidpassword")); - $this->assertFalse($mgr->isCorrectPassword("jsmith", "nonvalidpassword")); - $this->assertFalse($mgr->isCorrectPassword("hans", "validpassword")); - } - -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 - - - -### Splitting up assertions - -The test is now not that bad, but still has a few issues: - -- If an assert fails, we don't know which one, as the message will be rather generic ("failed asserting that False is True") -- In this case it might be obvious what we test, but if someone sees the class and the assertions, he doesn't know what -assumptions are made - -To fix those issues, we have to split up our big test method in several smaller one and give the testmethod **talking names**. -Also, the assertions should get an error message that will be printed on failure. - - /** - * Testcases for the UserManager class - * - **/ - class UserManagerTest extends \PHPUnit_Framework_TestCase - { - /** - * Creates a new UserManager with a mocked AuthManage - * - * @returns UserManager - **/ - public function getUserManager() - { - $authMock = new AuthManagerMock(array( - "jdoe" => "validpassword", - "jsmith" => "validpassword" - )); - $mgrConfg = new \Zend_Config(array(), $authMock); - return new UserManager($mgrConfig); - } - - /** - * Tests whether correct user/name combinations are considered valid - * - **/ - public function testCorrectUserPasswordCombinations() - { - $mgr = $this->getUserManager(); - $this->assertTrue( - $mgr->isCorrectPassword("jdoe", "validpassword"), - "Asserted that a correct user/password combination is considered valid for jdoe" - ); - $this->assertTrue( - $mgr->isCorrectPassword("jsmith", "validpassword"), - "Asserted that a correct user/password combination is considered valid for jsmith" - ); - } - - /** - * Tests whether invalid names are rejected - * - **/ - public function testInvalidUsernameRecognition() - { - $mgr = $this->getUserManager(); - $this->assertFalse( - $mgr->isCorrectPassword("hans", "validpassword"), - "Asserted a non-existing user to be be considered invalid" - ); - } - - /** - * Tests whether invalid passwords for existing users are rejected - * - **/ - public function testInvalidPasswordRecognition() - { - $mgr = $this->getUserManager(); - $this->assertFalse( - $mgr->isCorrectPassword("jsmith", "nonvalidpassword"), - "Asserted that an invalid password for an existing user is considered invalid" - ); - } - } - -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. diff --git a/doc/testing.md b/doc/testing.md deleted file mode 100644 index 5e58d9a1b..000000000 --- a/doc/testing.md +++ /dev/null @@ -1,93 +0,0 @@ -# Testing guide - - -## Testing controllers for compatibility with different monitoring datasources - - -When it comes to writing controllers, it is important that your actions and queries work on every monitoring -datasource supported by icinga2 web. For this, the monitoring module provides a test library for controllers. - -## The database setup for every testcase - -When testing PostgreSQL and MySQL databases, the test library (normally) executes the following test procedure for every -test case: - -- Log in to the rdbms as the user icinga_unittest with password icinga_unittest -- Use the icinga_unittest database (which must be existing) -- Drop all tables in the icinga_unittest database (so *NEVER* run unit tests on your production system) -- Create a new, clean database schema - -If anything goes wrong during this procedure, the test will be skipped (because maybe you don't have a pgsql database, but -want to test mysql, for example) - -## Setting up a test user and database in MySQL - -In MySQL, it's best to create a user icinga_unittest@localhost, a database icinga_unittest and grant all privileges on -this database: - - mysql -u root -p - mysql> CREATE USER `icinga_unittest`@`localhost` IDENTIFIED BY 'icinga_unittest'; - mysql> CREATE DATABASE `icinga_unittest`; - mysql> GRANT ALL PRIVILEGES ON `icinga_unittest`.* TO `icinga_unittest`@`localhost`; - mysql> FLUSH PRIVILEGES; - mysql> quit - -## Setting up a test user and database in PostgreSQL - -In PostgreSQL, you have to modify the pg_hba database if you don't have password authentication set up (which often is -the case). In this setup the icinga_unittest user is set to trust authentication on localhost, which means that no -password is queried when connecting from the local machine: - - sudo su postgres - psql - postgres=# CREATE USER icinga_unittest WITH PASSWORD 'icinga_unittest'; - postgres=# CREATE DATABASE icinga_unittest; - postgres=# \q - bash$ createlang plpgsql icinga; - -## Writing tests for icinga - -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. - -### Writing database tests - -The base test uses the PHPUnit dataProvider annotation system to create database connections. Typically a -database test looks like this: - - /** - * @dataProvider mysqlDb - * @param Icinga\Data\Db\DbConnection $mysqlDb - */ - public function testSomethingWithMySql($mysqlDb) - { - $this->setupDbProvider($mysqlDb); // Drops everything from existing database - - // Load a dump file into database - $this->loadSql($mysqlDb, BaseTestCase::$etcDir . '/etc/schema/mydump.mysql.sql'); - - // Test your code - } - -Available data providers are: mysqlDb, pgsqlDb, oracleDb. The test will be skipped if a provider -could not be initialized. - -### Write form tests - -BaseTestCase holds method to require form libraries and create form classes based on class names. - - public function testShowModifiedOrder() - { - $this->requireFormLibraries(); - $form = $this->createForm( - 'Icinga\Form\Config\AuthenticationForm', - array( - 'priority' => 'test-ldap,test-db' - ) - ); - - // Testing your code - } - -The second parameter of createForm() can be omitted. You can set initial post request data as -an array if needed. diff --git a/doc/widgets.md b/doc/widgets.md deleted file mode 100644 index bab71c170..000000000 --- a/doc/widgets.md +++ /dev/null @@ -1,122 +0,0 @@ -# Widgets - -Widgets are reusable UI components that are able to render themselves and return HTML to be included in your template. - -## Basic interface - -The interface needed for implementing widgets can be found under library/Icinga/Web/Widget/Widget.php. This is a rather -simple interface, only providing a `render()` method that takes a view and returns HTML: - - interface Widget - { - public function render(Zend_View_Abstract $view); - } - -When implementing own Widgets you just have to make sure that you provide this render method. - -## Using widgets - -Widgets are normally created in the controller and added to the view: - - // in your Controller - - public function myControllerAction() - { - $this->view->myWidget = new MyWidget(); - } - -The HTML is then rendered in the template using the `render()` method described above. As the '$this' scope in a view is -a reference to your current view, you can just pass it to the `render()` method: - - // in your template - -
-

Look at my beautiful widget

- myWidget->render($this); ?> -
- -## The 'Tabs' widget - -The Tabs `\Icinga\Web\Widgets\Tabs` widget handles creation of Tab bars and allows you to create and add single tabs to -this view. To create an empty Tab bar, you just have to call: - - $tabbar = new Tabs(); - -> **Note**: Controllers subclassing `\Icinga\Web\Controller\ActionController` (which all existing controller do so and -> yours should too) have already an empty tabs object created under `$this->view->tabs`. This is done in the -> `preDispatch` function. - -### Adding tabs - -Afterwards you can add tabs by calling the `add($name, $tab)` function, whereas `$name` is the name of your tab and -`$tab` is either an array with tab parameters or an existing Tab object. - - // Add a tab - - $tabbar->add( - 'myTab', - array( - 'title' => 'My hosts', // Displayed as the tab text - 'iconCls' => 'myicon', // icon-myicon will be used as an icon in a tag - 'url' => '/my/url', // The url to use - 'urlParams' => array('host' => 'localhost') // Will be used as GET parameter - ) - ); - -### Adding tabs to the dropdown list - -Sometimes you want additional actions to be displayed in your tabbar. This can be accomplished with the -`addAsDropdown()` method. This one is similar to the `add()` method, but displays your tab in a dropdown list on the -right side of the tabbar. - -## Using tabextensions - -Often you find yourself adding the same tabs over and over again. You can write a Tabextension that does this for you -and just apply them on your tabs. Tabextensions are located at Icinga/Web/Widgets/Tabextension/ and they use the simple -Tabextension interface that just defines `apply(Tabs $tab)`. A simple example is the DashboardAction Tabextender which -just adds a new field to the dropdown list: - - class DashboardAction implements Tabextension - { - /** - * @see Tabextension::apply() - */ - public function apply(Tabs $tabs) - { - $tabs->addAsDropdown( - 'dashboard', - array( - 'title' => 'Add to Dashboard', - 'iconCls' => 'dashboard', - 'url' => Url::fromPath('dashboard/addurl'), - 'urlParams' => array( - 'url' => Url::fromRequest()->getRelativeUrl() - ) - ) - ); - } - } - -You can now either extend your Tabs object using the DashboardAction's `apply()` method or by calling the Tabs -`extend()` method (which is more fluent): - - $tabs->extend(new DashboardAction()); - -## The SortBox widget - -The "SortBox" Widget allows you to create a generic sort input for sortable views. -It automatically creates a form containing a select box with all sort options and a dropbox with the sort direction. It -also handles automatic submission of sorting changes and draws an additional submit button when JavaScript is disabled. - -The constructor takes an string for the component name ad an array containing the select options, where the key is -the value to be submitted and the value is the label that will be shown. You then should call applyRequest in order to -make sure the form is correctly populated when a request with a sort parameter is being made. - - $this->view->sortControl = new SortBox( - $this->getRequest()->getActionName(), - $columns - ); - $this->view->sortControl->applyRequest($this->getRequest()); - - -By default the sortBox uses the GET parameter 'sort' for the sorting key and 'dir' for the sorting direction diff --git a/etc/apache/.gitignore b/etc/apache/.gitignore deleted file mode 100644 index 839e1f407..000000000 --- a/etc/apache/.gitignore +++ /dev/null @@ -1 +0,0 @@ -icingaweb.conf diff --git a/etc/apache/icingaweb.conf.in b/etc/apache/icingaweb.conf.in deleted file mode 100644 index 3884aea5a..000000000 --- a/etc/apache/icingaweb.conf.in +++ /dev/null @@ -1,32 +0,0 @@ -Alias @web_path@ "@prefix@/public" - - - Options SymLinksIfOwnerMatch - AllowOverride None - - - # Apache 2.4 - - Require all granted - - - - - # Apache 2.2 - Order allow,deny - Allow from all - - - SetEnv ICINGAWEB_CONFIGDIR @icingaweb_config_path@ - - EnableSendfile Off - - RewriteEngine on - RewriteBase @web_path@/ - RewriteCond %{REQUEST_FILENAME} -s [OR] - RewriteCond %{REQUEST_FILENAME} -l [OR] - RewriteCond %{REQUEST_FILENAME} -d - RewriteRule ^.*$ - [NC,L] - RewriteRule ^.*$ index.php [NC,L] - - diff --git a/etc/schema/accounts.mysql.sql b/etc/schema/accounts.mysql.sql deleted file mode 100644 index 72eeee4fc..000000000 --- a/etc/schema/accounts.mysql.sql +++ /dev/null @@ -1,24 +0,0 @@ -create table account ( - `username` varchar(255) COLLATE latin1_general_ci NOT NULL, - `salt` varchar(255) NOT NULL, - `password` varchar(255) NOT NULL, - `active` tinyint(1) DEFAULT NULL, - PRIMARY KEY (`username`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - -/* - * user: icingaadmin - * password: icinga - */ -INSERT INTO account ( - `username`, - `salt`, - `password`, - `active` - ) - VALUES ( - 'icingaadmin', - '57cfd5746224be4f60c25d4e8514bec35ad2d01810723a138756b285898e71b2', - '43f8e0588eb39f1a41383b48def0b1fdc45e79b8f67194cccee4453eb3f4ea13', - 1 - ); diff --git a/etc/schema/accounts.pgsql.sql b/etc/schema/accounts.pgsql.sql deleted file mode 100644 index 84ecb54e8..000000000 --- a/etc/schema/accounts.pgsql.sql +++ /dev/null @@ -1,28 +0,0 @@ -create table "account" ( - "username" character varying(255) NOT NULL, - "salt" character varying(255), - "password" character varying(255) NOT NULL, - "active" boolean -); - -ALTER TABLE ONLY "account" - ADD CONSTRAINT account_pkey PRIMARY KEY ("username"); - -CREATE UNIQUE INDEX username_lower_unique_idx ON "account" USING btree (lower((username)::text)); - -/* - * user: icingaadmin - * password: icinga - */ -INSERT INTO "account" ( - "username", - "salt", - "password", - "active" - ) - VALUES ( - 'icingaadmin', - '57cfd5746224be4f60c25d4e8514bec35ad2d01810723a138756b285898e71b2', - '43f8e0588eb39f1a41383b48def0b1fdc45e79b8f67194cccee4453eb3f4ea13', - true - ); diff --git a/etc/schema/mysql.schema.sql b/etc/schema/mysql.schema.sql index 7867796b4..74d2665d4 100644 --- a/etc/schema/mysql.schema.sql +++ b/etc/schema/mysql.schema.sql @@ -27,9 +27,10 @@ CREATE TABLE `icingaweb_user`( CREATE TABLE `icingaweb_user_preference`( `username` varchar(64) COLLATE utf8_unicode_ci NOT NULL, + `section` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `name` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `value` varchar(255) NOT NULL, `ctime` timestamp NULL DEFAULT NULL, `mtime` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`username`,`name`) + PRIMARY KEY (`username`,`section`,`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/etc/schema/pgsql.schema.sql b/etc/schema/pgsql.schema.sql new file mode 100644 index 000000000..77971222b --- /dev/null +++ b/etc/schema/pgsql.schema.sql @@ -0,0 +1,99 @@ +/** + * Table "icingaweb_group" + */ +CREATE TABLE "icingaweb_group" ( + "name" character varying(64) NOT NULL, + "parent" character varying(64) NULL DEFAULT NULL, + "ctime" timestamp NULL DEFAULT NULL, + "mtime" timestamp NULL DEFAULT NULL +); + +ALTER TABLE ONLY "icingaweb_group" + ADD CONSTRAINT pk_icingaweb_group + PRIMARY KEY ( + "name" +); + +CREATE UNIQUE INDEX idx_icingaweb_group + ON "icingaweb_group" + USING btree ( + lower((name)::text) +); + + +/** + * Table "icingaweb_group_membership" + */ +CREATE TABLE "icingaweb_group_membership" ( + "group_name" character varying(64) NOT NULL, + "username" character varying(64) NOT NULL, + "ctime" timestamp NULL DEFAULT NULL, + "mtime" timestamp NULL DEFAULT NULL +); + +ALTER TABLE ONLY "icingaweb_group_membership" + ADD CONSTRAINT pk_icingaweb_group_membership + PRIMARY KEY ( + "group_name", + "username" +); + +CREATE UNIQUE INDEX idx_icingaweb_group_membership + ON "icingaweb_group_membership" + USING btree ( + lower((group_name)::text), + lower((username)::text) +); + + +/** + * Table "icingaweb_user" + */ +CREATE TABLE "icingaweb_user" ( + "name" character varying(64) NOT NULL, + "active" smallint NOT NULL, + "password_hash" bytea NOT NULL, + "ctime" timestamp NULL DEFAULT NULL, + "mtime" timestamp NULL DEFAULT NULL +); + +ALTER TABLE ONLY "icingaweb_user" + ADD CONSTRAINT pk_icingaweb_user + PRIMARY KEY ( + "name" +); + +CREATE UNIQUE INDEX idx_icingaweb_user + ON "icingaweb_user" + USING btree ( + lower((name)::text) +); + + +/** + * Table "icingaweb_user_preference" + */ +CREATE TABLE "icingaweb_user_preference" ( + "username" character varying(64) NOT NULL, + "name" character varying(64) NOT NULL, + "section" character varying(64) NOT NULL, + "value" character varying(255) NOT NULL, + "ctime" timestamp NULL DEFAULT NULL, + "mtime" timestamp NULL DEFAULT NULL +); + +ALTER TABLE ONLY "icingaweb_user_preference" + ADD CONSTRAINT pk_icingaweb_user_preference + PRIMARY KEY ( + "username", + "section", + "name" +); + +CREATE UNIQUE INDEX idx_icingaweb_user_preference + ON "icingaweb_user_preference" + USING btree ( + lower((username)::text), + lower((section)::text), + lower((name)::text) +); \ No newline at end of file diff --git a/etc/schema/preferences.mysql.sql b/etc/schema/preferences.mysql.sql deleted file mode 100644 index 5549daa3f..000000000 --- a/etc/schema/preferences.mysql.sql +++ /dev/null @@ -1,6 +0,0 @@ -create table `preference`( - `username` VARCHAR(255) COLLATE latin1_general_ci NOT NULL, - `key` VARCHAR(100) COLLATE latin1_general_ci NOT NULL, - `value` VARCHAR(255) NOT NULL, - PRIMARY KEY (`username`, `key`) -) ENGINE=InnoDB; \ No newline at end of file diff --git a/etc/schema/preferences.pgsql.sql b/etc/schema/preferences.pgsql.sql deleted file mode 100644 index 8b694f0a0..000000000 --- a/etc/schema/preferences.pgsql.sql +++ /dev/null @@ -1,10 +0,0 @@ -create table "preference"( - "username" VARCHAR(255) NOT NULL, - "key" VARCHAR(100) NOT NULL, - "value" VARCHAR(255) NOT NULL -); - -ALTER TABLE ONLY "preference" - ADD CONSTRAINT preference_pkey PRIMARY KEY ("username", "key"); - -CREATE UNIQUE INDEX username_and_key_lower_unique_idx ON "preference" USING btree (lower((username)::text), lower((key)::text)); \ No newline at end of file diff --git a/icingaweb2.spec b/icingaweb2.spec index db0929f7b..fb628f995 100644 --- a/icingaweb2.spec +++ b/icingaweb2.spec @@ -31,7 +31,7 @@ %define prefixdir %{_datadir}/%{name} %define usermodparam -a -G %define logdir %{_localstatedir}/log/%{name} -%define docdir %{sharedir}/log +%define docdir %{sharedir}/doc %if "%{_vendor}" == "suse" %define phpname php5 @@ -167,7 +167,7 @@ Icinga Web 2 PHP Libraries required by the web frontend and cli tool. # prepare configuration for sub packages # install rhel apache config -install -D -m0644 packages/rpm/etc/httpd/conf.d/icingaweb.conf %{buildroot}/%{apacheconfdir}/icingaweb.conf +install -D -m0644 packages/files/apache/icingaweb.conf %{buildroot}/%{apacheconfdir}/icingaweb.conf # install public, library, modules %{__mkdir} -p %{buildroot}/%{sharedir} @@ -179,23 +179,16 @@ install -D -m0644 packages/rpm/etc/httpd/conf.d/icingaweb.conf %{buildroot}/%{ap %{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/modules/monitoring %{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/enabledModules -%{__cp} -r application doc library modules public %{buildroot}/%{sharedir}/ - -## config -# authentication is db only -install -D -m0644 packages/rpm/etc/%{name}/authentication.ini %{buildroot}/%{_sysconfdir}/%{name}/authentication.ini -# custom resource paths -install -D -m0644 packages/rpm/etc/%{name}/resources.ini %{buildroot}/%{_sysconfdir}/%{name}/resources.ini -# monitoring module (icinga2) -install -D -m0644 packages/rpm/etc/%{name}/modules/monitoring/backends.ini %{buildroot}/%{_sysconfdir}/%{name}/modules/monitoring/backends.ini -install -D -m0644 packages/rpm/etc/%{name}/modules/monitoring/instances.ini %{buildroot}/%{_sysconfdir}/%{name}/modules/monitoring/instances.ini +# make sure to install local icingacli for setup wizard token generation & webserver config +%{__cp} -r application doc library modules public bin %{buildroot}/%{sharedir}/ # enable the monitoring module by default ln -s %{sharedir}/modules/monitoring %{buildroot}/%{_sysconfdir}/%{name}/enabledModules/monitoring ## config -# install icingacli -install -D -m0755 packages/rpm/usr/bin/icingacli %{buildroot}/usr/bin/icingacli +# symlink icingacli +mkdir -p %{buildroot}/usr/bin +ln -sf %{sharedir}/bin/icingacli %{buildroot}/usr/bin/icingacli %pre # Add apacheuser in the icingacmd group @@ -220,7 +213,7 @@ fi %files # main dirs %defattr(-,root,root) -%doc etc/schema doc packages/rpm/README.md +%doc etc/schema doc packages/RPM.md %attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/public %attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/modules # configs @@ -238,5 +231,7 @@ fi %files -n icingacli %attr(0755,root,root) /usr/bin/icingacli +%attr(0755,root,root) %{sharedir}/bin/icingacli +%attr(0755,root,root) %{sharedir}/bin/license_writer.py %changelog diff --git a/install-sh b/install-sh deleted file mode 100755 index 6781b987b..000000000 --- a/install-sh +++ /dev/null @@ -1,520 +0,0 @@ -#!/bin/sh -# install - install a program, script, or datafile - -scriptversion=2009-04-28.21; # UTC - -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. - -nl=' -' -IFS=" "" $nl" - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit=${DOITPROG-} -if test -z "$doit"; then - doit_exec=exec -else - doit_exec=$doit -fi - -# Put in absolute file names if you don't have them in your path; -# or use environment vars. - -chgrpprog=${CHGRPPROG-chgrp} -chmodprog=${CHMODPROG-chmod} -chownprog=${CHOWNPROG-chown} -cmpprog=${CMPPROG-cmp} -cpprog=${CPPROG-cp} -mkdirprog=${MKDIRPROG-mkdir} -mvprog=${MVPROG-mv} -rmprog=${RMPROG-rm} -stripprog=${STRIPPROG-strip} - -posix_glob='?' -initialize_posix_glob=' - test "$posix_glob" != "?" || { - if (set -f) 2>/dev/null; then - posix_glob= - else - posix_glob=: - fi - } -' - -posix_mkdir= - -# Desired mode of installed file. -mode=0755 - -chgrpcmd= -chmodcmd=$chmodprog -chowncmd= -mvcmd=$mvprog -rmcmd="$rmprog -f" -stripcmd= - -src= -dst= -dir_arg= -dst_arg= - -copy_on_change=false -no_target_directory= - -usage="\ -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE - or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 [OPTION]... -t DIRECTORY SRCFILES... - or: $0 [OPTION]... -d DIRECTORIES... - -In the 1st form, copy SRCFILE to DSTFILE. -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. -In the 4th, create DIRECTORIES. - -Options: - --help display this help and exit. - --version display version info and exit. - - -c (ignored) - -C install only if different (preserve the last data modification time) - -d create directories instead of installing files. - -g GROUP $chgrpprog installed files to GROUP. - -m MODE $chmodprog installed files to MODE. - -o USER $chownprog installed files to USER. - -s $stripprog installed files. - -t DIRECTORY install into DIRECTORY. - -T report an error if DSTFILE is a directory. - -Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG - RMPROG STRIPPROG -" - -while test $# -ne 0; do - case $1 in - -c) ;; - - -C) copy_on_change=true;; - - -d) dir_arg=true;; - - -g) chgrpcmd="$chgrpprog $2" - shift;; - - --help) echo "$usage"; exit $?;; - - -m) mode=$2 - case $mode in - *' '* | *' '* | *' -'* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; - - -o) chowncmd="$chownprog $2" - shift;; - - -s) stripcmd=$stripprog;; - - -t) dst_arg=$2 - shift;; - - -T) no_target_directory=true;; - - --version) echo "$0 $scriptversion"; exit $?;; - - --) shift - break;; - - -*) echo "$0: invalid option: $1" >&2 - exit 1;; - - *) break;; - esac - shift -done - -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then - # When -d is used, all remaining arguments are directories to create. - # When -t is used, the destination is already specified. - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dst_arg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dst_arg" - shift # fnord - fi - shift # arg - dst_arg=$arg - done -fi - -if test $# -eq 0; then - if test -z "$dir_arg"; then - echo "$0: no input file specified." >&2 - exit 1 - fi - # It's OK to call `install-sh -d' without argument. - # This can happen when creating conditional directories. - exit 0 -fi - -if test -z "$dir_arg"; then - trap '(exit $?); exit' 1 2 13 15 - - # Set umask so as not to create temps with too-generous modes. - # However, 'strip' requires both read and write access to temps. - case $mode in - # Optimize common cases. - *644) cp_umask=133;; - *755) cp_umask=22;; - - *[0-7]) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw='% 200' - fi - cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; - *) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw=,u+rw - fi - cp_umask=$mode$u_plus_rw;; - esac -fi - -for src -do - # Protect names starting with `-'. - case $src in - -*) src=./$src;; - esac - - if test -n "$dir_arg"; then - dst=$src - dstdir=$dst - test -d "$dstdir" - dstdir_status=$? - else - - # Waiting for this to be detected by the "$cpprog $src $dsttmp" command - # might cause directories to be created, which would be especially bad - # if $src (and thus $dsttmp) contains '*'. - if test ! -f "$src" && test ! -d "$src"; then - echo "$0: $src does not exist." >&2 - exit 1 - fi - - if test -z "$dst_arg"; then - echo "$0: no destination specified." >&2 - exit 1 - fi - - dst=$dst_arg - # Protect names starting with `-'. - case $dst in - -*) dst=./$dst;; - esac - - # If destination is a directory, append the input filename; won't work - # if double slashes aren't ignored. - if test -d "$dst"; then - if test -n "$no_target_directory"; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 - fi - dstdir=$dst - dst=$dstdir/`basename "$src"` - dstdir_status=0 - else - # Prefer dirname, but fall back on a substitute if dirname fails. - dstdir=` - (dirname "$dst") 2>/dev/null || - expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$dst" : 'X\(//\)[^/]' \| \ - X"$dst" : 'X\(//\)$' \| \ - X"$dst" : 'X\(/\)' \| . 2>/dev/null || - echo X"$dst" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q' - ` - - test -d "$dstdir" - dstdir_status=$? - fi - fi - - obsolete_mkdir_used=false - - if test $dstdir_status != 0; then - case $posix_mkdir in - '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 - - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writeable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; - esac - - if - $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" - ) - then : - else - - # The umask is ridiculous, or mkdir does not conform to POSIX, - # or it failed possibly due to a race condition. Create the - # directory the slow way, step by step, checking for races as we go. - - case $dstdir in - /*) prefix='/';; - -*) prefix='./';; - *) prefix='';; - esac - - eval "$initialize_posix_glob" - - oIFS=$IFS - IFS=/ - $posix_glob set -f - set fnord $dstdir - shift - $posix_glob set +f - IFS=$oIFS - - prefixes= - - for d - do - test -z "$d" && continue - - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ - done - - if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true - fi - fi - fi - - if test -n "$dir_arg"; then - { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && - { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || - test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 - else - - # Make a couple of temp file names in the proper directory. - dsttmp=$dstdir/_inst.$$_ - rmtmp=$dstdir/_rm.$$_ - - # Trap to clean up those temp files at exit. - trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - - # Copy the file name to the temp name. - (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && - - # and set any options; do chmod last to preserve setuid bits. - # - # If any of these fail, we abort the whole thing. If we want to - # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $cpprog $src $dsttmp" command. - # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && - { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && - { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && - - # If -C, don't bother to copy if it wouldn't change the file. - if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - - eval "$initialize_posix_glob" && - $posix_glob set -f && - set X $old && old=:$2:$4:$5:$6 && - set X $new && new=:$2:$4:$5:$6 && - $posix_glob set +f && - - test "$old" = "$new" && - $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 - then - rm -f "$dsttmp" - else - # Rename the file to the real destination. - $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || - - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" - } - fi || exit 1 - - trap '' 0 - fi -done - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" -# time-stamp-end: "; # UTC" -# End: diff --git a/library/Icinga/Application/ApplicationBootstrap.php b/library/Icinga/Application/ApplicationBootstrap.php index 958642940..7f1667e5b 100644 --- a/library/Icinga/Application/ApplicationBootstrap.php +++ b/library/Icinga/Application/ApplicationBootstrap.php @@ -6,12 +6,13 @@ namespace Icinga\Application; use ErrorException; use Exception; -use Zend_Config; +use LogicException; use Icinga\Application\Modules\Manager as ModuleManager; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Exception\ConfigurationError; use Icinga\Exception\NotReadableError; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\Util\DateTimeFactory; use Icinga\Util\Translator; use Icinga\Exception\IcingaException; @@ -40,6 +41,43 @@ use Icinga\Exception\IcingaException; */ abstract class ApplicationBootstrap { + /** + * Base directory + * + * Parent folder for at least application, bin, modules, library/vendor and public + * + * @var string + */ + protected $baseDir; + + /** + * Application directory + * + * @var string + */ + protected $appDir; + + /** + * Vendor library directory + * + * @var string + */ + protected $vendorDir; + + /** + * Library directory + * + * @var string + */ + protected $libDir; + + /** + * Configuration directory + * + * @var string + */ + protected $configDir; + /** * Icinga auto loader * @@ -47,34 +85,13 @@ abstract class ApplicationBootstrap */ private $loader; - /** - * Library directory - * - * @var string - */ - private $libDir; - /** * Config object * - * @var Zend_Config + * @var Config */ protected $config; - /** - * Configuration directory - * - * @var string - */ - private $configDir; - - /** - * Application directory - * - * @var string - */ - private $appDir; - /** * Module manager * @@ -98,27 +115,20 @@ abstract class ApplicationBootstrap /** * Constructor + * + * @param string $baseDir Icinga Web 2 base directory + * @param string $configDir Path to Icinga Web 2's configuration files */ - protected function __construct($configDir = null) + protected function __construct($baseDir = null, $configDir = null) { + if ($baseDir === null) { + $baseDir = dirname($this->getBootstrapDirectory()); + } + $this->baseDir = $baseDir; + $this->appDir = $baseDir . '/application'; + $this->vendorDir = $baseDir . '/library/vendor'; $this->libDir = realpath(__DIR__ . '/../..'); - if (!defined('ICINGA_LIBDIR')) { - define('ICINGA_LIBDIR', $this->libDir); - } - - if (defined('ICINGAWEB_APPDIR')) { - $this->appDir = ICINGAWEB_APPDIR; - } elseif (array_key_exists('ICINGAWEB_APPDIR', $_SERVER)) { - $this->appDir = $_SERVER['ICINGAWEB_APPDIR']; - } else { - $this->appDir = realpath($this->libDir. '/../application'); - } - - if (!defined('ICINGAWEB_APPDIR')) { - define('ICINGAWEB_APPDIR', $this->appDir); - } - if ($configDir === null) { if (array_key_exists('ICINGAWEB_CONFIGDIR', $_SERVER)) { $configDir = $_SERVER['ICINGAWEB_CONFIGDIR']; @@ -130,7 +140,13 @@ abstract class ApplicationBootstrap $this->configDir = $canonical ? $canonical : $configDir; $this->setupAutoloader(); - $this->setupZendAutoloader(); + + set_include_path( + implode( + PATH_SEPARATOR, + array($this->vendorDir, get_include_path()) + ) + ); Benchmark::measure('Bootstrap, autoloader registered'); @@ -196,44 +212,6 @@ abstract class ApplicationBootstrap return $this->isWeb; } - /** - * Getter for application dir - * - * Optional append sub directory - * - * @param string $subdir optional subdir - * - * @return string - */ - public function getApplicationDir($subdir = null) - { - return $this->getDirWithSubDir($this->appDir, $subdir); - } - - /** - * Getter for config dir - * - * @param string $subdir - * - * @return string - */ - public function getConfigDir($subdir = null) - { - return $this->getDirWithSubDir($this->configDir, $subdir); - } - - /** - * Get the path to the bootstrapping directory. - * - * This is usually /public for Web and EmbeddedWeb - * - * @return string - */ - public function getBootstrapDirecory() - { - return dirname($_SERVER['SCRIPT_FILENAME']); - } - /** * Helper to glue directories together * @@ -252,15 +230,102 @@ abstract class ApplicationBootstrap } /** - * Starting concrete bootstrap classes + * Get the base directory * - * @param string $configDir + * @param string $subDir Optional sub directory to get * - * @return ApplicationBootstrap + * @return string */ - public static function start($configDir = null) + public function getBaseDir($subDir = null) { - $application = new static($configDir); + return $this->getDirWithSubDir($this->baseDir, $subDir); + } + + /** + * Get the application directory + * + * @param string $subDir Optional sub directory to get + * + * @return string + */ + public function getApplicationDir($subDir = null) + { + return $this->getDirWithSubDir($this->appDir, $subDir); + } + + /** + * Get the vendor library directory + * + * @param string $subDir Optional sub directory to get + * + * @return string + */ + public function getVendorDir($subDir = null) + { + return $this->getDirWithSubDir($this->vendorDir, $subDir); + } + + /** + * Get the configuration directory + * + * @param string $subDir Optional sub directory to get + * + * @return string + */ + public function getConfigDir($subDir = null) + { + return $this->getDirWithSubDir($this->configDir, $subDir); + } + + /** + * Get the Icinga library directory + * + * @param string $subDir Optional sub directory to get + * + * @return string + */ + public function getLibraryDir($subDir = null) + { + return $this->getDirWithSubDir($this->libDir, $subDir); + } + + /** + * Get the path to the bootstrapping directory + * + * This is usually /public for Web and EmbeddedWeb and /bin for the CLI + * + * @return string + * + * @throws LogicException If the base directory can not be detected + */ + public function getBootstrapDirectory() + { + $script = $_SERVER['SCRIPT_FILENAME']; + $canonical = realpath($script); + if ($canonical !== false) { + $dir = dirname($canonical); + } elseif (substr($script, -14) === '/webrouter.php') { + // If Icinga Web 2 is served using PHP's built-in webserver with our webrouter.php script, the $_SERVER + // variable SCRIPT_FILENAME is set to DOCUMENT_ROOT/webrouter.php which is not a valid path to + // realpath but DOCUMENT_ROOT here still is the bootstrapping directory + $dir = dirname($script); + } else { + throw new LogicException('Can\'t detected base directory'); + } + return $dir; + } + + /** + * Start the bootstrap + * + * @param string $baseDir Icinga Web 2 base directory + * @param string $configDir Path to Icinga Web 2's configuration files + * + * @return static + */ + public static function start($baseDir = null, $configDir = null) + { + $application = new static($baseDir, $configDir); $application->bootstrap(); return $application; } @@ -284,7 +349,7 @@ abstract class ApplicationBootstrap /** * Register the Zend Autoloader * - * @return self + * @return $this */ protected function setupZendAutoloader() { @@ -292,17 +357,12 @@ abstract class ApplicationBootstrap \Zend_Loader_Autoloader::getInstance(); - // Unfortunately this is needed to get the Zend Plugin loader working: - set_include_path( - implode( - PATH_SEPARATOR, - array($this->libDir, get_include_path()) - ) + \Zend_Paginator::addScrollingStylePrefixPath( + 'Icinga_Web_Paginator_ScrollingStyle_', $this->libDir . '/Icinga/Web/Paginator/ScrollingStyle' ); return $this; } - /** * Setup module manager * @@ -313,16 +373,26 @@ abstract class ApplicationBootstrap $this->moduleManager = new ModuleManager( $this, $this->configDir . '/enabledModules', - explode( - ':', - $this->config->global !== null - ? $this->config->global->get('modulePath', ICINGAWEB_APPDIR . '/../modules') - : ICINGAWEB_APPDIR . '/../modules' - ) + explode(':', $this->config->get('global', 'module_path', $this->baseDir . '/modules')) ); return $this; } + /** + * Load all core modules + * + * @return self + */ + protected function loadCoreModules() + { + try { + $this->moduleManager->loadCoreModules(); + } catch (NotReadableError $e) { + Logger::error(new IcingaException('Cannot load core modules. An exception was thrown:', $e)); + } + return $this; + } + /** * Load all enabled modules * @@ -346,7 +416,7 @@ abstract class ApplicationBootstrap protected function setupLogging() { Logger::create( - new Zend_Config( + new ConfigObject( array( 'log' => 'syslog' ) @@ -363,12 +433,14 @@ abstract class ApplicationBootstrap protected function loadConfig() { Config::$configDir = $this->configDir; + try { $this->config = Config::app(); } catch (NotReadableError $e) { Logger::error(new IcingaException('Cannot load application configuration. An exception was thrown:', $e)); - $this->config = new Zend_Config(array()); + $this->config = new Config(); } + return $this; } @@ -388,6 +460,8 @@ abstract class ApplicationBootstrap return false; // Continue with the normal error handler } switch($errno) { + case E_NOTICE: + case E_WARNING: case E_STRICT: throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } @@ -403,9 +477,9 @@ abstract class ApplicationBootstrap */ protected function setupLogger() { - if ($this->config->logging !== null) { + if ($this->config->hasSection('logging')) { try { - Logger::create($this->config->logging); + Logger::create($this->config->getSection('logging')); } catch (ConfigurationError $e) { Logger::error($e); } @@ -433,42 +507,62 @@ abstract class ApplicationBootstrap } /** - * Setup default timezone + * Detect the timezone * - * @return self - * @throws ConfigurationError if the timezone in config.ini isn't valid + * @return null|string */ - protected function setupTimezone() + protected function detectTimezone() { - $default = @date_default_timezone_get(); - if (! $default) { - $default = 'UTC'; + return null; + } + + /** + * Set up the timezone + * + * @return $this + */ + protected final function setupTimezone() + { + $timezone = $this->detectTimeZone(); + if ($timezone === null || @date_default_timezone_set($timezone) === false) { + $timezone = @date_default_timezone_get(); + if ($timezone === false) { + $timezone = 'UTC'; + date_default_timezone_set($timezone); + } } - $timeZoneString = $this->config->global !== null ? $this->config->global->get('timezone', $default) : $default; - date_default_timezone_set($timeZoneString); - DateTimeFactory::setConfig(array('timezone' => $timeZoneString)); + DateTimeFactory::setConfig(array('timezone' => $timezone)); return $this; } /** - * Setup internationalization using gettext + * Detect the locale * - * Uses the preferred language sent by the browser or the default one - * - * @return self + * @return null|string */ - protected function setupInternationalization() + protected function detectLocale() + { + return null; + } + + /** + * Set up internationalization using gettext + * + * @return $this + */ + protected final function setupInternationalization() { if ($this->hasLocales()) { Translator::registerDomain(Translator::DEFAULT_DOMAIN, $this->getLocaleDir()); } + $locale = $this->detectLocale(); + if ($locale === null) { + $locale = Translator::DEFAULT_LOCALE; + } + try { - Translator::setupLocale( - isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) - ? Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']) - : Translator::DEFAULT_LOCALE - ); + Translator::setupLocale($locale); } catch (Exception $error) { Logger::error($error); } diff --git a/library/Icinga/Application/Cli.php b/library/Icinga/Application/Cli.php index d329ce439..abf46262f 100644 --- a/library/Icinga/Application/Cli.php +++ b/library/Icinga/Application/Cli.php @@ -9,10 +9,10 @@ use Icinga\Application\ApplicationBootstrap; use Icinga\Cli\Params; use Icinga\Cli\Loader; use Icinga\Cli\Screen; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\Application\Benchmark; +use Icinga\Data\ConfigObject; use Icinga\Exception\ProgrammingError; -use Zend_Config; require_once __DIR__ . '/ApplicationBootstrap.php'; @@ -43,17 +43,17 @@ class Cli extends ApplicationBootstrap ->parseBasicParams() ->setupLogger() ->setupResourceFactory() - ->setupModuleManager(); + ->setupModuleManager() + ->loadCoreModules(); } protected function setupLogging() { Logger::create( - new Zend_Config( + new ConfigObject( array( 'level' => Logger::INFO, - 'log' => 'file', - 'file' => 'php://stderr' + 'log' => 'stdout', ) ) ); diff --git a/library/Icinga/Application/Config.php b/library/Icinga/Application/Config.php index c7998a0bb..dcb837fde 100644 --- a/library/Icinga/Application/Config.php +++ b/library/Icinga/Application/Config.php @@ -4,14 +4,16 @@ namespace Icinga\Application; -use Zend_Config; -use Zend_Config_Ini; +use Iterator; +use Countable; +use UnexpectedValueException; +use Icinga\Data\ConfigObject; use Icinga\Exception\NotReadableError; /** - * Global registry of application and module configuration. + * Container for INI like configuration and global registry of application and module related configuration. */ -class Config extends Zend_Config +class Config implements Countable, Iterator { /** * Configuration directory where ALL (application and module) configuration is located @@ -20,13 +22,6 @@ class Config extends Zend_Config */ public static $configDir; - /** - * The INI file this configuration has been loaded from or should be written to - * - * @var string - */ - protected $configFile; - /** * Application config instances per file * @@ -42,96 +37,27 @@ class Config extends Zend_Config protected static $modules = array(); /** - * Load configuration from the given INI file + * The internal ConfigObject * - * @param string $file The file to parse - * - * @throws NotReadableError When the file does not exist or cannot be read + * @var ConfigObject */ - public static function fromIni($file) - { - $config = new static(array(), true); - $filepath = realpath($file); - - if ($filepath === false) { - $config->setConfigFile($file); - } elseif (is_readable($filepath)) { - $config->setConfigFile($filepath); - $config->merge(new Zend_Config_Ini($filepath)); - } else { - throw new NotReadableError('Cannot read config file "%s". Permission denied', $filepath); - } - - return $config; - } + protected $config; /** - * Retrieve a application config instance + * The INI file this config has been loaded from or should be written to * - * @param string $configname The configuration name (without ini suffix) to read and return - * @param bool $fromDisk When set true, the configuration will be read from the disk, even - * if it already has been read - * - * @return Config The configuration object that has been requested + * @var string */ - public static function app($configname = 'config', $fromDisk = false) - { - if (!isset(self::$app[$configname]) || $fromDisk) { - self::$app[$configname] = Config::fromIni(self::resolvePath($configname . '.ini')); - } - return self::$app[$configname]; - } + protected $configFile; /** - * Set module config + * Create a new config * - * @param string $moduleName - * @param string $configName - * @param Zend_Config $config + * @param ConfigObject $config The config object to handle */ - public static function setModuleConfig($moduleName, $configName, Zend_Config $config) + public function __construct(ConfigObject $config = null) { - self::$modules[$moduleName][$configName] = $config; - } - - /** - * Retrieve a module config instance - * - * @param string $modulename The name of the module to look for configurations - * @param string $configname The configuration name (without ini suffix) to read and return - * @param string $fromDisk Whether to read the configuration from disk - * - * @return Config The configuration object that has been requested - */ - public static function module($modulename, $configname = 'config', $fromDisk = false) - { - if (!isset(self::$modules[$modulename])) { - self::$modules[$modulename] = array(); - } - $moduleConfigs = self::$modules[$modulename]; - if (!isset($moduleConfigs[$configname]) || $fromDisk) { - $moduleConfigs[$configname] = Config::fromIni( - self::resolvePath('modules/' . $modulename . '/' . $configname . '.ini') - ); - } - return $moduleConfigs[$configname]; - } - - /** - * Retrieve names of accessible sections or properties - * - * @param $name - * @return array - */ - public function keys($name = null) - { - if ($name === null) { - return array_keys($this->toArray()); - } elseif ($this->$name === null) { - return array(); - } else { - return array_keys($this->$name->toArray()); - } + $this->config = $config !== null ? $config : new ConfigObject(); } /** @@ -147,7 +73,7 @@ class Config extends Zend_Config /** * Set this config's file path * - * @param string $filepath The path to the config file + * @param string $filepath The path to the ini file * * @return self */ @@ -158,13 +84,274 @@ class Config extends Zend_Config } /** - * Prepend configuration base dir if input is relative + * Return the count of available sections * - * @param string $path Input path - * @return string Absolute path + * @return int + */ + public function count() + { + return $this->config->count(); + } + + /** + * Reset the current position of the internal config object + * + * @return ConfigObject + */ + public function rewind() + { + return $this->config->rewind(); + } + + /** + * Return the section of the current iteration + * + * @return ConfigObject + */ + public function current() + { + return $this->config->current(); + } + + /** + * Return whether the position of the current iteration is valid + * + * @return bool + */ + public function valid() + { + return $this->config->valid(); + } + + /** + * Return the section's name of the current iteration + * + * @return string + */ + public function key() + { + return $this->config->key(); + } + + /** + * Advance the position of the current iteration and return the new section + * + * @return ConfigObject + */ + public function next() + { + return $this->config->next(); + } + + /** + * Return whether this config has any sections + * + * @return bool + */ + public function isEmpty() + { + return $this->config->isEmpty(); + } + + /** + * Return this config's section names + * + * @return array + */ + public function keys() + { + return $this->config->keys(); + } + + /** + * Return this config's data as associative array + * + * @return array + */ + public function toArray() + { + return $this->config->toArray(); + } + + /** + * Return the value from a section's property + * + * @param string $section The section where the given property can be found + * @param string $key The section's property to fetch the value from + * @param mixed $default The value to return in case the section or the property is missing + * + * @return mixed + * + * @throws UnexpectedValueException In case the given section does not hold any configuration + */ + public function get($section, $key, $default = null) + { + $value = $this->config->$section; + if ($value instanceof ConfigObject) { + $value = $value->$key; + } elseif ($value !== null) { + throw new UnexpectedValueException( + sprintf('Value "%s" is not of type "%s" or a sub-type of it', $value, get_class($this->config)) + ); + } + + if ($value === null && $default !== null) { + $value = $default; + } + + return $value; + } + + /** + * Return the given section + * + * @param string $name The section's name + * + * @return ConfigObject + */ + public function getSection($name) + { + $section = $this->config->get($name); + return $section !== null ? $section : new ConfigObject(); + } + + /** + * Set or replace a section + * + * @param string $name + * @param array|ConfigObject $config + * + * @return self + */ + public function setSection($name, $config = null) + { + if ($config === null) { + $config = new ConfigObject(); + } elseif (! $config instanceof ConfigObject) { + $config = new ConfigObject($config); + } + + $this->config->$name = $config; + return $this; + } + + /** + * Remove a section + * + * @param string $name + * + * @return self + */ + public function removeSection($name) + { + unset($this->config->$name); + return $this; + } + + /** + * Return whether the given section exists + * + * @param string $name + * + * @return bool + */ + public function hasSection($name) + { + return isset($this->config->$name); + } + + /** + * Initialize a new config using the given array + * + * The returned config has no file associated to it. + * + * @param array $array The array to initialize the config with + * + * @return Config + */ + public static function fromArray(array $array) + { + return new static(new ConfigObject($array)); + } + + /** + * Load configuration from the given INI file + * + * @param string $file The file to parse + * + * @throws NotReadableError When the file does not exist or cannot be read + */ + public static function fromIni($file) + { + $emptyConfig = new static(); + + $filepath = realpath($file); + if ($filepath === false) { + $emptyConfig->setConfigFile($file); + } elseif (is_readable($filepath)) { + $config = new static(new ConfigObject(parse_ini_file($filepath, true))); + $config->setConfigFile($filepath); + return $config; + } else { + throw new NotReadableError(t('Cannot read config file "%s". Permission denied'), $filepath); + } + + return $emptyConfig; + } + + /** + * Prepend configuration base dir to the given relative path + * + * @param string $path A relative path + * + * @return string */ public static function resolvePath($path) { return self::$configDir . DIRECTORY_SEPARATOR . ltrim($path, DIRECTORY_SEPARATOR); } + + /** + * Retrieve a application config + * + * @param string $configname The configuration name (without ini suffix) to read and return + * @param bool $fromDisk When set true, the configuration will be read from disk, even + * if it already has been read + * + * @return Config The requested configuration + */ + public static function app($configname = 'config', $fromDisk = false) + { + if (!isset(self::$app[$configname]) || $fromDisk) { + self::$app[$configname] = static::fromIni(static::resolvePath($configname . '.ini')); + } + + return self::$app[$configname]; + } + + /** + * Retrieve a module config + * + * @param string $modulename The name of the module where to look for the requested configuration + * @param string $configname The configuration name (without ini suffix) to read and return + * @param string $fromDisk When set true, the configuration will be read from disk, even + * if it already has been read + * + * @return Config The requested configuration + */ + public static function module($modulename, $configname = 'config', $fromDisk = false) + { + if (!isset(self::$modules[$modulename])) { + self::$modules[$modulename] = array(); + } + + $moduleConfigs = self::$modules[$modulename]; + if (!isset($moduleConfigs[$configname]) || $fromDisk) { + $moduleConfigs[$configname] = static::fromIni( + static::resolvePath('modules/' . $modulename . '/' . $configname . '.ini') + ); + } + + return $moduleConfigs[$configname]; + } } diff --git a/library/Icinga/Application/EmbeddedWeb.php b/library/Icinga/Application/EmbeddedWeb.php index 6a160017c..23cb365f0 100644 --- a/library/Icinga/Application/EmbeddedWeb.php +++ b/library/Icinga/Application/EmbeddedWeb.php @@ -27,7 +27,9 @@ class EmbeddedWeb extends ApplicationBootstrap */ protected function bootstrap() { - return $this->loadConfig() + return $this + ->setupZendAutoloader() + ->loadConfig() ->setupErrorHandling() ->setupTimezone() ->setupModuleManager() diff --git a/library/Icinga/Logger/Logger.php b/library/Icinga/Application/Logger.php similarity index 89% rename from library/Icinga/Logger/Logger.php rename to library/Icinga/Application/Logger.php index a5458e498..70eaa774b 100644 --- a/library/Icinga/Logger/Logger.php +++ b/library/Icinga/Application/Logger.php @@ -2,13 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Logger; +namespace Icinga\Application; use Exception; -use Zend_Config; +use Icinga\Data\ConfigObject; +use Icinga\Application\Logger\Writer\FileWriter; +use Icinga\Application\Logger\Writer\SyslogWriter; use Icinga\Exception\ConfigurationError; -use Icinga\Logger\Writer\FileWriter; -use Icinga\Logger\Writer\SyslogWriter; /** * Logger @@ -57,7 +57,7 @@ class Logger /** * Log writer * - * @var \Icinga\Logger\LogWriter + * @var \Icinga\Application\Logger\LogWriter */ protected $writer; @@ -71,12 +71,12 @@ class Logger /** * Create a new logger object * - * @param Zend_Config $config + * @param ConfigObject $config * * @throws ConfigurationError If the logging configuration directive 'log' is missing or if the logging level is * not defined */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { if ($config->log === null) { throw new ConfigurationError('Required logging configuration directive \'log\' missing'); @@ -118,11 +118,11 @@ class Logger /** * Create a new logger object * - * @param Zend_Config $config + * @param ConfigObject $config * * @return static */ - public static function create(Zend_Config $config) + public static function create(ConfigObject $config) { static::$instance = new static($config); return static::$instance; @@ -131,14 +131,14 @@ class Logger /** * Create a log writer * - * @param Zend_Config $config The configuration to initialize the writer with + * @param ConfigObject $config The configuration to initialize the writer with * - * @return \Icinga\Logger\LogWriter The requested log writer - * @throws ConfigurationError If the requested writer cannot be found + * @return \Icinga\Application\Logger\LogWriter The requested log writer + * @throws ConfigurationError If the requested writer cannot be found */ - protected function createWriter(Zend_Config $config) + protected function createWriter(ConfigObject $config) { - $class = 'Icinga\\Logger\\Writer\\' . ucfirst(strtolower($config->log)) . 'Writer'; + $class = 'Icinga\\Application\\Logger\\Writer\\' . ucfirst(strtolower($config->log)) . 'Writer'; if (! class_exists($class)) { throw new ConfigurationError( 'Cannot find log writer of type "%s"', @@ -258,7 +258,7 @@ class Logger /** * Get the log writer to use * - * @return \Icinga\Logger\LogWriter + * @return \Icinga\Application\Logger\LogWriter */ public function getWriter() { diff --git a/library/Icinga/Logger/LogWriter.php b/library/Icinga/Application/Logger/LogWriter.php similarity index 61% rename from library/Icinga/Logger/LogWriter.php rename to library/Icinga/Application/Logger/LogWriter.php index 3222e50be..b89fec62f 100644 --- a/library/Icinga/Logger/LogWriter.php +++ b/library/Icinga/Application/Logger/LogWriter.php @@ -2,19 +2,27 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Logger; +namespace Icinga\Application\Logger; -use Zend_Config; +use Icinga\Data\ConfigObject; /** * Abstract class for writers that write messages to a log */ abstract class LogWriter { + /** + * @var ConfigObject + */ + protected $config; + /** * Create a new log writer initialized with the given configuration */ - abstract public function __construct(Zend_Config $config); + public function __construct(ConfigObject $config) + { + $this->config = $config; + } /** * Log a message with the given severity diff --git a/library/Icinga/Logger/Writer/FileWriter.php b/library/Icinga/Application/Logger/Writer/FileWriter.php similarity index 88% rename from library/Icinga/Logger/Writer/FileWriter.php rename to library/Icinga/Application/Logger/Writer/FileWriter.php index 527358e1c..2f5a292ec 100644 --- a/library/Icinga/Logger/Writer/FileWriter.php +++ b/library/Icinga/Application/Logger/Writer/FileWriter.php @@ -2,13 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Logger\Writer; +namespace Icinga\Application\Logger\Writer; use Exception; -use Zend_Config; +use Icinga\Data\ConfigObject; +use Icinga\Application\Logger; +use Icinga\Application\Logger\LogWriter; use Icinga\Exception\ConfigurationError; -use Icinga\Logger\Logger; -use Icinga\Logger\LogWriter; use Icinga\Util\File; /** @@ -26,12 +26,12 @@ class FileWriter extends LogWriter /** * Create a new file log writer * - * @param Zend_Config $config + * @param ConfigObject $config * * @throws ConfigurationError If the configuration directive 'file' is missing or if the path to 'file' does * not exist or if writing to 'file' is not possible */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { if ($config->file === null) { throw new ConfigurationError('Required logging configuration directive \'file\' missing'); diff --git a/library/Icinga/Application/Logger/Writer/StdoutWriter.php b/library/Icinga/Application/Logger/Writer/StdoutWriter.php new file mode 100644 index 000000000..1fe929d92 --- /dev/null +++ b/library/Icinga/Application/Logger/Writer/StdoutWriter.php @@ -0,0 +1,50 @@ +screen === null) { + $this->screen = Screen::instance(); + } + return $this->screen; + } + + /** + * Log a message with the given severity + * + * @param int $severity The severity to use + * @param string $message The message to log + */ + public function log($severity, $message) + { + $color = 'black'; + switch ($severity) { + case Logger::$ERROR: + $color = 'red'; + break; + case Logger::$WARNING: + $color = 'orange'; + break; + case Logger::$INFO: + $color = 'green'; + break; + case Logger::$DEBUG: + $color = 'blue'; + break; + } + file_put_contents('php://stderr', $this->screen()->colorize($message, $color) . "\n"); + } +} diff --git a/library/Icinga/Logger/Writer/SyslogWriter.php b/library/Icinga/Application/Logger/Writer/SyslogWriter.php similarity index 84% rename from library/Icinga/Logger/Writer/SyslogWriter.php rename to library/Icinga/Application/Logger/Writer/SyslogWriter.php index f67c618d2..7a69e4cba 100644 --- a/library/Icinga/Logger/Writer/SyslogWriter.php +++ b/library/Icinga/Application/Logger/Writer/SyslogWriter.php @@ -2,11 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Logger\Writer; +namespace Icinga\Application\Logger\Writer; -use Zend_Config; -use Icinga\Logger\Logger; -use Icinga\Logger\LogWriter; +use Icinga\Data\ConfigObject; +use Icinga\Application\Logger; +use Icinga\Application\Logger\LogWriter; /** * Log to the syslog service @@ -51,9 +51,9 @@ class SyslogWriter extends LogWriter /** * Create a new syslog log writer * - * @param Zend_Config $config + * @param ConfigObject $config */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { $this->ident = $config->get('application', 'icingaweb'); $this->facility = static::$facilities['user']; diff --git a/library/Icinga/Application/Modules/Manager.php b/library/Icinga/Application/Modules/Manager.php index 60c2ee85b..6469d3929 100644 --- a/library/Icinga/Application/Modules/Manager.php +++ b/library/Icinga/Application/Modules/Manager.php @@ -6,13 +6,14 @@ namespace Icinga\Application\Modules; use Icinga\Application\ApplicationBootstrap; use Icinga\Application\Icinga; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\Data\DataArray\ArrayDatasource; use Icinga\Data\SimpleQuery; use Icinga\Exception\ConfigurationError; use Icinga\Exception\SystemPermissionException; use Icinga\Exception\ProgrammingError; use Icinga\Exception\NotReadableError; +use Icinga\Exception\NotFoundError; /** * Module manager that handles detecting, enabling and disabling of modules @@ -67,6 +68,18 @@ class Manager */ private $modulePaths = array(); + /** + * The core modules + * + * Core modules do not need to be enabled to load and cannot be disabled + * by the user. This must not be writable programmatically! + * + * @var array + */ + private $coreModules = array( + 'setup' + ); + /** * Create a new instance of the module manager * @@ -157,7 +170,21 @@ class Manager } /** - * Try to set all enabled modules in loaded sate + * Try to set all core modules in loaded state + * + * @return self + * @see Manager::loadModule() + */ + public function loadCoreModules() + { + foreach ($this->coreModules as $name) { + $this->loadModule($name); + } + return $this; + } + + /** + * Try to set all enabled modules in loaded state * * @return self * @see Manager::loadModule() @@ -202,6 +229,7 @@ class Manager * * @return self * @throws ConfigurationError When trying to enable a module that is not installed + * @throws NotFoundError In case the "enabledModules" directory does not exist * @throws SystemPermissionException When insufficient permissions for the application exist */ public function enableModule($name) @@ -211,15 +239,19 @@ class Manager 'Cannot enable module "%s". Module is not installed.', $name ); + } elseif (in_array($name, $this->coreModules)) { + return $this; } clearstatcache(true); $target = $this->installedBaseDirs[$name]; $link = $this->enableDir . '/' . $name; - if (!is_writable($this->enableDir)) { + if (! is_dir($this->enableDir)) { + throw new NotFoundError('Cannot enable module "%s". Path "%s" not found.', $name, $this->enableDir); + } elseif (!is_writable($this->enableDir)) { throw new SystemPermissionException( - 'Can not enable module "%s". Insufficient system permissions for enabling modules.', + 'Cannot enable module "%s". Insufficient system permissions for enabling modules.', $name ); } @@ -372,10 +404,9 @@ class Manager } /** - * Return an array containing all loaded modules + * Get the currently loaded modules * - * @return array - * @see Module + * @return Module[] */ public function getLoadedModules() { @@ -427,7 +458,7 @@ class Manager } $installed = $this->listInstalledModules(); - foreach ($installed as $name) { + foreach (array_diff($installed, $this->coreModules) as $name) { $info[$name] = (object) array( 'name' => $name, 'path' => $this->installedBaseDirs[$name], @@ -487,11 +518,14 @@ class Manager /** * Detect installed modules from every path provided in modulePaths * + * @param array $availableDirs Installed modules location + * * @return self */ - public function detectInstalledModules() + public function detectInstalledModules(array $availableDirs = null) { - foreach ($this->modulePaths as $basedir) { + $modulePaths = $availableDirs !== null ? $availableDirs : $this->modulePaths; + foreach ($modulePaths as $basedir) { $canonical = realpath($basedir); if ($canonical === false) { Logger::warning('Module path "%s" does not exist', $basedir); @@ -528,4 +562,14 @@ class Manager ksort($this->installedBaseDirs); return $this; } + + /** + * Get the directories where to look for installed modules + * + * @return array + */ + public function getModuleDirs() + { + return $this->modulePaths; + } } diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index b1b051a6c..8c01eb05e 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -5,19 +5,20 @@ namespace Icinga\Application\Modules; use Exception; -use Zend_Config; use Zend_Controller_Router_Route_Abstract; use Zend_Controller_Router_Route as Route; use Zend_Controller_Router_Route_Regex as RegexRoute; use Icinga\Application\ApplicationBootstrap; use Icinga\Application\Config; use Icinga\Application\Icinga; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; +use Icinga\Data\ConfigObject; use Icinga\Util\Translator; use Icinga\Web\Hook; use Icinga\Web\Menu; use Icinga\Web\Widget; use Icinga\Web\Widget\Dashboard\Pane; +use Icinga\Module\Setup\SetupWizard; use Icinga\Util\File; use Icinga\Exception\ProgrammingError; use Icinga\Exception\IcingaException; @@ -134,6 +135,13 @@ class Module */ private $configTabs = array(); + /** + * Provided setup wizard + * + * @var string + */ + private $setupWizard; + /** * Icinga application * @@ -235,7 +243,7 @@ class Module if (array_key_exists($name, $this->menuItems)) { $this->menuItems[$name]->setProperties($properties); } else { - $this->menuItems[$name] = new Menu($name, new Zend_Config($properties)); + $this->menuItems[$name] = new Menu($name, new ConfigObject($properties)); } return $this->menuItems[$name]; @@ -642,6 +650,31 @@ class Module return $tabs; } + /** + * Whether this module provides a setup wizard + * + * @return bool + */ + public function providesSetupWizard() + { + $this->launchConfigScript(); + if (class_exists($this->setupWizard)) { + $wizard = new $this->setupWizard; + return $wizard instanceof SetupWizard; + } + + return false; + } + + /** + * Return this module's setup wizard + * + * @return SetupWizard + */ + public function getSetupWizard() + { + return new $this->setupWizard; + } /** * Provide a named permission @@ -705,6 +738,19 @@ class Module return $this; } + /** + * Provide a setup wizard + * + * @param string $className The name of the class + * + * @return self + */ + protected function provideSetupWizard($className) + { + $this->setupWizard = $className; + return $this; + } + /** * Register new namespaces on the autoloader * @@ -718,7 +764,7 @@ class Module $this->app->getLoader()->registerNamespace('Icinga\\Module\\' . $moduleName, $moduleLibraryDir); if (is_dir($this->getFormDir())) { $this->app->getLoader()->registerNamespace( - 'Icinga\\Module\\' . $moduleName. '\\Form', + 'Icinga\\Module\\' . $moduleName. '\\Forms', $this->getFormDir() ); } diff --git a/library/Icinga/Application/Platform.php b/library/Icinga/Application/Platform.php index 1ca738741..259219435 100644 --- a/library/Icinga/Application/Platform.php +++ b/library/Icinga/Application/Platform.php @@ -30,6 +30,16 @@ class Platform */ protected static $fqdn; + /** + * Return the operating system's name + * + * @return string + */ + public static function getOperatingSystemName() + { + return php_uname('s'); + } + /** * Test of windows * @@ -37,7 +47,7 @@ class Platform */ public static function isWindows() { - return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; + return strtoupper(substr(self::getOperatingSystemName(), 0, 3)) === 'WIN'; } /** @@ -47,7 +57,7 @@ class Platform */ public static function isLinux() { - return strtoupper(substr(PHP_OS, 0, 5)) === 'LINUX'; + return strtoupper(substr(self::getOperatingSystemName(), 0, 5)) === 'LINUX'; } /** @@ -116,7 +126,35 @@ class Platform if (substr(self::$fqdn, 0, strlen(self::$hostname)) === self::$hostname) { self::$domain = substr(self::$fqdn, strlen(self::$hostname) + 1); } else { - self::$domain = array_shift(preg_split('~\.~', self::$hostname, 2)); + $parts = preg_split('~\.~', self::$hostname, 2); + self::$domain = array_shift($parts); + } + } + + /** + * Return the version of PHP + * + * @return string + */ + public static function getPhpVersion() + { + return phpversion(); + } + + /** + * Return the username PHP is running as + * + * @return string + */ + public static function getPhpUser() + { + if (static::isWindows()) { + return get_current_user(); // http://php.net/manual/en/function.get-current-user.php#75059 + } + + if (function_exists('posix_geteuid')) { + $userInfo = posix_getpwuid(posix_geteuid()); + return $userInfo['name']; } } @@ -131,4 +169,32 @@ class Platform { return extension_loaded($extensionName); } + + /** + * Return the value for the given PHP configuration option + * + * @param string $option The option name for which to return the value + * + * @return string|false + */ + public static function getPhpConfig($option) + { + return ini_get($option); + } + + /** + * Return whether the given Zend framework class exists + * + * @param string $name The name of the class to check + * + * @return bool + */ + public static function zendClassExists($name) + { + if (class_exists($name)) { + return true; + } + + return (@include str_replace('_', '/', $name) . '.php') !== false; + } } diff --git a/library/Icinga/Application/Web.php b/library/Icinga/Application/Web.php index 89cad22ab..37ec5138a 100644 --- a/library/Icinga/Application/Web.php +++ b/library/Icinga/Application/Web.php @@ -7,13 +7,16 @@ namespace Icinga\Application; require_once __DIR__ . '/ApplicationBootstrap.php'; use Icinga\Authentication\Manager as AuthenticationManager; +use Icinga\Authentication\Manager; use Icinga\Exception\ConfigurationError; use Icinga\Exception\NotReadableError; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\Util\TimezoneDetect; use Icinga\Web\Request; use Icinga\Web\Response; use Icinga\Web\View; +use Icinga\Web\Session\Session as BaseSession; +use Icinga\Web\Session; use Icinga\User; use Icinga\Util\Translator; use Icinga\Util\DateTimeFactory; @@ -58,6 +61,13 @@ class Web extends ApplicationBootstrap */ private $request; + /** + * Session object + * + * @var BaseSession + */ + private $session; + /** * User object * @@ -80,10 +90,12 @@ class Web extends ApplicationBootstrap protected function bootstrap() { return $this + ->setupZendAutoloader() ->setupLogging() ->setupErrorHandling() ->loadConfig() ->setupResourceFactory() + ->setupSession() ->setupUser() ->setupTimezone() ->setupLogger() @@ -92,6 +104,7 @@ class Web extends ApplicationBootstrap ->setupZendMvc() ->setupFormNamespace() ->setupModuleManager() + ->loadCoreModules() ->loadEnabledModules() ->setupRoute() ->setupPagination(); @@ -163,6 +176,7 @@ class Web extends ApplicationBootstrap $this->setupFrontController(); $this->setupViewRenderer(); + return $this; } @@ -182,6 +196,17 @@ class Web extends ApplicationBootstrap return $this; } + /** + * Initialize a session provider + * + * @return self + */ + private function setupSession() + { + $this->session = Session::create(); + return $this; + } + /** * Inject dependencies into request * @@ -234,9 +259,7 @@ class Web extends ApplicationBootstrap $view->view->addHelperPath($this->getApplicationDir('/views/helpers')); $view->view->setEncoding('UTF-8'); - $view->view->headTitle()->prepend( - $this->config->global !== null ? $this->config->global->get('project', 'Icinga') : 'Icinga' - ); + $view->view->headTitle()->prepend($this->config->get('global', 'project', 'Icinga')); $view->view->headTitle()->setSeparator(' :: '); @@ -267,29 +290,19 @@ class Web extends ApplicationBootstrap } /** - * Setup user timezone if set and valid, otherwise global default timezone - * - * @return self - * @see ApplicationBootstrap::setupTimezone + * (non-PHPDoc) + * @see ApplicationBootstrap::detectTimezone() For the method documentation. */ - protected function setupTimezone() + protected function detectTimezone() { - $userTimezone = null; - - if ($this->user !== null && $this->user->getPreferences() !== null) { + $auth = Manager::getInstance(); + if (! $auth->isAuthenticated() + || ($timezone = $auth->getUser()->getPreferences()->getValue('icingaweb', 'timezone')) === null + ) { $detect = new TimezoneDetect(); - $userTimezone = $this->user->getPreferences() - ->getValue('icingaweb', 'timezone', $detect->getTimezoneName()); + $timezone = $detect->getTimezoneName(); } - - try { - DateTimeFactory::setConfig(array('timezone' => $userTimezone)); - date_default_timezone_set($userTimezone); - } catch (ConfigurationError $e) { - return parent::setupTimezone(); - } - - return $this; + return $timezone; } /** @@ -299,35 +312,30 @@ class Web extends ApplicationBootstrap * * @return self */ - protected function setupInternationalization() + protected function detectLocale() { - parent::setupInternationalization(); - if ($this->user !== null && $this->user->getPreferences() !== null - && (($locale = $this->user->getPreferences()->getValue('icingaweb', 'language')) !== null) + $auth = Manager::getInstance(); + if (! $auth->isAuthenticated() + || ($locale = $auth->getUser()->getPreferences()->getValue('icingaweb', 'language')) === null + && isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ) { - try { - Translator::setupLocale($locale); - } catch (Exception $error) { - Logger::warning( - 'Cannot set locale "' . $locale . '" configured in ' . - 'preferences of user "' . $this->user->getUsername() . '"' - ); - } + $locale = Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']); } - return $this; + return $locale; } /** - * Setup an autoloader namespace for Icinga\Form + * Setup an autoloader namespace for Icinga\Forms * * @return self */ private function setupFormNamespace() { $this->getLoader()->registerNamespace( - 'Icinga\\Form', + 'Icinga\\Forms', $this->getApplicationDir('forms') ); return $this; } } +// @codeCoverageIgnoreEnd diff --git a/library/Icinga/Authentication/AdmissionLoader.php b/library/Icinga/Authentication/AdmissionLoader.php index 50624003c..d97fc534e 100644 --- a/library/Icinga/Authentication/AdmissionLoader.php +++ b/library/Icinga/Authentication/AdmissionLoader.php @@ -5,7 +5,9 @@ namespace Icinga\Authentication; use Icinga\Application\Config; +use Icinga\Application\Logger; use Icinga\Exception\NotReadableError; +use Icinga\Data\ConfigObject; use Icinga\User; use Icinga\Util\String; @@ -15,13 +17,13 @@ use Icinga\Util\String; class AdmissionLoader { /** - * @param string $username - * @param array $userGroups - * @param mixed $section + * @param string $username + * @param array $userGroups + * @param ConfigObject $section * * @return bool */ - protected function match($username, $userGroups, $section) + protected function match($username, $userGroups, ConfigObject $section) { $username = strtolower($username); if (! empty($section->users)) { @@ -42,72 +44,46 @@ class AdmissionLoader } /** - * Get user permissions + * Get user permissions and restrictions * - * @param User $user + * @param User $user * * @return array */ - public function getPermissions(User $user) + public function getPermissionsAndRestrictions(User $user) { $permissions = array(); + $restrictions = array(); + $username = $user->getUsername(); try { - $config = Config::app('permissions'); + $roles = Config::app('roles'); } catch (NotReadableError $e) { Logger::error( - 'Can\'t get permissions for user \'%s\'. An exception was thrown:', - $user->getUsername(), + 'Can\'t get permissions and restrictions for user \'%s\'. An exception was thrown:', + $username, $e ); - return $permissions; + return array($permissions, $restrictions); } - $username = $user->getUsername(); $userGroups = $user->getGroups(); - foreach ($config as $section) { - if (! empty($section->permissions) - && $this->match($username, $userGroups, $section) - ) { + foreach ($roles as $role) { + if ($this->match($username, $userGroups, $role)) { $permissions = array_merge( $permissions, - array_diff(String::trimSplit($section->permissions), $permissions) + array_diff(String::trimSplit($role->permissions), $permissions) ); + $restrictionsFromRole = $role->toArray(); + unset($restrictionsFromRole['users']); + unset($restrictionsFromRole['groups']); + unset($restrictionsFromRole['permissions']); + foreach ($restrictionsFromRole as $name => $restriction) { + if (! isset($restrictions[$name])) { + $restrictions[$name] = array(); + } + $restrictions[$name][] = $restriction; + } } } - return $permissions; - } - - /** - * Get user restrictions - * - * @param User $user - * - * @return array - */ - public function getRestrictions(User $user) - { - $restrictions = array(); - try { - $config = Config::app('restrictions'); - } catch (NotReadableError $e) { - Logger::error( - 'Can\'t get restrictions for user \'%s\'. An exception was thrown:', - $user->getUsername(), - $e - ); - return $restrictions; - } - $username = $user->getUsername(); - $userGroups = $user->getGroups(); - foreach ($config as $section) { - if (! empty($section->restriction) - && $this->match($username, $userGroups, $section) - ) { - $restrictions = array_merge( - $restrictions, - array_diff(String::trimSplit($section->restriction), $restrictions) - ); - } - } - return $restrictions; + return array($permissions, $restrictions); } } diff --git a/library/Icinga/Authentication/AuthChain.php b/library/Icinga/Authentication/AuthChain.php index 4ab87f7ae..24c12c9de 100644 --- a/library/Icinga/Authentication/AuthChain.php +++ b/library/Icinga/Authentication/AuthChain.php @@ -5,8 +5,9 @@ namespace Icinga\Authentication; use Iterator; -use Zend_Config; -use Icinga\Logger\Logger; +use Icinga\Data\ConfigObject; +use Icinga\Application\Config; +use Icinga\Application\Logger; use Icinga\Exception\ConfigurationError; /** @@ -17,7 +18,7 @@ class AuthChain implements Iterator /** * User backends configuration * - * @var Zend_Config + * @var Config */ private $config; @@ -31,20 +32,22 @@ class AuthChain implements Iterator /** * Create a new authentication chain from config * - * @param Zend_Config $config User backends configuration + * @param Config $config User backends configuration */ - public function __construct(Zend_Config $config) + public function __construct(Config $config) { $this->config = $config; } /** * Rewind the chain + * + * @return ConfigObject */ public function rewind() { - $this->config->rewind(); $this->currentBackend = null; + return $this->config->rewind(); } /** @@ -60,7 +63,7 @@ class AuthChain implements Iterator /** * Return the key of the current user backend config * - * @return string + * @return string */ public function key() { @@ -69,16 +72,18 @@ class AuthChain implements Iterator /** * Move forward to the next user backend config + * + * @return ConfigObject */ public function next() { - $this->config->next(); + return $this->config->next(); } /** - * Check if the current user backend is valid, i.e. it's enabled and the config's valid + * Check if the current user backend is valid, i.e. it's enabled and the config is valid * - * @return bool + * @return bool */ public function valid() { @@ -86,13 +91,15 @@ class AuthChain implements Iterator // Stop when there are no more backends to check return false; } + $backendConfig = $this->config->current(); if ((bool) $backendConfig->get('disabled', false) === true) { $this->next(); return $this->valid(); } + + $name = $this->key(); try { - $name = $this->key(); $backend = UserBackend::create($name, $backendConfig); } catch (ConfigurationError $e) { Logger::error( @@ -105,6 +112,7 @@ class AuthChain implements Iterator $this->next(); return $this->valid(); } + $this->currentBackend = $backend; return true; } diff --git a/library/Icinga/Authentication/Backend/AutoLoginBackend.php b/library/Icinga/Authentication/Backend/AutoLoginBackend.php index 16373bb6c..b4a70bd4f 100644 --- a/library/Icinga/Authentication/Backend/AutoLoginBackend.php +++ b/library/Icinga/Authentication/Backend/AutoLoginBackend.php @@ -4,8 +4,8 @@ namespace Icinga\Authentication\Backend; -use Zend_Config; use Icinga\Authentication\UserBackend; +use Icinga\Data\ConfigObject; use Icinga\User; /** @@ -23,9 +23,9 @@ class AutoLoginBackend extends UserBackend /** * Create new autologin backend * - * @param Zend_Config $config + * @param ConfigObject $config */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { $this->stripUsernameRegexp = $config->get('strip_username_regexp'); } @@ -54,7 +54,7 @@ class AutoLoginBackend extends UserBackend if (isset($_SERVER['REMOTE_USER'])) { $username = $_SERVER['REMOTE_USER']; $user->setRemoteUserInformation($username, 'REMOTE_USER'); - if ($this->stripUsernameRegexp !== null) { + if ($this->stripUsernameRegexp) { $stripped = preg_replace($this->stripUsernameRegexp, '', $username); if ($stripped !== false) { // TODO(el): PHP issues a warning when PHP cannot compile the regular expression. Should we log an diff --git a/library/Icinga/Authentication/Backend/DbUserBackend.php b/library/Icinga/Authentication/Backend/DbUserBackend.php index a89a07c81..d2d0147e5 100644 --- a/library/Icinga/Authentication/Backend/DbUserBackend.php +++ b/library/Icinga/Authentication/Backend/DbUserBackend.php @@ -4,6 +4,7 @@ namespace Icinga\Authentication\Backend; +use PDO; use Icinga\Authentication\UserBackend; use Icinga\Data\Db\DbConnection; use Icinga\User; @@ -11,16 +12,29 @@ use Icinga\Exception\AuthenticationException; use Exception; use Zend_Db_Expr; use Zend_Db_Select; -use Icinga\Exception\IcingaException; class DbUserBackend extends UserBackend { + /** + * The algorithm to use when hashing passwords + * + * @var string + */ + const HASH_ALGORITHM = '$1$'; // MD5 + + /** + * The length of the salt to use when hashing a password + * + * @var int + */ + const SALT_LENGTH = 12; // 12 is required by MD5 + /** * Connection to the database * * @var DbConnection */ - private $conn; + protected $conn; public function __construct(DbConnection $conn) { @@ -36,45 +50,69 @@ class DbUserBackend extends UserBackend */ public function hasUser(User $user) { - $select = new Zend_Db_Select($this->conn->getConnection()); - $row = $select->from('account', array(new Zend_Db_Expr(1))) - ->where('username = ?', $user->getUsername()) + $select = new Zend_Db_Select($this->conn->getDbAdapter()); + $row = $select->from('icingaweb_user', array(new Zend_Db_Expr(1))) + ->where('name = ?', $user->getUsername()) ->query()->fetchObject(); return ($row !== false) ? true : false; } /** - * Authenticate the given user and return true on success, false on failure and null on error + * Add a new user + * + * @param string $username The name of the new user + * @param string $password The new user's password + * @param bool $active Whether the user is active + */ + public function addUser($username, $password, $active = true) + { + $passwordHash = $this->hashPassword($password); + + $stmt = $this->conn->getDbAdapter()->prepare( + 'INSERT INTO icingaweb_user VALUES (:name, :active, :password_hash, now(), DEFAULT);' + ); + $stmt->bindParam(':name', $username, PDO::PARAM_STR); + $stmt->bindParam(':active', $active, PDO::PARAM_INT); + $stmt->bindParam(':password_hash', $passwordHash, PDO::PARAM_LOB); + $stmt->execute(); + } + + /** + * Fetch the hashed password for the given user + * + * @param string $username The name of the user + * + * @return string + */ + protected function getPasswordHash($username) + { + $stmt = $this->conn->getDbAdapter()->prepare( + 'SELECT password_hash FROM icingaweb_user WHERE name = :name AND active = 1' + ); + $stmt->execute(array(':name' => $username)); + $stmt->bindColumn(1, $lob, PDO::PARAM_LOB); + $stmt->fetch(PDO::FETCH_BOUND); + return is_resource($lob) ? stream_get_contents($lob) : $lob; + } + + /** + * Authenticate the given user and return true on success, false on failure and throw an exception on error * * @param User $user * @param string $password * - * @return bool|null + * @return bool + * * @throws AuthenticationException */ public function authenticate(User $user, $password) { try { - $salt = $this->getSalt($user->getUsername()); - if ($salt === null) { - return false; - } - if ($salt === '') { - throw new IcingaException( - 'Cannot find salt for user %s', - $user->getUsername() - ); - } - - $select = new Zend_Db_Select($this->conn->getConnection()); - $row = $select->from('account', array(new Zend_Db_Expr(1))) - ->where('username = ?', $user->getUsername()) - ->where('active = ?', true) - ->where('password = ?', $this->hashPassword($password, $salt)) - ->query()->fetchObject(); - - return ($row !== false) ? true : false; + $passwordHash = $this->getPasswordHash($user->getUsername()); + $passwordSalt = $this->getSalt($passwordHash); + $hashToCompare = $this->hashPassword($password, $passwordSalt); + return $hashToCompare === $passwordHash; } catch (Exception $e) { throw new AuthenticationException( 'Failed to authenticate user "%s" against backend "%s". An exception was thrown:', @@ -86,29 +124,40 @@ class DbUserBackend extends UserBackend } /** - * Get salt by username + * Extract salt from the given password hash * - * @param string $username + * @param string $hash The hashed password * - * @return string|null + * @return string */ - private function getSalt($username) + protected function getSalt($hash) { - $select = new Zend_Db_Select($this->conn->getConnection()); - $row = $select->from('account', array('salt'))->where('username = ?', $username)->query()->fetchObject(); - return ($row !== false) ? $row->salt : null; + return substr($hash, strlen(self::HASH_ALGORITHM), self::SALT_LENGTH); + } + + /** + * Return a random salt + * + * The returned salt is safe to be used for hashing a user's password + * + * @return string + */ + protected function generateSalt() + { + return openssl_random_pseudo_bytes(self::SALT_LENGTH); } /** * Hash a password * - * @param string $password - * @param string $salt + * @param string $password + * @param string $salt * * @return string */ - private function hashPassword($password, $salt) { - return hash_hmac('sha256', $password, $salt); + protected function hashPassword($password, $salt = null) + { + return crypt($password, self::HASH_ALGORITHM . ($salt !== null ? $salt : $this->generateSalt())); } /** @@ -118,12 +167,29 @@ class DbUserBackend extends UserBackend */ public function count() { - $select = new Zend_Db_Select($this->conn->getConnection()); + $select = new Zend_Db_Select($this->conn->getDbAdapter()); $row = $select->from( - 'account', + 'icingaweb_user', array('count' => 'COUNT(*)') )->query()->fetchObject(); return ($row !== false) ? $row->count : 0; } + + /** + * Return the names of all available users + * + * @return array + */ + public function listUsers() + { + $query = $this->conn->select()->from('icingaweb_user', array('name')); + + $users = array(); + foreach ($query->fetchAll() as $row) { + $users[] = $row->name; + } + + return $users; + } } diff --git a/library/Icinga/Authentication/Backend/LdapUserBackend.php b/library/Icinga/Authentication/Backend/LdapUserBackend.php index 3ee3c17dd..519dd3c48 100644 --- a/library/Icinga/Authentication/Backend/LdapUserBackend.php +++ b/library/Icinga/Authentication/Backend/LdapUserBackend.php @@ -4,7 +4,6 @@ namespace Icinga\Authentication\Backend; -use Icinga\Logger\Logger; use Icinga\User; use Icinga\Authentication\UserBackend; use Icinga\Protocol\Ldap\Connection; @@ -20,20 +19,36 @@ class LdapUserBackend extends UserBackend **/ protected $conn; + protected $baseDn; + protected $userClass; protected $userNameAttribute; protected $groupOptions; - public function __construct(Connection $conn, $userClass, $userNameAttribute, $groupOptions = null) + public function __construct(Connection $conn, $userClass, $userNameAttribute, $baseDn, $groupOptions = null) { $this->conn = $conn; + $this->baseDn = trim($baseDn) !== '' ? $baseDn : $conn->getDN(); $this->userClass = $userClass; $this->userNameAttribute = $userNameAttribute; $this->groupOptions = $groupOptions; } + /** + * @return \Icinga\Protocol\Ldap\Query + */ + protected function selectUsers() + { + return $this->conn->select()->setBase($this->baseDn)->from( + $this->userClass, + array( + $this->userNameAttribute + ) + ); + } + /** * Create query * @@ -41,14 +56,9 @@ class LdapUserBackend extends UserBackend * * @return \Icinga\Protocol\Ldap\Query **/ - protected function createQuery($username) + protected function selectUser($username) { - return $this->conn->select() - ->from( - $this->userClass, - array($this->userNameAttribute) - ) - ->where( + return $this->selectUsers()->where( $this->userNameAttribute, str_replace('*', '', $username) ); @@ -68,13 +78,18 @@ class LdapUserBackend extends UserBackend */ public function assertAuthenticationPossible() { - $q = $this->conn->select()->from($this->userClass); - $result = $q->fetchRow(); + try { + $q = $this->conn->select()->setBase($this->baseDn)->from($this->userClass); + $result = $q->fetchRow(); + } catch (LdapException $e) { + throw new AuthenticationException('Connection not possible.', $e); + } + if (! isset($result)) { throw new AuthenticationException( 'No objects with objectClass="%s" in DN="%s" found.', $this->userClass, - $this->conn->getDN() + $this->baseDn ); } @@ -94,12 +109,12 @@ class LdapUserBackend extends UserBackend * * @param string $dn * - * @return array|null + * @return array */ public function getGroups($dn) { if (empty($this->groupOptions) || ! isset($this->groupOptions['group_base_dn'])) { - return null; + return array(); } $q = $this->conn->select() @@ -135,7 +150,7 @@ class LdapUserBackend extends UserBackend public function hasUser(User $user) { $username = $user->getUsername(); - return $this->conn->fetchOne($this->createQuery($username)) === $username; + return $this->conn->fetchOne($this->selectUser($username)) === $username; } /** @@ -158,7 +173,7 @@ class LdapUserBackend extends UserBackend } catch (AuthenticationException $e) { // Authentication not possible throw new AuthenticationException( - 'Authentication against backend "%s" not possible: ', + 'Authentication against backend "%s" not possible.', $this->getName(), $e ); @@ -168,7 +183,7 @@ class LdapUserBackend extends UserBackend return false; } try { - $userDn = $this->conn->fetchDN($this->createQuery($user->getUsername())); + $userDn = $this->conn->fetchDN($this->selectUser($user->getUsername())); $authenticated = $this->conn->testCredentials( $userDn, $password @@ -198,14 +213,20 @@ class LdapUserBackend extends UserBackend */ public function count() { + return $this->conn->count($this->selectUsers()); + } - return $this->conn->count( - $this->conn->select()->from( - $this->userClass, - array( - $this->userNameAttribute - ) - ) - ); + /** + * Return the names of all available users + * + * @return array + */ + public function listUsers() + { + $users = array(); + foreach ($this->selectUsers()->fetchAll() as $row) { + $users[] = $row->{$this->userNameAttribute}; + } + return $users; } } diff --git a/library/Icinga/Authentication/Manager.php b/library/Icinga/Authentication/Manager.php index fa974546d..0a9b40981 100644 --- a/library/Icinga/Authentication/Manager.php +++ b/library/Icinga/Authentication/Manager.php @@ -5,11 +5,10 @@ namespace Icinga\Authentication; use Exception; -use Zend_Config; use Icinga\Application\Config; use Icinga\Exception\IcingaException; use Icinga\Exception\NotReadableError; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\User; use Icinga\User\Preferences; use Icinga\User\Preferences\PreferencesStore; @@ -62,9 +61,10 @@ class Manager $e ) ); - $config = new Zend_Config(array()); + $config = new Config(); } - if (($preferencesConfig = $config->preferences) !== null) { + if ($config->hasSection('preferences')) { + $preferencesConfig = $config->getSection('preferences'); try { $preferencesStore = PreferencesStore::create( $preferencesConfig, @@ -107,8 +107,9 @@ class Manager } $user->setGroups($groups); $admissionLoader = new AdmissionLoader(); - $user->setPermissions($admissionLoader->getPermissions($user)); - $user->setRestrictions($admissionLoader->getRestrictions($user)); + list($permissions, $restrictions) = $admissionLoader->getPermissionsAndRestrictions($user); + $user->setPermissions($permissions); + $user->setRestrictions($restrictions); $this->user = $user; if ($persist) { $this->persistCurrentUser(); @@ -120,10 +121,7 @@ class Manager */ public function persistCurrentUser() { - $session = Session::getSession(); - $session->set('user', $this->user); - $session->write(); - $session->refreshId(); + Session::getSession()->set('user', $this->user)->refreshId(); } /** diff --git a/library/Icinga/Authentication/UserBackend.php b/library/Icinga/Authentication/UserBackend.php index 7829210fd..eaf39e49d 100644 --- a/library/Icinga/Authentication/UserBackend.php +++ b/library/Icinga/Authentication/UserBackend.php @@ -6,9 +6,9 @@ namespace Icinga\Authentication; use Countable; use Icinga\Authentication\Backend\AutoLoginBackend; -use Zend_Config; use Icinga\Authentication\Backend\DbUserBackend; use Icinga\Authentication\Backend\LdapUserBackend; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Exception\ConfigurationError; use Icinga\User; @@ -45,7 +45,7 @@ abstract class UserBackend implements Countable return $this->name; } - public static function create($name, Zend_Config $backendConfig) + public static function create($name, ConfigObject $backendConfig) { if ($backendConfig->name !== null) { $name = $backendConfig->name; @@ -103,6 +103,7 @@ abstract class UserBackend implements Countable $resource, $backendConfig->get('user_class', 'user'), $backendConfig->get('user_name_attribute', 'sAMAccountName'), + $backendConfig->get('base_dn', $resource->getDN()), $groupOptions ); break; @@ -129,6 +130,7 @@ abstract class UserBackend implements Countable $resource, $backendConfig->user_class, $backendConfig->user_name_attribute, + $backendConfig->get('base_dn', $resource->getDN()), $groupOptions ); break; diff --git a/library/Icinga/Authentication/UserGroupBackend.php b/library/Icinga/Authentication/UserGroupBackend.php index e411aee03..f1a41adcb 100644 --- a/library/Icinga/Authentication/UserGroupBackend.php +++ b/library/Icinga/Authentication/UserGroupBackend.php @@ -4,9 +4,9 @@ namespace Icinga\Authentication; -use Zend_Config; use Icinga\Authentication\Backend\DbUserGroupBackend; use Icinga\Authentication\Backend\IniUserGroupBackend; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Exception\ConfigurationError; use Icinga\Exception\IcingaException; @@ -50,13 +50,13 @@ abstract class UserGroupBackend /** * Create a user group backend * - * @param string $name - * @param Zend_Config $backendConfig + * @param string $name + * @param ConfigObject $backendConfig * * @return DbUserGroupBackend|IniUserGroupBackend * @throws ConfigurationError If the backend configuration is invalid */ - public static function create($name, Zend_Config $backendConfig) + public static function create($name, ConfigObject $backendConfig) { if ($backendConfig->name !== null) { $name = $backendConfig->name; diff --git a/library/Icinga/Cli/Loader.php b/library/Icinga/Cli/Loader.php index 11ca2b70b..655ef7c18 100644 --- a/library/Icinga/Cli/Loader.php +++ b/library/Icinga/Cli/Loader.php @@ -66,7 +66,7 @@ class Loader public function __construct(App $app) { $this->app = $app; - $this->coreAppDir = ICINGAWEB_APPDIR . '/clicommands'; + $this->coreAppDir = $app->getApplicationDir('clicommands'); } /** diff --git a/library/Icinga/Data/ConfigObject.php b/library/Icinga/Data/ConfigObject.php new file mode 100644 index 000000000..23b2e1651 --- /dev/null +++ b/library/Icinga/Data/ConfigObject.php @@ -0,0 +1,304 @@ +data = array(); + + foreach ($data as $key => $value) { + if (is_array($value)) { + $this->data[$key] = new static($value); + } else { + $this->data[$key] = $value; + } + } + } + + /** + * Deep clone this config + */ + public function __clone() + { + $array = array(); + foreach ($this->data as $key => $value) { + if ($value instanceof self) { + $array[$key] = clone $value; + } else { + $array[$key] = $value; + } + } + + $this->data = $array; + } + + /** + * Return the count of available sections and properties + * + * @return int + */ + public function count() + { + return count($this->data); + } + + /** + * Reset the current position of $this->data + * + * @return mixed + */ + public function rewind() + { + return reset($this->data); + } + + /** + * Return the section's or property's value of the current iteration + * + * @return mixed + */ + public function current() + { + return current($this->data); + } + + /** + * Return whether the position of the current iteration is valid + * + * @return bool + */ + public function valid() + { + return key($this->data) !== null; + } + + /** + * Return the section's or property's name of the current iteration + * + * @return mixed + */ + public function key() + { + return key($this->data); + } + + /** + * Advance the position of the current iteration and return the new section's or property's value + * + * @return mixed + */ + public function next() + { + return next($this->data); + } + + /** + * Return whether the given section or property is set + * + * @param string $key The name of the section or property + * + * @return bool + */ + public function __isset($key) + { + return isset($this->data[$key]); + } + + /** + * Return the value for the given property or the config for the given section + * + * @param string $key The name of the property or section + * + * @return mixed|NULL The value or NULL in case $key does not exist + */ + public function __get($key) + { + return $this->get($key); + } + + /** + * Add a new property or section + * + * @param string $key The name of the new property or section + * @param mixed $value The value to set for the new property or section + */ + public function __set($key, $value) + { + if (is_array($value)) { + $this->data[$key] = new static($value); + } else { + $this->data[$key] = $value; + } + } + + /** + * Remove the given property or section + * + * @param string $key The property or section to remove + */ + public function __unset($key) + { + unset($this->data[$key]); + } + + /** + * Return whether the given section or property is set + * + * @param string $key The name of the section or property + * + * @return bool + */ + public function offsetExists($key) + { + return isset($this->$key); + } + + /** + * Return the value for the given property or the config for the given section + * + * @param string $key The name of the property or section + * + * @return mixed|NULL The value or NULL in case $key does not exist + */ + public function offsetGet($key) + { + return $this->get($key); + } + + /** + * Add a new property or section + * + * @param string $key The name of the new property or section + * @param mixed $value The value to set for the new property or section + */ + public function offsetSet($key, $value) + { + if ($key === null) { + throw new LogicException('Appending values without an explicit key is not supported'); + } + + $this->$key = $value; + } + + /** + * Remove the given property or section + * + * @param string $key The property or section to remove + */ + public function offsetUnset($key) + { + unset($this->$key); + } + + /** + * Return whether this config has any data + * + * @return bool + */ + public function isEmpty() + { + return empty($this->data); + } + + /** + * Return the value for the given property or the config for the given section + * + * @param string $key The name of the property or section + * @param mixed $default The value to return in case the property or section is missing + * + * @return mixed + */ + public function get($key, $default = null) + { + if (array_key_exists($key, $this->data)) { + return $this->data[$key]; + } + + return $default !== null ? $default : null; + } + + /** + * Return all section and property names + * + * @return array + */ + public function keys() + { + return array_keys($this->data); + } + + /** + * Return this config's data as associative array + * + * @return array + */ + public function toArray() + { + $array = array(); + foreach ($this->data as $key => $value) { + if ($value instanceof self) { + $array[$key] = $value->toArray(); + } else { + $array[$key] = $value; + } + } + + return $array; + } + + /** + * Merge the given data with this config + * + * @param array|Config $data An array or a config + * + * @return self + */ + public function merge($data) + { + if ($data instanceof self) { + $data = $data->toArray(); + } + + foreach ($data as $key => $value) { + if (array_key_exists($key, $this->data)) { + if (is_array($value)) { + if ($this->data[$key] instanceof self) { + $this->data[$key]->merge($value); + } else { + $this->data[$key] = new static($value); + } + } else { + $this->data[$key] = $value; + } + } else { + $this->data[$key] = is_array($value) ? new static($value) : $value; + } + } + + return $this; + } +} diff --git a/library/Icinga/Data/Db/DbConnection.php b/library/Icinga/Data/Db/DbConnection.php index 0157bcd72..38153a1cf 100644 --- a/library/Icinga/Data/Db/DbConnection.php +++ b/library/Icinga/Data/Db/DbConnection.php @@ -4,14 +4,14 @@ namespace Icinga\Data\Db; +use PDO; +use Zend_Db; use Icinga\Application\Benchmark; +use Icinga\Data\ConfigObject; use Icinga\Data\Db\DbQuery; use Icinga\Data\ResourceFactory; use Icinga\Data\Selectable; use Icinga\Exception\ConfigurationError; -use PDO; -use Zend_Config; -use Zend_Db; /** * Encapsulate database connections and query creation @@ -21,7 +21,7 @@ class DbConnection implements Selectable /** * Connection config * - * @var Zend_Config + * @var ConfigObject */ private $config; @@ -59,9 +59,9 @@ class DbConnection implements Selectable /** * Create a new connection object * - * @param Zend_Config $config + * @param ConfigObject $config */ - public function __construct(Zend_Config $config = null) + public function __construct(ConfigObject $config = null) { $this->config = $config; if (isset($config->prefix)) { @@ -216,7 +216,10 @@ class DbConnection implements Selectable */ public function fetchRow(DbQuery $query) { - return $this->dbAdapter->fetchRow($query->getSelectQuery()); + Benchmark::measure('DB is fetching row'); + $result = $this->dbAdapter->fetchRow($query->getSelectQuery()); + Benchmark::measure('DB row done'); + return $result; } /** diff --git a/library/Icinga/Data/Db/DbQuery.php b/library/Icinga/Data/Db/DbQuery.php index 94765d98f..bad1261aa 100644 --- a/library/Icinga/Data/Db/DbQuery.php +++ b/library/Icinga/Data/Db/DbQuery.php @@ -72,6 +72,12 @@ class DbQuery extends SimpleQuery parent::init(); } + public function setUseSubqueryCount($useSubqueryCount = true) + { + $this->useSubqueryCount = $useSubqueryCount; + return $this; + } + public function where($condition, $value = null) { // $this->count = $this->select = null; @@ -128,11 +134,11 @@ class DbQuery extends SimpleQuery return $select; } - public function applyFilterSql($query) + protected function applyFilterSql($select) { $where = $this->renderFilter($this->filter); if ($where !== '') { - $query->where($where); + $select->where($where); } } @@ -156,7 +162,10 @@ class DbQuery extends SimpleQuery $parts = array(); if (! $filter->isEmpty()) { foreach ($filter->filters() as $f) { - $parts[] = $this->renderFilter($f, $level + 1); + $filterPart = $this->renderFilter($f, $level + 1); + if ($filterPart !== '') { + $parts[] = $filterPart; + } } if ($level > 0) { $str .= ' (' . implode($op, $parts) . ') '; @@ -245,10 +254,12 @@ class DbQuery extends SimpleQuery if (is_array($expression) && $sign === '=') { // TODO: Should we support this? Doesn't work for blub* return $col . ' IN (' . $this->escapeForSql($expression) . ')'; - } elseif (strpos($expression, '*') === false) { - return $col . ' ' . $sign . ' ' . $this->escapeForSql($expression); - } else { + } elseif ($sign === '=' && strpos($expression, '*') !== false) { return $col . ' LIKE ' . $this->escapeForSql($this->escapeWildcards($expression)); + } elseif ($sign === '!=' && strpos($expression, '*') !== false) { + return $col . ' NOT LIKE ' . $this->escapeForSql($this->escapeWildcards($expression)); + } else { + return $col . ' ' . $sign . ' ' . $this->escapeForSql($expression); } } @@ -259,11 +270,13 @@ class DbQuery extends SimpleQuery */ public function getCountQuery() { - // TODO: there may be situations where we should clone the "select" + // TODO: there may be situations where we should clone the "select" $count = $this->dbSelect(); - + if ($this->group) { + $count->group($this->group); + } $this->applyFilterSql($count); - if ($this->useSubqueryCount) { + if ($this->useSubqueryCount || $this->group) { $count->columns($this->columns); $columns = array('cnt' => 'COUNT(*)'); return $this->db->select()->from($count, $columns); @@ -305,6 +318,13 @@ class DbQuery extends SimpleQuery . "\n\n"; } + public function __clone() + { + if ($this->select) { + $this->select = clone $this->select; + } + } + /** * @return string */ diff --git a/library/Icinga/Data/Filter/Filter.php b/library/Icinga/Data/Filter/Filter.php index 64607a4a0..5793a4749 100644 --- a/library/Icinga/Data/Filter/Filter.php +++ b/library/Icinga/Data/Filter/Filter.php @@ -22,7 +22,17 @@ abstract class Filter return $this; } - abstract function toQueryString(); + abstract public function isExpression(); + + abstract public function isChain(); + + abstract public function isEmpty(); + + abstract public function toQueryString(); + + abstract public function andFilter(Filter $filter); + + abstract public function orFilter(Filter $filter); public function getUrlParams() { @@ -52,6 +62,8 @@ abstract class Filter return false === strpos($this->id, '-'); } + abstract public function listFilteredColumns(); + public function applyChanges($changes) { $filter = $this; @@ -79,7 +91,7 @@ abstract class Filter } } - krsort($operators, SORT_NATURAL); + krsort($operators, version_compare(PHP_VERSION, '5.4.0') >= 0 ? SORT_NATURAL : SORT_REGULAR); foreach ($operators as $id => $operator) { $f = $filter->getById($id); if ($f->getOperatorName() !== $operator) { @@ -96,7 +108,7 @@ abstract class Filter public function getParentId() { - if ($self->isRootNode()) { + if ($this->isRootNode()) { throw new ProgrammingError('Filter root nodes have no parent'); } return substr($this->id, 0, strrpos($this->id, '-')); diff --git a/library/Icinga/Data/Filter/FilterAnd.php b/library/Icinga/Data/Filter/FilterAnd.php index 899f488ce..8fd2f2411 100644 --- a/library/Icinga/Data/Filter/FilterAnd.php +++ b/library/Icinga/Data/Filter/FilterAnd.php @@ -30,4 +30,14 @@ class FilterAnd extends FilterChain } return true; } + + public function andFilter(Filter $filter) + { + return $this->addFilter($filter); + } + + public function orFilter(Filter $filter) + { + return Filter::matchAny($this, $filter); + } } diff --git a/library/Icinga/Data/Filter/FilterChain.php b/library/Icinga/Data/Filter/FilterChain.php index 9d32252fe..cdb3a1123 100644 --- a/library/Icinga/Data/Filter/FilterChain.php +++ b/library/Icinga/Data/Filter/FilterChain.php @@ -117,6 +117,20 @@ abstract class FilterChain extends Filter return $this->operatorSymbol; } + public function listFilteredColumns() + { + $columns = array(); + foreach ($this->filters as $filter) { + if ($filter instanceof FilterExpression) { + $columns[] = $filter->getColumn(); + } else { + $columns += $filter->listFilteredColumns(); + } + } + // array_unique? + return $columns; + } + public function toQueryString() { $parts = array(); @@ -166,6 +180,16 @@ abstract class FilterChain extends Filter } } + public function isExpression() + { + return false; + } + + public function isChain() + { + return true; + } + public function isEmpty() { return empty($this->filters); @@ -174,7 +198,8 @@ abstract class FilterChain extends Filter public function addFilter(Filter $filter) { $this->filters[] = $filter; - $filter->setId($this->getId() . '-' . (count($this->filters))); + $filter->setId($this->getId() . '-' . $this->count()); + return $this; } public function &filters() @@ -182,6 +207,11 @@ abstract class FilterChain extends Filter return $this->filters; } + public function count() + { + return count($this->filters); + } + public function __clone() { foreach ($this->filters as & $filter) { diff --git a/library/Icinga/Data/Filter/FilterExpression.php b/library/Icinga/Data/Filter/FilterExpression.php index 8378b5ae3..0782bcd89 100644 --- a/library/Icinga/Data/Filter/FilterExpression.php +++ b/library/Icinga/Data/Filter/FilterExpression.php @@ -19,6 +19,16 @@ class FilterExpression extends Filter $this->expression = $expression; } + public function isExpression() + { + return true; + } + + public function isChain() + { + return false; + } + public function isEmpty() { return false; @@ -59,6 +69,11 @@ class FilterExpression extends Filter return $this; } + public function listFilteredColumns() + { + return array($this->getColumn()); + } + public function __toString() { $expression = is_array($this->expression) ? @@ -97,4 +112,14 @@ class FilterExpression extends Filter return (bool) preg_match($pattern, $row->{$this->column}); } } + + public function andFilter(Filter $filter) + { + return Filter::matchAll($this, $filter); + } + + public function orFilter(Filter $filter) + { + return Filter::matchAny($this, $filter); + } } diff --git a/library/Icinga/Data/Filter/FilterGreaterThan.php b/library/Icinga/Data/Filter/FilterGreaterThan.php index bda8665b1..62ba16fca 100644 --- a/library/Icinga/Data/Filter/FilterGreaterThan.php +++ b/library/Icinga/Data/Filter/FilterGreaterThan.php @@ -6,9 +6,12 @@ namespace Icinga\Data\Filter; class FilterGreaterThan extends FilterExpression { - public function matches($row) { + if (! isset($row->{$this->column})) { + // TODO: REALLY? Exception? + return false; + } return (string) $row->{$this->column} > (string) $this->expression; } } diff --git a/library/Icinga/Data/Filter/FilterMatch.php b/library/Icinga/Data/Filter/FilterMatch.php index ef3cad801..159feb04e 100644 --- a/library/Icinga/Data/Filter/FilterMatch.php +++ b/library/Icinga/Data/Filter/FilterMatch.php @@ -8,6 +8,10 @@ class FilterMatch extends FilterExpression { public function matches($row) { + if (! isset($row->{$this->column})) { + // TODO: REALLY? Exception? + return false; + } $expression = (string) $this->expression; if (strpos($expression, '*') === false) { return (string) $row->{$this->column} === $expression; diff --git a/library/Icinga/Data/Filter/FilterNot.php b/library/Icinga/Data/Filter/FilterNot.php index a49a7ab3d..5e63691f1 100644 --- a/library/Icinga/Data/Filter/FilterNot.php +++ b/library/Icinga/Data/Filter/FilterNot.php @@ -22,6 +22,16 @@ class FilterNot extends FilterChain return true; } + public function andFilter(Filter $filter) + { + return Filter::matchAll($this, $filter); + } + + public function orFilter(Filter $filter) + { + return Filter::matchAny($filter); + } + public function toQueryString() { $parts = array(); diff --git a/library/Icinga/Data/Filter/FilterOr.php b/library/Icinga/Data/Filter/FilterOr.php index 427c17fd2..8291d32dc 100644 --- a/library/Icinga/Data/Filter/FilterOr.php +++ b/library/Icinga/Data/Filter/FilterOr.php @@ -19,4 +19,22 @@ class FilterOr extends FilterChain } return false; } + + public function setOperatorName($name) + { + if ($this->count() > 1 && $name === 'NOT') { + return Filter::not(clone $this); + } + return parent::setOperatorName($name); + } + + public function andFilter(Filter $filter) + { + return Filter::matchAll($this, $filter); + } + + public function orFilter(Filter $filter) + { + return $this->addFilter($filter); + } } diff --git a/library/Icinga/Data/PivotTable.php b/library/Icinga/Data/PivotTable.php index ab6fab13d..0a1f009fe 100644 --- a/library/Icinga/Data/PivotTable.php +++ b/library/Icinga/Data/PivotTable.php @@ -69,11 +69,13 @@ class PivotTable protected function prepareQueries() { $this->xAxisQuery = clone $this->baseQuery; - $this->xAxisQuery->distinct(); + $this->xAxisQuery->group($this->xAxisColumn); $this->xAxisQuery->columns(array($this->xAxisColumn)); + $this->xAxisQuery->setUseSubqueryCount(); $this->yAxisQuery = clone $this->baseQuery; - $this->yAxisQuery->distinct(); + $this->yAxisQuery->group($this->yAxisColumn); $this->yAxisQuery->columns(array($this->yAxisColumn)); + $this->yAxisQuery->setUseSubqueryCount(); return $this; } @@ -85,24 +87,14 @@ class PivotTable */ protected function adjustSorting() { - $currentOrderColumns = $this->baseQuery->getOrder(); - $xAxisOrderColumns = array(array($this->baseQuery->getMappedField($this->xAxisColumn), SimpleQuery::SORT_ASC)); - $yAxisOrderColumns = array(array($this->baseQuery->getMappedField($this->yAxisColumn), SimpleQuery::SORT_ASC)); - - foreach ($currentOrderColumns as $orderInfo) { - if ($orderInfo[0] === $xAxisOrderColumns[0][0]) { - $xAxisOrderColumns[0] = $orderInfo; - } elseif ($orderInfo[0] === $yAxisOrderColumns[0][0]) { - $yAxisOrderColumns[0] = $orderInfo; - } else { - $xAxisOrderColumns[] = $orderInfo; - $yAxisOrderColumns[] = $orderInfo; - } + if (false === $this->xAxisQuery->hasOrder($this->xAxisColumn)) { + $this->xAxisQuery->order($this->xAxisColumn, 'ASC'); } -//TODO: simplify this whole function. No need to care about mapping -// foreach ($xAxisOrderColumns as -// $this->xAxisQuery->setOrder($xAxisOrderColumns); -// $this->yAxisQuery->setOrder($yAxisOrderColumns); + + if (false === $this->yAxisQuery->hasOrder($this->yAxisColumn)) { + $this->yAxisQuery->order($this->yAxisColumn, 'ASC'); + } + return $this; } diff --git a/library/Icinga/Data/ResourceFactory.php b/library/Icinga/Data/ResourceFactory.php index 1c443f9d0..754360740 100644 --- a/library/Icinga/Data/ResourceFactory.php +++ b/library/Icinga/Data/ResourceFactory.php @@ -4,7 +4,6 @@ namespace Icinga\Data; -use Zend_Config; use Icinga\Application\Config; use Icinga\Exception\ProgrammingError; use Icinga\Util\ConfigAwareFactory; @@ -22,14 +21,14 @@ class ResourceFactory implements ConfigAwareFactory /** * Resource configuration * - * @var Zend_Config + * @var Config */ private static $resources; /** * Set resource configurations * - * @param Zend_Config $config + * @param Config $config */ public static function setConfig($config) { @@ -41,14 +40,15 @@ class ResourceFactory implements ConfigAwareFactory * * @param $resourceName String The resource's name * - * @return Zend_Config The configuration of the resource + * @return ConfigObject The configuration of the resource * * @throws ConfigurationError */ public static function getResourceConfig($resourceName) { self::assertResourcesExist(); - if (($resourceConfig = self::$resources->get($resourceName)) === null) { + $resourceConfig = self::$resources->getSection($resourceName); + if ($resourceConfig->isEmpty()) { throw new ConfigurationError( 'Cannot load resource config "%s". Resource does not exist', $resourceName @@ -60,24 +60,12 @@ class ResourceFactory implements ConfigAwareFactory /** * Return the configuration of all existing resources, or get all resources of a given type. * - * @param String|null $type Fetch only resources that have the given type. - * - * @return Zend_Config The configuration containing all resources + * @return Config The configuration containing all resources */ - public static function getResourceConfigs($type = null) + public static function getResourceConfigs() { self::assertResourcesExist(); - if (!isset($type)) { - return self::$resources; - } else { - $resources = array(); - foreach (self::$resources as $name => $resource) { - if (strtolower($resource->type) === $type) { - $resources[$name] = $resource; - } - } - return new Zend_Config($resources); - } + return self::$resources; } /** @@ -100,13 +88,13 @@ class ResourceFactory implements ConfigAwareFactory * NOTE: The factory does not test if the given configuration is valid and the resource is accessible, this * depends entirely on the implementation of the returned resource. * - * @param Zend_Config $config The configuration for the created resource. + * @param ConfigObject $config The configuration for the created resource. * * @return DbConnection|LdapConnection|LivestatusConnection An object that can be used to access * the given resource. The returned class depends on the configuration property 'type'. * @throws ConfigurationError When an unsupported type is given */ - public static function createResource(Zend_Config $config) + public static function createResource(ConfigObject $config) { switch (strtolower($config->type)) { case 'db': diff --git a/library/Icinga/Data/SimpleQuery.php b/library/Icinga/Data/SimpleQuery.php index 6a0b71c35..41d050ea2 100644 --- a/library/Icinga/Data/SimpleQuery.php +++ b/library/Icinga/Data/SimpleQuery.php @@ -210,7 +210,7 @@ class SimpleQuery implements QueryInterface, Queryable $dir = $this->order[$col_num][1]; // TODO: throw Exception if column is missing //$res = strnatcmp(strtolower($a->$col), strtolower($b->$col)); - $res = strcmp(strtolower($a->$col), strtolower($b->$col)); + $res = @strcmp(strtolower($a->$col), strtolower($b->$col)); if ($res === 0) { // return $this->compare($a, $b, $col_num++); diff --git a/library/Icinga/Exception/NotFoundError.php b/library/Icinga/Exception/NotFoundError.php new file mode 100644 index 000000000..c90b0322b --- /dev/null +++ b/library/Icinga/Exception/NotFoundError.php @@ -0,0 +1,9 @@ + $separator) { + $key[$i] = $this->sanitize($separator); + } return implode($this->nestSeparator, $key); } @@ -490,7 +493,7 @@ class IniEditor private function isPropertyDeclaration($lineContent, array $key) { return preg_match( - '/^\s*' . $this->formatKey($key) . '\s*=\s*/', + '/^\s*' . preg_quote($this->formatKey($key), '/') . '\s*=\s*/', $lineContent ) === 1; } @@ -599,7 +602,7 @@ class IniEditor } /** - * Prepare a value for INe + * Prepare a value for INI * * @param $value The value of the string * @@ -613,10 +616,12 @@ class IniEditor return $value; } elseif (is_bool($value)) { return ($value ? 'true' : 'false'); - } elseif (strpos($value, '"') === false) { - return '"' . $value . '"'; - } else { - return '"' . str_replace('"', '\"', $value) . '"'; } + return '"' . str_replace('"', '\"', $this->sanitize($value)) . '"'; + } + + private function sanitize($value) + { + return str_replace('\n', '', $value); } } diff --git a/library/Icinga/Config/PreservingIniWriter.php b/library/Icinga/File/Ini/IniWriter.php similarity index 76% rename from library/Icinga/Config/PreservingIniWriter.php rename to library/Icinga/File/Ini/IniWriter.php index 2cafd5416..94a20faa5 100644 --- a/library/Icinga/Config/PreservingIniWriter.php +++ b/library/Icinga/File/Ini/IniWriter.php @@ -2,17 +2,18 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Config; +namespace Icinga\File\Ini; use Zend_Config; use Zend_Config_Ini; +use Zend_Config_Exception; use Zend_Config_Writer_FileAbstract; -use Icinga\Config\IniEditor; +use Icinga\Application\Config; /** - * 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 +class IniWriter extends Zend_Config_Writer_FileAbstract { /** * Stores the options @@ -22,10 +23,17 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract protected $options; /** - * Create a new PreservingIniWriter + * The mode to set on new files * - * @param array $options Supports all options of Zend_Config_Writer and additional - * options for the internal IniEditor: + * @var int + */ + public static $fileMode = 0664; + + /** + * Create a new INI writer + * + * @param array $options Supports all options of Zend_Config_Writer and additional options: + * * filemode: The mode to set on new files * * valueIndentation: The indentation level of the values * * commentIndentation: The indentation level of the comments * * sectionSeparators: The amount of newlines between sections @@ -34,49 +42,16 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract */ public function __construct(array $options = null) { + if (isset($options['config']) && $options['config'] instanceof Config) { + // As this class inherits from Zend_Config_Writer_FileAbstract we must + // not pass the config directly as it needs to be of type Zend_Config + $options['config'] = new Zend_Config($options['config']->toArray(), true); + } + $this->options = $options; parent::__construct($options); } - /** - * Find all keys containing dots and convert it to a nested configuration - * - * Ensure that configurations with the same ini representation the have - * similarly nested Zend_Config objects. The configuration may be altered - * during that process. - * - * @param Zend_Config $config The configuration to normalize - * @return Zend_Config The normalized config - */ - private function normalizeKeys(Zend_Config $config) - { - foreach ($config as $key => $value) { - if (preg_match('/\./', $key) > 0) { - // remove old key - unset ($config->$key); - - // insert new key - $nests = explode('.', $key); - $current = $config; - $i = 0; - for (; $i < count($nests) - 1; $i++) { - if (! isset($current->{$nests[$i]})) { - // configuration key doesn't exist, create a new nesting level - $current->{$nests[$i]} = new Zend_Config (array(), true); - } - // move to next nesting level - $current = $current->{$nests[$i]}; - } - // reached last nesting level, insert value - $current->{$nests[$i]} = $value; - } - if ($value instanceof Zend_Config) { - $config->$key = $this->normalizeKeys ($value); - } - } - return $config; - } - /** * Render the Zend_Config into a config file string * @@ -86,27 +61,43 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract { if (file_exists($this->_filename)) { $oldconfig = new Zend_Config_Ini($this->_filename); + $content = file_get_contents($this->_filename); } else { $oldconfig = new Zend_Config(array()); + $content = ''; } - // create an internal copy of the given configuration, since the user of this class - // won't expect that a configuration will ever be altered during - // the rendering process. - $extends = $this->_config->getExtends(); - $this->_config = new Zend_Config ($this->_config->toArray(), true); - foreach ($extends as $extending => $extended) { - $this->_config->setExtend($extending, $extended); - } - $this->_config = $this->normalizeKeys($this->_config); - $newconfig = $this->_config; - $editor = new IniEditor(file_get_contents($this->_filename), $this->options); + $editor = new IniEditor($content, $this->options); $this->diffConfigs($oldconfig, $newconfig, $editor); $this->updateSectionOrder($newconfig, $editor); return $editor->getText(); } + /** + * Write configuration to file and set file mode in case it does not exist yet + * + * @param string $filename + * @param Zend_Config $config + * @param bool $exclusiveLock + */ + public function write($filename = null, Zend_Config $config = null, $exclusiveLock = null) + { + $filePath = $filename !== null ? $filename : $this->_filename; + $setMode = false === file_exists($filePath); + + parent::write($filename, $config, $exclusiveLock); + + if ($setMode) { + $mode = isset($this->options['filemode']) ? $this->options['filemode'] : static::$fileMode; + $old = umask(0); // Make sure that the mode we're going to set doesn't get mangled + if (is_int($mode) && false === @chmod($filePath, $mode)) { + throw new Zend_Config_Exception(sprintf('Failed to set file mode "%o" on file "%s"', $mode, $filePath)); + } + umask($old); + } + } + /** * Create a property diff and apply the changes to the editor * @@ -240,4 +231,14 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract return $combinations; } + + /** + * Getter for filename + * + * @return string + */ + public function getFilename() + { + return $this->_filename; + } } diff --git a/library/Icinga/File/Pdf.php b/library/Icinga/File/Pdf.php index 2e8a97887..44d1a107a 100644 --- a/library/Icinga/File/Pdf.php +++ b/library/Icinga/File/Pdf.php @@ -13,9 +13,8 @@ use Icinga\Web\StyleSheet; use Icinga\Web\Url; use Icinga\Exception\ProgrammingError; -require_once 'IcingaVendor/dompdf/dompdf_config.inc.php'; - -spl_autoload_register('DOMPDF_autoload'); +require_once 'dompdf/dompdf_config.inc.php'; +require_once 'dompdf/include/autoload.inc.php'; class Pdf extends DOMPDF { @@ -49,7 +48,7 @@ class Pdf extends DOMPDF $layout->content = $controller->getResponse(); $html = $layout->render(); $imgDir = Url::fromPath('img'); - $html = preg_replace('~src="' . $imgDir . '/~', 'src="' . Icinga::app()->getBootstrapDirecory() . '/img/', $html); + $html = preg_replace('~src="' . $imgDir . '/~', 'src="' . Icinga::app()->getBootstrapDirectory() . '/img/', $html); $html = preg_replace('~src="/svg/chart.php(.*)"~', 'class="icon" src="http://master1.com/png/chart.php$1"', $html); $this->load_html($html); $this->render(); diff --git a/library/Icinga/Protocol/Dns.php b/library/Icinga/Protocol/Dns.php index 92e8b2a4d..950c22f44 100644 --- a/library/Icinga/Protocol/Dns.php +++ b/library/Icinga/Protocol/Dns.php @@ -9,7 +9,6 @@ namespace Icinga\Protocol; */ class Dns { - /** * Discover all service records on a given domain * @@ -17,21 +16,12 @@ class Dns * @param string $service The type of the service, like for example 'ldaps' or 'ldap' * @param string $protocol The transport protocol used by the service, defaults to 'tcp' * - * @return array|null An array of all service domains + * @return array An array of all found service records */ public static function getSrvRecords($domain, $service, $protocol = 'tcp') { $records = dns_get_record('_' . $service . '._' . $protocol . '.' . $domain, DNS_SRV); - if ($records === false) { - return null; - } - $targets = array(); - foreach ($records as $record) { - if (array_key_exists('target', $record)) { - $targets[] = $record['target']; - } - } - return $targets; + return $records === false ? array() : $records; } /** diff --git a/library/Icinga/Protocol/File/FileReader.php b/library/Icinga/Protocol/File/FileReader.php index 49da989ef..363f8e173 100644 --- a/library/Icinga/Protocol/File/FileReader.php +++ b/library/Icinga/Protocol/File/FileReader.php @@ -4,9 +4,9 @@ namespace Icinga\Protocol\File; -use Icinga\Data\Selectable; use Countable; -use Zend_Config; +use Icinga\Data\Selectable; +use Icinga\Data\ConfigObject; /** * Read file line by line @@ -30,11 +30,11 @@ class FileReader implements Selectable, Countable /** * Create a new reader * - * @param Zend_Config $config + * @param ConfigObject $config * * @throws FileReaderException If a required $config directive (filename or fields) is missing */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { foreach (array('filename', 'fields') as $key) { if (isset($config->{$key})) { diff --git a/library/Icinga/Protocol/Ldap/Connection.php b/library/Icinga/Protocol/Ldap/Connection.php index 6fa41e2aa..2f8737c8b 100644 --- a/library/Icinga/Protocol/Ldap/Connection.php +++ b/library/Icinga/Protocol/Ldap/Connection.php @@ -7,8 +7,8 @@ namespace Icinga\Protocol\Ldap; use Icinga\Protocol\Ldap\Exception as LdapException; use Icinga\Application\Platform; use Icinga\Application\Config; -use Icinga\Logger\Logger; -use Zend_Config; +use Icinga\Application\Logger; +use Icinga\Data\ConfigObject; /** * Backend class managing all the LDAP stuff for you. @@ -95,15 +95,16 @@ class Connection protected $capabilities; protected $namingContexts; + protected $discoverySuccess = false; /** * Constructor * * TODO: Allow to pass port and SSL options * - * @param Zend_Config $config + * @param ConfigObject $config */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { $this->hostname = $config->hostname; $this->bind_dn = $config->bind_dn; @@ -112,6 +113,16 @@ class Connection $this->port = $config->get('port', $this->port); } + public function getHostname() + { + return $this->hostname; + } + + public function getPort() + { + return $this->port; + } + public function getDN() { return $this->root_dn; @@ -336,9 +347,9 @@ class Connection public function testCredentials($username, $password) { - $ds = $this->prepareNewConnection(); + $this->connect(); - $r = @ldap_bind($ds, $username, $password); + $r = @ldap_bind($this->ds, $username, $password); if ($r) { Logger::debug( 'Successfully tested LDAP credentials (%s / %s)', @@ -351,7 +362,7 @@ class Connection 'Testing LDAP credentials (%s / %s) failed: %s', $username, '***', - ldap_error($ds) + ldap_error($this->ds) ); return false; } @@ -364,7 +375,7 @@ class Connection */ protected function getConfigDir($sub = null) { - $dir = Config::getInstance()->getConfigDir() . '/ldap'; + $dir = Config::$configDir . '/ldap'; if ($sub !== null) { $dir .= '/' . $sub; } @@ -388,7 +399,20 @@ class Connection } $ds = ldap_connect($this->hostname, $this->port); - list($cap, $namingContexts) = $this->discoverCapabilities($ds); + try { + $capabilities = $this->discoverCapabilities($ds); + list($cap, $namingContexts) = $capabilities; + $this->discoverySuccess = true; + } catch (LdapException $e) { + + // discovery failed, guess defaults + $cap = (object) array( + 'supports_ldapv3' => true, + 'supports_starttls' => false, + 'msCapabilities' => array() + ); + $namingContexts = null; + } $this->capabilities = $cap; $this->namingContexts = $namingContexts; @@ -590,6 +614,17 @@ class Connection return $this->namingContexts; } + /** + * Whether service discovery was successful + * + * @return boolean True when ldap settings were discovered, false when + * settings were guessed + */ + public function discoverySuccessful() + { + return $this->discoverySuccess; + } + /** * Discover the capabilities of the given ldap-server * @@ -626,7 +661,8 @@ class Connection if (! $result) { throw new LdapException( sprintf( - 'Capability query failed (%s:%d): %s', + 'Capability query failed (%s:%d): %s. Check if hostname and port of the ldap resource are correct ' + . ' and if anonymous access is permitted.', $this->hostname, $this->port, ldap_error($ds) @@ -634,6 +670,16 @@ class Connection ); } $entry = ldap_first_entry($ds, $result); + if ($entry === false) { + throw new LdapException( + sprintf( + 'Capabilities not available (%s:%d): %s. Discovery of root DSE probably not permitted.', + $this->hostname, + $this->port, + ldap_error($ds) + ) + ); + } $cap = (object) array( 'supports_ldapv3' => false, @@ -641,10 +687,6 @@ class Connection 'msCapabilities' => array() ); - if ($entry === false) { - // TODO: Is it OK to have no capabilities? - return false; - } $ldapAttributes = ldap_get_attributes($ds, $entry); $result = $this->cleanupAttributes($ldapAttributes); $cap->supports_ldapv3 = $this->hasCapabilityLdapV3($result); diff --git a/library/Icinga/Protocol/Ldap/Discovery.php b/library/Icinga/Protocol/Ldap/Discovery.php new file mode 100644 index 000000000..b876a5d6f --- /dev/null +++ b/library/Icinga/Protocol/Ldap/Discovery.php @@ -0,0 +1,158 @@ +connection = $conn; + } + + /** + * Execute the discovery on the underlying connection + */ + private function execDiscovery() + { + if (! $this->discovered) { + $this->connection->connect(); + $this->discovered = true; + } + } + + /** + * Suggests a resource configuration of hostname, port and root_dn + * based on the discovery + * + * @return array The suggested configuration as an array + */ + public function suggestResourceSettings() + { + if (! $this->discovered) { + $this->execDiscovery(); + } + + return array( + 'hostname' => $this->connection->getHostname(), + 'port' => $this->connection->getPort(), + 'root_dn' => $this->connection->getDefaultNamingContext() + ); + } + + /** + * Suggests a backend configuration of base_dn, user_class and user_name_attribute + * based on the discovery + * + * @return array The suggested configuration as an array + */ + public function suggestBackendSettings() + { + $this->execDiscovery(); + if ($this->isAd()) { + return array( + 'base_dn' => $this->connection->getDefaultNamingContext(), + 'user_class' => 'user', + 'user_name_attribute' => 'sAMAccountName' + ); + } else { + return array( + 'base_dn' => $this->connection->getDefaultNamingContext(), + 'user_class' => 'getDefaultNamingContext', + 'user_name_attribute' => 'uid' + ); + } + } + + /** + * Whether the suggested ldap server is an ActiveDirectory + * + * @return boolean + */ + public function isAd() + { + $this->execDiscovery(); + $caps = $this->connection->getCapabilities(); + return isset($caps->msCapabilities->ActiveDirectoryOid) && $caps->msCapabilities->ActiveDirectoryOid; + } + + /** + * Whether the discovery was successful + * + * @return bool False when the suggestions are guessed + */ + public function isSuccess() + { + $this->execDiscovery(); + return $this->connection->discoverySuccessful(); + } + + /** + * Discover LDAP servers on the given domain + * + * @param string $domain The object containing the form elements + * + * @return Discovery True when the discovery was successful, false when the configuration was guessed + */ + public static function discoverDomain($domain) + { + if (! isset($domain)) { + return false; + } + + // Attempt 1: Connect to the domain directly + $disc = Discovery::discover($domain, 389); + if ($disc->isSuccess()) { + return $disc; + } + + // Attempt 2: Discover all available ldap dns records and connect to the first one + $records = array_merge(Dns::getSrvRecords($domain, 'ldap'), Dns::getSrvRecords($domain, 'ldaps')); + if (isset($records[0])) { + $record = $records[0]; + return Discovery::discover( + isset($record['target']) ? $record['target'] : $domain, + isset($record['port']) ? $record['port'] : $domain + ); + } + + // Return the first failed discovery, which will suggest properties based on guesses + return $disc; + } + + /** + * Convenience method to instantiate a new Discovery + * + * @param $host The host on which to execute the discovery + * @param $port The port on which to execute the discovery + * + * @return Discover The resulting Discovery + */ + public static function discover($host, $port) + { + $conn = new Connection(new ConfigObject(array( + 'hostname' => $host, + 'port' => $port + ))); + return new Discovery($conn); + } +} \ No newline at end of file diff --git a/library/Icinga/Protocol/Livestatus/Connection.php b/library/Icinga/Protocol/Livestatus/Connection.php index c014ba70f..b2340eeec 100644 --- a/library/Icinga/Protocol/Livestatus/Connection.php +++ b/library/Icinga/Protocol/Livestatus/Connection.php @@ -5,8 +5,11 @@ namespace Icinga\Protocol\Livestatus; use Icinga\Application\Benchmark; -use Exception; +use Icinga\Exception\ConfigurationError; +use Icinga\Exception\SystemPermissionException; use Icinga\Exception\IcingaException; +use Exception; +use SplFixedArray; /** * Backend class managing handling MKI Livestatus connections @@ -31,6 +34,15 @@ class Connection const TYPE_UNIX = 1; const TYPE_TCP = 2; + const FIELD_SEPARATOR = '`'; + + protected $bytesRead = 0; + protected $responseSize; + protected $status; + protected $headers; + + // List of available Livestatus tables. Kept here as we otherwise get no + // useful error message protected $available_tables = array( 'hosts', // hosts 'services', // services, joined with all data from hosts @@ -64,6 +76,13 @@ class Connection protected $socket_type; protected $connection; + /** + * Whether the given table name is valid + * + * @param string $name table name + * + * @return bool + */ public function hasTable($name) { return in_array($name, $this->available_tables); @@ -74,7 +93,7 @@ class Connection $this->assertPhpExtensionLoaded('sockets'); if ($socket[0] === '/') { if (! is_writable($socket)) { - throw new IcingaException( + throw new SystemPermissionException( 'Cannot write to livestatus socket "%s"', $socket ); @@ -83,52 +102,106 @@ class Connection $this->socket_path = $socket; } else { if (! preg_match('~^tcp://([^:]+):(\d+)~', $socket, $m)) { - throw new IcingaException( + throw new ConfigurationError( 'Invalid TCP socket syntax: "%s"', $socket ); } - // TODO: Better syntax checks + // TODO: Better config syntax checks $this->socket_host = $m[1]; $this->socket_port = (int) $m[2]; $this->socket_type = self::TYPE_TCP; } } - public function select() - { - $select = new Query($this); - return $select; - } - + /** + * Count unlimited rows matching the query filter + * + * TODO: Currently hardcoded value, as the old variant was stupid + * Create a working variant doing this->execute(query->renderCount())... + * + * @param Query $query the query object + * + * @return int + */ public function count(Query $query) { + return 100; $count = clone($query); - $count->count(); + // WTF? $count->count(); Benchmark::measure('Sending Livestatus Count Query'); - $data = $this->doFetch((string) $count); + $this->execute($query); + $data = $this->fetchRowFromSocket(); Benchmark::measure('Got Livestatus count result'); return $data[0][0]; } + /** + * Fetch a single row + * + * TODO: Currently based on fetchAll, that's bullshit + * + * @param Query $query the query object + * + * @return object the first result row + */ + public function fetchRow(Query $query) + { + $all = $this->fetchAll($query); + return array_shift($all); + } + + /** + * Fetch key/value pairs + * + * TODO: Currently slow, needs improvement + * + * @param Query $query the query object + * + * @return array + */ + public function fetchPairs(Query $query) + { + $res = array(); + $all = $this->fetchAll($query); + foreach ($all as $row) { + // slow + $keys = array_keys((array) $row); + $res[$row->{$keys[0]}] = $row->{$keys[1]}; + } + return $res; + } + + /** + * Fetch all result rows + * + * @param Query $query the query object + * + * @return array + */ public function fetchAll(Query $query) { Benchmark::measure('Sending Livestatus Query'); - $data = $this->doFetch((string) $query); + $this->execute($query); Benchmark::measure('Got Livestatus Data'); + if ($query->hasColumns()) { $headers = $query->getColumnAliases(); } else { + // TODO: left this here, find out how to handle it better + die('F*** no data'); $headers = array_shift($data); } $result = array(); - foreach ($data as $row) { - $result_row = & $result[]; - $result_row = (object) array(); - foreach ($row as $key => $val) { - $result_row->{$headers[$key]} = $val; - } + $filter = $query->filterIsSupported() ? null : $query->getFilter(); + + while ($row = $this->fetchRowFromSocket()) { + $r = new ResponseRow($row, $query); + $res = $query->resultRow($row); + if ($filter !== null && ! $filter->matches($res)) continue; + $result[] = $res; } + if ($query->hasOrder()) { usort($result, array($query, 'compare')); } @@ -144,70 +217,137 @@ class Connection return $result; } - protected function doFetch($raw_query) + protected function hasBeenExecuted() { - $conn = $this->getConnection(); - $this->writeToSocket($raw_query); - $header = $this->readFromSocket(16); - $status = (int) substr($header, 0, 3); - $length = (int) trim(substr($header, 4)); - $body = $this->readFromSocket($length); - if ($status !== 200) { - throw new IcingaException( - 'Problem while reading %d bytes from livestatus: %s', - $length, - $body - ); - } - $result = json_decode($body); - if ($result === null) { - throw new IcingaException('Got invalid response body from livestatus'); - } - - return $result; + return $this->status !== null; } - protected function readFromSocket($length) + protected function execute($query) { - $offset = 0; - $buffer = ''; + // Reset state + $this->status = null; + $this->responseSize = null; + $this->bytesRead = 0; - while ($offset < $length) { - $data = socket_read($this->connection, $length - $offset); - if ($data === false) { - throw new IcingaException( - 'Failed to read from livestatus socket: %s', - socket_strerror(socket_last_error($this->connection)) - ); - } - $size = strlen($data); - $offset += $size; - $buffer .= $data; + $raw = $query->toString(); - if ($size === 0) { - break; - } - } - if ($offset !== $length) { - throw new IcingaException( - 'Got only %d instead of %d bytes from livestatus socket', - $offset, - $length + Benchmark::measure($raw); + + // "debug" + // echo $raw . "\n
"; + $this->writeToSocket($raw); + $header = $this->readLineFromSocket(); + + if (! preg_match('~^(\d{3})\s\s*(\d+)$~', $header, $m)) { + $this->disconnect(); + throw new Exception( + sprintf('Got invalid header. First 16 Bytes: %s', $header) ); } - - return $buffer; + $this->status = (int) $m[1]; + $this->bytesRead = 0; + $this->responseSize = (int) $m[2]; + if ($this->status !== 200) { + // "debug" + //die(var_export($raw, 1)); + throw new Exception( + sprintf( + 'Error %d while querying livestatus: %s %s', + $this->status, + $raw, + $this->readLineFromSocket() + ) + ); + } + $this->discoverColumnHeaders($query); } + protected function discoverColumnHeaders($query) + { + if ($query->hasColumns()) { + $this->headers = $query->getColumnAliases(); + } else { + $this->headers = $this->splitLine($this->readLineFromSocket()); + } + } + + protected function splitLine(& $line) + { + if ($this->headers === null) { + $res = array(); + } else { + $res = new SplFixedArray(count($this->headers)); + $size = count($res); + } + $start = 0; + $col = 0; + while (false !== ($pos = strpos($line, self::FIELD_SEPARATOR, $start))) { +// TODO: safety measure for not killing the SPL. To be removed once code is clean +if ($col > $size -1 ) return $res; // ??? + $res[$col] = substr($line, $start, $pos - $start); + $start = $pos + 1; + $col++; + } +// TODO: safety measure for not killing the SPL. To be removed once code is clean +if ($col > $size - 1) return $res; + $res[$col] = rtrim(substr($line, $start), "\r\n"); + return $res; + } + + public function fetchRowFromSocket() + { + $line = $this->readLineFromSocket(); + if (! $line) { + return false; + } + return $this->splitLine($line); + } + + protected function readLineFromSocket() + { + if ($this->bytesRead === $this->responseSize) { + return false; + } + $maxRowLength = 100 * 1024; + $row = socket_read($this->getConnection(), $maxRowLength, PHP_NORMAL_READ); + $this->bytesRead += strlen($row); + + if ($row === false) { + $this->socketError('Failed to read next row from livestatus socket'); + } + return $row; + } + + /** + * Write given string to livestatus socket + * + * @param string $data Data string to write to the socket + * + * @return boolean + */ protected function writeToSocket($data) { - $res = socket_write($this->connection, $data); + $res = @socket_write($this->getConnection(), $data); if ($res === false) { - throw new IcingaException('Writing to livestatus socket failed'); + $this->socketError('Writing to livestatus socket failed'); } return true; } + /** + * Raise an exception showing given message string and last socket error + * + * TODO: Find a better exception type for such errors + * + * @throws IcingaException + */ + protected function socketError($msg) + { + throw new IcingaException( + $msg . ': ' . socket_strerror(socket_last_error($this->connection)) + ); + } + protected function assertPhpExtensionLoaded($name) { if (! extension_loaded($name)) { @@ -221,22 +361,24 @@ class Connection protected function getConnection() { if ($this->connection === null) { + Benchmark::measure('Establishing livestatus connection...'); + if ($this->socket_type === self::TYPE_TCP) { $this->establishTcpConnection(); + Benchmark::measure('...got TCP socket'); } else { $this->establishSocketConnection(); + Benchmark::measure('...got local socket'); } } return $this->connection; } + /** + * Establish a TCP socket connection + */ protected function establishTcpConnection() { - // TODO: find a bedder place for this - if (! defined('TCP_NODELAY')) { - define('TCP_NODELAY', 1); - } - $this->connection = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (! @socket_connect($this->connection, $this->socket_host, $this->socket_port)) { throw new IcingaException( @@ -249,6 +391,9 @@ class Connection socket_set_option($this->connection, SOL_TCP, TCP_NODELAY, 1); } + /** + * Establish a UNIX socket connection + */ protected function establishSocketConnection() { $this->connection = socket_create(AF_UNIX, SOCK_STREAM, 0); @@ -269,13 +414,26 @@ class Connection return $this; } + /** + * Disconnect in case we are connected to a Livestatus socket + * + * @return self + */ public function disconnect() { - if ($this->connection) { + if (is_resource($this->connection) + && get_resource_type($this->connection) === 'Socket') + { + Benchmark::measure('Disconnecting livestatus...'); socket_close($this->connection); + Benchmark::measure('...socket closed'); } + return $this; } + /** + * Try to cleanly close the socket on shutdown + */ public function __destruct() { $this->disconnect(); diff --git a/library/Icinga/Protocol/Livestatus/Query.php b/library/Icinga/Protocol/Livestatus/Query.php index 7c1e73c8a..a421c7e71 100644 --- a/library/Icinga/Protocol/Livestatus/Query.php +++ b/library/Icinga/Protocol/Livestatus/Query.php @@ -4,135 +4,49 @@ namespace Icinga\Protocol\Livestatus; -use Icinga\Protocol\AbstractQuery; +use Icinga\Data\SimpleQuery; use Icinga\Exception\IcingaException; +use Icinga\Data\Filter\Filter; +use Icinga\Data\Filter\FilterChain; +use Icinga\Data\Filter\FilterExpression; +use Icinga\Data\Filter\FilterOr; +use Icinga\Data\Filter\FilterAnd; +use Icinga\Data\Filter\FilterNot; +use Exception; -class Query extends AbstractQuery +class Query extends SimpleQuery { + protected $customvars = array(); + + /** + * Columns in this array are always "combined" ones creating their value + * based on a filter expression. The result is always either "1" or "0" + */ + protected $filter_flags = array(); + + /** + * Columns that return arrays. Will be decoded. + */ + protected $arrayColumns = array( + 'members' => true, + ); + + /** + * Columns to be fetched for sorting / filtering, will not be returned + */ + protected $extraFiltercolumns = array(); + + /** + * All available columns. To be overridden by specific query implementations + */ + protected $available_columns = array(); - protected $connection; - protected $table; - protected $filters = array(); - protected $limit_count; - protected $limit_offset; - protected $columns; - protected $order_columns = array(); protected $count = false; - public function __construct(Connection $connection) - { - $this->connection = $connection; - } - - public function getAdapter() - { - return $this->connection; - } - - public function compare(& $a, & $b, $col_num = 0) - { - if (! array_key_exists($col_num, $this->order_columns)) { - return 0; - } - $col = $this->order_columns[$col_num][0]; - $dir = $this->order_columns[$col_num][1]; - - //$res = strnatcmp(strtolower($a->$col), strtolower($b->$col)); - $res = strcmp(strtolower($a->$col), strtolower($b->$col)); - if ($res === 0) { - if (array_key_exists(++$col_num, $this->order_columns)) { - return $this->compare($a, $b, $col_num); - } else { - return 0; - } - } - if ($dir === self::SORT_ASC) { - return $res; - } else { - return $res * -1; - } - } - - public function hasOrder() - { - return ! empty($this->order_columns); - } - - public function where($key, $val = null) - { - $this->filters[$key] = $val; - return $this; - } - - public function order($col) - { - if (($pos = strpos($col, ' ')) === false) { - $col = $col; - $dir = self::SORT_ASC; - } else { - $dir = strtoupper(substr($col, $pos + 1)); - if ($dir === 'DESC') { - $dir = self::SORT_DESC; - } else { - $dir = self::SORT_ASC; - } - $col = substr($col, 0, $pos); - } - $this->order_columns[] = array($col, $dir); - return $this; - } - - // Nur wenn keine stats, sonst im RAM!! - // Offset gibt es nicht, muss simuliert werden - public function limit($count = null, $offset = null) - { - if (! preg_match('~^\d+~', $count . $offset)) { - throw new IcingaException( - 'Got invalid limit: %s, %s', - $count, - $offset - ); - } - $this->limit_count = (int) $count; - $this->limit_offset = (int) $offset; - return $this; - } - - public function hasLimit() - { - return $this->limit_count !== null; - } - - public function hasOffset() - { - return $this->limit_offset > 0; - } - - public function getLimit() - { - return $this->limit_count; - } - - public function getOffset() - { - return $this->limit_offset; - } - - public function from($table, $columns = null) - { - if (! $this->connection->hasTable($table)) { - throw new IcingaException( - 'This livestatus connection does not provide "%s"', - $table - ); - } - $this->table = $table; - if (is_array($columns)) { - // TODO: check for valid names? - $this->columns = $columns; - } - return $this; - } + /** + * Headers for columns sent to Livestatus socket + */ + protected $preparedHeaders = array(); public function hasColumns() { @@ -144,10 +58,133 @@ class Query extends AbstractQuery return $this->columns; } + public function withHeaders(& $row) + { + return array_combine($this->preparedHeaders, $row->toArray()); + } + + /** + * Whether the named columns value is generated by a filter expression + */ + public function isFilterFlag($column) + { + return array_key_exists($column, $this->filter_flags); + } + + // completes a given row + public function resultRow(& $row) + { + // $row -> raw SplArray + // $res -> object + // $cv -> + // $result -> object to be returned + $result = (object) array(); + $res = $this->withHeaders($row); + $cv = array(); + if (array_key_exists('custom_variables', $res)) { + foreach ($this->parseArray($res['custom_variables']) as $cvp) { + $cv[$cvp[0]] = $cvp[1]; + } + } + + $combined = array(); + + foreach ($this->columns as $alias => $col) { + if (is_int($alias)) { + $alias = $col; + } + if ($col[0] === '_') { + $result->$alias = array_key_exists($alias, $cv) ? $cv[$alias] : null; + } else { + $func = 'mungeResult_' . $col; + if (method_exists($this, $func)) { + $this->$func($res[$this->available_columns[$col]], $result); + } elseif (is_array($this->available_columns[$col])) { + $combined[$alias] = $col; + $result->$alias = null; + } else { + if (strpos($this->available_columns[$col], ' ') === false) { + $result->$alias = $res[$this->available_columns[$col]]; + } else { + $result->$alias = $res[$alias]; + } + } + } + } + // TODO: Quite some redundancy here :( + if (! $this->filterIsSupported()) { + foreach ($this->filter->listFilteredColumns() as $col) { + if ($this->isFilterFlag($col)) { + $result->$col = (string) (int) $this->filterStringToFilter( + $this->filter_flags[$col] + )->matches((object) $res); + } else { + $func = 'combineResult_' . $col; + if (method_exists($this, $func)) { + $result->$col = $this->$func($result, $res); + } + } + } + } + + foreach ($combined as $alias => $col) { + if ($this->isFilterFlag($col)) { + $result->$alias = (string) (int) $this->filterStringToFilter( + $this->filter_flags[$col] + )->matches((object) $res); + continue; + } + $func = 'combineResult_' . $col; + if (method_exists($this, $func)) { + $result->$alias = $this->$func($result, $res); + } else { + $result->$alias = implode(' - ', $this->available_columns[$col]); + } + } + + + return $result; + } + + /** + * Parse the given encoded array + * + * @param string $str the encoded array string + * + * @return array + */ + public function parseArray($str) + { + if (empty($str)) { + return array(); + } + + $result = array(); + $entries = preg_split('/,/', $str); + foreach ($entries as $e) { + $result[] = preg_split('/;/', $e); + } + + return $result; + } + public function getColumnAliases() { + $this->columnsToString(); + return $this->preparedHeaders; + + // TODO: Remove once no longer needed: $aliases = array(); + $hasCustom = false; foreach ($this->getColumns() as $key => $val) { + if ($val[0] === '_') { + $this->customvars[$val] = null; + if (! $hasCustom) { + $aliases[] = 'custom_variables'; + $hasCustom = true; + } + continue; + } if (is_int($key)) { $aliases[] = $val; } else { @@ -156,57 +193,277 @@ class Query extends AbstractQuery } return $aliases; } - +/* public function count() { $this->count = true; return $this; } +*/ + /** + * Automagic string casting + * + * @return string + */ public function __toString() + { + try { + return $this->toString(); + } catch (Exception $e) { + trigger_error( + sprintf( + '%s in %s on line %d', + $e->getMessage(), + $e->getFile(), + $e->getLine() + ), + E_USER_ERROR + ); + } + } + + /** + * Render query string + * + * @return string + */ + public function toString() { if ($this->table === null) { throw new IcingaException('Table is required'); } + + // Headers we always send $default_headers = array( - 'OutputFormat: json', + // Our preferred output format is CSV as it allows us to fetch and + // process the result row by row + 'OutputFormat: csv', 'ResponseHeader: fixed16', + // Tried to find a save list of separators, this might be subject to + // change and eventually be transforment into constants + 'Separators: ' . implode(' ', array(ord("\n"), ord('`'), ord(','), ord(';'))), + // We always use the keepalive feature, connection teardown happens + // in the connection destructor 'KeepAlive: on' ); $parts = array( sprintf('GET %s', $this->table) ); - if ($this->count === false && $this->columns !== null) { - $parts[] = 'Columns: ' . implode(' ', $this->columns); - } - foreach ($this->filters as $key => $val) { - if ($key === 'search') { - $parts[] = 'Filter: host_name ~~ ' . $val; - $parts[] = 'Filter: description ~~ ' . $val; - $parts[] = 'Or: 2'; - continue; - } - if ($val === null) { - $parts[] = 'Filter: ' . $key; - } elseif (strpos($key, '?') === false) { - $parts[] = sprintf('Filter: %s = %s', $key, $val); - } else { - $parts[] = sprintf('Filter: %s', str_replace('?', $val, $key)); - } + + // Fetch all required columns + $parts[] = $this->columnsToString(); + + // In case we need to apply a userspace filter as of Livestatus lacking + // support for some of them we also need to fetch all filtered columns + if ($this->filterIsSupported() && $filter = $this->filterToString()) { + $parts[] = $filter; } + + // TODO: Old way of rendering a count query, this should definitively be + // improved if ($this->count === true) { $parts[] = 'Stats: state >= 0'; } + + // TODO: Well... ordering is still missing if (! $this->count && $this->hasLimit() && ! $this->hasOrder()) { - $parts[] = 'Limit: ' . ($this->limit_count + $this->limit_offset); + $parts[] = 'Limit: ' . ($this->getLimit() + $this->getOffset()); } $lql = implode("\n", $parts) . "\n" . implode("\n", $default_headers) . "\n\n"; + return $lql; } + /** + * Get all available columns + * + * @return array + */ + public function getAvailableColumns() + { + return $this->available_columns; + } + + protected function columnsToString() + { + $columns = array(); + $this->preparedHeaders = array(); + + + $usedColumns = $this->columns; + if (! $this->filterIsSupported()) { + foreach ($this->filter->listFilteredColumns() as $col) { + if (! in_array($col, $usedColumns)) { + $usedColumns[] = $col; + } + } + } + foreach ($usedColumns as $col) { +// TODO: No alias if filter??? + if (array_key_exists($col, $this->available_columns)) { + // Alias if such + $col = $this->available_columns[$col]; + } + if ($col[0] === '_') { + $columns['custom_variables'] = true; + } elseif (is_array($col)) { + foreach ($col as $k) { + $columns[$k] = true; + } + } else { + $columns[$col] = true; + } + } + + $this->preparedHeaders = array_keys($columns); + + if ($this->count === false && $this->columns !== null) { + return 'Columns: ' . implode(' ', array_keys($columns)); + } else { + return ''; // TODO: 'Stats: state >= 0'; when count + } + } + + /** + * Whether Livestatus is able to apply the current filter + * + * TODO: find a better method name + * TODO: more granular checks, also render filter-flag columns with lql + * + * @return bool + */ + public function filterIsSupported() + { + foreach ($this->filter->listFilteredColumns() as $column) { + if (is_array($this->available_columns[$column])) { + // Combined column, hardly filterable. Is it? May work! + return false; + } + } + return true; + } + + /** + * Create a Filter object for a given URL-like filter string. We allow + * for spaces as we do not search for custom string values here. This is + * internal voodoo. + * + * @param string $string Filter string + * + * @return Filter + */ + protected function filterStringToFilter($string) + { + return Filter::fromQueryString(str_replace(' ', '', $string)); + } + + /** + * Render the current filter to LQL + * + * @return string + */ + protected function filterToString() + { + return $this->renderFilter($this->filter); + } + + /** + * Filter rendering + * + * Happens recursively, useful for filters and for Stats expressions + * + * @param Filter $filter The filter that should be rendered + * @param string $type Filter type. Usually "Filter" or "Stats" + * @param int $level Nesting level during recursion. Don't touch + * @param bool $keylookup Whether to resolve alias names + * + * @return string + */ + protected function renderFilter(Filter $filter, $type = 'Filter', $level = 0, $keylookup = true) + { + $str = ''; + if ($filter instanceof FilterChain) { + if ($filter instanceof FilterAnd) { + $op = 'And'; + } elseif ($filter instanceof FilterOr) { + $op = 'Or'; + } elseif ($filter instanceof FilterNot) { + $op = 'Negate'; + } else { + throw new IcingaException( + 'Cannot render filter: %s', + $filter + ); + } + $parts = array(); + if (! $filter->isEmpty()) { + foreach ($filter->filters() as $f) { + $parts[] = $this->renderFilter($f, $type, $level + 1, $keylookup); + } + $str .= implode("\n", $parts); + if ($type === 'Filter') { + if (count($parts) > 1) { + $str .= "\n" . $op . ': ' . count($parts); + } + } else { + $str .= "\n" . $type . $op . ': ' . count($parts); + } + } + } else { + $str .= $type . ': ' . $this->renderFilterExpression($filter, $keylookup); + } + + return $str; + } + + /** + * Produce a safe regex string as required by LQL + * + * @param string $expression search expression + * + * @return string + */ + protected function safeRegex($expression) + { + return '^' . preg_replace('/\*/', '.*', $expression) . '$'; + } + + /** + * Render a single filter expression + * + * @param FilterExpression $filter the filter expression + * @param bool $keylookup whether to resolve alias names + * + * @return string + */ + public function renderFilterExpression(FilterExpression $filter, $keylookup = true) + { + if ($keylookup) { + $col = $this->available_columns[$filter->getColumn()]; + } else { + $col = $filter->getColumn(); + } + + $isArray = array_key_exists($col, $this->arrayColumns); + + $sign = $filter->getSign(); + if ($isArray && $sign === '=') { + $sign = '>='; + } + $expression = $filter->getExpression(); + if ($sign === '=' && strpos($expression, '*') !== false) { + return $col . ' ~~ ' . $this->safeRegex($expression); + } elseif ($sign === '!=' && strpos($expression, '*') !== false) { + return $col . ' !~~ ' . $this->safeRegex($expression); + } else { + return $col . ' ' . $sign . ' ' . $expression; + } + } + public function __destruct() { unset($this->connection); diff --git a/library/Icinga/Protocol/Livestatus/ResponseRow.php b/library/Icinga/Protocol/Livestatus/ResponseRow.php new file mode 100644 index 000000000..d4b0fd7cb --- /dev/null +++ b/library/Icinga/Protocol/Livestatus/ResponseRow.php @@ -0,0 +1,18 @@ +raw = $raw; + $this->query = $query; + } +} diff --git a/library/Icinga/Test/BaseTestCase.php b/library/Icinga/Test/BaseTestCase.php index a735550cb..c70bc5cd9 100644 --- a/library/Icinga/Test/BaseTestCase.php +++ b/library/Icinga/Test/BaseTestCase.php @@ -24,10 +24,10 @@ namespace Icinga\Test { use Exception; use RuntimeException; use Mockery; - use Zend_Config; use PHPUnit_Framework_TestCase; use Icinga\Application\Icinga; use Icinga\Util\DateTimeFactory; + use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Data\Db\DbConnection; @@ -158,11 +158,17 @@ namespace Icinga\Test { ->andReturnUsing(function ($name, $default) { return $default; })->byDefault(); $responseMock = Mockery::mock('Icinga\Web\Response')->shouldDeferMissing(); - // Can't express this as demeter chains. See: https://github.com/padraic/mockery/issues/59 $bootstrapMock = Mockery::mock('Icinga\Application\ApplicationBootstrap')->shouldDeferMissing(); + $libDir = dirname(self::$libDir); $bootstrapMock->shouldReceive('getFrontController')->andReturn($bootstrapMock) ->shouldReceive('getApplicationDir')->andReturn(self::$appDir) + ->shouldReceive('getLibraryDir')->andReturnUsing(function ($subdir = null) use ($libDir) { + if ($subdir !== null) { + $libDir .= '/' . ltrim($subdir, '/'); + } + return $libDir; + }) ->shouldReceive('getRequest')->andReturn($requestMock) ->shouldReceive('getResponse')->andReturn($responseMock); @@ -191,17 +197,17 @@ namespace Icinga\Test { } /** - * Create Zend_Config for database configuration + * Create Config for database configuration * * @param string $name * - * @return Zend_Config + * @return ConfigObject * @throws RuntimeException */ protected function createDbConfigFor($name) { if (array_key_exists($name, self::$dbConfiguration)) { - return new Zend_Config(self::$dbConfiguration[$name]); + return new ConfigObject(self::$dbConfiguration[$name]); } throw new RuntimeException('Configuration for database type not available: ' . $name); diff --git a/library/Icinga/User/Preferences/PreferencesStore.php b/library/Icinga/User/Preferences/PreferencesStore.php index b8121eb25..c2cba0c41 100644 --- a/library/Icinga/User/Preferences/PreferencesStore.php +++ b/library/Icinga/User/Preferences/PreferencesStore.php @@ -4,13 +4,13 @@ namespace Icinga\User\Preferences; -use Zend_Config; +use Icinga\Application\Config; use Icinga\User; use Icinga\User\Preferences; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Exception\ConfigurationError; use Icinga\Data\Db\DbConnection; -use Icinga\Application\Config as IcingaConfig; /** * Preferences store factory @@ -19,14 +19,14 @@ use Icinga\Application\Config as IcingaConfig; * * 'ini', + * new ConfigObject( + * 'type' => 'ini', * 'config_path' => '/path/to/preferences' * ), * $user // Instance of \Icinga\User @@ -42,7 +42,7 @@ abstract class PreferencesStore /** * Store config * - * @var Zend_Config + * @var ConfigObject */ protected $config; @@ -56,10 +56,10 @@ abstract class PreferencesStore /** * Create a new store * - * @param Zend_Config $config The config for this adapter + * @param ConfigObject $config The config for this adapter * @param User $user The user to which these preferences belong */ - public function __construct(Zend_Config $config, User $user) + public function __construct(ConfigObject $config, User $user) { $this->config = $config; $this->user = $user; @@ -69,7 +69,7 @@ abstract class PreferencesStore /** * Getter for the store config * - * @return Zend_Config + * @return ConfigObject */ public function getStoreConfig() { @@ -108,14 +108,14 @@ abstract class PreferencesStore /** * Create preferences storage adapter from config * - * @param Zend_Config $config The config for the adapter + * @param ConfigObject $config The config for the adapter * @param User $user The user to which these preferences belong * * @return self * * @throws ConfigurationError When the configuration defines an invalid storage type */ - public static function create(Zend_Config $config, User $user) + public static function create(ConfigObject $config, User $user) { if (($type = $config->type) === null) { throw new ConfigurationError( @@ -133,7 +133,7 @@ abstract class PreferencesStore } if ($type === 'Ini') { - $config->location = IcingaConfig::resolvePath('preferences'); + $config->location = Config::resolvePath('preferences'); } elseif ($type === 'Db') { $config->connection = new DbConnection(ResourceFactory::getResourceConfig($config->resource)); } diff --git a/library/Icinga/User/Preferences/Store/DbStore.php b/library/Icinga/User/Preferences/Store/DbStore.php index 348a4f04d..4d7b10584 100644 --- a/library/Icinga/User/Preferences/Store/DbStore.php +++ b/library/Icinga/User/Preferences/Store/DbStore.php @@ -9,6 +9,7 @@ use Icinga\Exception\NotReadableError; use Icinga\Exception\NotWritableError; use Icinga\User\Preferences; use Icinga\User\Preferences\PreferencesStore; +use Zend_Db_Expr; /** * Load and save user preferences by using a database @@ -20,22 +21,37 @@ class DbStore extends PreferencesStore */ const COLUMN_USERNAME = 'username'; + /** + * Column name for section + */ + const COLUMN_SECTION = 'section'; + /** * Column name for preference */ - const COLUMN_PREFERENCE = 'key'; + const COLUMN_PREFERENCE = 'name'; /** * Column name for value */ const COLUMN_VALUE = 'value'; + /** + * Column name for created time + */ + const COLUMN_CREATED_TIME = 'ctime'; + + /** + * Column name for modified time + */ + const COLUMN_MODIFIED_TIME = 'mtime'; + /** * Table name * * @var string */ - protected $table = 'preference'; + protected $table = 'icingaweb_user_preference'; /** * Stored preferences @@ -72,9 +88,11 @@ class DbStore extends PreferencesStore public function load() { try { - $select = $this->getStoreConfig()->connection->select(); - $result = $select->from($this->table, array(self::COLUMN_PREFERENCE, self::COLUMN_VALUE)) + $select = $this->getStoreConfig()->connection->getDbAdapter()->select(); + $result = $select + ->from($this->table, array(self::COLUMN_SECTION, self::COLUMN_PREFERENCE, self::COLUMN_VALUE)) ->where(self::COLUMN_USERNAME . ' = ?', $this->getUser()->getUsername()) + ->query() ->fetchAll(); } catch (Exception $e) { throw new NotReadableError( @@ -87,7 +105,7 @@ class DbStore extends PreferencesStore if ($result !== false) { $values = array(); foreach ($result as $row) { - $values[$row->{self::COLUMN_PREFERENCE}] = $row->{self::COLUMN_VALUE}; + $values[$row->{self::COLUMN_SECTION}][$row->{self::COLUMN_PREFERENCE}] = $row->{self::COLUMN_VALUE}; } $this->preferences = $values; } @@ -104,22 +122,32 @@ class DbStore extends PreferencesStore { $preferences = $preferences->toArray(); - $toBeInserted = array_diff_key($preferences, $this->preferences); - if (!empty($toBeInserted)) { - $this->insert($toBeInserted); - } + $sections = array_keys($preferences); - $toBeUpdated = array_intersect_key( - array_diff_assoc($preferences, $this->preferences), - array_diff_assoc($this->preferences, $preferences) - ); - if (!empty($toBeUpdated)) { - $this->update($toBeUpdated); - } + foreach ($sections as $section) { + if (! array_key_exists($section, $this->preferences)) { + $this->preferences[$section] = array(); + } + if (! array_key_exists($section, $preferences)) { + $preferences[$section] = array(); + } + $toBeInserted = array_diff_key($preferences[$section], $this->preferences[$section]); + if (!empty($toBeInserted)) { + $this->insert($toBeInserted, $section); + } - $toBeDeleted = array_keys(array_diff_key($this->preferences, $preferences)); - if (!empty($toBeDeleted)) { - $this->delete($toBeDeleted); + $toBeUpdated = array_intersect_key( + array_diff_assoc($preferences[$section], $this->preferences[$section]), + array_diff_assoc($this->preferences[$section], $preferences[$section]) + ); + if (!empty($toBeUpdated)) { + $this->update($toBeUpdated, $section); + } + + $toBeDeleted = array_keys(array_diff_key($this->preferences[$section], $preferences[$section])); + if (!empty($toBeDeleted)) { + $this->delete($toBeDeleted, $section); + } } } @@ -127,12 +155,14 @@ class DbStore extends PreferencesStore * Insert the given preferences into the database * * @param array $preferences The preferences to insert + * @param string $section The preferences in section to update * * @throws NotWritableError In case the database operation failed */ - protected function insert(array $preferences) + protected function insert(array $preferences, $section) { - $db = $this->getStoreConfig()->connection->getConnection(); + /** @var \Zend_Db_Adapter_Abstract $db */ + $db = $this->getStoreConfig()->connection->getDbAdapter(); try { foreach ($preferences as $key => $value) { @@ -140,8 +170,11 @@ class DbStore extends PreferencesStore $this->table, array( self::COLUMN_USERNAME => $this->getUser()->getUsername(), + $db->quoteIdentifier(self::COLUMN_SECTION) => $section, $db->quoteIdentifier(self::COLUMN_PREFERENCE) => $key, - self::COLUMN_VALUE => $value + self::COLUMN_VALUE => $value, + self::COLUMN_CREATED_TIME => new Zend_Db_Expr('NOW()'), + self::COLUMN_MODIFIED_TIME => new Zend_Db_Expr('NOW()') ) ); } @@ -158,12 +191,14 @@ class DbStore extends PreferencesStore * Update the given preferences in the database * * @param array $preferences The preferences to update + * @param string $section The preferences in section to update * * @throws NotWritableError In case the database operation failed */ - protected function update(array $preferences) + protected function update(array $preferences, $section) { - $db = $this->getStoreConfig()->connection->getConnection(); + /** @var \Zend_Db_Adapter_Abstract $db */ + $db = $this->getStoreConfig()->connection->getDbAdapter(); try { foreach ($preferences as $key => $value) { @@ -172,7 +207,9 @@ class DbStore extends PreferencesStore array(self::COLUMN_VALUE => $value), array( self::COLUMN_USERNAME . '=?' => $this->getUser()->getUsername(), - $db->quoteIdentifier(self::COLUMN_PREFERENCE) . '=?' => $key + $db->quoteIdentifier(self::COLUMN_SECTION) . '=?' => $section, + $db->quoteIdentifier(self::COLUMN_PREFERENCE) . '=?' => $key, + self::COLUMN_MODIFIED_TIME => new Zend_Db_Expr('NOW()') ) ); } @@ -189,18 +226,21 @@ class DbStore extends PreferencesStore * Delete the given preference names from the database * * @param array $preferenceKeys The preference names to delete + * @param string $section The preferences in section to update * * @throws NotWritableError In case the database operation failed */ - protected function delete(array $preferenceKeys) + protected function delete(array $preferenceKeys, $section) { - $db = $this->getStoreConfig()->connection->getConnection(); + /** @var \Zend_Db_Adapter_Abstract $db */ + $db = $this->getStoreConfig()->connection->getDbAdapter(); try { $db->delete( $this->table, array( self::COLUMN_USERNAME . '=?' => $this->getUser()->getUsername(), + $db->quoteIdentifier(self::COLUMN_SECTION) . '=?' => $section, $db->quoteIdentifier(self::COLUMN_PREFERENCE) . ' IN (?)' => $preferenceKeys ) ); diff --git a/library/Icinga/User/Preferences/Store/IniStore.php b/library/Icinga/User/Preferences/Store/IniStore.php index 1f01925c9..1ba780184 100644 --- a/library/Icinga/User/Preferences/Store/IniStore.php +++ b/library/Icinga/User/Preferences/Store/IniStore.php @@ -4,13 +4,13 @@ namespace Icinga\User\Preferences\Store; -use Zend_Config; -use Icinga\Util\File; -use Icinga\Config\PreservingIniWriter; +use Icinga\Application\Config; use Icinga\Exception\NotReadableError; use Icinga\Exception\NotWritableError; +use Icinga\File\Ini\IniWriter; use Icinga\User\Preferences; use Icinga\User\Preferences\PreferencesStore; +use Icinga\Util\File; /** * Load and save user preferences from and to INI files @@ -34,7 +34,7 @@ class IniStore extends PreferencesStore /** * Writer which stores the preferences * - * @var PreservingIniWriter + * @var IniWriter */ protected $writer; @@ -46,7 +46,7 @@ class IniStore extends PreferencesStore $this->preferencesFile = sprintf( '%s/%s.ini', $this->getStoreConfig()->location, - $this->getUser()->getUsername() + strtolower($this->getUser()->getUsername()) ); } @@ -60,14 +60,14 @@ class IniStore extends PreferencesStore public function load() { if (file_exists($this->preferencesFile)) { - if (!is_readable($this->preferencesFile)) { + if (! is_readable($this->preferencesFile)) { throw new NotReadableError( 'Preferences INI file %s for user %s is not readable', $this->preferencesFile, $this->getUser()->getUsername() ); } else { - $this->preferences = parse_ini_file($this->preferencesFile); + $this->preferences = parse_ini_file($this->preferencesFile, true); } } @@ -81,9 +81,13 @@ class IniStore extends PreferencesStore */ public function save(Preferences $preferences) { - $preferences = $preferences->toArray(); - $this->update(array_diff_assoc($preferences, $this->preferences)); - $this->delete(array_keys(array_diff_key($this->preferences, $preferences))); + $this->preferences = $preferences->toArray(); + + // TODO: Elaborate whether we need to patch the contents + // $preferences = $preferences->toArray(); + // $this->update(array_diff_assoc($preferences, $this->preferences)); + // $this->delete(array_keys(array_diff_key($this->preferences, $preferences))); + $this->write(); } @@ -95,8 +99,8 @@ class IniStore extends PreferencesStore public function write() { if ($this->writer === null) { - if (!file_exists($this->preferencesFile)) { - if (!is_writable($this->getStoreConfig()->location)) { + if (! file_exists($this->preferencesFile)) { + if (! is_writable($this->getStoreConfig()->location)) { throw new NotWritableError( 'Path to the preferences INI files %s is not writable', $this->getStoreConfig()->location @@ -106,7 +110,7 @@ class IniStore extends PreferencesStore File::create($this->preferencesFile, 0664); } - if (!is_writable($this->preferencesFile)) { + if (! is_writable($this->preferencesFile)) { throw new NotWritableError( 'Preferences INI file %s for user %s is not writable', $this->preferencesFile, @@ -114,9 +118,9 @@ class IniStore extends PreferencesStore ); } - $this->writer = new PreservingIniWriter( + $this->writer = new IniWriter( array( - 'config' => new Zend_Config($this->preferences), + 'config' => Config::fromArray($this->preferences), 'filename' => $this->preferencesFile ) ); diff --git a/library/Icinga/Util/Translator.php b/library/Icinga/Util/Translator.php index 755203474..52a84bd62 100644 --- a/library/Icinga/Util/Translator.php +++ b/library/Icinga/Util/Translator.php @@ -224,6 +224,7 @@ class Translator } } } + sort($codes); return $codes; } diff --git a/library/Icinga/Web/Controller.php b/library/Icinga/Web/Controller.php new file mode 100644 index 000000000..111ee244c --- /dev/null +++ b/library/Icinga/Web/Controller.php @@ -0,0 +1,14 @@ +getResponse()->setHeader('X-Icinga-Reload-Css', 'now'); } + $this->shutdownSession(); + $this->getResponse() ->setHeader('X-Icinga-Redirect', rawurlencode($url->getAbsoluteUrl())) ->sendHeaders(); - // TODO: Session shutdown? exit; } + protected function redirectHttp($url) + { + if (! $url instanceof Url) { + $url = Url::fromPath($url); + } + $this->shutdownSession(); + $this->_helper->Redirector->gotoUrlAndExit($url->getRelativeUrl()); + } + /** * Redirect to a specific url, updating the browsers URL field * @@ -343,10 +351,7 @@ class ActionController extends Zend_Controller_Action if ($this->isXhr()) { $this->redirectXhr($url); } else { - if (! $url instanceof Url) { - $url = Url::fromPath($url); - } - $this->_helper->Redirector->gotoUrlAndExit($url->getRelativeUrl()); + $this->redirectHttp($url); } } @@ -374,6 +379,7 @@ class ActionController extends Zend_Controller_Action if ($req->getParam('format') === 'pdf') { $layout->setLayout('pdf'); + $this->shutdownSession(); $this->sendAsPdf(); exit; } @@ -381,6 +387,8 @@ class ActionController extends Zend_Controller_Action if ($this->isXhr()) { $this->postDispatchXhr(); } + + $this->shutdownSession(); } protected function postDispatchXhr() @@ -430,6 +438,14 @@ class ActionController extends Zend_Controller_Action $pdf->renderControllerAction($this); } + protected function shutdownSession() + { + $session = Session::getSession(); + if ($session->hasChanged()) { + $session->write(); + } + } + /** * Render the benchmark * diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index 631b2eb07..37d8789fe 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -36,10 +36,17 @@ class Form extends Zend_Form */ protected $created = false; + /** + * The request associated with this form + * + * @var Request + */ + protected $request; + /** * The callback to call instead of Form::onSuccess() * - * @var Callback + * @var callable */ protected $onSuccess; @@ -94,46 +101,69 @@ class Form extends Zend_Form */ protected $uidElementName = 'formUID'; + /** + * Whether the form should validate the sent data when being automatically submitted + * + * @var bool + */ + protected $validatePartial = false; + /** * Default element decorators * * @var array */ public static $defaultElementDecorators = array( - 'ViewHelper', - 'Errors', - array('Description', array('tag' => 'span', 'class' => 'description')), - 'Label', - array('HtmlTag', array('tag' => 'div')) + array('ViewHelper', array('separator' => '')), + array('Errors', array('separator' => '')), + array('Label', array('separator' => '')), + array('HtmlTag', array('tag' => 'div', 'class' => 'element')) ); /** - * Create a new form - * - * Accepts an additional option `onSuccess' which is a callback that is called instead of this - * form's method. It is called using the following signature: (Request $request, Form $form). - * - * @see Zend_Form::__construct() - * - * @throws LogicException In case `onSuccess' is not callable + * (non-PHPDoc) + * @see \Zend_Form::construct() For the method documentation. */ public function __construct($options = null) { - if (is_array($options) && isset($options['onSuccess'])) { - $this->onSuccess = $options['onSuccess']; - unset($options['onSuccess']); - } elseif (isset($options->onSuccess)) { - $this->onSuccess = $options->onSuccess; - unset($options->onSuccess); - } - - if ($this->onSuccess !== null && false === is_callable($this->onSuccess)) { - throw new LogicException('The option `onSuccess\' is not callable'); - } + // Zend's plugin loader reverses the order of added prefix paths thus trying our paths first before trying + // Zend paths + $this->addPrefixPaths(array( + array( + 'prefix' => 'Icinga\\Web\\Form\\Element\\', + 'path' => Icinga::app()->getLibraryDir('Icinga/Web/Form/Element'), + 'type' => static::ELEMENT + ), + array( + 'prefix' => 'Icinga\\Web\\Form\\Decorator\\', + 'path' => Icinga::app()->getLibraryDir('Icinga/Web/Form/Decorator'), + 'type' => static::DECORATOR + ) + )); parent::__construct($options); } + /** + * Set a callback that is called instead of this form's onSuccess method + * + * It is called using the following signature: (Request $request, Form $form). + * + * @param callable $onSuccess Callback + * + * @return $this + * + * @throws LogicException If the callback is not callable + */ + public function setOnSuccess($onSuccess) + { + if (! is_callable($onSuccess)) { + throw new LogicException('The option `onSuccess\' is not callable'); + } + $this->onSuccess = $onSuccess; + return $this; + } + /** * Set the label to use for the standard submit button * @@ -311,6 +341,29 @@ class Form extends Zend_Form return $this->uidElementName; } + /** + * Set whether this form should validate the sent data when being automatically submitted + * + * @param bool $state + * + * @return self + */ + public function setValidatePartial($state) + { + $this->validatePartial = $state; + return $this; + } + + /** + * Return whether this form should validate the sent data when being automatically submitted + * + * @return bool + */ + public function getValidatePartial() + { + return $this->validatePartial; + } + /** * Create this form * @@ -355,11 +408,9 @@ class Form extends Zend_Form * * Intended to be implemented by concrete form classes. The base implementation returns always FALSE. * - * @param Request $request The valid request used to process this form - * * @return null|bool Return FALSE in case no redirect should take place */ - public function onSuccess(Request $request) + public function onSuccess() { return false; } @@ -368,10 +419,8 @@ class Form extends Zend_Form * Perform actions when no form dependent data was sent * * Intended to be implemented by concrete form classes. - * - * @param Request $request The current request */ - public function onRequest(Request $request) + public function onRequest() { } @@ -437,8 +486,8 @@ class Form extends Zend_Form * `disableLoadDefaultDecorators' option to any other value than `true'. For loading custom element decorators use * the 'decorators' option. * - * @param string $type String element type - * @param string $name The name of the element to add + * @param string $type The type of the element + * @param string $name The name of the element * @param mixed $options The options for the element * * @return Zend_Form_Element @@ -462,8 +511,23 @@ class Form extends Zend_Form $el = parent::createElement($type, $name, $options); - if ($el && $el->getAttrib('autosubmit')) { - $el->addDecorator(new NoScriptApply()); // Non-JS environments + if (($description = $el->getDescription()) !== null && ($label = $el->getDecorator('label')) !== null) { + $label->setOptions(array( + 'title' => $description, + 'class' => 'has-feedback' + )); + } + + if ($el->getAttrib('autosubmit')) { + $noScript = new NoScriptApply(); // Non-JS environments + $decorators = $el->getDecorators(); + $pos = array_search('Zend_Form_Decorator_ViewHelper', array_keys($decorators)) + 1; + $el->setDecorators( + array_slice($decorators, 0, $pos, true) + + array(get_class($noScript) => $noScript) + + array_slice($decorators, $pos, count($decorators) - $pos, true) + ); + $class = $el->getAttrib('class'); if (is_array($class)) { $class[] = 'autosubmit'; @@ -473,6 +537,7 @@ class Form extends Zend_Form $class .= ' autosubmit'; } $el->setAttrib('class', $class); // JS environments + unset($el->autosubmit); } @@ -540,23 +605,25 @@ class Form extends Zend_Form { if ($request === null) { $request = $this->getRequest(); + } else { + $this->request = $request; } - $formData = $this->getRequestData($request); + $formData = $this->getRequestData(); if ($this->getUidDisabled() || $this->wasSent($formData)) { $this->populate($formData); // Necessary to get isSubmitted() to work if (! $this->getSubmitLabel() || $this->isSubmitted()) { if ($this->isValid($formData) - && (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $request, $this)) - || ($this->onSuccess === null && false !== $this->onSuccess($request)))) { + && (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $this)) + || ($this->onSuccess === null && false !== $this->onSuccess()))) { $this->getResponse()->redirectAndExit($this->getRedirectUrl()); } - } else { - // The form can't be processed but we want to show validation errors though + } elseif ($this->getValidatePartial()) { + // The form can't be processed but we may want to show validation errors though $this->isValidPartial($formData); } } else { - $this->onRequest($request); + $this->onRequest(); } return $request; @@ -606,6 +673,14 @@ class Form extends Zend_Form public function isValidPartial(array $formData) { $this->create($formData); + + // Ensure that disabled elements are not overwritten (http://www.zendframework.com/issues/browse/ZF-6909) + foreach ($this->getElements() as $name => $element) { + if ($element->getAttrib('disabled')) { + $formData[$name] = $element->getValue(); + } + } + return parent::isValidPartial($formData); } @@ -619,6 +694,14 @@ class Form extends Zend_Form public function isValid($formData) { $this->create($formData); + + // Ensure that disabled elements are not overwritten (http://www.zendframework.com/issues/browse/ZF-6909) + foreach ($this->getElements() as $name => $element) { + if ($element->getAttrib('disabled')) { + $formData[$name] = $element->getValue(); + } + } + return parent::isValid($formData); } @@ -682,29 +765,19 @@ class Form extends Zend_Form } /** - * Return the request data based on this form's request method + * Return the request associated with this form * - * @param Request $request The request to fetch the data from - * - * @return array - */ - public function getRequestData(Request $request) - { - if (strtolower($request->getMethod()) === $this->getMethod()) { - return $request->{'get' . ($request->isPost() ? 'Post' : 'Query')}(); - } - - return array(); - } - - /** - * Return the current request + * Returns the global request if none has been set for this form yet. * * @return Request */ public function getRequest() { - return Icinga::app()->getFrontController()->getRequest(); + if ($this->request === null) { + $this->request = Icinga::app()->getFrontController()->getRequest(); + } + + return $this->request; } /** @@ -717,6 +790,20 @@ class Form extends Zend_Form return Icinga::app()->getFrontController()->getResponse(); } + /** + * Return the request data based on this form's request method + * + * @return array + */ + protected function getRequestData() + { + if (strtolower($this->request->getMethod()) === $this->getMethod()) { + return $this->request->{'get' . ($this->request->isPost() ? 'Post' : 'Query')}(); + } + + return array(); + } + /** * Render this form * diff --git a/library/Icinga/Web/Form/Decorator/ElementDoubler.php b/library/Icinga/Web/Form/Decorator/ElementDoubler.php new file mode 100644 index 000000000..8bedf9492 --- /dev/null +++ b/library/Icinga/Web/Form/Decorator/ElementDoubler.php @@ -0,0 +1,64 @@ +getElement(); + if ($group->getElement($this->getOption('condition')) !== null) { + if ($this->getPlacement() === static::APPEND) { + return $content . $this->applyAttributes($group->getElement($this->getOption('double')))->render(); + } else { // $this->getPlacement() === static::PREPEND + return $this->applyAttributes($group->getElement($this->getOption('double')))->render() . $content; + } + } + + return $content; + } + + /** + * Apply all element attributes + * + * @param Zend_Form_Element $element The element to apply the attributes to + * + * @return Zend_Form_Element + */ + protected function applyAttributes(Zend_Form_Element $element) + { + $attributes = $this->getOption('attributes'); + if ($attributes !== null) { + foreach ($attributes as $name => $value) { + $element->setAttrib($name, $value); + } + } + + return $element; + } +} diff --git a/library/Icinga/Web/Form/Element/Button.php b/library/Icinga/Web/Form/Element/Button.php new file mode 100644 index 000000000..1c5499373 --- /dev/null +++ b/library/Icinga/Web/Form/Element/Button.php @@ -0,0 +1,81 @@ + $options); + } + + if (!isset($options['ignore'])) { + $options['ignore'] = true; + } + + parent::__construct($spec, $options); + + if ($label = $this->getLabel()) { + // Necessary to get the label shown on the generated HTML + $this->content = $label; + } + } + + /** + * Validate element value (pseudo) + * + * There is no need to reset the value + * + * @param mixed $value Is always ignored + * @param mixed $context Is always ignored + * + * @return bool Returns always TRUE + */ + public function isValid($value, $context = null) + { + return true; + } + + /** + * Has this button been selected? + * + * @return bool + */ + public function isChecked() + { + return $this->getRequest()->getParam($this->getName()) === $this->getValue(); + } + + /** + * Return the current request + * + * @return Request + */ + protected function getRequest() + { + return Icinga::app()->getFrontController()->getRequest(); + } +} diff --git a/library/Icinga/Web/Form/Element/Note.php b/library/Icinga/Web/Form/Element/Note.php index 78881ab44..37bc127e9 100644 --- a/library/Icinga/Web/Form/Element/Note.php +++ b/library/Icinga/Web/Form/Element/Note.php @@ -4,13 +4,12 @@ namespace Icinga\Web\Form\Element; -use Zend_Form_Element; -use Icinga\Web\Form; +use Icinga\Web\Form\FormElement; /** * A note */ -class Note extends Zend_Form_Element +class Note extends FormElement { /** * Form view helper to use for rendering @@ -32,7 +31,15 @@ class Note extends Zend_Form_Element */ public function init() { - $this->setDecorators(Form::$defaultElementDecorators); + if (count($this->getDecorators()) === 0) { + $this->setDecorators(array( + 'ViewHelper', + array( + 'HtmlTag', + array('tag' => 'p') + ) + )); + } } /** diff --git a/library/Icinga/Web/Form/Element/Number.php b/library/Icinga/Web/Form/Element/Number.php index 836142514..02f0aaad3 100644 --- a/library/Icinga/Web/Form/Element/Number.php +++ b/library/Icinga/Web/Form/Element/Number.php @@ -47,7 +47,6 @@ class Number extends FormElement */ public function init() { - $this->addValidator('Float', true); // true for breaking the validator chain on failure if ($this->min !== null) { $this->addValidator('GreaterThan', true, array('min' => $this->min)); } @@ -127,4 +126,19 @@ class Number extends FormElement { return $this->step; } + + /** + * (non-PHPDoc) + * @see \Zend_Form_Element::isValid() For the method documentation. + */ + public function isValid($value, $context = null) + { + $this->setValue($value); + $value = $this->getValue(); + if (! is_numeric($value)) { + $this->addError(sprintf($this->translate('\'%s\' is not a valid number'), $value)); + return false; + } + return parent::isValid($value, $context); + } } diff --git a/library/Icinga/Web/Form/Validator/WritablePathValidator.php b/library/Icinga/Web/Form/Validator/WritablePathValidator.php index 8387c5cf5..239ab77c8 100644 --- a/library/Icinga/Web/Form/Validator/WritablePathValidator.php +++ b/library/Icinga/Web/Form/Validator/WritablePathValidator.php @@ -5,7 +5,6 @@ namespace Icinga\Web\Form\Validator; use Zend_Validate_Abstract; -use Icinga\Application\Config as IcingaConfig; /** * Validator that interprets the value as a path and checks if it's writable diff --git a/library/Icinga/Web/Hook.php b/library/Icinga/Web/Hook.php index 36974fb5b..01d1e0e2c 100644 --- a/library/Icinga/Web/Hook.php +++ b/library/Icinga/Web/Hook.php @@ -5,7 +5,7 @@ namespace Icinga\Web; use Exception; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\Exception\ProgrammingError; /** diff --git a/library/Icinga/Web/JavaScript.php b/library/Icinga/Web/JavaScript.php index 6224b5b82..9fa687042 100644 --- a/library/Icinga/Web/JavaScript.php +++ b/library/Icinga/Web/JavaScript.php @@ -67,7 +67,7 @@ class JavaScript public static function send($minified = false) { header('Content-Type: application/javascript'); - $basedir = Icinga::app()->getBootstrapDirecory(); + $basedir = Icinga::app()->getBootstrapDirectory(); $js = $out = ''; $min = $minified ? '.min' : ''; @@ -118,7 +118,7 @@ class JavaScript } if ($minified) { - require_once 'IcingaVendor/JShrink/Minifier.php'; + require_once 'JShrink/Minifier.php'; $out .= Minifier::minify($js, array('flaggedComments' => false)); } else { $out .= $js; diff --git a/library/Icinga/Web/LessCompiler.php b/library/Icinga/Web/LessCompiler.php index 16514cf6d..791fdbab0 100644 --- a/library/Icinga/Web/LessCompiler.php +++ b/library/Icinga/Web/LessCompiler.php @@ -41,7 +41,7 @@ class LessCompiler */ public function __construct() { - require_once 'IcingaVendor/lessphp/lessc.inc.php'; + require_once 'lessphp/lessc.inc.php'; $this->lessc = new lessc(); $this->lessc->setVariables( diff --git a/library/Icinga/Web/Menu.php b/library/Icinga/Web/Menu.php index 305cdd705..dafe66a90 100644 --- a/library/Icinga/Web/Menu.php +++ b/library/Icinga/Web/Menu.php @@ -4,12 +4,13 @@ namespace Icinga\Web; +use Icinga\Authentication\Manager; use Icinga\Web\Menu\MenuItemRenderer; use RecursiveIterator; -use Zend_Config; use Icinga\Application\Config; use Icinga\Application\Icinga; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; +use Icinga\Data\ConfigObject; use Icinga\Exception\ConfigurationError; use Icinga\Exception\ProgrammingError; use Icinga\Web\Url; @@ -65,14 +66,14 @@ class Menu implements RecursiveIterator /** * A custom item renderer used instead of the default rendering logic * - * @var MenuItemRenderer + * @type MenuItemRenderer */ protected $itemRenderer = null; - + /* * Parent menu * - * @var Menu + * @type Menu */ protected $parent; @@ -80,9 +81,10 @@ class Menu implements RecursiveIterator * Create a new menu * * @param int $id The id of this menu - * @param Zend_Config $config The configuration for this menu + * @param ConfigObject $config The configuration for this menu + * @param Menu $parent Parent menu */ - public function __construct($id, Zend_Config $config = null, Menu $parent = null) + public function __construct($id, ConfigObject $config = null, Menu $parent = null) { $this->id = $id; if ($parent !== null) { @@ -94,7 +96,11 @@ class Menu implements RecursiveIterator /** * Set all given properties * - * @param array|Zend_Config $props Property list + * @param array|ConfigObject $props Property list + * + * @return $this + * + * @throws ConfigurationError If a property is invalid */ public function setProperties($props = null) { @@ -143,8 +149,9 @@ class Menu implements RecursiveIterator /** * Whether this Menu conflicts with the given Menu object * - * @param Menu $menu - * @return bool + * @param Menu $menu + * + * @return bool */ public function conflictsWith(Menu $menu) { @@ -157,9 +164,9 @@ class Menu implements RecursiveIterator /** * Create menu from the application's menu config file plus the config files from all enabled modules * - * THIS IS OBSOLATE. LEFT HERE FOR FUTURE USE WITH USER-SPECIFIC MODULES + * @return static * - * @return self + * @deprecated THIS IS OBSOLETE. LEFT HERE FOR FUTURE USE WITH USER-SPECIFIC MODULES */ public static function fromConfig() { @@ -170,7 +177,7 @@ class Menu implements RecursiveIterator foreach ($modules as $moduleName) { $moduleMenuConfig = Config::module($moduleName, 'menu'); - if (false === empty($moduleMenuConfig)) { + if (! $moduleMenuConfig->isEmpty()) { $menuConfigs[] = $moduleMenuConfig; } } @@ -181,7 +188,7 @@ class Menu implements RecursiveIterator /** * Create menu from the application's menu config plus menu entries provided by all enabled modules * - * @return self + * @return static */ public static function load() { @@ -201,41 +208,50 @@ class Menu implements RecursiveIterator */ protected function addMainMenuItems() { - $this->add(t('Dashboard'), array( - 'url' => 'dashboard', - 'icon' => 'img/icons/dashboard.png', - 'priority' => 10 - )); + $auth = Manager::getInstance(); - $section = $this->add(t('System'), array( - 'icon' => 'img/icons/configuration.png', - 'priority' => 200 - )); - $section->add(t('Preferences'), array( - 'url' => 'preference', - 'priority' => 200 - )); - $section->add(t('Configuration'), array( - 'url' => 'config', - 'priority' => 300 - )); - $section->add(t('Modules'), array( - 'url' => 'config/modules', - 'priority' => 400 - )); + if ($auth->isAuthenticated()) { - if (Logger::writesToFile()) { - $section->add(t('Application Log'), array( - 'url' => 'list/applicationlog', - 'priority' => 500 + $this->add(t('Dashboard'), array( + 'url' => 'dashboard', + 'icon' => 'dashboard', + 'priority' => 10 + )); + + $section = $this->add(t('System'), array( + 'icon' => 'wrench', + 'priority' => 200 + )); + $section->add(t('Configuration'), array( + 'url' => 'config', + 'priority' => 300 + )); + $section->add(t('Modules'), array( + 'url' => 'config/modules', + 'priority' => 400 + )); + + if (Logger::writesToFile()) { + $section->add(t('Application Log'), array( + 'url' => 'list/applicationlog', + 'priority' => 500 + )); + } + + $section = $this->add($auth->getUser()->getUsername(), array( + 'icon' => 'user', + 'priority' => 600 + )); + $section->add(t('Preferences'), array( + 'url' => 'preference', + 'priority' => 601 + )); + + $section->add(t('Logout'), array( + 'url' => 'authentication/logout', + 'priority' => 700 )); } - - $this->add(t('Logout'), array( - 'url' => 'authentication/logout', - 'icon' => 'img/icons/logout.png', - 'priority' => 300 - )); } /** @@ -243,7 +259,7 @@ class Menu implements RecursiveIterator * * @param string $id The id to set for this menu * - * @return self + * @return $this */ public function setId($id) { @@ -290,7 +306,7 @@ class Menu implements RecursiveIterator * * @param string $title The title to set for this menu * - * @return self + * @return $this */ public function setTitle($title) { @@ -313,7 +329,7 @@ class Menu implements RecursiveIterator * * @param int $priority The priority to set for this menu * - * @return self + * @return $this */ public function setPriority($priority) { @@ -336,7 +352,7 @@ class Menu implements RecursiveIterator * * @param Url|string $url The url to set for this menu * - * @return self + * @return $this */ public function setUrl($url) { @@ -363,7 +379,7 @@ class Menu implements RecursiveIterator * * @param string $path The path to the icon for this menu * - * @return self + * @return $this */ public function setIcon($path) { @@ -415,35 +431,23 @@ class Menu implements RecursiveIterator * Add a sub menu to this menu * * @param string $id The id of the menu to add - * @param Zend_Config $itemConfig The config with which to initialize the menu + * @param ConfigObject $menuConfig The config with which to initialize the menu * - * @return self + * @return static */ - public function addSubMenu($id, Zend_Config $menuConfig = null) + public function addSubMenu($id, ConfigObject $menuConfig = null) { - if (false === ($pos = strpos($id, '.'))) { - $subMenu = new self($id, $menuConfig, $this); - $this->subMenus[$id] = $subMenu; - } else { - list($parentId, $id) = explode('.', $id, 2); - - if ($this->hasSubMenu($parentId)) { - $parent = $this->getSubMenu($parentId); - } else { - $parent = $this->addSubMenu($parentId); - } - - $subMenu = $parent->addSubMenu($id, $menuConfig); - } - + $subMenu = new static($id, $menuConfig, $this); + $this->subMenus[$id] = $subMenu; return $subMenu; } /** * Set required Permissions * - * @param $permission - * @return $this + * @param $permission + * + * @return $this */ public function requirePermission($permission) { @@ -454,8 +458,9 @@ class Menu implements RecursiveIterator /** * Merge Sub Menus * - * @param array $submenus - * @return $this + * @param array $submenus + * + * @return $this */ public function mergeSubMenus(array $submenus) { @@ -468,8 +473,9 @@ class Menu implements RecursiveIterator /** * Merge Sub Menu * - * @param Menu $menu - * @return mixed + * @param Menu $menu + * + * @return static */ public function mergeSubMenu(Menu $menu) { @@ -503,13 +509,14 @@ class Menu implements RecursiveIterator /** * Add a Menu * - * @param $name - * @param array $config - * @return Menu + * @param $name + * @param array $config + * + * @return static */ public function add($name, $config = array()) { - return $this->addSubMenu($name, new Zend_Config($config)); + return $this->addSubMenu($name, new ConfigObject($config)); } /** @@ -529,7 +536,7 @@ class Menu implements RecursiveIterator * * @param string $id The id of the sub menu * - * @return Menu The found sub menu + * @return static The found sub menu * * @throws ProgrammingError In case there is no sub menu with the given id to be found */ @@ -548,7 +555,7 @@ class Menu implements RecursiveIterator /** * Order this menu's sub menus based on their priority * - * @return self + * @return $this */ public function order() { @@ -608,7 +615,7 @@ class Menu implements RecursiveIterator * * @param array $menus The menus to load, as key-value array * - * @return self + * @return static */ protected function loadSubMenus(array $menus) { @@ -665,7 +672,7 @@ class Menu implements RecursiveIterator /** * Return the current menu node * - * @return Menu + * @return static */ public function current() { @@ -691,7 +698,7 @@ class Menu implements RecursiveIterator } /** - * PHP 5.3 GC should not leak, but just to be on the safe side... + * PHP 5.3 GC should not leak, but just to be on the safe side... */ public function __destruct() { diff --git a/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php b/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php new file mode 100644 index 000000000..3bccb9327 --- /dev/null +++ b/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php @@ -0,0 +1,100 @@ +select()->from( + 'statusSummary', + array( + 'hosts_down_unhandled', + 'services_critical_unhandled' + ) + )->getQuery()->fetchRow(); + } + + if ($column === null) { + return self::$summary; + } elseif (isset(self::$summary->$column)) { + return self::$summary->$column; + } else { + return null; + } + } + + protected function getBadgeTitle() + { + $translations = array( + 'hosts_down_unhandled' => mt('monitoring', '%d unhandled hosts down'), + 'services_critical_unhandled' => mt('monitoring', '%d unhandled services critical') + ); + + $titles = array(); + $sum = $this->summary(); + + foreach ($this->columns as $col) { + if (isset($sum->$col) && $sum->$col > 0) { + $titles[] = sprintf($translations[$col], $sum->$col); + } + } + + return implode(', ', $titles); + } + + protected function countItems() + { + $sum = self::summary(); + $count = 0; + + foreach ($this->columns as $col) { + if (isset($sum->$col)) { + $count += $sum->$col; + } + } + + return $count; + } + + public function render(Menu $menu) + { + $count = $this->countItems(); + $badge = ''; + if ($count) { + $badge = sprintf( + '
%s
', + $this->getBadgeTitle(), + $count + ); + } + if ($menu->getIcon() && strpos($menu->getIcon(), '.') === false) { + return sprintf( + '%s %s', + $badge, + $menu->getUrl() ?: '#', + $menu->getIcon(), + htmlspecialchars($menu->getTitle()) + ); + } + + return sprintf( + '%s%s%s', + $badge, + $menu->getUrl() ?: '#', + $menu->getIcon() ? ' ' : '', + htmlspecialchars($menu->getTitle()) + ); + } +} diff --git a/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php b/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php index 1254033ae..58689547f 100644 --- a/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php +++ b/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php @@ -1,39 +1,11 @@ select()->from( - 'statusSummary', - array( - 'hosts_down_unhandled', - 'services_critical_unhandled' - ) - )->getQuery()->fetchRow(); - $unhandled = $statusSummary->hosts_down_unhandled + $statusSummary->services_critical_unhandled; - $badge = ''; - if ($unhandled) { - $badge = sprintf( - '
%s
', - $unhandled - ); - } - return sprintf( - '%s%s %s', - $menu->getUrl() ?: '#', - $menu->getIcon() ? ' ' : '', - htmlspecialchars($menu->getTitle()), - $badge - ); - } +class ProblemMenuItemRenderer extends MonitoringMenuItemRenderer +{ + protected $columns = array( + 'hosts_down_unhandled', + 'services_critical_unhandled' + ); } diff --git a/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php b/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php index c7e6036fb..10a75c00f 100644 --- a/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php +++ b/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php @@ -1,38 +1,12 @@ select()->from( - 'statusSummary', - array( - 'hosts_down_unhandled' - ) - )->getQuery()->fetchRow(); - $badge = ''; - if ($statusSummary->hosts_down_unhandled) { - $badge = sprintf( - '
%s
', - t(sprintf('%d unhandled host problems', $statusSummary->hosts_down_unhandled)), - $statusSummary->hosts_down_unhandled - ); - } - return sprintf( - '%s%s %s', - $menu->getUrl() ?: '#', - $menu->getIcon() ? ' ' : '', - htmlspecialchars($menu->getTitle()), - $badge - ); - } +class UnhandledHostMenuItemRenderer extends MonitoringMenuItemRenderer +{ + protected $columns = array( + 'hosts_down_unhandled', + ); } diff --git a/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php b/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php index b677a4935..8a59e9baa 100644 --- a/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php +++ b/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php @@ -1,38 +1,12 @@ select()->from( - 'statusSummary', - array( - 'services_critical_unhandled' - ) - )->getQuery()->fetchRow(); - $badge = ''; - if ($statusSummary->services_critical_unhandled) { - $badge = sprintf( - '
%s
', - t(sprintf('%d unhandled service problems', $statusSummary->services_critical_unhandled)), - $statusSummary->services_critical_unhandled - ); - } - return sprintf( - '%s%s %s', - $menu->getUrl() ?: '#', - $menu->getIcon() ? ' ' : '', - htmlspecialchars($menu->getTitle()), - $badge - ); - } +class UnhandledServiceMenuItemRenderer extends MonitoringMenuItemRenderer +{ + protected $columns = array( + 'services_critical_unhandled' + ); } diff --git a/library/Icinga/Web/MenuRenderer.php b/library/Icinga/Web/MenuRenderer.php index 2fbcedc01..8502e5215 100644 --- a/library/Icinga/Web/MenuRenderer.php +++ b/library/Icinga/Web/MenuRenderer.php @@ -6,7 +6,7 @@ namespace Icinga\Web; use Exception; use RecursiveIteratorIterator; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; /** * A renderer to draw a menu with its sub-menus using an unordered html list @@ -114,6 +114,14 @@ class MenuRenderer extends RecursiveIteratorIterator Logger::error('Could not invoke custom renderer. Exception: '. $e->getMessage()); } } + if ($child->getIcon() && strpos($child->getIcon(), '.') === false) { + return sprintf( + '%s', + $child->getUrl() ?: '#', + $child->getIcon(), + htmlspecialchars($child->getTitle()) + ); + } return sprintf( '%s%s', $child->getUrl() ?: '#', diff --git a/library/Icinga/Web/Notification.php b/library/Icinga/Web/Notification.php index 178a07e0a..b046476b3 100644 --- a/library/Icinga/Web/Notification.php +++ b/library/Icinga/Web/Notification.php @@ -6,7 +6,7 @@ namespace Icinga\Web; use Icinga\Exception\ProgrammingError; use Icinga\Application\Platform; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\Web\Session; /** @@ -75,35 +75,28 @@ class Notification return; } - $mo = (object) array( + $messages = & Session::getSession()->getByRef('messages'); + $messages[] = (object) array( 'type' => $type, 'message' => $message, ); - - // Get, change, set - just to be on the safe side: - $session = Session::getSession(); - $msgs = $session->messages; - $msgs[] = $mo; - $session->messages = $msgs; - $session->write(); } public function hasMessages() { $session = Session::getSession(); - return !empty($session->messages); + return false === empty($session->messages); } public function getMessages() { $session = Session::getSession(); - $msgs = $session->messages; - if (false === empty($msgs)) { + $messages = $session->messages; + if (false === empty($messages)) { $session->messages = array(); - $session->write(); } - return $msgs; + return $messages; } final private function __construct() diff --git a/library/Icinga/Web/Request.php b/library/Icinga/Web/Request.php index 8b09f68fb..ae957f6a9 100644 --- a/library/Icinga/Web/Request.php +++ b/library/Icinga/Web/Request.php @@ -19,6 +19,16 @@ class Request extends Zend_Controller_Request_Http */ private $user; + private $url; + + public function getUrl() + { + if ($this->url === null) { + $this->url = Url::fromRequest($this); + } + return $this->url; + } + /** * Setter for user * diff --git a/library/Icinga/Web/Response.php b/library/Icinga/Web/Response.php index 6ad4f6f87..d0d8912e6 100644 --- a/library/Icinga/Web/Response.php +++ b/library/Icinga/Web/Response.php @@ -21,6 +21,12 @@ class Response extends Zend_Controller_Response_Http } else { $this->setRedirect($url->getAbsoluteUrl()); } + + $session = Session::getSession(); + if ($session->hasChanged()) { + $session->write(); + } + $this->sendHeaders(); exit; } diff --git a/library/Icinga/Web/Session/PhpSession.php b/library/Icinga/Web/Session/PhpSession.php index 65f940a13..bef978c0b 100644 --- a/library/Icinga/Web/Session/PhpSession.php +++ b/library/Icinga/Web/Session/PhpSession.php @@ -4,7 +4,7 @@ namespace Icinga\Web\Session; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; use Icinga\Exception\ConfigurationError; /** @@ -121,7 +121,7 @@ class PhpSession extends Session foreach ($_SESSION as $key => $value) { if (strpos($key, self::NAMESPACE_PREFIX) === 0) { - $namespace = new SessionNamespace($this); + $namespace = new SessionNamespace(); $namespace->setAll($value); $this->namespaces[substr($key, strlen(self::NAMESPACE_PREFIX))] = $namespace; } else { diff --git a/library/Icinga/Web/Session/Session.php b/library/Icinga/Web/Session/Session.php index 0c60d7f98..ab73dcac7 100644 --- a/library/Icinga/Web/Session/Session.php +++ b/library/Icinga/Web/Session/Session.php @@ -75,7 +75,7 @@ abstract class Session extends SessionNamespace unset($this->removedNamespaces[array_search($identifier, $this->removedNamespaces)]); } - $this->namespaces[$identifier] = new SessionNamespace($this); + $this->namespaces[$identifier] = new SessionNamespace(); } return $this->namespaces[$identifier]; @@ -104,13 +104,22 @@ abstract class Session extends SessionNamespace $this->removedNamespaces[] = $identifier; } + /** + * Return whether the session has changed + * + * @return bool + */ + public function hasChanged() + { + return parent::hasChanged() || false === empty($this->namespaces) || false === empty($this->removedNamespaces); + } + /** * Clear all values and namespaces from the session cache */ public function clear() { - $this->values = array(); - $this->removed = array(); + parent::clear(); $this->namespaces = array(); $this->removedNamespaces = array(); } diff --git a/library/Icinga/Web/Session/SessionNamespace.php b/library/Icinga/Web/Session/SessionNamespace.php index b7495683b..c72d69c36 100644 --- a/library/Icinga/Web/Session/SessionNamespace.php +++ b/library/Icinga/Web/Session/SessionNamespace.php @@ -14,13 +14,6 @@ use IteratorAggregate; */ class SessionNamespace implements IteratorAggregate { - /** - * The session this namespace is associated to - * - * @var Session - */ - protected $session; - /** * The actual values stored in this container * @@ -35,16 +28,6 @@ class SessionNamespace implements IteratorAggregate */ protected $removed = array(); - /** - * Create a new session namespace - * - * @param Session $session The session this namespace is associated to - */ - public function __construct(Session $session = null) - { - $this->session = $session; - } - /** * Return an iterator for all values in this namespace * @@ -120,7 +103,18 @@ class SessionNamespace implements IteratorAggregate $this->values[$key] = $value; if (in_array($key, $this->removed)) { - unset($this->removed[array_search($key, $this->values)]); + unset($this->removed[array_search($key, $this->removed)]); + } + + return $this; + } + + public function setByRef($key, &$value) + { + $this->values[$key] = & $value; + + if (in_array($key, $this->removed)) { + unset($this->removed[array_search($key, $this->removed)]); } return $this; @@ -139,6 +133,16 @@ class SessionNamespace implements IteratorAggregate return isset($this->values[$key]) ? $this->values[$key] : $default; } + public function & getByRef($key, $default = null) + { + $value = $default; + if (isset($this->values[$key])) { + $value = & $this->values[$key]; + } + + return $value; + } + /** * Delete the given value from the session * @@ -177,14 +181,21 @@ class SessionNamespace implements IteratorAggregate } /** - * Save the session this namespace is associated to + * Return whether the session namespace has been changed + * + * @return bool */ - public function write() + public function hasChanged() { - if (!$this->session) { - throw new IcingaException('Cannot save, session not set'); - } + return false === empty($this->values) || false === empty($this->removed); + } - $this->session->write(); + /** + * Clear all values from the session namespace + */ + public function clear() + { + $this->values = array(); + $this->removed = array(); } } diff --git a/library/Icinga/Web/StyleSheet.php b/library/Icinga/Web/StyleSheet.php index 3c4baf943..719d1c829 100644 --- a/library/Icinga/Web/StyleSheet.php +++ b/library/Icinga/Web/StyleSheet.php @@ -11,6 +11,8 @@ use Icinga\Web\LessCompiler; class StyleSheet { protected static $lessFiles = array( + '../application/fonts/fontello-ifont/css/ifont-embedded.css', + 'css/vendor/tipsy.css', 'css/icinga/defaults.less', 'css/icinga/layout-colors.less', 'css/icinga/layout-structure.less', @@ -19,18 +21,19 @@ class StyleSheet 'css/icinga/main-content.less', 'css/icinga/tabs.less', 'css/icinga/forms.less', + 'css/icinga/setup.less', 'css/icinga/widgets.less', 'css/icinga/pagination.less', 'css/icinga/monitoring-colors.less', 'css/icinga/selection-toolbar.less', - 'css/icinga/login.less', - 'css/vendor/tipsy.css' + 'css/icinga/login.less' ); public static function compileForPdf() { + self::checkPhp(); $less = new LessCompiler(); - $basedir = Icinga::app()->getBootstrapDirecory(); + $basedir = Icinga::app()->getBootstrapDirectory(); foreach (self::$lessFiles as $file) { $less->addFile($basedir . '/' . $file); } @@ -53,10 +56,19 @@ class StyleSheet ); } + protected static function checkPhp() + { + // PHP had a rather conservative PCRE backtrack limit unless 5.3.7 + if (version_compare(PHP_VERSION, '5.3.7') <= 0) { + ini_set('pcre.backtrack_limit', 1000000); + } + } + public static function send($minified = false) { + self::checkPhp(); $app = Icinga::app(); - $basedir = $app->getBootstrapDirecory(); + $basedir = $app->getBootstrapDirectory(); foreach (self::$lessFiles as $file) { $lessFiles[] = $basedir . '/' . $file; } diff --git a/library/Icinga/Web/View/helpers/url.php b/library/Icinga/Web/View/helpers/url.php index 935a55a97..901e68803 100644 --- a/library/Icinga/Web/View/helpers/url.php +++ b/library/Icinga/Web/View/helpers/url.php @@ -51,19 +51,32 @@ $this->addHelperFunction('img', function ($url, array $properties = array()) use }); $this->addHelperFunction('icon', function ($img, $title = null, array $properties = array()) use ($view) { - // TODO: join with classes passed in $properties? - $attributes = array( - 'class' => 'icon', - ); - if ($title !== null) { - $attributes['alt'] = $title; - $attributes['title'] = $title; - } + $isClass = strpos($img, '.') === false; + $class = null; - return $view->img( - 'img/icons/' . $img, - array_merge($attributes, $properties) - ); + if ($isClass) { + $class = 'icon-' . $img; + } else { + $class = 'icon'; + } + if ($title !== null) { + $properties['alt'] = $title; + $properties['title'] = $title; + } + + if ($class !== null) { + if (isset($props['class'])) { + $properties['class'] .= ' ' . $class; + } else { + $properties['class'] = $class; + } + } + if ($isClass) { + return sprintf('', $view->propertiesToString($properties)); + + } else { + return $view->img('img/icons/' . $img, $properties); + } }); $this->addHelperFunction('propertiesToString', function ($properties) use ($view) { diff --git a/library/Icinga/Web/Widget/AbstractWidget.php b/library/Icinga/Web/Widget/AbstractWidget.php index fe4d2434d..5b9d8876b 100644 --- a/library/Icinga/Web/Widget/AbstractWidget.php +++ b/library/Icinga/Web/Widget/AbstractWidget.php @@ -34,7 +34,7 @@ abstract class AbstractWidget protected static $view; // TODO: Should we kick this? - protected $properties; + protected $properties = array(); /** * Getter for widget properties diff --git a/library/Icinga/Web/Widget/Chart/InlinePie.php b/library/Icinga/Web/Widget/Chart/InlinePie.php index 4b4409e78..3ff97b2df 100644 --- a/library/Icinga/Web/Widget/Chart/InlinePie.php +++ b/library/Icinga/Web/Widget/Chart/InlinePie.php @@ -7,7 +7,7 @@ namespace Icinga\Web\Widget\Chart; use Icinga\Web\Widget\AbstractWidget; use Icinga\Web\Url; use Icinga\Util\Format; -use Icinga\Logger\Logger; +use Icinga\Application\Logger; /** * A SVG-PieChart intended to be displayed as a small icon next to labels, to offer a better visualization of the @@ -73,28 +73,28 @@ EOD; * * @var int The value in px */ - private $width = 28; + private $width = 16; /** * The height of the rendered chart * * @var int The value in px */ - private $height = 28; + private $height = 16; /** * PieChart border width * * @var float */ - private $borderWidth = 0; + private $borderWidth = 1; /** * The color of the border * * @var string */ - private $borderColor = '#888'; + private $borderColor = '#fff'; /** * The title of the chart diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index a86204d87..45e1e6830 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -5,31 +5,29 @@ namespace Icinga\Web\Widget; use Icinga\Application\Icinga; -use Icinga\Application\Config as IcingaConfig; +use Icinga\Application\Config; +use Icinga\Data\ConfigObject; use Icinga\Exception\ConfigurationError; +use Icinga\Exception\NotReadableError; use Icinga\Exception\ProgrammingError; +use Icinga\Exception\SystemPermissionException; +use Icinga\File\Ini\IniWriter; +use Icinga\User; use Icinga\Web\Widget\Dashboard\Pane; -use Icinga\Web\Widget\Dashboard\Component as DashboardComponent; +use Icinga\Web\Widget\Dashboard\Dashlet as DashboardDashlet; use Icinga\Web\Url; /** * Dashboards display multiple views on a single page * * The terminology is as follows: - * - Component: A single view showing a specific url - * - Pane: Aggregates one or more components on one page, displays it's title as a tab + * - Dashlet: A single view showing a specific url + * - Pane: Aggregates one or more dashlets on one page, displays it's title as a tab * - Dashboard: Shows all panes * */ class Dashboard extends AbstractWidget { - /** - * The configuration containing information about this dashboard - * - * @var IcingaConfig; - */ - private $config; - /** * An array containing all panes of this dashboard * @@ -51,6 +49,11 @@ class Dashboard extends AbstractWidget */ private $tabParam = 'pane'; + /** + * @var User + */ + private $user; + /** * Set the given tab name as active. * @@ -67,33 +70,139 @@ class Dashboard extends AbstractWidget * * @return self */ - public static function load() + public function load() { - /** @var $dashboard Dashboard */ - $dashboard = new static('dashboard'); $manager = Icinga::app()->getModuleManager(); foreach ($manager->getLoadedModules() as $module) { /** @var $module \Icinga\Application\Modules\Module */ - $dashboard->mergePanes($module->getPaneItems()); + $this->mergePanes($module->getPaneItems()); } - return $dashboard; + if ($this->user !== null) { + $this->loadUserDashboards(); + } + + return $this; + } + + /** + * Create a writer object + * + * @return IniWriter + */ + public function createWriter() + { + $configFile = $this->getConfigFile(); + $output = array(); + foreach ($this->panes as $pane) { + if ($pane->isUserWidget() === true) { + $output[$pane->getName()] = $pane->toArray(); + } + foreach ($pane->getDashlets() as $dashlet) { + if ($dashlet->isUserWidget() === true) { + $output[$pane->getName() . '.' . $dashlet->getTitle()] = $dashlet->toArray(); + } + } + } + + $co = new ConfigObject($output); + $config = new Config($co); + return new IniWriter(array('config' => $config, 'filename' => $configFile)); + } + + /** + * Write user specific dashboards to disk + */ + public function write() + { + $this->createWriter()->write(); + } + + /** + * @return bool + */ + private function loadUserDashboards() + { + try { + $config = Config::fromIni($this->getConfigFile()); + } catch (NotReadableError $e) { + return; + } + if (! count($config)) { + return false; + } + $panes = array(); + $dashlets = array(); + foreach ($config as $key => $part) { + if (strpos($key, '.') === false) { + if ($this->hasPane($part->title)) { + $panes[$key] = $this->getPane($part->title); + } else { + $panes[$key] = new Pane($key); + $panes[$key]->setTitle($part->title); + } + $panes[$key]->setUserWidget(); + if ((bool) $part->get('disabled', false) === true) { + $panes[$key]->setDisabled(); + } + + } else { + list($paneName, $dashletName) = explode('.', $key, 2); + $part->pane = $paneName; + $part->dashlet = $dashletName; + $dashlets[] = $part; + } + } + foreach ($dashlets as $dashletData) { + $pane = null; + + if (array_key_exists($dashletData->pane, $panes) === true) { + $pane = $panes[$dashletData->pane]; + } elseif (array_key_exists($dashletData->pane, $this->panes) === true) { + $pane = $this->panes[$dashletData->pane]; + } else { + continue; + } + $dashlet = new DashboardDashlet( + $dashletData->title, + $dashletData->url, + $pane + ); + + if ((bool) $dashletData->get('disabled', false) === true) { + $dashlet->setDisabled(true); + } + + $dashlet->setUserWidget(); + $pane->addDashlet($dashlet); + } + + $this->mergePanes($panes); + + return true; } /** * Merge panes with existing panes * - * @param array $panes - * @return $this + * @param array $panes + * + * @return $this */ public function mergePanes(array $panes) { /** @var $pane Pane */ foreach ($panes as $pane) { - if (array_key_exists($pane->getName(), $this->panes)) { + if ($pane->getDisabled()) { + if ($this->hasPane($pane->getTitle()) === true) { + $this->removePane($pane->getTitle()); + } + continue; + } + if ($this->hasPane($pane->getTitle()) === true) { /** @var $current Pane */ $current = $this->panes[$pane->getName()]; - $current->addComponents($pane->getComponents()); + $current->addDashlets($pane->getDashlets()); } else { $this->panes[$pane->getName()] = $pane; } @@ -109,7 +218,7 @@ class Dashboard extends AbstractWidget */ public function getTabs() { - $url = Url::fromRequest()->getUrlWithout($this->tabParam); + $url = Url::fromPath('dashboard')->getUrlWithout($this->tabParam); if ($this->tabs === null) { $this->tabs = new Tabs(); @@ -137,20 +246,6 @@ class Dashboard extends AbstractWidget return $this->panes; } - /** - * Populate this dashboard via the given configuration file - * - * @param IcingaConfig $config The configuration file to populate this dashboard with - * - * @return self - */ - public function readConfig(IcingaConfig $config) - { - $this->config = $config; - $this->panes = array(); - $this->loadConfigPanes(); - return $this; - } /** * Creates a new empty pane with the given title @@ -168,34 +263,6 @@ class Dashboard extends AbstractWidget return $this; } - /** - * Update or adds a new component with the given url to a pane - * - * @TODO: Should only allow component objects to be added directly as soon as we store more information - * - * @param string $pane The pane to add the component to - * @param Component|string $component The component to add or the title of the newly created component - * @param string|null $url The url to use for the component - * - * @return self - */ - public function setComponentUrl($pane, $component, $url) - { - if ($component === null && strpos($pane, '.')) { - list($pane, $component) = preg_split('~\.~', $pane, 2); - } - if (!isset($this->panes[$pane])) { - $this->createPane($pane); - } - $pane = $this->getPane($pane); - if ($pane->hasComponent($component)) { - $pane->getComponent($component)->setUrl($url); - } else { - $pane->addComponent($component, $url); - } - return $this; - } - /** * Checks if the current dashboard has any panes * @@ -207,49 +274,14 @@ class Dashboard extends AbstractWidget } /** - * Check if this dashboard has a specific pane + * Check if a panel exist * - * @param $pane string The name of the pane - * @return bool + * @param string $pane + * @return bool */ public function hasPane($pane) { - return array_key_exists($pane, $this->panes); - } - - /** - * Remove a component $component from the given pane - * - * @param string $pane The pane to remove the component from - * @param Component|string $component The component to remove or it's name - * - * @return self - */ - public function removeComponent($pane, $component) - { - if ($component === null && strpos($pane, '.')) { - list($pane, $component) = preg_split('~\.~', $pane, 2); - } - $pane = $this->getPane($pane); - if ($pane !== null) { - $pane->removeComponent($component); - } - - return $this; - } - - /** - * Return an array with pane name=>title format used for comboboxes - * - * @return array - */ - public function getPaneKeyTitleArray() - { - $list = array(); - foreach ($this->panes as $name => $pane) { - $list[$name] = $pane->getTitle(); - } - return $list; + return $pane && array_key_exists($pane, $this->panes); } /** @@ -265,6 +297,21 @@ class Dashboard extends AbstractWidget return $this; } + public function removePane($title) + { + if ($this->hasPane($title) === true) { + $pane = $this->getPane($title); + if ($pane->isUserWidget() === true) { + unset($this->panes[$pane->getName()]); + } else { + $pane->setDisabled(); + $pane->setUserWidget(); + } + } else { + throw new ProgrammingError('Pane not found: ' . $title); + } + } + /** * Return the pane with the provided name * @@ -284,6 +331,20 @@ class Dashboard extends AbstractWidget return $this->panes[$name]; } + /** + * Return an array with pane name=>title format used for comboboxes + * + * @return array + */ + public function getPaneKeyTitleArray() + { + $list = array(); + foreach ($this->panes as $name => $pane) { + $list[$name] = $pane->getTitle(); + } + return $list; + } + /** * @see Icinga\Web\Widget::render */ @@ -292,6 +353,7 @@ class Dashboard extends AbstractWidget if (empty($this->panes)) { return ''; } + return $this->determineActivePane()->render(); } @@ -319,7 +381,10 @@ class Dashboard extends AbstractWidget /** * Determine the active pane either by the selected tab or the current request * - * @return Pane The currently active pane + * @throws \Icinga\Exception\ConfigurationError + * @throws \Icinga\Exception\ProgrammingError + * + * @return Pane The currently active pane */ public function determineActivePane() { @@ -346,36 +411,55 @@ class Dashboard extends AbstractWidget } /** - * Return this dashboard's structure as array + * Setter for user object * - * @return array + * @param User $user */ - public function toArray() + public function setUser(User $user) { - $array = array(); - foreach ($this->panes as $pane) { - $array += $pane->toArray(); - } - - return $array; + $this->user = $user; } /** - * Load all config panes from @see Dashboard::$config + * Getter for user object * + * @return User */ - private function loadConfigPanes() + public function getUser() { - $items = $this->config; - foreach ($items->keys() as $key) { - $item = $this->config->get($key, false); - if (false === strstr($key, '.')) { - $this->addPane(Pane::fromIni($key, $item)); - } else { - list($paneName, $title) = explode('.', $key, 2); - $pane = $this->getPane($paneName); - $pane->addComponent(DashboardComponent::fromIni($title, $item, $pane)); + return $this->user; + } + + /** + * Get config file + * + * @return string + */ + public function getConfigFile() + { + if ($this->user === null) { + return ''; + } + + $baseDir = '/var/lib/icingaweb'; + + if (! file_exists($baseDir)) { + throw new NotReadableError('Could not read: ' . $baseDir); + } + + $userDir = $baseDir . '/' . $this->user->getUsername(); + + if (! file_exists($userDir)) { + $success = @mkdir($userDir); + if (!$success) { + throw new SystemPermissionException('Could not create: ' . $userDir); } } + + if (! file_exists($userDir)) { + throw new NotReadableError('Could not read: ' . $userDir); + } + + return $userDir . '/dashboard.ini'; } } diff --git a/library/Icinga/Web/Widget/Dashboard/Component.php b/library/Icinga/Web/Widget/Dashboard/Dashlet.php similarity index 52% rename from library/Icinga/Web/Widget/Dashboard/Component.php rename to library/Icinga/Web/Widget/Dashboard/Dashlet.php index 7410c6210..1b7a7ef95 100644 --- a/library/Icinga/Web/Widget/Dashboard/Component.php +++ b/library/Icinga/Web/Widget/Dashboard/Dashlet.php @@ -4,40 +4,36 @@ namespace Icinga\Web\Widget\Dashboard; -use Icinga\Exception\IcingaException; -use Icinga\Util\Dimension; +use Zend_Form_Element_Button; use Icinga\Web\Form; use Icinga\Web\Url; use Icinga\Web\Widget\AbstractWidget; -use Icinga\Web\View; -use Zend_Config; -use Zend_Form_Element_Submit; -use Zend_Form_Element_Button; -use Exception; +use Icinga\Data\ConfigObject; +use Icinga\Exception\IcingaException; /** - * A dashboard pane component + * A dashboard pane dashlet * * This is the element displaying a specific view in icinga2web * */ -class Component extends AbstractWidget +class Dashlet extends UserWidget { /** - * The url of this Component + * The url of this Dashlet * * @var \Icinga\Web\Url */ private $url; /** - * The title being displayed on top of the component + * The title being displayed on top of the dashlet * @var */ private $title; /** - * The pane containing this component, needed for the 'remove button' + * The pane containing this dashlet, needed for the 'remove button' * @var Pane */ private $pane; @@ -57,7 +53,7 @@ class Component extends AbstractWidget private $template =<<<'EOD'
-

{REMOVE}{TITLE}

+

{TITLE}

@@ -65,11 +61,11 @@ class Component extends AbstractWidget EOD; /** - * Create a new component displaying the given url in the provided pane + * Create a new dashlet displaying the given url in the provided pane * - * @param string $title The title to use for this component - * @param Url|string $url The url this component uses for displaying information - * @param Pane $pane The pane this Component will be added to + * @param string $title The title to use for this dashlet + * @param Url|string $url The url this dashlet uses for displaying information + * @param Pane $pane The pane this Dashlet will be added to */ public function __construct($title, $url, Pane $pane) { @@ -81,14 +77,14 @@ EOD; $this->url = Url::fromPath($url); } else { throw new IcingaException( - 'Cannot create dashboard component "%s" without valid URL', + 'Cannot create dashboard dashlet "%s" without valid URL', $title ); } } /** - * Retrieve the components title + * Retrieve the dashlets title * * @return string */ @@ -98,7 +94,15 @@ EOD; } /** - * Retrieve the components url + * @param string $title + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * Retrieve the dashlets url * * @return Url */ @@ -108,7 +112,7 @@ EOD; } /** - * Set the components URL + * Set the dashlets URL * * @param string|Url $url The url to use, either as an Url object or as a path * @@ -145,15 +149,18 @@ EOD; } /** - * Return this component's structure as array + * Return this dashlet's structure as array * * @return array */ public function toArray() { - $array = array('url' => $this->url->getPath()); - foreach ($this->url->getParams()->toArray() as $param) { - $array[$param[0]] = $param[1]; + $array = array( + 'url' => $this->url->getRelativeUrl(), + 'title' => $this->getTitle() + ); + if ($this->getDisabled() === true) { + $array['disabled'] = 1; } return $array; } @@ -173,13 +180,23 @@ EOD; $iframeUrl = clone($url); $iframeUrl->setParam('isIframe'); - $html = str_replace('{URL}', $url, $this->template); - $html = str_replace('{IFRAME_URL}', $iframeUrl, $html); - $html = str_replace('{FULL_URL}', $url->getUrlWithout(array('view', 'limit')), $html); - $html = str_replace('{REMOVE_BTN}', $this->getRemoveForm($view), $html); - $html = str_replace('{TITLE}', $view->escape($this->getTitle()), $html); - $html = str_replace('{REMOVE}', $this->getRemoveForm(), $html); - return $html; + $searchTokens = array( + '{URL}', + '{IFRAME_URL}', + '{FULL_URL}', + '{TITLE}', + '{REMOVE}' + ); + + $replaceTokens = array( + $url, + $iframeUrl, + $url->getUrlWithout(array('view', 'limit')), + $view->escape($this->getTitle()), + $this->getRemoveLink() + ); + + return str_replace($searchTokens, $replaceTokens, $this->template); } /** @@ -187,44 +204,28 @@ EOD; * * @return string The html representation of the form */ - protected function getRemoveForm() + protected function getRemoveLink() { - // TODO: temporarily disabled, should point to a form asking for confirmal - return ''; - $removeUrl = Url::fromPath( - '/dashboard/removecomponent', - array( - 'pane' => $this->pane->getName(), - 'component' => $this->getTitle() - ) + return sprintf( + '%s', + Url::fromPath('dashboard/remove-dashlet', array( + 'dashlet' => $this->getTitle(), + 'pane' => $this->pane->getTitle() + )), + t('Remove') ); - $form = new Form(); - $form->setMethod('POST'); - $form->setAttrib('class', 'inline'); - $form->setAction($removeUrl); - $form->addElement( - new Zend_Form_Element_Button( - 'remove_pane_btn', - array( - 'class'=> 'link-like pull-right', - 'type' => 'submit', - 'label' => 'x' - ) - ) - ); - return $form; } /** - * Create a @see Component instance from the given Zend config, using the provided title + * Create a @see Dashlet instance from the given Zend config, using the provided title * - * @param $title The title for this component - * @param Zend_Config $config The configuration defining url, parameters, height, width, etc. - * @param Pane $pane The pane this component belongs to + * @param $title The title for this dashlet + * @param ConfigObject $config The configuration defining url, parameters, height, width, etc. + * @param Pane $pane The pane this dashlet belongs to * - * @return Component A newly created Component for use in the Dashboard + * @return Dashlet A newly created Dashlet for use in the Dashboard */ - public static function fromIni($title, Zend_Config $config, Pane $pane) + public static function fromIni($title, ConfigObject $config, Pane $pane) { $height = null; $width = null; @@ -232,7 +233,23 @@ EOD; $parameters = $config->toArray(); unset($parameters['url']); // otherwise there's an url = parameter in the Url - $cmp = new Component($title, Url::fromPath($url, $parameters), $pane); + $cmp = new Dashlet($title, Url::fromPath($url, $parameters), $pane); return $cmp; } + + /** + * @param \Icinga\Web\Widget\Dashboard\Pane $pane + */ + public function setPane(Pane $pane) + { + $this->pane = $pane; + } + + /** + * @return \Icinga\Web\Widget\Dashboard\Pane + */ + public function getPane() + { + return $this->pane; + } } diff --git a/library/Icinga/Web/Widget/Dashboard/Pane.php b/library/Icinga/Web/Widget/Dashboard/Pane.php index 8c1e66bad..52d9fa524 100644 --- a/library/Icinga/Web/Widget/Dashboard/Pane.php +++ b/library/Icinga/Web/Widget/Dashboard/Pane.php @@ -4,15 +4,15 @@ namespace Icinga\Web\Widget\Dashboard; -use Zend_Config; +use Icinga\Data\ConfigObject; use Icinga\Web\Widget\AbstractWidget; use Icinga\Exception\ProgrammingError; use Icinga\Exception\ConfigurationError; /** - * A pane, displaying different Dashboard components + * A pane, displaying different Dashboard dashlets */ -class Pane extends AbstractWidget +class Pane extends UserWidget { /** * The name of this pane, as defined in the ini file @@ -30,11 +30,18 @@ class Pane extends AbstractWidget private $title; /** - * An array of @see Components that are displayed in this pane + * An array of @see Dashlets that are displayed in this pane * * @var array */ - private $components = array(); + private $dashlets = array(); + + /** + * Disabled flag of a pane + * + * @var bool + */ + private $disabled; /** * Create a new pane @@ -81,86 +88,94 @@ class Pane extends AbstractWidget } /** - * Return true if a component with the given title exists in this pane + * Return true if a dashlet with the given title exists in this pane * - * @param string $title The title of the component to check for existence + * @param string $title The title of the dashlet to check for existence * * @return bool */ - public function hasComponent($title) + public function hasDashlet($title) { - return array_key_exists($title, $this->components); + return array_key_exists($title, $this->dashlets); } /** - * Checks if the current pane has any components + * Checks if the current pane has any dashlets * * @return bool */ - public function hasComponents() + public function hasDashlets() { - return ! empty($this->components); + return ! empty($this->dashlets); } /** - * Return a component with the given name if existing + * Return a dashlet with the given name if existing * - * @param string $title The title of the component to return + * @param string $title The title of the dashlet to return * - * @return Component The component with the given title - * @throws ProgrammingError If the component doesn't exist + * @return Dashlet The dashlet with the given title + * @throws ProgrammingError If the dashlet doesn't exist */ - public function getComponent($title) + public function getDashlet($title) { - if ($this->hasComponent($title)) { - return $this->components[$title]; + if ($this->hasDashlet($title)) { + return $this->dashlets[$title]; } throw new ProgrammingError( - 'Trying to access invalid component: %s', + 'Trying to access invalid dashlet: %s', $title ); } /** - * Removes the component with the given title if it exists in this pane + * Removes the dashlet with the given title if it exists in this pane * * @param string $title The pane * @return Pane $this */ - public function removeComponent($title) + public function removeDashlet($title) { - if ($this->hasComponent($title)) { - unset($this->components[$title]); + if ($this->hasDashlet($title)) { + $dashlet = $this->getDashlet($title); + if ($dashlet->isUserWidget() === true) { + unset($this->dashlets[$title]); + } else { + $dashlet->setDisabled(true); + $dashlet->setUserWidget(); + } + } else { + throw new ProgrammingError('Dashlet does not exist: ' . $title); } return $this; } /** - * Removes all or a given list of components from this pane + * Removes all or a given list of dashlets from this pane * - * @param array $components Optional list of component titles + * @param array $dashlets Optional list of dashlet titles * @return Pane $this */ - public function removeComponents(array $components = null) + public function removeDashlets(array $dashlets = null) { - if ($components === null) { - $this->components = array(); + if ($dashlets === null) { + $this->dashlets = array(); } else { - foreach ($components as $component) { - $this->removeComponent($component); + foreach ($dashlets as $dashlet) { + $this->removeDashlet($dashlet); } } return $this; } /** - * Return all components added at this pane + * Return all dashlets added at this pane * * @return array */ - public function getComponents() + public function getDashlets() { - return $this->components; + return $this->dashlets; } /** @@ -168,50 +183,56 @@ class Pane extends AbstractWidget */ public function render() { - return implode("\n", $this->components) . "\n"; + $dashlets = array_filter( + $this->dashlets, + function ($e) { + return ! $e->getDisabled(); + } + ); + return implode("\n", $dashlets) . "\n"; } /** - * Add a component to this pane, optionally creating it if $component is a string + * Add a dashlet to this pane, optionally creating it if $dashlet is a string * - * @param string|Component $component The component object or title - * (if a new component will be created) - * @param string|null $url An Url to be used when component is a string + * @param string|Dashlet $dashlet The dashlet object or title + * (if a new dashlet will be created) + * @param string|null $url An Url to be used when dashlet is a string * * @return self * @throws \Icinga\Exception\ConfigurationError */ - public function addComponent($component, $url = null) + public function addDashlet($dashlet, $url = null) { - if ($component instanceof Component) { - $this->components[$component->getTitle()] = $component; - } elseif (is_string($component) && $url !== null) { - $this->components[$component] = new Component($component, $url, $this); + if ($dashlet instanceof Dashlet) { + $this->dashlets[$dashlet->getTitle()] = $dashlet; + } elseif (is_string($dashlet) && $url !== null) { + $this->dashlets[$dashlet] = new Dashlet($dashlet, $url, $this); } else { - throw new ConfigurationError('Invalid component added: %s', $component); + throw new ConfigurationError('Invalid dashlet added: %s', $dashlet); } return $this; } /** - * Add new components to existing components + * Add new dashlets to existing dashlets * - * @param array $components + * @param array $dashlets * @return $this */ - public function addComponents(array $components) + public function addDashlets(array $dashlets) { - /* @var $component Component */ - foreach ($components as $component) { - if (array_key_exists($component->getTitle(), $this->components)) { - if (preg_match('/_(\d+)$/', $component->getTitle(), $m)) { - $name = preg_replace('/_\d+$/', $m[1]++, $component->getTitle()); + /* @var $dashlet Dashlet */ + foreach ($dashlets as $dashlet) { + if (array_key_exists($dashlet->getTitle(), $this->dashlets)) { + if (preg_match('/_(\d+)$/', $dashlet->getTitle(), $m)) { + $name = preg_replace('/_\d+$/', $m[1]++, $dashlet->getTitle()); } else { - $name = $component->getTitle() . '_2'; + $name = $dashlet->getTitle() . '_2'; } - $this->components[$name] = $component; + $this->dashlets[$name] = $dashlet; } else { - $this->components[$component->getTitle()] = $component; + $this->dashlets[$dashlet->getTitle()] = $dashlet; } } @@ -219,19 +240,19 @@ class Pane extends AbstractWidget } /** - * Add a component to the current pane + * Add a dashlet to the current pane * * @param $title * @param $url - * @return Component + * @return Dashlet * - * @see addComponent() + * @see addDashlet() */ public function add($title, $url = null) { - $this->addComponent($title, $url); + $this->addDashlet($title, $url); - return $this->components[$title]; + return $this->dashlets[$title]; } /** @@ -241,23 +262,26 @@ class Pane extends AbstractWidget */ public function toArray() { - $array = array($this->getName() => array('title' => $this->getTitle())); - foreach ($this->components as $title => $component) { - $array[$this->getName() . ".$title"] = $component->toArray(); + $pane = array( + 'title' => $this->getTitle(), + ); + + if ($this->getDisabled() === true) { + $pane['disabled'] = 1; } - return $array; + return $pane; } /** * Create a new pane with the title $title from the given configuration * * @param $title The title for this pane - * @param Zend_Config $config The configuration to use for setup + * @param ConfigObject $config The configuration to use for setup * * @return Pane */ - public static function fromIni($title, Zend_Config $config) + public static function fromIni($title, ConfigObject $config) { $pane = new Pane($title); if ($config->get('title', false)) { @@ -265,4 +289,26 @@ class Pane extends AbstractWidget } return $pane; } + + /** + * Setter for disabled + * + * @param boolean $disabled + */ + public function setDisabled($disabled = true) + { + $this->disabled = (bool) $disabled; + } + + /** + * Getter for disabled + * + * @return boolean + */ + public function getDisabled() + { + return $this->disabled; + } + + } diff --git a/library/Icinga/Web/Widget/Dashboard/UserWidget.php b/library/Icinga/Web/Widget/Dashboard/UserWidget.php new file mode 100644 index 000000000..0b171964e --- /dev/null +++ b/library/Icinga/Web/Widget/Dashboard/UserWidget.php @@ -0,0 +1,37 @@ +userWidget = (bool) $userWidget; + } + + /** + * Getter for user widget flag + * + * @return boolean + */ + public function isUserWidget() + { + return $this->userWidget; + } +} diff --git a/library/Icinga/Web/Widget/FilterEditor.php b/library/Icinga/Web/Widget/FilterEditor.php index af46a40f2..3b7f10e9e 100644 --- a/library/Icinga/Web/Widget/FilterEditor.php +++ b/library/Icinga/Web/Widget/FilterEditor.php @@ -8,7 +8,9 @@ use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\FilterExpression; use Icinga\Data\Filter\FilterChain; use Icinga\Web\Url; +use Icinga\Application\Icinga; use Icinga\Exception\ProgrammingError; +use Exception; /** * Filter @@ -24,6 +26,16 @@ class FilterEditor extends AbstractWidget protected $query; + protected $url; + + protected $addTo; + + protected $cachedColumnSelect; + + protected $preserveParams = array(); + + protected $ignoreParams = array(); + /** * @var string */ @@ -36,10 +48,205 @@ class FilterEditor extends AbstractWidget */ public function __construct($props) { - $this->filter = $props['filter']; - if (array_key_exists('query', $props)) { - $this->query = $props['query']; + if (array_key_exists('filter', $props)) { + $this->setFilter($props['filter']); } + if (array_key_exists('query', $props)) { + $this->setQuery($props['query']); + } + } + + public function setFilter(Filter $filter) + { + $this->filter = $filter; + return $this; + } + + public function getFilter() + { + if ($this->filter === null) { + $this->filter = Filter::fromQueryString((string) $this->url()->getParams()); + } + return $this->filter; + } + + public function setUrl($url) + { + $this->url = $url; + return $this; + } + + protected function url() + { + if ($this->url === null) { + $this->url = Url::fromRequest(); + } + return $this->url; + } + + public function setQuery($query) + { + $this->query = $query; + return $this; + } + + public function ignoreParams() + { + $this->ignoreParams = func_get_args(); + return $this; + } + + public function preserveParams() + { + $this->preserveParams = func_get_args(); + return $this; + } + + protected function redirectNow($url) + { + $response = Icinga::app()->getFrontController()->getResponse(); + $response->redirectAndExit($url); + } + + protected function mergeRootExpression($filter, $column, $sign, $expression) + { + $found = false; + if ($filter->isChain() && $filter->getOperatorName() === 'AND') { + foreach ($filter->filters() as $f) { + if ($f->isExpression() + && $f->getColumn() === $column + && $f->getSign() === $sign + ) { + $f->setExpression($expression); + $found = true; + break; + } + } + } elseif ($filter->isExpression()) { + if ($filter->getColumn() === $column && $filter->getSign() === $sign) { + $filter->setExpression($expression); + $found = true; + } + } + if (! $found) { + $filter = $filter->andFilter( + Filter::expression($column, $sign, $expression) + ); + } + return $filter; + } + + public function handleRequest($request) + { + $this->setUrl($request->getUrl()->without($this->ignoreParams)); + $params = $this->url()->getParams(); + + $preserve = array(); + foreach ($this->preserveParams as $key) { + if (null !== ($value = $params->shift($key))) { + $preserve[$key] = $value; + } + } + + $add = $params->shift('addFilter'); + $remove = $params->shift('removeFilter'); + $strip = $params->shift('stripFilter'); + $modify = $params->shift('modifyFilter'); + + + + $search = null; + if ($request->isPost()) { + $search = $request->getPost('q'); + } + + if ($search === null) { + $search = $params->shift('q'); + } + + $filter = $this->getFilter(); + + if ($search !== null) { + if (strpos($search, '=') === false) { + // TODO: Ask the view for (multiple) search columns + switch($request->getActionName()) { + case 'services': + $searchCol = 'service_description'; + break; + case 'hosts': + $searchCol = 'host_name'; + break; + case 'hostgroups': + $searchCol = 'hostgroup'; + break; + case 'servicegroups': + $searchCol = 'servicegroup'; + break; + default: + $searchCol = null; + } + + if ($searchCol === null) { + throw new Exception('Cannot search here'); + } + $filter = $this->mergeRootExpression($filter, $searchCol, '=', "*$search*"); + + } else { + list($k, $v) = preg_split('/=/', $search); + $filter = $this->mergeRootExpression($filter, $k, '=', $v); + } + + $url = $this->url()->setQueryString( + $filter->toQueryString() + )->addParams($preserve); + if ($modify) { + $url->getParams()->add('modifyFilter'); + } + $this->redirectNow($url); + } + + if ($remove) { + $redirect = $this->url(); + if ($filter->getById($remove)->isRootNode()) { + $redirect->setQueryString(''); + } else { + $filter->removeId($remove); + $redirect->setQueryString($filter->toQueryString())->getParams()->add('modifyFilter'); + } + $this->redirectNow($redirect->addParams($preserve)); + } + + if ($strip) { + $redirect = $this->url(); + $subId = $strip . '-1'; + if ($filter->getId() === $strip) { + $filter = $filter->getById($strip . '-1'); + } else { + $filter->replaceById($strip, $filter->getById($strip . '-1')); + } + $redirect->setQueryString($filter->toQueryString())->getParams()->add('modifyFilter'); + $this->redirectNow($redirect->addParams($preserve)); + } + + + if ($modify) { + if ($request->isPost()) { + if ($request->get('cancel') === 'Cancel') { + $this->redirectNow($this->url()->without('modifyFilter')); + } + + $filter = $this->applyChanges($request->getPost()); + $url = $this->url()->setQueryString($filter->toQueryString())->addParams($preserve); + $url->getParams()->add('modifyFilter'); + $this->redirectNow($url); + } + $this->url()->getParams()->add('modifyFilter'); + } + + if ($add) { + $this->addFilterToId($add); + } + return $this; } protected function select($name, $list, $selected, $attributes = null) @@ -50,9 +257,12 @@ class FilterEditor extends AbstractWidget } else { $attributes = $view->propertiesToString($attributes); } - $html = '' . "\n", + $view->escape($name), + $attributes + ); - asort($list); foreach ($list as $k => $v) { $active = ''; if ($k === $selected) { @@ -69,100 +279,169 @@ class FilterEditor extends AbstractWidget return $html; } - public function markIndex($idx) + protected function addFilterToId($id) + { + $this->addTo = $id; + return $this; + } + + protected function removeIndex($idx) { $this->selectedIdx = $idx; return $this; } - public function removeIndex($idx) + protected function removeLink(Filter $filter) { - $this->selectedIdx = $idx; - return $this; + return $this->view()->qlink( + '', + $this->url()->with('removeFilter', $filter->getId()), + null, + array( + 'title' => t('Click to remove this part of your filter'), + 'class' => 'icon-cancel' + ) + ); + } + + protected function addLink(Filter $filter) + { + return $this->view()->qlink( + '', + $this->url()->with('addFilter', $filter->getId()), + null, + array( + 'title' => t('Click to add another filter'), + 'class' => 'icon-plus' + ) + ); + } + + protected function stripLink(Filter $filter) + { + return $this->view()->qlink( + '', + $this->url()->with('stripFilter', $filter->getId()), + null, + array( + 'title' => t('Strip this filter'), + 'class' => 'icon-minus' + ) + ); + } + + protected function cancelLink() + { + return $this->view()->qlink( + '', + $this->url()->without('addFilter'), + null, + array( + 'title' => t('Cancel this operation'), + 'class' => 'icon-cancel' + ) + ); } protected function renderFilter($filter, $level = 0) { - $html = ''; - $url = Url::fromRequest(); - - $view = $this->view(); - $idx = $filter->getId(); - $markUrl = clone($url); - $markUrl->setParam('fIdx', $idx); - - $removeUrl = clone $url; - $removeUrl->setParam('removeFilter', $idx); - $removeLink = ' ' . $view->icon('remove.png') . ''; - - /* - // Temporarilly removed, not implemented yet - $addUrl = clone($url); - $addUrl->setParam('addToId', $idx); - $addLink = ' ' . t('Operator') . ' (&, !, |)'; - $addLink .= ' ' . t('Expression') . ' (=, <, >, <=, >=)'; - */ - $selectedIndex = ($idx === $this->selectedIdx ? ' -<--' : ''); - $selectIndex = ' o'; + if ($level === 0 && $filter->isChain() && $filter->isEmpty()) { + return '
  • ' . $this->renderNewFilter() . '
'; + } if ($filter instanceof FilterChain) { - $parts = array(); - $i = 0; + return $this->renderFilterChain($filter, $level); + } elseif ($filter instanceof FilterExpression) { + return $this->renderFilterExpression($filter); + } else { + throw new ProgrammingError('Got a Filter being neither expression nor chain'); + } + } - foreach ($filter->filters() as $f) { - $i++; - $parts[] = $this->renderFilter($f, $level + 1); - } + protected function renderFilterChain(FilterChain $filter, $level) + { + $html = ' ' + . $this->selectOperator($filter) + . $this->removeLink($filter) + . ($filter->count() === 1 ? $this->stripLink($filter) : '') + . $this->addLink($filter); - $op = $this->select( - 'operator_' . $filter->getId(), - array( - 'OR' => 'OR', - 'AND' => 'AND', - 'NOT' => 'NOT' - ), - $filter->getOperatorName(), - array('style' => 'width: 5em') - ) . $removeLink; // Disabled: . ' ' . t('Add') . ': ' . $addLink; - $html .= ' '; - - if ($level === 0) { - $html .= $op; - if (! empty($parts)) { - $html .= '
  • ' - . implode('
  • ', $parts) - . '
'; - } - } else { - $html .= $op . "
    \n
  • \n" . implode("
  • \n
  • ", $parts) . "
  • \n
\n"; - } + if ($filter->isEmpty() && ! $this->addTo) { return $html; } - if ($filter instanceof FilterExpression) { - $u = $url->without($filter->getColumn()); - } else { - throw new ProgrammingError('Got a Filter being neither expression nor chain'); + $parts = array(); + foreach ($filter->filters() as $f) { + $parts[] = '
  • ' . $this->renderFilter($f, $level + 1) . '
  • '; } - $value = $filter->getExpression(); + + if ($this->addTo && $this->addTo == $filter->getId()) { + $parts[] = '
  • ' . $this->renderNewFilter() .$this->cancelLink(). '
  • '; + } + + $class = $level === 0 ? ' class="datafilter"' : ''; + $html .= sprintf( + "\n%s\n", + $class, + implode("", $parts) + ); + return $html; + } + + protected function renderFilterExpression(FilterExpression $filter) + { + if ($this->addTo && $this->addTo === $filter->getId()) { + return + preg_replace( + '/ class="autosubmit"/', + ' class="autofocus"', + $this->selectOperator() + ) + . '
    • ' + . $this->selectColumn($filter) + . $this->selectSign($filter) + . $this->text($filter) + . $this->removeLink($filter) + . $this->addLink($filter) + . '
    • ' + . $this->renderNewFilter() .$this->cancelLink() + . '
    ' + ; + } else { + return $this->selectColumn($filter) + . $this->selectSign($filter) + . $this->text($filter) + . $this->removeLink($filter) + . $this->addLink($filter) + ; + + } + } + + protected function text(Filter $filter = null) + { + $value = $filter === null ? '' : $filter->getExpression(); if (is_array($value)) { $value = '(' . implode('|', $value) . ')'; } - $html .= $this->selectColumn($filter) . ' ' - . $this->selectSign($filter) - . ' ' . $removeLink; + return sprintf( + '', + $this->elementId('value', $filter), + $value + ); + } - return $html; + protected function renderNewFilter() + { + $html = $this->selectColumn() + . $this->selectSign() + . $this->text(); + + return preg_replace( + '/ class="autosubmit"/', + '', + $html + ); } protected function arrayForSelect($array) @@ -179,9 +458,33 @@ class FilterEditor extends AbstractWidget return $res; } - protected function selectSign($filter) + protected function elementId($prefix, Filter $filter = null) + { + if ($filter === null) { + return $prefix . '_new_' . ($this->addTo ?: '0'); + } else { + return $prefix . '_' . $filter->getId(); + } + } + + protected function selectOperator(Filter $filter = null) + { + $ops = array( + 'AND' => 'AND', + 'OR' => 'OR', + 'NOT' => 'NOT' + ); + + return $this->select( + $this->elementId('operator', $filter), + $ops, + $filter === null ? null : $filter->getOperatorName(), + array('style' => 'width: 5em') + ); + } + + protected function selectSign(Filter $filter = null) { - $name = 'sign_' . $filter->getId(); $signs = array( '=' => '=', '!=' => '!=', @@ -192,17 +495,30 @@ class FilterEditor extends AbstractWidget ); return $this->select( - $name, + $this->elementId('sign', $filter), $signs, - $filter->getSign(), + $filter === null ? null : $filter->getSign(), array('style' => 'width: 4em') ); } - protected function selectColumn($filter) + + protected function selectColumn(Filter $filter = null) { - $name = 'column_' . $filter->getId(); - $cols = $this->arrayForSelect($this->query->getColumns()); - $active = $filter->getColumn(); + $active = $filter === null ? null : $filter->getColumn(); + + if ($this->query === null) { + return sprintf( + '', + $this->elementId('column', $filter), + $this->view()->escape($active) // Escape attribute? + ); + } + + if ($this->cachedColumnSelect === null) { + $this->cachedColumnSelect = $this->arrayForSelect($this->query->getColumns()); + asort($this->cachedColumnSelect); + } + $cols = $this->cachedColumnSelect; $seen = false; foreach ($cols as $k => & $v) { $v = str_replace('_', ' ', ucfirst($v)); @@ -215,32 +531,169 @@ class FilterEditor extends AbstractWidget $cols[$active] = str_replace('_', ' ', ucfirst(ltrim($active, '_'))); } - if ($this->query === null) { - return sprintf( - '', - $name, - $filter->getColumn() - ); - } else { - return $this->select( - $name, - $cols, - $active - ); + return $this->select($this->elementId('column', $filter), $cols, $active); + } + + protected function applyChanges($changes) + { + $filter = $this->filter; + $pairs = array(); + $addTo = null; + $add = array(); + foreach ($changes as $k => $v) { + if (preg_match('/^(column|value|sign|operator)((?:_new)?)_([\d-]+)$/', $k, $m)) { + if ($m[2] === '_new') { + if ($addTo !== null && $addTo !== $m[3]) { + throw new \Exception('F...U'); + } + $addTo = $m[3]; + $add[$m[1]] = $v; + } else { + $pairs[$m[3]][$m[1]] = $v; + } + } } + + $operators = array(); + foreach ($pairs as $id => $fs) { + if (array_key_exists('operator', $fs)) { + $operators[$id] = $fs['operator']; + } else { + $f = $filter->getById($id); + $f->setColumn($fs['column']); + if ($f->getSign() !== $fs['sign']) { + if ($f->isRootNode()) { + $filter = $f->setSign($fs['sign']); + } else { + $filter->replaceById($id, $f->setSign($fs['sign'])); + } + } + $f->setExpression($fs['value']); + } + } + + krsort($operators, version_compare(PHP_VERSION, '5.4.0') >= 0 ? SORT_NATURAL : SORT_REGULAR); + foreach ($operators as $id => $operator) { + $f = $filter->getById($id); + if ($f->getOperatorName() !== $operator) { + if ($f->isRootNode()) { + $filter = $f->setOperatorName($operator); + } else { + $filter->replaceById($id, $f->setOperatorName($operator)); + } + } + } + + if ($addTo !== null) { + if ($addTo === '0') { + $filter = Filter::expression($add['column'], $add['sign'], $add['value']); + } else { + $parent = $filter->getById($addTo); + $f = Filter::expression($add['column'], $add['sign'], $add['value']); + if (isset($add['operator'])) { + switch($add['operator']) { + case 'AND': + if ($parent->isExpression()) { + if ($parent->isRootNode()) { + $filter = Filter::matchAll(clone $parent, $f); + } else { + $filter = $filter->replaceById($addTo, Filter::matchAll(clone $parent, $f)); + } + } else { + $parent->addFilter(Filter::matchAll($f)); + } + break; + case 'OR': + if ($parent->isExpression()) { + if ($parent->isRootNode()) { + $filter = Filter::matchAny(clone $parent, $f); + } else { + $filter = $filter->replaceById($addTo, Filter::matchAny(clone $parent, $f)); + } + } else { + $parent->addFilter(Filter::matchAny($f)); + } + break; + case 'NOT': + if ($parent->isExpression()) { + if ($parent->isRootNode()) { + $filter = Filter::not(Filter::matchAll($parent, $f)); + } else { + $filter = $filter->replaceById($addTo, Filter::not(Filter::matchAll($parent, $f))); + } + } else { + $parent->addFilter(Filter::not($f)); + } + break; + } + } else { + $parent->addFilter($f); + } + } + } + + return $filter; + } + + public function renderSearch() + { + $html = '
    '; + + if ($this->filter->isEmpty()) { + $title = t('Filter this list'); + } else { + $title = t('Modify this filter'); + if (! $this->filter->isEmpty()) { + $title .= ': ' . $this->filter; + } + } + return $html + . '' + . '' + . ''; } public function render() { - return '

    ' - . t('Modify this filter') - . '

    ' + if (! $this->url()->getParam('modifyFilter')) { + return $this->renderSearch() . $this->shorten($this->filter, 50); + } + return $this->renderSearch() . '
    ' - . '
    • ' + . '
      • ' . $this->renderFilter($this->filter) - . '

      ' + . '
    ' + . '
    ' + . '' + . '' + . '
    ' . '
    '; } + + protected function shorten($string, $length) + { + if (strlen($string) > $length) { + return substr($string, 0, $length) . '...'; + } + return $string; + } + + public function __toString() + { + try { + return $this->render(); + } catch (Exception $e) { + return 'ERROR in FilterEditor: ' . $e->getMessage(); + } + } } diff --git a/library/Icinga/Web/Widget/FilterWidget.php b/library/Icinga/Web/Widget/FilterWidget.php index 013f9b252..cf47ef581 100644 --- a/library/Icinga/Web/Widget/FilterWidget.php +++ b/library/Icinga/Web/Widget/FilterWidget.php @@ -88,7 +88,7 @@ class FilterWidget extends AbstractWidget $editorUrl->setParam('modifyFilter', true); if ($this->filter->isEmpty()) { $title = t('Filter this list'); - $txt = $view->icon('create.png'); + $txt = $view->icon('plus'); $remove = ''; } else { $txt = t('Filtered'); @@ -98,7 +98,7 @@ class FilterWidget extends AbstractWidget . '" title="' . t('Remove this filter') . '">' - . $view->icon('remove.png') + . $view->icon('cancel') . ''; } $filter = $this->filter->isEmpty() ? '' : ': ' . $this->filter; diff --git a/library/Icinga/Web/Widget/SearchDashboard.php b/library/Icinga/Web/Widget/SearchDashboard.php index 39cc12555..9e02f3373 100644 --- a/library/Icinga/Web/Widget/SearchDashboard.php +++ b/library/Icinga/Web/Widget/SearchDashboard.php @@ -48,7 +48,7 @@ class SearchDashboard extends Dashboard */ public function render() { - if (! $this->getPane(self::SEARCH_PANE)->hasComponents()) { + if (! $this->getPane(self::SEARCH_PANE)->hasDashlets()) { throw new ActionError('Site not found', 404); } return parent::render(); @@ -70,8 +70,8 @@ class SearchDashboard extends Dashboard $this->addSearchDashletsFromModule($searchString, $module, $pane); } - if ($searchString === '' && $pane->hasComponents()) { - $pane->removeComponents(); + if ($searchString === '' && $pane->hasDashlets()) { + $pane->removeDashlets(); $pane->add('Ready to search', 'search/hint'); return; } @@ -91,7 +91,7 @@ class SearchDashboard extends Dashboard if (! empty($searchUrls)) { $this->searchUrls[] = $module->getSearchUrls(); foreach ($searchUrls as $search) { - $pane->addComponent( + $pane->addDashlet( $search->title . ': ' . $searchString, Url::fromPath($search->url, array('q' => $searchString)) ); diff --git a/library/Icinga/Web/Widget/Tab.php b/library/Icinga/Web/Widget/Tab.php index 92a1a9954..a06389b98 100644 --- a/library/Icinga/Web/Widget/Tab.php +++ b/library/Icinga/Web/Widget/Tab.php @@ -85,7 +85,7 @@ class Tab extends AbstractWidget */ public function setIcon($icon) { - if (is_string($icon)) { + if (is_string($icon) && strpos($icon, '.') !== false) { $icon = Url::fromPath($icon); } $this->icon = $icon; @@ -197,27 +197,41 @@ class Tab extends AbstractWidget public function render() { $view = $this->view(); - $class = $this->active ? ' class="active" ' : ''; + $classes = array(); + if ($this->active) { + $classes[] = 'active'; + } $caption = $view->escape($this->title); + $tagParams = $this->tagParams; if ($this->icon !== null) { - $caption = $view->img($this->icon, array('class' => 'icon')) . ' ' . $caption; + if (strpos($this->icon, '.') === false) { + if ($tagParams && array_key_exists('class', $tagParams)) { + $tagParams['class'] .= ' icon-' . $this->icon; + } else { + $tagParams['class'] = 'icon-' . $this->icon; + } + } else { + $caption = $view->img($this->icon, array('class' => 'icon')) . $caption; + } } if ($this->url !== null) { $this->url->overwriteParams($this->urlParams); - $tagParams = ''; - if ($this->tagParams !== null) { - $tagParams = $view->propertiesToString($this->tagParams); + if ($tagParams !== null) { + $params = $view->propertiesToString($tagParams); + } else { + $params = ''; } $tab = sprintf( '%s', $this->url, - $tagParams, + $params, $caption ); } else { $tab = $caption; } + $class = empty($classes) ? '' : sprintf(' class="%s"', implode(' ', $classes)); return '
  • ' . $tab . "
  • \n"; } } diff --git a/library/Icinga/Web/Widget/Tabextension/DashboardAction.php b/library/Icinga/Web/Widget/Tabextension/DashboardAction.php index 241b83556..280a9b142 100644 --- a/library/Icinga/Web/Widget/Tabextension/DashboardAction.php +++ b/library/Icinga/Web/Widget/Tabextension/DashboardAction.php @@ -24,9 +24,9 @@ class DashboardAction implements Tabextension $tabs->addAsDropdown( 'dashboard', array( - 'icon' => 'img/icons/dashboard.png', + 'icon' => 'dashboard', 'title' => 'Add To Dashboard', - 'url' => Url::fromPath('dashboard/addurl'), + 'url' => Url::fromPath('dashboard/new-dashlet'), 'urlParams' => array( 'url' => rawurlencode(Url::fromRequest()->getRelativeUrl()) ) diff --git a/library/Icinga/Web/Widget/Tabextension/DashboardSettings.php b/library/Icinga/Web/Widget/Tabextension/DashboardSettings.php new file mode 100644 index 000000000..496fe3495 --- /dev/null +++ b/library/Icinga/Web/Widget/Tabextension/DashboardSettings.php @@ -0,0 +1,40 @@ +addAsDropdown( + 'dashboard_add', + array( + 'icon' => 'img/icons/dashboard.png', + 'title' => t('Add To Dashboard'), + 'url' => Url::fromPath('dashboard/new-dashlet') + ) + ); + + $tabs->addAsDropdown( + 'dashboard_settings', + array( + 'icon' => 'img/icons/dashboard.png', + 'title' => t('Settings'), + 'url' => Url::fromPath('dashboard/settings') + ) + ); + } +} \ No newline at end of file diff --git a/library/Icinga/Web/Widget/Tabextension/OutputFormat.php b/library/Icinga/Web/Widget/Tabextension/OutputFormat.php index 46c55fad2..b5426ea47 100644 --- a/library/Icinga/Web/Widget/Tabextension/OutputFormat.php +++ b/library/Icinga/Web/Widget/Tabextension/OutputFormat.php @@ -40,13 +40,13 @@ class OutputFormat implements Tabextension self::TYPE_PDF => array( 'name' => 'pdf', 'title' => 'PDF', - 'icon' => 'img/icons/pdf.png', + 'icon' => 'file-pdf', 'urlParams' => array('format' => 'pdf'), ), self::TYPE_CSV => array( 'name' => 'csv', 'title' => 'CSV', - 'icon' => 'img/icons/csv.png', + 'icon' => 'file-excel', 'urlParams' => array('format' => 'csv') ), self::TYPE_JSON => array( diff --git a/library/Icinga/Web/Widget/Tabs.php b/library/Icinga/Web/Widget/Tabs.php index b2a34e0ec..72522282e 100644 --- a/library/Icinga/Web/Widget/Tabs.php +++ b/library/Icinga/Web/Widget/Tabs.php @@ -34,7 +34,7 @@ EOT; */ private $dropdownTpl = <<< 'EOT'